Move: Implement "Move nested class to another class" UI
#KT-9027 Fixed
This commit is contained in:
+31
-10
@@ -32,8 +32,10 @@ import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackages
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import org.jetbrains.kotlin.idea.core.getPackage
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinNestedClassesToUpperLevelDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinSelectNestedClassRefactoringDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinNestedClassesDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
@@ -96,13 +98,23 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
|
||||
}
|
||||
|
||||
is KtClassOrObject -> {
|
||||
if (elementsToSearch.size > 1) return false
|
||||
|
||||
val outerClass = container.parent as KtClassOrObject
|
||||
val newContainer = targetContainer
|
||||
?: outerClass.containingClassOrObject
|
||||
?: outerClass.containingFile.let { it.containingDirectory ?: it }
|
||||
MoveKotlinNestedClassesToUpperLevelDialog(project, elementsToSearch.first() as KtClassOrObject, newContainer).show()
|
||||
if (elementsToSearch.size > 1) {
|
||||
// todo: allow moving multiple classes to upper level
|
||||
if (targetContainer !is KtClassOrObject) {
|
||||
val message = RefactoringBundle.getCannotRefactorMessage("Moving multiple nested classes to top-level is not supported")
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, message, MOVE_DECLARATIONS, null)
|
||||
return true
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
MoveKotlinNestedClassesDialog(project,
|
||||
elementsToSearch.filterIsInstance<KtClassOrObject>(),
|
||||
container,
|
||||
targetContainer,
|
||||
callback).show()
|
||||
return true
|
||||
}
|
||||
KotlinSelectNestedClassRefactoringDialog.chooseNestedClassRefactoring(elementsToSearch.first() as KtClassOrObject,
|
||||
targetContainer)
|
||||
}
|
||||
|
||||
else -> throw AssertionError("Unexpected container: ${container.getElementTextWithContext()}")
|
||||
@@ -113,7 +125,11 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
|
||||
|
||||
private fun canMove(elements: Array<out PsiElement>, targetContainer: PsiElement?, editorMode: Boolean): Boolean {
|
||||
if (!super.canMove(elements, targetContainer)) return false
|
||||
if (getUniqueContainer(elements) == null) return false
|
||||
val container = getUniqueContainer(elements) ?: return false
|
||||
|
||||
if (container is KtClassOrObject && targetContainer != null && targetContainer !is KtClassOrObject && elements.size > 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
return elements.all { e ->
|
||||
if (e is KtClass || (e is KtObjectDeclaration && !e.isObjectLiteral()) || e is KtNamedFunction || e is KtProperty) {
|
||||
@@ -128,7 +144,12 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
|
||||
}
|
||||
|
||||
override fun isValidTarget(psiElement: PsiElement?, sources: Array<out PsiElement>): Boolean {
|
||||
return psiElement is PsiPackage || (psiElement is PsiDirectory && psiElement.getPackage() != null) || psiElement is KtFile
|
||||
return psiElement is PsiPackage
|
||||
|| (psiElement is PsiDirectory && psiElement.getPackage() != null)
|
||||
|| psiElement is KtFile
|
||||
|| (psiElement is KtClassOrObject
|
||||
&& !(psiElement.hasModifier(KtTokens.ANNOTATION_KEYWORD))
|
||||
&& !sources.any { it.parent is KtFile })
|
||||
}
|
||||
|
||||
override fun doMove(project: Project, elements: Array<out PsiElement>, targetContainer: PsiElement?, callback: MoveCallback?) {
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui
|
||||
|
||||
import com.intellij.BundleBase
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.util.RadioUpDownListener
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import java.awt.BorderLayout
|
||||
import javax.swing.*
|
||||
|
||||
internal class KotlinSelectNestedClassRefactoringDialog private constructor (
|
||||
private val project: Project,
|
||||
private val nestedClass: KtClassOrObject,
|
||||
private val targetContainer: PsiElement?
|
||||
) : DialogWrapper(project, true) {
|
||||
private val moveToUpperLevelButton = JRadioButton()
|
||||
private val moveMembersButton = JRadioButton()
|
||||
|
||||
init {
|
||||
title = RefactoringBundle.message("select.refactoring.title")
|
||||
init()
|
||||
}
|
||||
|
||||
override fun createNorthPanel() = JLabel(RefactoringBundle.message("what.would.you.like.to.do"))
|
||||
|
||||
override fun getPreferredFocusedComponent() = moveToUpperLevelButton
|
||||
|
||||
override fun getDimensionServiceKey(): String {
|
||||
return "#org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.KotlinSelectInnerOrMembersRefactoringDialog"
|
||||
}
|
||||
|
||||
override fun createCenterPanel(): JComponent? {
|
||||
moveToUpperLevelButton.text = BundleBase.replaceMnemonicAmpersand("Move &nested class ${nestedClass.name} to upper level")
|
||||
moveToUpperLevelButton.isSelected = true
|
||||
|
||||
moveMembersButton.text = BundleBase.replaceMnemonicAmpersand("&Move nested class ${nestedClass.name} to another class")
|
||||
|
||||
ButtonGroup().apply {
|
||||
add(moveToUpperLevelButton)
|
||||
add(moveMembersButton)
|
||||
}
|
||||
|
||||
RadioUpDownListener(moveToUpperLevelButton, moveMembersButton)
|
||||
|
||||
return JPanel(BorderLayout()).apply {
|
||||
val box = Box.createVerticalBox().apply {
|
||||
add(Box.createVerticalStrut(5))
|
||||
add(moveToUpperLevelButton)
|
||||
add(moveMembersButton)
|
||||
}
|
||||
add(box, BorderLayout.CENTER)
|
||||
}
|
||||
}
|
||||
|
||||
fun getNextDialog(): DialogWrapper? {
|
||||
return when {
|
||||
moveToUpperLevelButton.isSelected -> MoveKotlinNestedClassesToUpperLevelDialog(nestedClass, targetContainer)
|
||||
moveMembersButton.isSelected -> MoveKotlinNestedClassesDialog(nestedClass, targetContainer)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun MoveKotlinNestedClassesToUpperLevelDialog(
|
||||
nestedClass: KtClassOrObject,
|
||||
targetContainer: PsiElement?
|
||||
): MoveKotlinNestedClassesToUpperLevelDialog {
|
||||
val outerClass = nestedClass.containingClassOrObject!!
|
||||
val newTarget = targetContainer
|
||||
?: outerClass.containingClassOrObject
|
||||
?: outerClass.containingFile.let { it.containingDirectory ?: it }
|
||||
return MoveKotlinNestedClassesToUpperLevelDialog(nestedClass.project, nestedClass, newTarget)
|
||||
}
|
||||
|
||||
private fun MoveKotlinNestedClassesDialog(
|
||||
nestedClass: KtClassOrObject,
|
||||
targetContainer: PsiElement?
|
||||
): MoveKotlinNestedClassesDialog {
|
||||
return MoveKotlinNestedClassesDialog(nestedClass.project,
|
||||
listOf(nestedClass),
|
||||
nestedClass.containingClassOrObject!!,
|
||||
targetContainer as? KtClassOrObject ?: nestedClass.containingClassOrObject!!,
|
||||
null)
|
||||
}
|
||||
|
||||
fun chooseNestedClassRefactoring(nestedClass: KtClassOrObject, targetContainer: PsiElement?) {
|
||||
val project = nestedClass.project
|
||||
val dialog = when {
|
||||
targetContainer != null && targetContainer !is KtClassOrObject ||
|
||||
nestedClass is KtClass && nestedClass.isInner() -> {
|
||||
MoveKotlinNestedClassesToUpperLevelDialog(nestedClass, targetContainer)
|
||||
}
|
||||
else -> {
|
||||
val selectionDialog = KotlinSelectNestedClassRefactoringDialog(project, nestedClass, targetContainer)
|
||||
selectionDialog.show()
|
||||
if (selectionDialog.exitCode != OK_EXIT_CODE) return
|
||||
selectionDialog.getNextDialog() ?: return
|
||||
}
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinNestedClassesDialog">
|
||||
<grid id="1a398" binding="mainPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="10" y="10" width="472" height="414"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none">
|
||||
<color color="-8355712"/>
|
||||
</border>
|
||||
<children>
|
||||
<grid id="64650" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="5" left="5" bottom="5" right="5"/>
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="c6d13" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="50ecd"/>
|
||||
<text value="Move members from:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="50ecd" class="javax.swing.JTextField" binding="originalClassField">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<editable value="false"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<vspacer id="e0fb3">
|
||||
<constraints>
|
||||
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<grid id="e4ac9" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="393db" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="To (fully qualified name):"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="1f1bc" binding="targetClassChooserPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="77b3c" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="fd527" class="javax.swing.JCheckBox" binding="openInEditorCheckBox">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<selected value="true"/>
|
||||
<text value="Open moved members in editor"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="cdd1d">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="a6a2e" binding="membersInfoPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
<buttonGroups>
|
||||
<group name="buttonGroup1">
|
||||
<member id="765d3"/>
|
||||
<member id="58e61"/>
|
||||
</group>
|
||||
</buttonGroups>
|
||||
</form>
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
||||
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.ide.util.TreeClassChooser;
|
||||
import com.intellij.ide.util.TreeJavaClassChooserDialog;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.JavaCodeFragment;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoChange;
|
||||
import com.intellij.refactoring.move.MoveCallback;
|
||||
import com.intellij.refactoring.move.MoveHandler;
|
||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||
import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.asJava.KtLightClassForExplicitDeclaration;
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil;
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
||||
import org.jetbrains.kotlin.idea.projectView.KtClassOrObjectTreeNode;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
|
||||
public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
||||
private static final String RECENTS_KEY = MoveKotlinNestedClassesDialog.class.getName() + ".RECENTS_KEY";
|
||||
|
||||
private static class MemberInfoModelImpl extends AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo> {
|
||||
|
||||
}
|
||||
|
||||
private JPanel mainPanel;
|
||||
private JTextField originalClassField;
|
||||
private JPanel membersInfoPanel;
|
||||
private ReferenceEditorComboWithBrowseButton targetClassChooser;
|
||||
private JCheckBox openInEditorCheckBox;
|
||||
private JPanel targetClassChooserPanel;
|
||||
private KotlinMemberSelectionTable memberTable;
|
||||
|
||||
private final KtClassOrObject originalClass;
|
||||
private KtClassOrObject targetClass;
|
||||
private final MoveCallback moveCallback;
|
||||
|
||||
public MoveKotlinNestedClassesDialog(
|
||||
@NotNull Project project,
|
||||
@NotNull List<KtClassOrObject> elementsToMove,
|
||||
@NotNull KtClassOrObject originalClass,
|
||||
@NotNull KtClassOrObject targetClass,
|
||||
@Nullable MoveCallback moveCallback
|
||||
) {
|
||||
super(project, true);
|
||||
|
||||
this.originalClass = originalClass;
|
||||
this.targetClass = targetClass;
|
||||
this.moveCallback = moveCallback;
|
||||
|
||||
init();
|
||||
|
||||
setTitle(MoveHandler.REFACTORING_NAME);
|
||||
|
||||
initClassChooser(targetClass);
|
||||
|
||||
initMemberInfo(elementsToMove);
|
||||
|
||||
validateButtons();
|
||||
}
|
||||
|
||||
private void initClassChooser(@NotNull KtClassOrObject initialTargetClass) {
|
||||
//noinspection ConstantConditions
|
||||
originalClassField.setText(originalClass.getFqName().asString());
|
||||
|
||||
//noinspection ConstantConditions
|
||||
targetClassChooser = new ReferenceEditorComboWithBrowseButton(
|
||||
new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TreeClassChooser chooser = new TreeJavaClassChooserDialog(
|
||||
RefactoringBundle.message("choose.destination.class"),
|
||||
myProject,
|
||||
GlobalSearchScope.projectScope(myProject),
|
||||
new ClassFilter() {
|
||||
@Override
|
||||
public boolean isAccepted(PsiClass aClass) {
|
||||
if (!(aClass instanceof KtLightClassForExplicitDeclaration)) return false;
|
||||
KtClassOrObject classOrObject = ((KtLightClassForExplicitDeclaration) aClass).getOrigin();
|
||||
|
||||
if (classOrObject.isTopLevel()) return true;
|
||||
|
||||
if (classOrObject instanceof KtObjectDeclaration) {
|
||||
return !((KtObjectDeclaration) classOrObject).isObjectLiteral();
|
||||
}
|
||||
|
||||
if (classOrObject instanceof KtClass) {
|
||||
return !((KtClass) classOrObject).isInner();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
null,
|
||||
null,
|
||||
true
|
||||
) {
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiClass getSelectedFromTreeUserObject(DefaultMutableTreeNode node) {
|
||||
PsiClass psiClass = super.getSelectedFromTreeUserObject(node);
|
||||
if (psiClass != null) return psiClass;
|
||||
|
||||
Object userObject = node.getUserObject();
|
||||
if (!(userObject instanceof KtClassOrObjectTreeNode)) return null;
|
||||
return LightClassUtilsKt.toLightClass(((KtClassOrObjectTreeNode) userObject).getValue());
|
||||
}
|
||||
};
|
||||
chooser.selectDirectory((targetClass != null ? targetClass : originalClass).getContainingFile().getContainingDirectory());
|
||||
chooser.showDialog();
|
||||
|
||||
PsiClass aClass = chooser.getSelected();
|
||||
if (aClass instanceof KtLightClassForExplicitDeclaration) {
|
||||
targetClass = ((KtLightClassForExplicitDeclaration) aClass).getOrigin();
|
||||
targetClassChooser.setText(aClass.getQualifiedName());
|
||||
}
|
||||
}
|
||||
},
|
||||
initialTargetClass.getFqName().asString(),
|
||||
myProject,
|
||||
true,
|
||||
JavaCodeFragment.VisibilityChecker.PROJECT_SCOPE_VISIBLE,
|
||||
RECENTS_KEY);
|
||||
targetClassChooser.getChildComponent().getDocument().addDocumentListener(
|
||||
new DocumentAdapter() {
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent e) {
|
||||
PsiClass aClass = JavaPsiFacade
|
||||
.getInstance(myProject)
|
||||
.findClass(targetClassChooser.getText(), GlobalSearchScope.projectScope(myProject));
|
||||
targetClass = aClass instanceof KtLightClassForExplicitDeclaration
|
||||
? ((KtLightClassForExplicitDeclaration) aClass).getOrigin()
|
||||
: null;
|
||||
validateButtons();
|
||||
}
|
||||
}
|
||||
);
|
||||
targetClassChooserPanel.add(targetClassChooser);
|
||||
}
|
||||
|
||||
private void initMemberInfo(@NotNull final List<KtClassOrObject> elementsToMove) {
|
||||
List<KotlinMemberInfo> memberInfos = CollectionsKt.mapNotNull(
|
||||
originalClass.getDeclarations(),
|
||||
new Function1<KtDeclaration, KotlinMemberInfo>() {
|
||||
@Override
|
||||
public KotlinMemberInfo invoke(KtDeclaration declaration) {
|
||||
if (!(declaration instanceof KtClassOrObject)) return null;
|
||||
|
||||
KotlinMemberInfo memberInfo = new KotlinMemberInfo((KtClassOrObject) declaration, false);
|
||||
memberInfo.setChecked(elementsToMove.contains(declaration));
|
||||
return memberInfo;
|
||||
}
|
||||
}
|
||||
);
|
||||
KotlinMemberSelectionPanel selectionPanel = new KotlinMemberSelectionPanel(getTitle(), memberInfos, null);
|
||||
memberTable = selectionPanel.getTable();
|
||||
MemberInfoModelImpl memberInfoModel = new MemberInfoModelImpl();
|
||||
memberInfoModel.memberInfoChanged(new MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo>(memberInfos));
|
||||
selectionPanel.getTable().setMemberInfoModel(memberInfoModel);
|
||||
selectionPanel.getTable().addMemberInfoChangeListener(memberInfoModel);
|
||||
membersInfoPanel.add(selectionPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private List<KtClassOrObject> getSelectedElementsToMove() {
|
||||
return CollectionsKt.map(
|
||||
memberTable.getSelectedMemberInfos(),
|
||||
new Function1<KotlinMemberInfo, KtClassOrObject>() {
|
||||
@Override
|
||||
public KtClassOrObject invoke(KotlinMemberInfo info) {
|
||||
return (KtClassOrObject) info.getMember();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDimensionServiceKey() {
|
||||
return "#" + getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void canRun() throws ConfigurationException {
|
||||
if (targetClass == null) throw new ConfigurationException("No destination class specified");
|
||||
|
||||
if (originalClass == targetClass) {
|
||||
throw new ConfigurationException(RefactoringBundle.message("source.and.destination.classes.should.be.different"));
|
||||
}
|
||||
|
||||
for (KtClassOrObject classOrObject : getSelectedElementsToMove()) {
|
||||
if (PsiTreeUtil.isAncestor(classOrObject, targetClass, false)) {
|
||||
throw new ConfigurationException("Cannot move nested class " + classOrObject.getName() + " to itself");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction() {
|
||||
List<KtClassOrObject> elementsToMove = getSelectedElementsToMove();
|
||||
KotlinMoveTarget target = new KotlinMoveTargetForExistingElement(targetClass);
|
||||
MoveDeclarationsDelegate.NestedClass delegate = new MoveDeclarationsDelegate.NestedClass();
|
||||
MoveDeclarationsDescriptor descriptor = new MoveDeclarationsDescriptor(
|
||||
elementsToMove, target, delegate, false, false, true, false, moveCallback, openInEditorCheckBox.isSelected()
|
||||
);
|
||||
invokeRefactoring(new MoveKotlinDeclarationsProcessor(myProject, descriptor, Mover.Default.INSTANCE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return targetClassChooser.getChildComponent();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user