Move: Implement member selection UI
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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
|
||||
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase
|
||||
import com.intellij.refactoring.classMembers.MemberInfoModel
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
|
||||
public class KotlinMemberInfo(member: JetNamedDeclaration) : MemberInfoBase<JetNamedDeclaration>(member) {
|
||||
init {
|
||||
isStatic = member.getParent() is JetFile
|
||||
displayName = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(member.resolveToDescriptor())
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -31,7 +31,6 @@ import com.intellij.psi.PsiPackage
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getPackage
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.getFileNameAfterMove
|
||||
import java.util.HashSet
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesImpl
|
||||
@@ -41,6 +40,7 @@ import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||
import java.util.*
|
||||
|
||||
public class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
||||
private fun doMoveWithCheck(
|
||||
@@ -68,7 +68,14 @@ public class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
||||
if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, elements.toList(), true)) return false
|
||||
|
||||
[suppress("UNCHECKED_CAST")]
|
||||
val elementsToSearch = elements.toList() as List<JetNamedDeclaration>
|
||||
val elementsToSearch = elements.toSet() as Set<JetNamedDeclaration>
|
||||
|
||||
val sourceFile = elementsToSearch.mapTo(LinkedHashSet<JetFile>()) { it.getContainingJetFile() }.singleOrNull()
|
||||
if (sourceFile == null) {
|
||||
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("move.title"), "All declarations must belong to the same file", null, project)
|
||||
return false
|
||||
}
|
||||
|
||||
val targetPackageName = MoveClassesOrPackagesImpl.getInitialTargetPackageName(targetContainer, elements)
|
||||
val targetDirectory = MoveClassesOrPackagesImpl.getInitialTargetDirectory(targetContainer, elements)
|
||||
val searchInComments = JavaRefactoringSettings.getInstance()!!.MOVE_SEARCH_IN_COMMENTS
|
||||
@@ -83,7 +90,7 @@ public class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
||||
val moveToPackage = targetContainer !is JetFile
|
||||
|
||||
MoveKotlinTopLevelDeclarationsDialog(
|
||||
project, elementsToSearch, targetPackageName, targetDirectory, targetFile, moveToPackage, searchInComments, searchInText, callback
|
||||
project, sourceFile, elementsToSearch, targetPackageName, targetDirectory, targetFile, moveToPackage, searchInComments, searchInText, callback
|
||||
).show()
|
||||
|
||||
return true
|
||||
|
||||
+8
-10
@@ -10,16 +10,6 @@
|
||||
<color color="-8355712"/>
|
||||
</border>
|
||||
<children>
|
||||
<component id="ec4f" class="javax.swing.JLabel" binding="elementDescription">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="true"/>
|
||||
<font style="1"/>
|
||||
<text value="Move"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="74471" class="com.intellij.ui.NonFocusableCheckBox" binding="cbSearchInComments">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="3" indent="0" use-parent-layout="false"/>
|
||||
@@ -106,6 +96,14 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="c5589" binding="memberInfoPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<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/>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
<buttonGroups>
|
||||
|
||||
+76
-24
@@ -34,6 +34,9 @@ import com.intellij.refactoring.JavaRefactoringSettings;
|
||||
import com.intellij.refactoring.MoveDestination;
|
||||
import com.intellij.refactoring.PackageWrapper;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.classMembers.DependencyMemberInfoModel;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoChange;
|
||||
import com.intellij.refactoring.classMembers.UsesMemberDependencyGraph;
|
||||
import com.intellij.refactoring.move.MoveCallback;
|
||||
import com.intellij.refactoring.move.MoveHandler;
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.DestinationFolderComboBox;
|
||||
@@ -43,29 +46,51 @@ import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.ui.ComboboxWithBrowseButton;
|
||||
import com.intellij.ui.RecentsManager;
|
||||
import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import kotlin.Function0;
|
||||
import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage;
|
||||
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle;
|
||||
import org.jetbrains.kotlin.idea.refactoring.KotlinMemberInfo;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*;
|
||||
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinMemberSelectionPanel;
|
||||
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinMemberSelectionTable;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration;
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
private static final String RECENTS_KEY = "MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY";
|
||||
|
||||
private JLabel elementDescription;
|
||||
private class MemberInfoModelImpl extends DependencyMemberInfoModel<JetNamedDeclaration, KotlinMemberInfo> {
|
||||
public MemberInfoModelImpl() {
|
||||
super(new UsesMemberDependencyGraph<JetNamedDeclaration, JetFile, KotlinMemberInfo>(sourceFile, null, false), WARNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Boolean isFixedAbstract(KotlinMemberInfo member) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckedWhenDisabled(KotlinMemberInfo member) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private JCheckBox cbSearchInComments;
|
||||
private JCheckBox cbSearchTextOccurences;
|
||||
private JPanel mainPanel;
|
||||
@@ -76,13 +101,16 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
private JRadioButton rbMoveToPackage;
|
||||
private JRadioButton rbMoveToFile;
|
||||
private TextFieldWithBrowseButton fileChooser;
|
||||
private JPanel memberInfoPanel;
|
||||
private KotlinMemberSelectionTable memberTable;
|
||||
|
||||
private final List<JetNamedDeclaration> elementsToMove;
|
||||
private final JetFile sourceFile;
|
||||
private final MoveCallback moveCallback;
|
||||
|
||||
public MoveKotlinTopLevelDeclarationsDialog(
|
||||
@NotNull Project project,
|
||||
@NotNull List<JetNamedDeclaration> elementsToMove,
|
||||
@NotNull JetFile sourceFile,
|
||||
@NotNull Set<JetNamedDeclaration> elementsToMove,
|
||||
@Nullable String targetPackageName,
|
||||
@Nullable PsiDirectory targetDirectory,
|
||||
@Nullable JetFile targetFile,
|
||||
@@ -93,15 +121,13 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
) {
|
||||
super(project, true);
|
||||
|
||||
this.elementsToMove = elementsToMove;
|
||||
this.sourceFile = sourceFile;
|
||||
this.moveCallback = moveCallback;
|
||||
|
||||
init();
|
||||
|
||||
setTitle(MoveHandler.REFACTORING_NAME);
|
||||
|
||||
initElementDescription(elementsToMove);
|
||||
|
||||
initSearchOptions(searchInComments, searchForTextOccurences);
|
||||
|
||||
initPackageChooser(targetPackageName, targetDirectory);
|
||||
@@ -110,7 +136,32 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
|
||||
initMoveToButtons(moveToPackage);
|
||||
|
||||
initMemberInfo(elementsToMove);
|
||||
|
||||
updateControls();
|
||||
|
||||
pack();
|
||||
}
|
||||
|
||||
private void initMemberInfo(@NotNull final Set<JetNamedDeclaration> elementsToMove) {
|
||||
List<KotlinMemberInfo> memberInfos = KotlinPackage.map(
|
||||
KotlinPackage.filterIsInstance(sourceFile.getDeclarations(), JetNamedDeclaration.class),
|
||||
new Function1<JetNamedDeclaration, KotlinMemberInfo>() {
|
||||
@Override
|
||||
public KotlinMemberInfo invoke(JetNamedDeclaration declaration) {
|
||||
KotlinMemberInfo memberInfo = new KotlinMemberInfo(declaration);
|
||||
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<JetNamedDeclaration, KotlinMemberInfo>(memberInfos));
|
||||
selectionPanel.getTable().setMemberInfoModel(memberInfoModel);
|
||||
selectionPanel.getTable().addMemberInfoChangeListener(memberInfoModel);
|
||||
memberInfoPanel.add(selectionPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private void initPackageChooser(String targetPackageName, PsiDirectory targetDirectory) {
|
||||
@@ -177,22 +228,6 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private void initElementDescription(List<JetNamedDeclaration> elementsToMove) {
|
||||
if (elementsToMove.size() == 1) {
|
||||
PsiElement element = elementsToMove.get(0);
|
||||
elementDescription.setText(
|
||||
JetRefactoringBundle.message(
|
||||
"refactoring.move.specifc.element",
|
||||
UsageViewUtil.getType(element),
|
||||
UsageViewUtil.getLongName(element)
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (elementsToMove.size() > 1) {
|
||||
elementDescription.setText(JetRefactoringBundle.message("refactoring.move.selected.elements"));
|
||||
}
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
classPackageChooser = createPackageChooser();
|
||||
|
||||
@@ -298,6 +333,8 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
|
||||
@Nullable
|
||||
private String verifyBeforeRun() {
|
||||
if (memberTable.getSelectedMemberInfos().isEmpty()) return "At least one member must be selected";
|
||||
|
||||
if (isMoveToPackage()) {
|
||||
String name = getTargetPackage().trim();
|
||||
if (name.length() != 0 && !PsiNameHelper.getInstance(myProject).isQualifiedName(name)) {
|
||||
@@ -314,6 +351,18 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<JetNamedDeclaration> getSelectedElementsToMove() {
|
||||
return KotlinPackage.map(
|
||||
memberTable.getSelectedMemberInfos(),
|
||||
new Function1<KotlinMemberInfo, JetNamedDeclaration>() {
|
||||
@Override
|
||||
public JetNamedDeclaration invoke(KotlinMemberInfo info) {
|
||||
return info.getMember();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
boolean isDestinationVisible = hasAnySourceRoots();
|
||||
@@ -354,6 +403,9 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
if (target == null) return;
|
||||
|
||||
saveRefactoringSettings();
|
||||
|
||||
List<JetNamedDeclaration> elementsToMove = getSelectedElementsToMove();
|
||||
|
||||
for (PsiElement element : elementsToMove) {
|
||||
String message = target.verify(element.getContainingFile());
|
||||
if (message != null) {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.ui
|
||||
|
||||
import com.intellij.refactoring.ui.AbstractMemberSelectionPanel
|
||||
import com.intellij.ui.ScrollPaneFactory
|
||||
import com.intellij.ui.SeparatorFactory
|
||||
import org.jetbrains.kotlin.idea.refactoring.KotlinMemberInfo
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import java.awt.BorderLayout
|
||||
|
||||
public class KotlinMemberSelectionPanel(title: String,
|
||||
memberInfo: List<KotlinMemberInfo>,
|
||||
abstractColumnHeader: String?
|
||||
) : AbstractMemberSelectionPanel<JetNamedDeclaration, KotlinMemberInfo>() {
|
||||
private val table = createMemberSelectionTable(memberInfo, abstractColumnHeader)
|
||||
|
||||
init {
|
||||
setLayout(BorderLayout())
|
||||
|
||||
val scrollPane = ScrollPaneFactory.createScrollPane(table)
|
||||
add(SeparatorFactory.createSeparator(title, table), BorderLayout.NORTH)
|
||||
add(scrollPane, BorderLayout.CENTER)
|
||||
}
|
||||
|
||||
protected fun createMemberSelectionTable(
|
||||
memberInfo: List<KotlinMemberInfo>,
|
||||
abstractColumnHeader: String?
|
||||
): KotlinMemberSelectionTable {
|
||||
return KotlinMemberSelectionTable(memberInfo, null, abstractColumnHeader)
|
||||
}
|
||||
|
||||
override fun getTable() = table
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.ui
|
||||
|
||||
import com.intellij.refactoring.classMembers.MemberInfoModel
|
||||
import com.intellij.refactoring.ui.AbstractMemberSelectionTable
|
||||
import com.intellij.ui.RowIcon
|
||||
import com.intellij.util.IconUtil
|
||||
import org.jetbrains.kotlin.idea.JetIconProvider
|
||||
import org.jetbrains.kotlin.idea.refactoring.KotlinMemberInfo
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
|
||||
public class KotlinMemberSelectionTable(
|
||||
memberInfos: List<KotlinMemberInfo>,
|
||||
memberInfoModel: MemberInfoModel<JetNamedDeclaration, KotlinMemberInfo>?,
|
||||
abstractColumnHeader: String?
|
||||
) : AbstractMemberSelectionTable<JetNamedDeclaration, KotlinMemberInfo>(memberInfos, memberInfoModel, abstractColumnHeader) {
|
||||
override fun getAbstractColumnValue(memberInfo: KotlinMemberInfo) = null
|
||||
|
||||
override fun isAbstractColumnEditable(rowIndex: Int) = false
|
||||
|
||||
override fun setVisibilityIcon(memberInfo: KotlinMemberInfo, icon: RowIcon) {
|
||||
icon.setIcon(JetIconProvider.getVisibilityIcon(memberInfo.getMember().getModifierList()), 1);
|
||||
}
|
||||
|
||||
override fun getOverrideIcon(memberInfo: KotlinMemberInfo) = AbstractMemberSelectionTable.EMPTY_OVERRIDE_ICON
|
||||
}
|
||||
Reference in New Issue
Block a user