d064482904e85e84243ed208e49386e9b70f3213
[idea/community.git] / platform / platform-api / src / com / intellij / openapi / ide / KillRingTransferable.java
1 /*
2  * Copyright 2000-2011 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.ide;
17
18 import com.intellij.openapi.editor.Document;
19 import org.jetbrains.annotations.NotNull;
20 import org.jetbrains.annotations.Nullable;
21
22 import java.awt.datatransfer.DataFlavor;
23 import java.awt.datatransfer.StringSelection;
24 import java.awt.datatransfer.Transferable;
25 import java.awt.datatransfer.UnsupportedFlavorException;
26 import java.io.IOException;
27 import java.lang.ref.WeakReference;
28
29 /**
30  * This class represents usual {@link StringSelection transferable string} with additional meta-information that describes the place
31  * of the document that from there it was retrieved.
32  * <p/>
33  * The main idea is that we want to be able to combine adjacent text into single unit like
34  * <a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/Kill-Ring.html#Kill-Ring">emacs kill ring</a> does.
35  * E.g. if the user invokes 'cut to the line end' subsequently we may want to paste all of them, hence, we need to be able
36  * to distinguish if particular copy-paste strings are adjacent.
37  * <p/>
38  * Thread-safe.
39  * 
40  * @author Denis Zhdanov
41  * @since 4/15/11 6:29 PM
42  */
43 public class KillRingTransferable implements Transferable {
44
45   private static final DataFlavor[] DATA_FLAVORS = {DataFlavor.stringFlavor};
46
47   private final String                  myData;
48   private final WeakReference<Document> myDocument;
49   private final int                     myStartOffset;
50   private final int myEndOffset;
51   private final boolean                 myCut;
52   
53   private volatile boolean myReadyToCombine = true;
54
55   /**
56    * Creates new <code>KillRingTransferable</code> object.
57    * 
58    * @param data                target text to transfer
59    * @param document            document that contained given text
60    * @param startOffset         start offset of the given text at the given document
61    * @param endOffset       end offset of the given text during current object construction
62    * @param cut                 flag that identifies whether target text was cut or copied from the document
63    */
64   public KillRingTransferable(@NotNull String data,
65                               @NotNull Document document,
66                               int startOffset,
67                               int endOffset,
68                               boolean cut)
69   {
70     myData = data;
71     myDocument = new WeakReference<>(document);
72     myStartOffset = startOffset;
73     myEndOffset = endOffset;
74     myCut = cut;
75   }
76
77   @Override
78   public DataFlavor[] getTransferDataFlavors() {
79     return DATA_FLAVORS;
80   }
81
82   @Override
83   public boolean isDataFlavorSupported(DataFlavor flavor) {
84     return flavor == DataFlavor.stringFlavor;
85   }
86
87   @Nullable
88   @Override
89   public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
90     return isDataFlavorSupported(flavor) ? myData : null;
91   }
92
93   @Nullable
94   public Document getDocument() {
95     return myDocument.get();
96   }
97
98   public int getStartOffset() {
99     return myStartOffset;
100   }
101
102   /**
103    * @return    offset of the target text end on the moment of the current object construction
104    */
105   public int getEndOffset() {
106     return myEndOffset;
107   }
108
109   public boolean isCut() {
110     return myCut;
111   }
112
113   /**
114    * @return    <code>true</code> if current object can be combined with adjacent text; <code>false</code> otherwise.
115    *            Default value is <code>true</code>
116    */
117   public boolean isReadyToCombine() {
118     return myReadyToCombine;
119   }
120
121   /**
122    * Allows to define if current object can be combined with adjacent text. 
123    * 
124    * @param readyToCombine    <code>true</code> if current object can be combined with adjacent text; <code>false</code> otherwise
125    */
126   public void setReadyToCombine(boolean readyToCombine) {
127     myReadyToCombine = readyToCombine;
128   }
129
130   @Override
131   public String toString() {
132     return "data='" + myData + "', startOffset=" + myStartOffset + ", endOffset=" + myEndOffset +", cut=" + myCut;
133   }
134 }