Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,206 +15,230 @@
*/
package com.intellij.java.impl.codeInsight.editorActions;

import consulo.language.editor.CodeInsightSettings;
import consulo.language.editor.util.CollectHighlightsUtil;
import consulo.ide.impl.idea.codeInsight.editorActions.CopyPastePostProcessor;
import com.intellij.java.language.psi.JavaPsiFacade;
import com.intellij.java.language.psi.PsiClass;
import com.intellij.java.language.psi.PsiClassOwner;
import consulo.application.ApplicationManager;
import consulo.document.Document;
import consulo.annotation.access.RequiredReadAction;
import consulo.application.Application;
import consulo.codeEditor.Editor;
import consulo.document.Document;
import consulo.document.RangeMarker;
import consulo.project.DumbService;
import consulo.project.Project;
import consulo.util.lang.Comparing;
import consulo.util.lang.ref.Ref;
import consulo.document.util.TextRange;
import consulo.ide.impl.idea.codeInsight.editorActions.CopyPastePostProcessor;
import consulo.language.editor.CodeInsightSettings;
import consulo.language.editor.util.CollectHighlightsUtil;
import consulo.language.psi.*;
import consulo.util.collection.ArrayUtil;
import consulo.logging.Logger;

import consulo.project.DumbService;
import consulo.project.Project;
import consulo.ui.annotation.RequiredUIAccess;
import consulo.util.collection.ArrayUtil;
import consulo.util.lang.Comparing;
import consulo.util.lang.ref.SimpleReference;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> extends CopyPastePostProcessor<ReferenceTransferableData> {
private static final Logger LOG = Logger.getInstance(CopyPasteReferenceProcessor.class);

@Nonnull
@Override
public List<ReferenceTransferableData> collectTransferableData(PsiFile file, final Editor editor, final int[] startOffsets,
final int[] endOffsets) {
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.NO) {
return Collections.emptyList();
}
private static final Logger LOG = Logger.getInstance(CopyPasteReferenceProcessor.class);

@Nonnull
@Override
@RequiredReadAction
public List<ReferenceTransferableData> collectTransferableData(
PsiFile file,
Editor editor,
int[] startOffsets,
int[] endOffsets
) {
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.NO) {
return Collections.emptyList();
}

if (file instanceof PsiCompiledFile) {
file = ((PsiCompiledFile) file).getDecompiledPsiFile();
}
if (!(file instanceof PsiClassOwner)) {
return Collections.emptyList();
}
if (file instanceof PsiCompiledFile) {
file = ((PsiCompiledFile)file).getDecompiledPsiFile();
}
if (!(file instanceof PsiClassOwner)) {
return Collections.emptyList();
}

final ArrayList<ReferenceData> array = new ArrayList<ReferenceData>();
for (int j = 0; j < startOffsets.length; j++) {
final int startOffset = startOffsets[j];
for (final PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffsets[j])) {
addReferenceData(file, startOffset, element, array);
}
}
ArrayList<ReferenceData> array = new ArrayList<>();
for (int j = 0; j < startOffsets.length; j++) {
int startOffset = startOffsets[j];
for (PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffsets[j])) {
addReferenceData(file, startOffset, element, array);
}
}

if (array.isEmpty()) {
return Collections.emptyList();
}
if (array.isEmpty()) {
return Collections.emptyList();
}

return Collections.singletonList(new ReferenceTransferableData(array.toArray(new ReferenceData[array.size()])));
}
return Collections.singletonList(new ReferenceTransferableData(array.toArray(new ReferenceData[array.size()])));
}

protected abstract void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList<ReferenceData> to);
protected abstract void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList<ReferenceData> to);

@Nonnull
@Override
public List<ReferenceTransferableData> extractTransferableData(Transferable content) {
ReferenceTransferableData referenceData = null;
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE != CodeInsightSettings.NO) {
try {
DataFlavor flavor = ReferenceData.getDataFlavor();
if (flavor != null) {
referenceData = (ReferenceTransferableData)content.getTransferData(flavor);
}
}
catch (UnsupportedFlavorException | IOException ignored) {
}
}

@Nonnull
@Override
public List<ReferenceTransferableData> extractTransferableData(final Transferable content) {
ReferenceTransferableData referenceData = null;
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE != CodeInsightSettings.NO) {
try {
final DataFlavor flavor = ReferenceData.getDataFlavor();
if (flavor != null) {
referenceData = (ReferenceTransferableData) content.getTransferData(flavor);
if (referenceData != null) { // copy to prevent changing of original by convertLineSeparators
return Collections.singletonList(referenceData.clone());
}
} catch (UnsupportedFlavorException ignored) {
} catch (IOException ignored) {
}
}

if (referenceData != null) { // copy to prevent changing of original by convertLineSeparators
return Collections.singletonList(referenceData.clone());
return Collections.emptyList();
}

return Collections.emptyList();
}
@Override
@RequiredUIAccess
public void processTransferableData(
Project project,
Editor editor,
RangeMarker bounds,
int caretOffset,
SimpleReference<Boolean> indented,
List<ReferenceTransferableData> values
) {
if (DumbService.getInstance(project).isDumb()) {
return;
}
Document document = editor.getDocument();
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);

@Override
public void processTransferableData(final Project project, final Editor editor, final RangeMarker bounds, int caretOffset,
Ref<Boolean> indented, final List<ReferenceTransferableData> values) {
if (DumbService.getInstance(project).isDumb()) {
return;
}
final Document document = editor.getDocument();
final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (!(file instanceof PsiClassOwner)) {
return;
}

if (!(file instanceof PsiClassOwner)) {
return;
PsiDocumentManager.getInstance(project).commitAllDocuments();
assert values.size() == 1;
ReferenceData[] referenceData = values.get(0).getData();
TRef[] refs = findReferencesToRestore(file, bounds, referenceData);
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.ASK) {
askReferencesToRestore(project, refs, referenceData);
}
PsiDocumentManager.getInstance(project).commitAllDocuments();
Application.get().runWriteAction(() -> restoreReferences(referenceData, refs));
}

PsiDocumentManager.getInstance(project).commitAllDocuments();
assert values.size() == 1;
final ReferenceData[] referenceData = values.get(0).getData();
final TRef[] refs = findReferencesToRestore(file, bounds, referenceData);
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.ASK) {
askReferencesToRestore(project, refs, referenceData);
@RequiredReadAction
protected static void addReferenceData(
PsiElement element,
ArrayList<ReferenceData> array,
int startOffset,
String qClassName,
@Nullable String staticMemberName
) {
TextRange range = element.getTextRange();
array.add(new ReferenceData(
range.getStartOffset() - startOffset,
range.getEndOffset() - startOffset,
qClassName,
staticMemberName
));
}
PsiDocumentManager.getInstance(project).commitAllDocuments();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
restoreReferences(referenceData, refs);
}
});
}

protected static void addReferenceData(final PsiElement element, final ArrayList<ReferenceData> array, final int startOffset,
final String qClassName, @Nullable final String staticMemberName) {
final TextRange range = element.getTextRange();
array.add(new ReferenceData(range.getStartOffset() - startOffset, range.getEndOffset() - startOffset, qClassName, staticMemberName));
}

protected abstract TRef[] findReferencesToRestore(PsiFile file, RangeMarker bounds, ReferenceData[] referenceData);

protected PsiElement resolveReferenceIgnoreOverriding(PsiPolyVariantReference reference) {
PsiElement referent = reference.resolve();
if (referent == null) {
final ResolveResult[] results = reference.multiResolve(true);
if (results.length > 0) {
referent = results[0].getElement();
}
}
return referent;
}

protected abstract void restoreReferences(ReferenceData[] referenceData, TRef[] refs);

private static void askReferencesToRestore(Project project, PsiElement[] refs, ReferenceData[] referenceData) {
PsiManager manager = PsiManager.getInstance(project);

ArrayList<Object> array = new ArrayList<Object>();
Object[] refObjects = new Object[refs.length];
for (int i = 0; i < referenceData.length; i++) {
PsiElement ref = refs[i];
if (ref != null) {
LOG.assertTrue(ref.isValid());
ReferenceData data = referenceData[i];
PsiClass refClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(data.qClassName, ref.getResolveScope());
if (refClass == null) {
continue;
}

Object refObject = refClass;
if (data.staticMemberName != null) {
//Show static members as Strings
refObject = refClass.getQualifiedName() + "." + data.staticMemberName;
}
refObjects[i] = refObject;
protected abstract TRef[] findReferencesToRestore(PsiFile file, RangeMarker bounds, ReferenceData[] referenceData);

if (!array.contains(refObject)) {
array.add(refObject);
@RequiredReadAction
protected PsiElement resolveReferenceIgnoreOverriding(PsiPolyVariantReference reference) {
PsiElement referent = reference.resolve();
if (referent == null) {
ResolveResult[] results = reference.multiResolve(true);
if (results.length > 0) {
referent = results[0].getElement();
}
}
}
}
if (array.isEmpty()) {
return;
return referent;
}

Object[] selectedObjects = ArrayUtil.toObjectArray(array);
Arrays.sort(selectedObjects, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
String fqName1 = getFQName(o1);
String fqName2 = getFQName(o2);
return fqName1.compareToIgnoreCase(fqName2);
}
});

RestoreReferencesDialog dialog = new RestoreReferencesDialog(project, selectedObjects);
dialog.show();
selectedObjects = dialog.getSelectedElements();

for (int i = 0; i < referenceData.length; i++) {
PsiElement ref = refs[i];
if (ref != null) {
LOG.assertTrue(ref.isValid());
Object refObject = refObjects[i];
boolean found = false;
for (Object selected : selectedObjects) {
if (Comparing.equal(refObject, selected)) {
found = true;
break;
}
protected abstract void restoreReferences(ReferenceData[] referenceData, TRef[] refs);

@RequiredUIAccess
private static void askReferencesToRestore(Project project, PsiElement[] refs, ReferenceData[] referenceData) {
PsiManager manager = PsiManager.getInstance(project);

ArrayList<Object> array = new ArrayList<>();
Object[] refObjects = new Object[refs.length];
for (int i = 0; i < referenceData.length; i++) {
PsiElement ref = refs[i];
if (ref != null) {
LOG.assertTrue(ref.isValid());
ReferenceData data = referenceData[i];
PsiClass refClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(data.qClassName, ref.getResolveScope());
if (refClass == null) {
continue;
}

Object refObject = refClass;
if (data.staticMemberName != null) {
//Show static members as Strings
refObject = refClass.getQualifiedName() + "." + data.staticMemberName;
}
refObjects[i] = refObject;

if (!array.contains(refObject)) {
array.add(refObject);
}
}
}
if (!found) {
refs[i] = null;
if (array.isEmpty()) {
return;
}

Object[] selectedObjects = ArrayUtil.toObjectArray(array);
Arrays.sort(
selectedObjects,
(o1, o2) -> {
String fqName1 = getFQName(o1);
String fqName2 = getFQName(o2);
return fqName1.compareToIgnoreCase(fqName2);
}
);

RestoreReferencesDialog dialog = new RestoreReferencesDialog(project, selectedObjects);
dialog.show();
selectedObjects = dialog.getSelectedElements();

for (int i = 0; i < referenceData.length; i++) {
PsiElement ref = refs[i];
if (ref != null) {
LOG.assertTrue(ref.isValid());
Object refObject = refObjects[i];
boolean found = false;
for (Object selected : selectedObjects) {
if (Comparing.equal(refObject, selected)) {
found = true;
break;
}
}
if (!found) {
refs[i] = null;
}
}
}
}
}
}

private static String getFQName(Object element) {
return element instanceof PsiClass ? ((PsiClass) element).getQualifiedName() : (String) element;
}
private static String getFQName(Object element) {
return element instanceof PsiClass psiClass ? psiClass.getQualifiedName() : (String)element;
}
}
Loading
Loading