update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / editorActions / CopyPasteReferenceProcessor.java
blob30c4ebcc7c31114dd90695cf23e6e116cdd80a5b
1 /*
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();
63 if (qName != null) {
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()]));
83 @Nullable
84 public TextBlockTransferableData extractTransferableData(final Transferable content) {
85 ReferenceTransferableData referenceData = null;
86 if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE != CodeInsightSettings.NO) {
87 try {
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();
100 return null;
103 public void processTransferableData(final Project project, final Editor editor, final RangeMarker bounds, final TextBlockTransferableData value) {
104 if (DumbService.getInstance(project).isDumb()) {
105 return;
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() {
119 public void run() {
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();
130 array.add(
131 new ReferenceTransferableData.ReferenceData(
132 range.getStartOffset() - startOffset,
133 range.getEndOffset() - startOffset,
134 qClassName, staticMemberName));
137 private static PsiJavaCodeReferenceElement[] findReferencesToRestore(PsiFile file,
138 RangeMarker bounds,
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)) {
161 refs[i] = reference;
164 else {
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())) {
172 refs[i] = reference;
179 return refs;
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;
187 try {
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);
195 else {
196 LOG.assertTrue(reference instanceof PsiReferenceExpression);
197 ((PsiReferenceExpression)reference).bindToElementViaStaticImport(refClass);
201 catch (IncorrectOperationException e) {
202 LOG.error(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];
215 if (ref != null) {
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()]);
236 Arrays.sort(
237 selectedObjects,
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);
248 dialog.show();
249 selectedObjects = dialog.getSelectedElements();
251 for (int i = 0; i < referenceData.length; i++) {
252 PsiJavaCodeReferenceElement ref = refs[i];
253 if (ref != null) {
254 LOG.assertTrue(ref.isValid());
255 Object refObject = refObjects[i];
256 boolean found = false;
257 for (Object selected : selectedObjects) {
258 if (refObject.equals(selected)) {
259 found = true;
260 break;
263 if (!found) {
264 refs[i] = null;
270 private static String getFQName(Object element) {
271 return element instanceof PsiClass ? ((PsiClass)element).getQualifiedName() : (String)element;