2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.intellij
.codeInsight
.editorActions
;
18 import com
.intellij
.codeInsight
.CodeInsightSettings
;
19 import com
.intellij
.codeInsight
.daemon
.impl
.CollectHighlightsUtil
;
20 import com
.intellij
.openapi
.editor
.Editor
;
21 import com
.intellij
.openapi
.editor
.Document
;
22 import com
.intellij
.openapi
.editor
.RangeMarker
;
23 import com
.intellij
.openapi
.util
.TextRange
;
24 import com
.intellij
.openapi
.project
.Project
;
25 import com
.intellij
.openapi
.project
.DumbService
;
26 import com
.intellij
.openapi
.application
.ApplicationManager
;
27 import com
.intellij
.openapi
.diagnostic
.Logger
;
28 import com
.intellij
.psi
.*;
29 import com
.intellij
.util
.IncorrectOperationException
;
30 import org
.jetbrains
.annotations
.Nullable
;
32 import java
.awt
.datatransfer
.Transferable
;
33 import java
.awt
.datatransfer
.UnsupportedFlavorException
;
34 import java
.io
.IOException
;
35 import java
.util
.ArrayList
;
36 import java
.util
.List
;
37 import java
.util
.Arrays
;
38 import java
.util
.Comparator
;
40 public class CopyPasteReferenceProcessor
implements CopyPastePostProcessor
{
41 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.editorActions.CopyPasteReferenceProcessor");
43 public TextBlockTransferableData
collectTransferableData(PsiFile file
, final Editor editor
, final int[] startOffsets
, final int[] endOffsets
) {
44 if (file
instanceof PsiCompiledElement
) {
45 file
= (PsiFile
) ((PsiCompiledElement
) file
).getMirror();
48 final ArrayList
<ReferenceTransferableData
.ReferenceData
> array
= new ArrayList
<ReferenceTransferableData
.ReferenceData
>();
49 for (int j
= 0; j
< startOffsets
.length
; j
++) {
50 final int startOffset
= startOffsets
[j
];
51 final int endOffset
= endOffsets
[j
];
52 final List
<PsiElement
> elements
= CollectHighlightsUtil
.getElementsInRange(file
, startOffset
, endOffset
);
53 for (final PsiElement element
: elements
) {
54 if (element
instanceof PsiJavaCodeReferenceElement
) {
55 if (!((PsiJavaCodeReferenceElement
)element
).isQualified()) {
56 final JavaResolveResult resolveResult
= ((PsiJavaCodeReferenceElement
)element
).advancedResolve(false);
57 final PsiElement refElement
= resolveResult
.getElement();
58 if (refElement
!= null && refElement
.getContainingFile() != file
) {
60 if (refElement
instanceof PsiClass
) {
61 if (refElement
.getContainingFile() != element
.getContainingFile()) {
62 final String qName
= ((PsiClass
)refElement
).getQualifiedName();
64 addReferenceData(element
, array
, startOffset
, qName
, null);
68 else if (resolveResult
.getCurrentFileResolveScope() instanceof PsiImportStaticStatement
) {
69 final String classQName
= ((PsiMember
)refElement
).getContainingClass().getQualifiedName();
70 final String name
= ((PsiNamedElement
)refElement
).getName();
71 if (classQName
!= null && name
!= null) {
72 addReferenceData(element
, array
, startOffset
, classQName
, name
);
80 return new ReferenceTransferableData(array
.toArray(new ReferenceTransferableData
.ReferenceData
[array
.size()]));
84 public TextBlockTransferableData
extractTransferableData(final Transferable content
) {
85 ReferenceTransferableData referenceData
= null;
86 if (CodeInsightSettings
.getInstance().ADD_IMPORTS_ON_PASTE
!= CodeInsightSettings
.NO
) {
88 referenceData
= (ReferenceTransferableData
)content
.getTransferData(ReferenceTransferableData
.ReferenceData
.FLAVOR
);
90 catch (UnsupportedFlavorException ignored
) {
92 catch (IOException ignored
) {
96 if (referenceData
!= null) { // copy to prevent changing of original by convertLineSeparators
97 return referenceData
.clone();
103 public void processTransferableData(final Project project
, final Editor editor
, final RangeMarker bounds
, final TextBlockTransferableData value
) {
104 if (DumbService
.getInstance(project
).isDumb()) {
108 final Document document
= editor
.getDocument();
109 final PsiFile file
= PsiDocumentManager
.getInstance(project
).getPsiFile(document
);
111 PsiDocumentManager
.getInstance(project
).commitAllDocuments();
112 final ReferenceTransferableData
.ReferenceData
[] referenceData
= ((ReferenceTransferableData
)value
).getData();
113 final PsiJavaCodeReferenceElement
[] refs
= findReferencesToRestore(file
, bounds
, referenceData
);
114 if (CodeInsightSettings
.getInstance().ADD_IMPORTS_ON_PASTE
== CodeInsightSettings
.ASK
) {
115 askReferencesToRestore(project
, refs
, referenceData
);
117 PsiDocumentManager
.getInstance(project
).commitAllDocuments();
118 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
120 restoreReferences(referenceData
, refs
);
125 private static void addReferenceData(final PsiElement element
,
126 final ArrayList
<ReferenceTransferableData
.ReferenceData
> array
,
127 final int startOffset
,
128 final String qClassName
, final String staticMemberName
) {
129 final TextRange range
= element
.getTextRange();
131 new ReferenceTransferableData
.ReferenceData(
132 range
.getStartOffset() - startOffset
,
133 range
.getEndOffset() - startOffset
,
134 qClassName
, staticMemberName
));
137 private static PsiJavaCodeReferenceElement
[] findReferencesToRestore(PsiFile file
,
139 ReferenceTransferableData
.ReferenceData
[] referenceData
) {
140 PsiManager manager
= file
.getManager();
141 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(manager
.getProject());
142 PsiResolveHelper helper
= facade
.getResolveHelper();
143 PsiJavaCodeReferenceElement
[] refs
= new PsiJavaCodeReferenceElement
[referenceData
.length
];
144 for (int i
= 0; i
< referenceData
.length
; i
++) {
145 ReferenceTransferableData
.ReferenceData data
= referenceData
[i
];
147 PsiClass refClass
= facade
.findClass(data
.qClassName
, file
.getResolveScope());
148 if (refClass
== null) continue;
150 int startOffset
= data
.startOffset
+ bounds
.getStartOffset();
151 int endOffset
= data
.endOffset
+ bounds
.getStartOffset();
152 PsiElement element
= file
.findElementAt(startOffset
);
154 if (element
instanceof PsiIdentifier
&& element
.getParent() instanceof PsiJavaCodeReferenceElement
) {
155 PsiJavaCodeReferenceElement reference
= (PsiJavaCodeReferenceElement
)element
.getParent();
156 TextRange range
= reference
.getTextRange();
157 if (range
.getStartOffset() == startOffset
&& range
.getEndOffset() == endOffset
) {
158 if (data
.staticMemberName
== null) {
159 PsiClass refClass1
= helper
.resolveReferencedClass(reference
.getText(), reference
);
160 if (refClass1
== null || !manager
.areElementsEquivalent(refClass
, refClass1
)) {
165 if (reference
instanceof PsiReferenceExpression
) {
166 PsiElement referent
= reference
.resolve();
167 if (!(referent
instanceof PsiNamedElement
)
168 || !data
.staticMemberName
.equals(((PsiNamedElement
)referent
).getName())
169 || !(referent
instanceof PsiMember
)
170 || ((PsiMember
)referent
).getContainingClass() == null
171 || !data
.qClassName
.equals(((PsiMember
)referent
).getContainingClass().getQualifiedName())) {
182 private static void restoreReferences(ReferenceTransferableData
.ReferenceData
[] referenceData
,
183 PsiJavaCodeReferenceElement
[] refs
) {
184 for (int i
= 0; i
< refs
.length
; i
++) {
185 PsiJavaCodeReferenceElement reference
= refs
[i
];
186 if (reference
== null) continue;
188 PsiManager manager
= reference
.getManager();
189 ReferenceTransferableData
.ReferenceData refData
= referenceData
[i
];
190 PsiClass refClass
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass(refData
.qClassName
, reference
.getResolveScope());
191 if (refClass
!= null) {
192 if (refData
.staticMemberName
== null) {
193 reference
.bindToElement(refClass
);
196 LOG
.assertTrue(reference
instanceof PsiReferenceExpression
);
197 ((PsiReferenceExpression
)reference
).bindToElementViaStaticImport(refClass
);
201 catch (IncorrectOperationException e
) {
207 private static void askReferencesToRestore(Project project
, PsiJavaCodeReferenceElement
[] refs
,
208 ReferenceTransferableData
.ReferenceData
[] referenceData
) {
209 PsiManager manager
= PsiManager
.getInstance(project
);
211 ArrayList
<Object
> array
= new ArrayList
<Object
>();
212 Object
[] refObjects
= new Object
[refs
.length
];
213 for (int i
= 0; i
< referenceData
.length
; i
++) {
214 PsiJavaCodeReferenceElement ref
= refs
[i
];
216 LOG
.assertTrue(ref
.isValid());
217 ReferenceTransferableData
.ReferenceData data
= referenceData
[i
];
218 PsiClass refClass
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass(data
.qClassName
, ref
.getResolveScope());
219 if (refClass
== null) continue;
221 Object refObject
= refClass
;
222 if (data
.staticMemberName
!= null) {
223 //Show static members as Strings
224 refObject
= refClass
.getQualifiedName() + "." + data
.staticMemberName
;
226 refObjects
[i
] = refObject
;
228 if (!array
.contains(refObject
)) {
229 array
.add(refObject
);
233 if (array
.isEmpty()) return;
235 Object
[] selectedObjects
= array
.toArray(new Object
[array
.size()]);
238 new Comparator
<Object
>() {
239 public int compare(Object o1
, Object o2
) {
240 String fqName1
= getFQName(o1
);
241 String fqName2
= getFQName(o2
);
242 return fqName1
.compareToIgnoreCase(fqName2
);
247 RestoreReferencesDialog dialog
= new RestoreReferencesDialog(project
, selectedObjects
);
249 selectedObjects
= dialog
.getSelectedElements();
251 for (int i
= 0; i
< referenceData
.length
; i
++) {
252 PsiJavaCodeReferenceElement ref
= refs
[i
];
254 LOG
.assertTrue(ref
.isValid());
255 Object refObject
= refObjects
[i
];
256 boolean found
= false;
257 for (Object selected
: selectedObjects
) {
258 if (refObject
.equals(selected
)) {
270 private static String
getFQName(Object element
) {
271 return element
instanceof PsiClass ?
((PsiClass
)element
).getQualifiedName() : (String
)element
;