mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 23:06:24 +07:00
PY-9679 Properly highlight top-level symbol dependencies in the dialog
This commit is contained in:
@@ -356,7 +356,7 @@
|
||||
<codeInsight.overrideMethod language="Python" implementationClass="com.jetbrains.python.codeInsight.override.PyOverrideMethodsHandler"/>
|
||||
<lang.refactoringSupport language="Python" implementationClass="com.jetbrains.python.refactoring.PyRefactoringProvider"/>
|
||||
<lang.refactoringSupport.classMembersRefactoringSupport language="Python"
|
||||
implementationClass="com.jetbrains.python.refactoring.classes.PyClassMembersRefactoringSupport"/>
|
||||
implementationClass="com.jetbrains.python.refactoring.classes.PyMembersRefactoringSupport"/>
|
||||
<inlineActionHandler implementation="com.jetbrains.python.refactoring.inline.PyInlineLocalHandler"/>
|
||||
<codeInsight.gotoSuper language="Python" implementationClass="com.jetbrains.python.codeInsight.PyGotoSuperHandler"/>
|
||||
<gotoDeclarationHandler implementation="com.jetbrains.python.codeInsight.PyBreakContinueGotoProvider" order="FIRST"/>
|
||||
|
||||
@@ -17,8 +17,6 @@ package com.jetbrains.python.refactoring.classes;
|
||||
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
@@ -79,7 +77,7 @@ public abstract class PyClassRefactoringHandler implements RefactoringActionHand
|
||||
if (!inClass(clazz, project, editor, "refactoring.pull.up.error.cannot.perform.refactoring.not.inside.class")) return;
|
||||
assert clazz != null;
|
||||
|
||||
final PyMemberInfoStorage infoStorage = PyClassMembersRefactoringSupport.getSelectedMemberInfos(clazz, element1, element2);
|
||||
final PyMemberInfoStorage infoStorage = PyMembersRefactoringSupport.getSelectedMemberInfos(clazz, element1, element2);
|
||||
|
||||
doRefactorImpl(project, clazz, infoStorage, editor);
|
||||
}
|
||||
|
||||
+4
-3
@@ -16,14 +16,15 @@
|
||||
package com.jetbrains.python.refactoring.classes;
|
||||
|
||||
import com.intellij.refactoring.classMembers.DependentMembersCollectorBase;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.refactoring.classes.membersManager.MembersManager;
|
||||
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
*/
|
||||
public class PyDependentMembersCollector extends DependentMembersCollectorBase<PyElement,PyClass> {
|
||||
public PyDependentMembersCollector(PyClass clazz, PyClass superClass) {
|
||||
public class PyDependentClassMembersCollector extends DependentMembersCollectorBase<PyElement,PyClass> {
|
||||
public PyDependentClassMembersCollector(PyClass clazz, PyClass superClass) {
|
||||
super(clazz, superClass);
|
||||
}
|
||||
|
||||
+10
-2
@@ -22,12 +22,14 @@ import com.intellij.refactoring.classMembers.DependentMembersCollectorBase;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
|
||||
import com.jetbrains.python.refactoring.move.PyDependentModuleMembersCollector;
|
||||
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
*/
|
||||
public class PyClassMembersRefactoringSupport implements ClassMembersRefactoringSupport {
|
||||
public class PyMembersRefactoringSupport implements ClassMembersRefactoringSupport {
|
||||
|
||||
public static PyMemberInfoStorage getSelectedMemberInfos(PyClass clazz, PsiElement element1, PsiElement element2) {
|
||||
final PyMemberInfoStorage infoStorage = new PyMemberInfoStorage(clazz);
|
||||
@@ -40,7 +42,13 @@ public class PyClassMembersRefactoringSupport implements ClassMembersRefactoring
|
||||
}
|
||||
|
||||
public DependentMembersCollectorBase createDependentMembersCollector(Object clazz, Object superClass) {
|
||||
return new PyDependentMembersCollector((PyClass)clazz, (PyClass)superClass);
|
||||
if (clazz instanceof PyClass) {
|
||||
return new PyDependentClassMembersCollector((PyClass)clazz, (PyClass)superClass);
|
||||
}
|
||||
else if (clazz instanceof PyFile) {
|
||||
return new PyDependentModuleMembersCollector(((PyFile)clazz));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isProperMember(MemberInfoBase member) {
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.jetbrains.python.refactoring.move;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.refactoring.classMembers.DependentMembersCollectorBase;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyRecursiveElementVisitor;
|
||||
import com.jetbrains.python.psi.PyUtil;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Collects dependencies of the top-level symbols in the given module. This information is used then to highlight them
|
||||
* in "Move ..." dialog the same way as it's done for members of classes in various class-related refactorings.
|
||||
*
|
||||
* @see PyModuleMemberInfoModel
|
||||
*
|
||||
* @author Mikhail Golubev
|
||||
*/
|
||||
public class PyDependentModuleMembersCollector extends DependentMembersCollectorBase<PyElement, PyFile> {
|
||||
private final PyFile myModule;
|
||||
|
||||
public PyDependentModuleMembersCollector(@NotNull PyFile module) {
|
||||
super(module, null);
|
||||
myModule = module;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(final PyElement member) {
|
||||
if (member.getContainingFile() == myModule) {
|
||||
final PyResolveContext resolveContext = PyResolveContext.defaultContext();
|
||||
member.accept(new PyRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
for (PsiElement result : PyUtil.multiResolveTopPriority(element, resolveContext)) {
|
||||
if (isValidSameModuleDependency(result) && result != member) {
|
||||
myCollection.add(((PyElement)result));
|
||||
}
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidSameModuleDependency(@NotNull PsiElement element) {
|
||||
return PyMoveClassOrFunctionDelegate.canMoveElement(element) && element.getContainingFile() == myModule;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.jetbrains.python.refactoring.move;
|
||||
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
|
||||
/**
|
||||
* Helper object that describes top-level symbol of the module (class, function or assignment) for
|
||||
* the table in "Move ..." dialog. Concrete properties of given symbol is described in {@link PyModuleMemberInfoModel}.
|
||||
*
|
||||
* @author Mikhail Golubev
|
||||
* @see PyModuleMemberInfoModel
|
||||
*/
|
||||
class PyModuleMemberInfo extends MemberInfoBase<PyElement> {
|
||||
public PyModuleMemberInfo(PyElement member) {
|
||||
super(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return getMember().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PyModuleMemberInfo(" + getMember() + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.jetbrains.python.refactoring.move;
|
||||
|
||||
import com.intellij.refactoring.classMembers.AbstractUsesDependencyMemberInfoModel;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Mikhail Golubev
|
||||
*/
|
||||
class PyModuleMemberInfoModel extends AbstractUsesDependencyMemberInfoModel<PyElement, PyFile, PyModuleMemberInfo> {
|
||||
final PyFile myPyFile;
|
||||
|
||||
public PyModuleMemberInfoModel(@NotNull PyFile file) {
|
||||
super(file, null, false);
|
||||
myPyFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstractEnabled(PyModuleMemberInfo member) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doCheck(@NotNull PyModuleMemberInfo memberInfo, int problem) {
|
||||
return problem == ERROR ? WARNING : problem;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PyElement> collectTopLevelSymbols() {
|
||||
final List<PyElement> result = new ArrayList<PyElement>();
|
||||
result.addAll(myPyFile.getTopLevelAttributes());
|
||||
result.addAll(myPyFile.getTopLevelClasses());
|
||||
result.addAll(myPyFile.getTopLevelFunctions());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PyModuleMemberInfo> collectTopLevelSymbolsInfo() {
|
||||
return ContainerUtil.mapNotNull(collectTopLevelSymbols(), new Function<PyElement, PyModuleMemberInfo>() {
|
||||
@Override
|
||||
public PyModuleMemberInfo fun(PyElement element) {
|
||||
return new PyModuleMemberInfo(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+14
-2
@@ -46,12 +46,24 @@ public class PyMoveClassOrFunctionDelegate extends MoveHandlerDelegate {
|
||||
@Override
|
||||
public boolean canMove(PsiElement[] elements, @Nullable PsiElement targetContainer) {
|
||||
for (PsiElement element : elements) {
|
||||
if ((element instanceof PyClass || element instanceof PyFunction) && PyUtil.isTopLevel(element)) continue;
|
||||
return false;
|
||||
if (!canMoveElement(element)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.canMove(elements, targetContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that given element is suitable for "Move ..." refactoring. Currently it means that it's top-level function, class or
|
||||
* target expression.
|
||||
*
|
||||
* @param element PSI element to check
|
||||
* @return whether this element is acceptable for "Move ..." refactoring
|
||||
*/
|
||||
public static boolean canMoveElement(@NotNull PsiElement element) {
|
||||
return (element instanceof PyClass || element instanceof PyFunction) && PyUtil.isTopLevel(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doMove(Project project,
|
||||
PsiElement[] elements,
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoChange;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoModel;
|
||||
import com.intellij.refactoring.ui.AbstractMemberSelectionTable;
|
||||
@@ -31,7 +30,6 @@ import org.jetbrains.annotations.TestOnly;
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -46,7 +44,7 @@ public class PyMoveTopLevelSymbolDialog extends RefactoringDialog {
|
||||
private static PyMoveTopLevelSymbolDialog ourInstanceToReplace = null;
|
||||
|
||||
private final TopLevelSymbolsSelectionTable myMemberSelectionTable;
|
||||
private final ModuleMemberInfoModel myModuleMemberModel;
|
||||
private final PyModuleMemberInfoModel myModuleMemberModel;
|
||||
private JPanel myCenterPanel;
|
||||
private JPanel myTablePanel;
|
||||
private TextFieldWithBrowseButton myBrowseFieldWithButton;
|
||||
@@ -115,13 +113,15 @@ public class PyMoveTopLevelSymbolDialog extends RefactoringDialog {
|
||||
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
|
||||
|
||||
final PyFile pyFile = (PyFile)firstElement.getContainingFile();
|
||||
myModuleMemberModel = new ModuleMemberInfoModel(pyFile);
|
||||
myModuleMemberModel = new PyModuleMemberInfoModel(pyFile);
|
||||
|
||||
final List<TopLevelSymbolInfo> symbolsInfo = myModuleMemberModel.getTopLevelSymbolInfo();
|
||||
for (TopLevelSymbolInfo info : symbolsInfo) {
|
||||
final List<PyModuleMemberInfo> symbolsInfos = myModuleMemberModel.collectTopLevelSymbolsInfo();
|
||||
for (PyModuleMemberInfo info : symbolsInfos) {
|
||||
info.setChecked(elements.contains(info.getMember()));
|
||||
}
|
||||
myMemberSelectionTable = new TopLevelSymbolsSelectionTable(symbolsInfo, myModuleMemberModel);
|
||||
myModuleMemberModel.memberInfoChanged(new MemberInfoChange<PyElement, PyModuleMemberInfo>(symbolsInfos));
|
||||
myMemberSelectionTable = new TopLevelSymbolsSelectionTable(symbolsInfos, myModuleMemberModel);
|
||||
myMemberSelectionTable.addMemberInfoChangeListener(myModuleMemberModel);
|
||||
// MoveMemberDialog for Java uses SeparatorFactory.createSeparator instead of custom border
|
||||
myTablePanel.add(ScrollPaneFactory.createScrollPane(myMemberSelectionTable), BorderLayout.CENTER);
|
||||
|
||||
@@ -156,9 +156,9 @@ public class PyMoveTopLevelSymbolDialog extends RefactoringDialog {
|
||||
|
||||
@NotNull
|
||||
public List<PyElement> getSelectedTopLevelSymbols() {
|
||||
return ContainerUtil.map(myMemberSelectionTable.getSelectedMemberInfos(), new Function<TopLevelSymbolInfo, PyElement>() {
|
||||
return ContainerUtil.map(myMemberSelectionTable.getSelectedMemberInfos(), new Function<PyModuleMemberInfo, PyElement>() {
|
||||
@Override
|
||||
public PyElement fun(TopLevelSymbolInfo info) {
|
||||
public PyElement fun(PyModuleMemberInfo info) {
|
||||
return info.getMember();
|
||||
}
|
||||
});
|
||||
@@ -175,95 +175,12 @@ public class PyMoveTopLevelSymbolDialog extends RefactoringDialog {
|
||||
}
|
||||
}
|
||||
|
||||
static class ModuleMemberInfoModel implements MemberInfoModel<PyElement, TopLevelSymbolInfo> {
|
||||
final PyFile myPyFile;
|
||||
|
||||
public ModuleMemberInfoModel(@NotNull PyFile pyFile) {
|
||||
myPyFile = pyFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PyElement> getTopLevelSymbols() {
|
||||
final List<PyElement> result = new ArrayList<PyElement>();
|
||||
result.addAll(myPyFile.getTopLevelAttributes());
|
||||
result.addAll(myPyFile.getTopLevelClasses());
|
||||
result.addAll(myPyFile.getTopLevelFunctions());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<TopLevelSymbolInfo> getTopLevelSymbolInfo() {
|
||||
return ContainerUtil.mapNotNull(getTopLevelSymbols(), new Function<PyElement, TopLevelSymbolInfo>() {
|
||||
@Override
|
||||
public TopLevelSymbolInfo fun(PyElement element) {
|
||||
return new TopLevelSymbolInfo(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMemberEnabled(TopLevelSymbolInfo member) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckedWhenDisabled(TopLevelSymbolInfo member) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstractEnabled(TopLevelSymbolInfo member) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstractWhenDisabled(TopLevelSymbolInfo member) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isFixedAbstract(TopLevelSymbolInfo member) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkForProblems(@NotNull TopLevelSymbolInfo member) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTooltipText(TopLevelSymbolInfo member) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void memberInfoChanged(MemberInfoChange<PyElement, TopLevelSymbolInfo> event) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class TopLevelSymbolInfo extends MemberInfoBase<PyElement> {
|
||||
public TopLevelSymbolInfo(PyElement member) {
|
||||
super(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return getMember().getName();
|
||||
}
|
||||
}
|
||||
|
||||
static class TopLevelSymbolsSelectionTable extends AbstractMemberSelectionTable<PyElement, TopLevelSymbolInfo> {
|
||||
public TopLevelSymbolsSelectionTable(@NotNull Collection<TopLevelSymbolInfo> memberInfos,
|
||||
@Nullable MemberInfoModel<PyElement, TopLevelSymbolInfo> memberInfoModel) {
|
||||
static class TopLevelSymbolsSelectionTable extends AbstractMemberSelectionTable<PyElement, PyModuleMemberInfo> {
|
||||
public TopLevelSymbolsSelectionTable(@NotNull Collection<PyModuleMemberInfo> memberInfos,
|
||||
@Nullable MemberInfoModel<PyElement, PyModuleMemberInfo> memberInfoModel) {
|
||||
super(memberInfos, memberInfoModel, null);
|
||||
// TODO: It's better to make AbstractMemberSelectionTable more flexible than to patch model like that
|
||||
myTableModel = new MyTableModel<PyElement, TopLevelSymbolInfo>(this) {
|
||||
myTableModel = new MyTableModel<PyElement, PyModuleMemberInfo>(this) {
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return column == DISPLAY_NAME_COLUMN ? "Symbol" : super.getColumnName(column);
|
||||
@@ -278,7 +195,7 @@ public class PyMoveTopLevelSymbolDialog extends RefactoringDialog {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Object getAbstractColumnValue(TopLevelSymbolInfo memberInfo) {
|
||||
protected Object getAbstractColumnValue(PyModuleMemberInfo memberInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -288,12 +205,12 @@ public class PyMoveTopLevelSymbolDialog extends RefactoringDialog {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setVisibilityIcon(TopLevelSymbolInfo memberInfo, RowIcon icon) {
|
||||
protected void setVisibilityIcon(PyModuleMemberInfo memberInfo, RowIcon icon) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Icon getOverrideIcon(TopLevelSymbolInfo memberInfo) {
|
||||
protected Icon getOverrideIcon(PyModuleMemberInfo memberInfo) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user