Move Declarations: Support multiple files
#KT-8431 Fixed
This commit is contained in:
+8
-4
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiManager
|
|||||||
import com.intellij.refactoring.PackageWrapper
|
import com.intellij.refactoring.PackageWrapper
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
public interface KotlinMoveTarget {
|
public interface KotlinMoveTarget {
|
||||||
val packageWrapper: PackageWrapper?
|
val packageWrapper: PackageWrapper?
|
||||||
@@ -48,13 +49,16 @@ public class JetFileKotlinMoveTarget(val targetFile: JetFile): KotlinMoveTarget
|
|||||||
|
|
||||||
public class DeferredJetFileKotlinMoveTarget(
|
public class DeferredJetFileKotlinMoveTarget(
|
||||||
project: Project,
|
project: Project,
|
||||||
val packageFqName: FqName,
|
private val packageFqName: FqName,
|
||||||
createFile: () -> JetFile?): KotlinMoveTarget {
|
private val createFile: (JetFile) -> JetFile?): KotlinMoveTarget {
|
||||||
val createdFile: JetFile? by lazy(createFile)
|
private val createdFiles = HashMap<JetFile, JetFile?>()
|
||||||
|
|
||||||
override val packageWrapper: PackageWrapper = PackageWrapper(PsiManager.getInstance(project), packageFqName.asString())
|
override val packageWrapper: PackageWrapper = PackageWrapper(PsiManager.getInstance(project), packageFqName.asString())
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = createdFile
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement): PsiFile? {
|
||||||
|
val originalFile = originalPsi.containingFile as? JetFile ?: return null
|
||||||
|
return createdFiles.getOrPut(originalFile) { createFile(originalFile) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||||
|
|
||||||
|
|||||||
+14
-17
@@ -20,42 +20,39 @@ import com.intellij.openapi.actionSystem.DataContext
|
|||||||
import com.intellij.openapi.actionSystem.LangDataKeys
|
import com.intellij.openapi.actionSystem.LangDataKeys
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.PsiDirectory
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiPackage
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.refactoring.JavaRefactoringSettings
|
import com.intellij.refactoring.JavaRefactoringSettings
|
||||||
import com.intellij.refactoring.RefactoringBundle
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
import com.intellij.refactoring.move.MoveCallback
|
import com.intellij.refactoring.move.MoveCallback
|
||||||
import com.intellij.refactoring.move.MoveHandlerDelegate
|
import com.intellij.refactoring.move.MoveHandlerDelegate
|
||||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesImpl
|
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesImpl
|
||||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
|
|
||||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||||
|
import org.jetbrains.kotlin.idea.core.getPackage
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.isInJavaSourceRoot
|
import org.jetbrains.kotlin.idea.core.refactoring.isInJavaSourceRoot
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.*
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.idea.core.getPackage
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.guessNewFileName
|
|
||||||
import java.util.HashSet
|
|
||||||
import java.util.LinkedHashSet
|
import java.util.LinkedHashSet
|
||||||
|
|
||||||
public class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
public class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
||||||
|
private fun getSourceDirectories(elements: Array<out PsiElement>) = elements.mapTo(LinkedHashSet()) { it.containingFile?.parent }
|
||||||
|
|
||||||
private fun doMoveWithCheck(
|
private fun doMoveWithCheck(
|
||||||
project: Project, elements: Array<out PsiElement>, targetContainer: PsiElement?, callback: MoveCallback?
|
project: Project, elements: Array<out PsiElement>, targetContainer: PsiElement?, callback: MoveCallback?
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, elements.toList(), true)) return false
|
if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, elements.toList(), true)) return false
|
||||||
|
if (getSourceDirectories(elements).singleOrNull() == null) {
|
||||||
@suppress("UNCHECKED_CAST")
|
|
||||||
val elementsToSearch = elements.toSet() as Set<JetNamedDeclaration>
|
|
||||||
|
|
||||||
val sourceFiles = elementsToSearch.mapTo(LinkedHashSet<JetFile>()) { it.getContainingJetFile() }
|
|
||||||
val sourceFile = sourceFiles.singleOrNull()
|
|
||||||
if (sourceFile == null) {
|
|
||||||
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("move.title"),
|
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("move.title"),
|
||||||
"All declarations must belong to the same file",
|
"All declarations must belong to the same directory",
|
||||||
null,
|
null,
|
||||||
project)
|
project)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val elementsToSearch = elements.mapTo(LinkedHashSet()) { it as JetNamedDeclaration }
|
||||||
|
|
||||||
val targetPackageName = MoveClassesOrPackagesImpl.getInitialTargetPackageName(targetContainer, elements)
|
val targetPackageName = MoveClassesOrPackagesImpl.getInitialTargetPackageName(targetContainer, elements)
|
||||||
val targetDirectory = MoveClassesOrPackagesImpl.getInitialTargetDirectory(targetContainer, elements)
|
val targetDirectory = MoveClassesOrPackagesImpl.getInitialTargetDirectory(targetContainer, elements)
|
||||||
val searchInComments = JavaRefactoringSettings.getInstance()!!.MOVE_SEARCH_IN_COMMENTS
|
val searchInComments = JavaRefactoringSettings.getInstance()!!.MOVE_SEARCH_IN_COMMENTS
|
||||||
@@ -64,7 +61,7 @@ public class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
|||||||
val moveToPackage = targetContainer !is JetFile
|
val moveToPackage = targetContainer !is JetFile
|
||||||
|
|
||||||
MoveKotlinTopLevelDeclarationsDialog(
|
MoveKotlinTopLevelDeclarationsDialog(
|
||||||
project, sourceFile, elementsToSearch, targetPackageName, targetDirectory, targetFile, moveToPackage, searchInComments, searchInText, callback
|
project, elementsToSearch, targetPackageName, targetDirectory, targetFile, moveToPackage, searchInComments, searchInText, callback
|
||||||
).show()
|
).show()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -72,11 +69,11 @@ public class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
|||||||
|
|
||||||
override fun canMove(elements: Array<out PsiElement>, targetContainer: PsiElement?): Boolean {
|
override fun canMove(elements: Array<out PsiElement>, targetContainer: PsiElement?): Boolean {
|
||||||
if (!super.canMove(elements, targetContainer)) return false
|
if (!super.canMove(elements, targetContainer)) return false
|
||||||
if (elements.map { it.getContainingFile() }.distinct().size() != 1) return false
|
if (getSourceDirectories(elements).singleOrNull() == null) return false
|
||||||
|
|
||||||
return elements.all { e ->
|
return elements.all { e ->
|
||||||
if (e is JetClass || (e is JetObjectDeclaration && !e.isObjectLiteral()) || e is JetNamedFunction || e is JetProperty) {
|
if (e is JetClass || (e is JetObjectDeclaration && !e.isObjectLiteral()) || e is JetNamedFunction || e is JetProperty) {
|
||||||
val parent = e.getParent()
|
val parent = e.parent
|
||||||
parent is JetFile && parent.isInJavaSourceRoot()
|
parent is JetFile && parent.isInJavaSourceRoot()
|
||||||
}
|
}
|
||||||
else false
|
else false
|
||||||
|
|||||||
+241
-108
@@ -31,13 +31,15 @@ import com.intellij.openapi.ui.TextComponentAccessor;
|
|||||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||||
import com.intellij.openapi.util.EmptyRunnable;
|
import com.intellij.openapi.util.EmptyRunnable;
|
||||||
import com.intellij.openapi.util.Pass;
|
import com.intellij.openapi.util.Pass;
|
||||||
import com.intellij.openapi.util.io.FileUtilRt;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.refactoring.*;
|
import com.intellij.refactoring.JavaRefactoringSettings;
|
||||||
import com.intellij.refactoring.classMembers.DependencyMemberInfoModel;
|
import com.intellij.refactoring.MoveDestination;
|
||||||
|
import com.intellij.refactoring.PackageWrapper;
|
||||||
|
import com.intellij.refactoring.RefactoringBundle;
|
||||||
|
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel;
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoChange;
|
import com.intellij.refactoring.classMembers.MemberInfoChange;
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoChangeListener;
|
import com.intellij.refactoring.classMembers.MemberInfoChangeListener;
|
||||||
import com.intellij.refactoring.classMembers.UsesMemberDependencyGraph;
|
|
||||||
import com.intellij.refactoring.move.MoveCallback;
|
import com.intellij.refactoring.move.MoveCallback;
|
||||||
import com.intellij.refactoring.move.MoveHandler;
|
import com.intellij.refactoring.move.MoveHandler;
|
||||||
import com.intellij.refactoring.move.moveClassesOrPackages.DestinationFolderComboBox;
|
import com.intellij.refactoring.move.moveClassesOrPackages.DestinationFolderComboBox;
|
||||||
@@ -49,6 +51,7 @@ import com.intellij.ui.ComboboxWithBrowseButton;
|
|||||||
import com.intellij.ui.RecentsManager;
|
import com.intellij.ui.RecentsManager;
|
||||||
import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
|
import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
|
||||||
import com.intellij.usageView.UsageInfo;
|
import com.intellij.usageView.UsageInfo;
|
||||||
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.IncorrectOperationException;
|
import com.intellij.util.IncorrectOperationException;
|
||||||
import com.intellij.util.text.UniqueNameGenerator;
|
import com.intellij.util.text.UniqueNameGenerator;
|
||||||
import com.intellij.util.ui.UIUtil;
|
import com.intellij.util.ui.UIUtil;
|
||||||
@@ -62,10 +65,10 @@ import org.jetbrains.kotlin.idea.core.CorePackage;
|
|||||||
import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage;
|
import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle;
|
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.MovePackage;
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*;
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.move.MovePackage;
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*;
|
||||||
import org.jetbrains.kotlin.idea.util.application.ApplicationPackage;
|
import org.jetbrains.kotlin.idea.util.application.ApplicationPackage;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.psi.JetFile;
|
import org.jetbrains.kotlin.psi.JetFile;
|
||||||
@@ -76,28 +79,14 @@ import java.awt.*;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||||
private static final String RECENTS_KEY = "MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY";
|
private static final String RECENTS_KEY = "MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY";
|
||||||
|
|
||||||
private class MemberInfoModelImpl extends DependencyMemberInfoModel<JetNamedDeclaration, KotlinMemberInfo> {
|
private static class MemberInfoModelImpl extends AbstractMemberInfoModel<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 cbSearchInComments;
|
||||||
@@ -115,12 +104,10 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
private JCheckBox cbUpdatePackageDirective;
|
private JCheckBox cbUpdatePackageDirective;
|
||||||
private KotlinMemberSelectionTable memberTable;
|
private KotlinMemberSelectionTable memberTable;
|
||||||
|
|
||||||
private final JetFile sourceFile;
|
|
||||||
private final MoveCallback moveCallback;
|
private final MoveCallback moveCallback;
|
||||||
|
|
||||||
public MoveKotlinTopLevelDeclarationsDialog(
|
public MoveKotlinTopLevelDeclarationsDialog(
|
||||||
@NotNull Project project,
|
@NotNull Project project,
|
||||||
@NotNull JetFile sourceFile,
|
|
||||||
@NotNull Set<JetNamedDeclaration> elementsToMove,
|
@NotNull Set<JetNamedDeclaration> elementsToMove,
|
||||||
@Nullable String targetPackageName,
|
@Nullable String targetPackageName,
|
||||||
@Nullable PsiDirectory targetDirectory,
|
@Nullable PsiDirectory targetDirectory,
|
||||||
@@ -132,7 +119,8 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
) {
|
) {
|
||||||
super(project, true);
|
super(project, true);
|
||||||
|
|
||||||
this.sourceFile = sourceFile;
|
List<JetFile> sourceFiles = getSourceFiles(elementsToMove);
|
||||||
|
|
||||||
this.moveCallback = moveCallback;
|
this.moveCallback = moveCallback;
|
||||||
|
|
||||||
init();
|
init();
|
||||||
@@ -141,22 +129,78 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
initSearchOptions(searchInComments, searchForTextOccurences);
|
initSearchOptions(searchInComments, searchForTextOccurences);
|
||||||
|
|
||||||
initPackageChooser(targetPackageName, targetDirectory);
|
initPackageChooser(targetPackageName, targetDirectory, sourceFiles);
|
||||||
|
|
||||||
initFileChooser(targetFile, elementsToMove);
|
initFileChooser(targetFile, elementsToMove, sourceFiles);
|
||||||
|
|
||||||
initMoveToButtons(moveToPackage);
|
initMoveToButtons(moveToPackage);
|
||||||
|
|
||||||
initMemberInfo(elementsToMove);
|
initMemberInfo(elementsToMove, sourceFiles);
|
||||||
|
|
||||||
updateControls();
|
updateControls();
|
||||||
|
|
||||||
pack();
|
pack();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initMemberInfo(@NotNull final Set<JetNamedDeclaration> elementsToMove) {
|
private static List<JetFile> getSourceFiles(@NotNull Collection<JetNamedDeclaration> elementsToMove) {
|
||||||
|
return KotlinPackage.distinct(
|
||||||
|
KotlinPackage.map(
|
||||||
|
elementsToMove,
|
||||||
|
new Function1<JetNamedDeclaration, JetFile>() {
|
||||||
|
@Override
|
||||||
|
public JetFile invoke(JetNamedDeclaration declaration) {
|
||||||
|
return declaration.getContainingJetFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static PsiDirectory getSourceDirectory(@NotNull Collection<JetFile> sourceFiles) {
|
||||||
|
return KotlinPackage.single(
|
||||||
|
KotlinPackage.distinct(
|
||||||
|
KotlinPackage.map(
|
||||||
|
sourceFiles,
|
||||||
|
new Function1<JetFile, PsiDirectory>() {
|
||||||
|
@Override
|
||||||
|
public PsiDirectory invoke(JetFile jetFile) {
|
||||||
|
return jetFile.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<JetNamedDeclaration> getAllDeclarations(Collection<JetFile> sourceFiles) {
|
||||||
|
return KotlinPackage.filterIsInstance(
|
||||||
|
KotlinPackage.flatMap(
|
||||||
|
sourceFiles,
|
||||||
|
new Function1<JetFile, Iterable<?>>() {
|
||||||
|
@Override
|
||||||
|
public Iterable<?> invoke(JetFile jetFile) {
|
||||||
|
return jetFile.getDeclarations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
JetNamedDeclaration.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean arePackagesAndDirectoryMatched(List<JetFile> sourceFiles) {
|
||||||
|
for (JetFile sourceFile : sourceFiles) {
|
||||||
|
if (!CorePackage.packageMatchesDirectory(sourceFile)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initMemberInfo(
|
||||||
|
@NotNull final Set<JetNamedDeclaration> elementsToMove,
|
||||||
|
@NotNull List<JetFile> sourceFiles
|
||||||
|
) {
|
||||||
final List<KotlinMemberInfo> memberInfos = KotlinPackage.map(
|
final List<KotlinMemberInfo> memberInfos = KotlinPackage.map(
|
||||||
KotlinPackage.filterIsInstance(sourceFile.getDeclarations(), JetNamedDeclaration.class),
|
getAllDeclarations(sourceFiles),
|
||||||
new Function1<JetNamedDeclaration, KotlinMemberInfo>() {
|
new Function1<JetNamedDeclaration, KotlinMemberInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public KotlinMemberInfo invoke(JetNamedDeclaration declaration) {
|
public KotlinMemberInfo invoke(JetNamedDeclaration declaration) {
|
||||||
@@ -190,13 +234,14 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
);
|
);
|
||||||
String suggestedText = previousDeclarations.isEmpty()
|
String suggestedText = previousDeclarations.isEmpty()
|
||||||
? ""
|
? ""
|
||||||
: MovePackage.guessNewFileName(sourceFile, previousDeclarations);
|
: MovePackage.guessNewFileName(previousDeclarations);
|
||||||
return tfFileNameInPackage.getText().equals(suggestedText);
|
return tfFileNameInPackage.getText().equals(suggestedText);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void memberInfoChanged(MemberInfoChange<JetNamedDeclaration, KotlinMemberInfo> event) {
|
public void memberInfoChanged(MemberInfoChange<JetNamedDeclaration, KotlinMemberInfo> event) {
|
||||||
updatePackageDirectiveCheckBox();
|
updatePackageDirectiveCheckBox();
|
||||||
|
updateFileNameInPackageField();
|
||||||
// Update file name field only if it user hasn't changed it to some non-default value
|
// Update file name field only if it user hasn't changed it to some non-default value
|
||||||
if (shouldUpdateFileNameField(event.getChangedMembers())) {
|
if (shouldUpdateFileNameField(event.getChangedMembers())) {
|
||||||
updateSuggestedFileName();
|
updateSuggestedFileName();
|
||||||
@@ -205,19 +250,25 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
memberInfoPanel.add(selectionPanel, BorderLayout.CENTER);
|
memberInfoPanel.add(selectionPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSuggestedFileName() {
|
private void updateSuggestedFileName() {
|
||||||
tfFileNameInPackage.setText(MovePackage.guessNewFileName(sourceFile, getSelectedElementsToMove()));
|
tfFileNameInPackage.setText(MovePackage.guessNewFileName(getSelectedElementsToMove()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFileNameInPackageField() {
|
private void updateFileNameInPackageField() {
|
||||||
cbSpecifyFileNameInPackage.setEnabled(isMoveToPackage());
|
boolean movingSingleFileToPackage = isMoveToPackage()
|
||||||
tfFileNameInPackage.setEnabled(isMoveToPackage() && cbSpecifyFileNameInPackage.isSelected());
|
&& getSourceFiles(getSelectedElementsToMove()).size() == 1;
|
||||||
|
cbSpecifyFileNameInPackage.setEnabled(movingSingleFileToPackage);
|
||||||
|
tfFileNameInPackage.setEnabled(movingSingleFileToPackage && cbSpecifyFileNameInPackage.isSelected());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initPackageChooser(String targetPackageName, PsiDirectory targetDirectory) {
|
private void initPackageChooser(
|
||||||
|
String targetPackageName,
|
||||||
|
PsiDirectory targetDirectory,
|
||||||
|
List<JetFile> sourceFiles
|
||||||
|
) {
|
||||||
if (targetPackageName != null) {
|
if (targetPackageName != null) {
|
||||||
classPackageChooser.prependItem(targetPackageName);
|
classPackageChooser.prependItem(targetPackageName);
|
||||||
}
|
}
|
||||||
@@ -243,7 +294,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
cbUpdatePackageDirective.setSelected(CorePackage.packageMatchesDirectory(sourceFile));
|
cbUpdatePackageDirective.setSelected(arePackagesAndDirectoryMatched(sourceFiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initSearchOptions(boolean searchInComments, boolean searchForTextOccurences) {
|
private void initSearchOptions(boolean searchInComments, boolean searchForTextOccurences) {
|
||||||
@@ -280,7 +331,11 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initFileChooser(@Nullable JetFile targetFile, @NotNull Set<JetNamedDeclaration> elementsToMove) {
|
private void initFileChooser(
|
||||||
|
@Nullable JetFile targetFile,
|
||||||
|
@NotNull Set<JetNamedDeclaration> elementsToMove,
|
||||||
|
@NotNull List<JetFile> sourceFiles
|
||||||
|
) {
|
||||||
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()
|
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()
|
||||||
.withRoots(ProjectRootManager.getInstance(myProject).getContentRoots())
|
.withRoots(ProjectRootManager.getInstance(myProject).getContentRoots())
|
||||||
.withTreeRootVisible(true);
|
.withTreeRootVisible(true);
|
||||||
@@ -291,7 +346,9 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
String initialTargetPath =
|
String initialTargetPath =
|
||||||
targetFile != null
|
targetFile != null
|
||||||
? targetFile.getVirtualFile().getPath()
|
? targetFile.getVirtualFile().getPath()
|
||||||
: sourceFile.getVirtualFile().getParent().getPath() + "/" + MovePackage.guessNewFileName(sourceFile, elementsToMove);
|
: sourceFiles.get(0).getVirtualFile().getParent().getPath() +
|
||||||
|
"/" +
|
||||||
|
MovePackage.guessNewFileName(elementsToMove);
|
||||||
fileChooser.setText(initialTargetPath);
|
fileChooser.setText(initialTargetPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,8 +388,24 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
validateButtons();
|
validateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isFullFileMove() {
|
||||||
|
Map<JetFile, List<? extends JetNamedDeclaration>> fileToElements = KotlinPackage.groupBy(
|
||||||
|
getSelectedElementsToMove(),
|
||||||
|
new Function1<JetNamedDeclaration, JetFile>() {
|
||||||
|
@Override
|
||||||
|
public JetFile invoke(JetNamedDeclaration declaration) {
|
||||||
|
return declaration.getContainingJetFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
for (Map.Entry<JetFile, List<? extends JetNamedDeclaration>> entry : fileToElements.entrySet()) {
|
||||||
|
if (entry.getKey().getDeclarations().size() != entry.getValue().size()) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void updatePackageDirectiveCheckBox() {
|
private void updatePackageDirectiveCheckBox() {
|
||||||
cbUpdatePackageDirective.setEnabled(isMoveToPackage() && getSelectedElementsToMove().size() == sourceFile.getDeclarations().size());
|
cbUpdatePackageDirective.setEnabled(isMoveToPackage() && isFullFileMove());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAnySourceRoots() {
|
private boolean hasAnySourceRoots() {
|
||||||
@@ -367,6 +440,40 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static List<PsiFile> getFilesExistingInTargetDir(
|
||||||
|
@NotNull List<JetFile> sourceFiles,
|
||||||
|
@Nullable String targetFileName,
|
||||||
|
@Nullable final PsiDirectory targetDirectory
|
||||||
|
) {
|
||||||
|
if (targetDirectory == null) return Collections.emptyList();
|
||||||
|
|
||||||
|
List<String> fileNames =
|
||||||
|
targetFileName != null
|
||||||
|
? Collections.singletonList(targetFileName)
|
||||||
|
: KotlinPackage.map(
|
||||||
|
sourceFiles,
|
||||||
|
new Function1<JetFile, String>() {
|
||||||
|
@Override
|
||||||
|
public String invoke(JetFile jetFile) {
|
||||||
|
return jetFile.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return KotlinPackage.filterNotNull(
|
||||||
|
KotlinPackage.map(
|
||||||
|
fileNames,
|
||||||
|
new Function1<String, PsiFile>() {
|
||||||
|
@Override
|
||||||
|
public PsiFile invoke(String s) {
|
||||||
|
return targetDirectory.findFile(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private KotlinMoveTarget selectMoveTarget() {
|
private KotlinMoveTarget selectMoveTarget() {
|
||||||
String message = verifyBeforeRun();
|
String message = verifyBeforeRun();
|
||||||
@@ -377,39 +484,63 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
setErrorText(null);
|
setErrorText(null);
|
||||||
|
|
||||||
|
List<JetFile> sourceFiles = getSourceFiles(getSelectedElementsToMove());
|
||||||
|
PsiDirectory sourceDirectory = getSourceDirectory(sourceFiles);
|
||||||
|
|
||||||
if (isMoveToPackage()) {
|
if (isMoveToPackage()) {
|
||||||
final MoveDestination moveDestination = selectPackageBasedMoveDestination(true);
|
final MoveDestination moveDestination = selectPackageBasedMoveDestination(true);
|
||||||
if (moveDestination == null) return null;
|
if (moveDestination == null) return null;
|
||||||
|
|
||||||
final String targetFileName = tfFileNameInPackage.getText();
|
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||||
if (!checkTargetFileName(targetFileName)) return null;
|
if (targetFileName != null && !checkTargetFileName(targetFileName)) return null;
|
||||||
|
|
||||||
PsiDirectory directory = moveDestination.getTargetIfExists(sourceFile);
|
PsiDirectory targetDirectory = moveDestination.getTargetIfExists(sourceDirectory);
|
||||||
PsiFile targetFile = directory != null ? directory.findFile(targetFileName) : null;
|
|
||||||
if (targetFile != null) {
|
List<PsiFile> filesExistingInTargetDir = getFilesExistingInTargetDir(sourceFiles, targetFileName, targetDirectory);
|
||||||
if (targetFile == sourceFile) {
|
if (!filesExistingInTargetDir.isEmpty()) {
|
||||||
setErrorText("Can't move to the original file");
|
if (!KotlinPackage.intersect(sourceFiles, filesExistingInTargetDir).isEmpty()) {
|
||||||
|
setErrorText("Can't move to the original file(s)");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String question = "File '" +
|
if (filesExistingInTargetDir.size() > 1) {
|
||||||
directory.getVirtualFile().getPath() +
|
String filePathsToReport = StringUtil.join(
|
||||||
"/" +
|
filesExistingInTargetDir,
|
||||||
targetFileName +
|
new Function<PsiFile, String>() {
|
||||||
"' already exists." +
|
@Override
|
||||||
"Do you want to move selected declarations to this file?";
|
public String fun(PsiFile file) {
|
||||||
int ret = Messages.showYesNoDialog(myProject, question, RefactoringBundle.message("move.title"), Messages.getQuestionIcon());
|
return file.getVirtualFile().getPath();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
myProject,
|
||||||
|
"Cannot perform refactoring since the following files already exist:\n\n" + filePathsToReport,
|
||||||
|
RefactoringBundle.message("move.title")
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String question = String.format(
|
||||||
|
"File '%s' already exists. Do you want to move selected declarations to this file?",
|
||||||
|
filesExistingInTargetDir.get(0).getVirtualFile().getPath()
|
||||||
|
);
|
||||||
|
int ret =
|
||||||
|
Messages.showYesNoDialog(myProject, question, RefactoringBundle.message("move.title"), Messages.getQuestionIcon());
|
||||||
if (ret != Messages.YES) return null;
|
if (ret != Messages.YES) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DeferredJetFileKotlinMoveTarget(
|
return new DeferredJetFileKotlinMoveTarget(
|
||||||
myProject,
|
myProject,
|
||||||
new FqName(getTargetPackage()),
|
new FqName(getTargetPackage()),
|
||||||
new Function0<JetFile>() {
|
new Function1<JetFile, JetFile>() {
|
||||||
@Override
|
@Override
|
||||||
public JetFile invoke() {
|
public JetFile invoke(@NotNull JetFile originalFile) {
|
||||||
PsiDirectory directory = moveDestination.getTargetDirectory(sourceFile);
|
return RefactoringPackage.getOrCreateKotlinFile(
|
||||||
return RefactoringPackage.getOrCreateKotlinFile(targetFileName, directory);
|
targetFileName != null ? targetFileName : originalFile.getName(),
|
||||||
|
moveDestination.getTargetDirectory(originalFile)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -419,7 +550,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
if (!checkTargetFileName(targetFile.getName())) return null;
|
if (!checkTargetFileName(targetFile.getName())) return null;
|
||||||
JetFile jetFile = (JetFile) RefactoringPackage.toPsiFile(targetFile, myProject);
|
JetFile jetFile = (JetFile) RefactoringPackage.toPsiFile(targetFile, myProject);
|
||||||
if (jetFile != null) {
|
if (jetFile != null) {
|
||||||
if (jetFile == sourceFile) {
|
if (sourceFiles.size() == 1 && sourceFiles.contains(jetFile)) {
|
||||||
setErrorText("Can't move to the original file");
|
setErrorText("Can't move to the original file");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -427,14 +558,6 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
return new JetFileKotlinMoveTarget(jetFile);
|
return new JetFileKotlinMoveTarget(jetFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = Messages.showYesNoDialog(
|
|
||||||
myProject,
|
|
||||||
JetRefactoringBundle.message("file.does.not.exist", targetFile.getName()),
|
|
||||||
RefactoringBundle.message("move.title"),
|
|
||||||
Messages.getQuestionIcon()
|
|
||||||
);
|
|
||||||
if (ret != Messages.YES) return null;
|
|
||||||
|
|
||||||
File targetDir = targetFile.getParentFile();
|
File targetDir = targetFile.getParentFile();
|
||||||
final PsiDirectory psiDirectory = RefactoringPackage.toPsiDirectory(targetDir, myProject);
|
final PsiDirectory psiDirectory = RefactoringPackage.toPsiDirectory(targetDir, myProject);
|
||||||
assert psiDirectory != null : "No directory found: " + targetDir.getPath();
|
assert psiDirectory != null : "No directory found: " + targetDir.getPath();
|
||||||
@@ -448,9 +571,9 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
return new DeferredJetFileKotlinMoveTarget(
|
return new DeferredJetFileKotlinMoveTarget(
|
||||||
myProject,
|
myProject,
|
||||||
new FqName(psiPackage.getQualifiedName()),
|
new FqName(psiPackage.getQualifiedName()),
|
||||||
new Function0<JetFile>() {
|
new Function1<JetFile, JetFile>() {
|
||||||
@Override
|
@Override
|
||||||
public JetFile invoke() {
|
public JetFile invoke(@NotNull JetFile originalFile) {
|
||||||
return RefactoringPackage.getOrCreateKotlinFile(targetFile.getName(), psiDirectory);
|
return RefactoringPackage.getOrCreateKotlinFile(targetFile.getName(), psiDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,7 +597,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tfFileNameInPackage.getText().isEmpty()) {
|
if (getSourceFiles(getSelectedElementsToMove()).size() == 1 && tfFileNameInPackage.getText().isEmpty()) {
|
||||||
return "File name may not be empty";
|
return "File name may not be empty";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,6 +650,8 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
saveRefactoringSettings();
|
saveRefactoringSettings();
|
||||||
|
|
||||||
List<JetNamedDeclaration> elementsToMove = getSelectedElementsToMove();
|
List<JetNamedDeclaration> elementsToMove = getSelectedElementsToMove();
|
||||||
|
final List<JetFile> sourceFiles = getSourceFiles(elementsToMove);
|
||||||
|
final PsiDirectory sourceDirectory = getSourceDirectory(sourceFiles);
|
||||||
|
|
||||||
for (PsiElement element : elementsToMove) {
|
for (PsiElement element : elementsToMove) {
|
||||||
String message = target.verify(element.getContainingFile());
|
String message = target.verify(element.getContainingFile());
|
||||||
@@ -538,27 +663,32 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
boolean deleteSourceFile = false;
|
boolean deleteSourceFile = false;
|
||||||
|
|
||||||
if (elementsToMove.size() == sourceFile.getDeclarations().size()) {
|
if (isFullFileMove()) {
|
||||||
if (isMoveToPackage()) {
|
if (isMoveToPackage()) {
|
||||||
final MoveDestination moveDestination = selectPackageBasedMoveDestination(false);
|
final MoveDestination moveDestination = selectPackageBasedMoveDestination(false);
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
PsiDirectory targetDir = moveDestination.getTargetIfExists(sourceFile);
|
PsiDirectory targetDir = moveDestination.getTargetIfExists(sourceDirectory);
|
||||||
final String targetFileName = tfFileNameInPackage.getText();
|
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||||
if (targetDir == null || targetDir.findFile(targetFileName) == null) {
|
List<PsiFile> filesExistingInTargetDir = getFilesExistingInTargetDir(sourceFiles, targetFileName, targetDir);
|
||||||
|
if (filesExistingInTargetDir.isEmpty()) {
|
||||||
PsiDirectory targetDirectory = ApplicationPackage.runWriteAction(
|
PsiDirectory targetDirectory = ApplicationPackage.runWriteAction(
|
||||||
new Function0<PsiDirectory>() {
|
new Function0<PsiDirectory>() {
|
||||||
@Override
|
@Override
|
||||||
public PsiDirectory invoke() {
|
public PsiDirectory invoke() {
|
||||||
return moveDestination.getTargetDirectory(sourceFile);
|
return moveDestination.getTargetDirectory(sourceDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
MovePackage.setUpdatePackageDirective(sourceFile, cbUpdatePackageDirective.isSelected());
|
|
||||||
|
for (JetFile sourceFile : sourceFiles) {
|
||||||
|
MovePackage.setUpdatePackageDirective(sourceFile, cbUpdatePackageDirective.isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
invokeRefactoring(
|
invokeRefactoring(
|
||||||
new MoveFilesOrDirectoriesProcessor(
|
new MoveFilesOrDirectoriesProcessor(
|
||||||
myProject,
|
myProject,
|
||||||
new PsiElement[] {sourceFile},
|
sourceFiles.toArray(new PsiElement[sourceFiles.size()]),
|
||||||
targetDirectory,
|
targetDirectory,
|
||||||
true,
|
true,
|
||||||
isSearchInComments(),
|
isSearchInComments(),
|
||||||
@@ -567,7 +697,9 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
@Override
|
@Override
|
||||||
public void refactoringCompleted() {
|
public void refactoringCompleted() {
|
||||||
try {
|
try {
|
||||||
sourceFile.setName(targetFileName);
|
if (targetFileName != null) {
|
||||||
|
KotlinPackage.single(sourceFiles).setName(targetFileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (moveCallback != null) {
|
if (moveCallback != null) {
|
||||||
@@ -580,47 +712,48 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
) {
|
) {
|
||||||
@Override
|
@Override
|
||||||
protected String getCommandName() {
|
protected String getCommandName() {
|
||||||
return "Move " + sourceFile.getName();
|
return targetFileName != null ? "Move " + KotlinPackage.single(sourceFiles).getName() : "Move";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void performRefactoring(UsageInfo[] usages) {
|
protected void performRefactoring(@NotNull UsageInfo[] usages) {
|
||||||
//noinspection ConstantConditions
|
if (targetFileName != null) {
|
||||||
String temporaryName = UniqueNameGenerator.generateUniqueName(
|
JetFile sourceFile = KotlinPackage.single(sourceFiles);
|
||||||
"temp",
|
//noinspection ConstantConditions
|
||||||
"",
|
String temporaryName = UniqueNameGenerator.generateUniqueName(
|
||||||
".kt",
|
"temp",
|
||||||
KotlinPackage.map(
|
"",
|
||||||
sourceFile.getContainingDirectory().getFiles(),
|
".kt",
|
||||||
new Function1<PsiFile, String>() {
|
KotlinPackage.map(
|
||||||
@Override
|
sourceFile.getContainingDirectory().getFiles(),
|
||||||
public String invoke(PsiFile file) {
|
new Function1<PsiFile, String>() {
|
||||||
return file.getName();
|
@Override
|
||||||
|
public String invoke(PsiFile file) {
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
);
|
||||||
);
|
sourceFile.setName(temporaryName);
|
||||||
sourceFile.setName(temporaryName);
|
}
|
||||||
|
|
||||||
super.performRefactoring(usages);
|
super.performRefactoring(usages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = Messages.showYesNoCancelDialog(
|
|
||||||
myProject,
|
|
||||||
"You are going to move all declarations out of '" +
|
|
||||||
sourceFile.getVirtualFile().getPath() +
|
|
||||||
"'. Do you want to delete this file?",
|
|
||||||
RefactoringBundle.message("move.title"),
|
|
||||||
Messages.getQuestionIcon()
|
|
||||||
);
|
|
||||||
if (ret == Messages.CANCEL) return;
|
|
||||||
deleteSourceFile = ret == Messages.YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ret = Messages.showYesNoCancelDialog(
|
||||||
|
myProject,
|
||||||
|
"You are about to move all declarations out of the source file(s). Do you want to delete empty files?",
|
||||||
|
RefactoringBundle.message("move.title"),
|
||||||
|
Messages.getQuestionIcon()
|
||||||
|
);
|
||||||
|
if (ret == Messages.CANCEL) return;
|
||||||
|
deleteSourceFile = ret == Messages.YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveKotlinTopLevelDeclarationsOptions options = new MoveKotlinTopLevelDeclarationsOptions(
|
MoveKotlinTopLevelDeclarationsOptions options = new MoveKotlinTopLevelDeclarationsOptions(
|
||||||
|
|||||||
@@ -17,18 +17,15 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.move
|
package org.jetbrains.kotlin.idea.refactoring.move
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.ui.DialogWrapper
|
import com.intellij.openapi.ui.DialogWrapper
|
||||||
import com.intellij.openapi.util.Comparing
|
import com.intellij.openapi.util.Comparing
|
||||||
import com.intellij.openapi.util.Computable
|
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.refactoring.RefactoringBundle
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
import com.intellij.refactoring.RefactoringSettings
|
import com.intellij.refactoring.RefactoringSettings
|
||||||
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
|
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
|
||||||
import com.intellij.refactoring.move.MoveCallback
|
|
||||||
import com.intellij.refactoring.move.MoveHandler
|
import com.intellij.refactoring.move.MoveHandler
|
||||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesDialog
|
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesDialog
|
||||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor
|
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor
|
||||||
@@ -40,12 +37,10 @@ import com.intellij.refactoring.util.CommonRefactoringUtil
|
|||||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||||
import com.intellij.refactoring.util.NonCodeUsageInfo
|
import com.intellij.refactoring.util.NonCodeUsageInfo
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import com.intellij.util.Function
|
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind
|
|
||||||
import org.jetbrains.kotlin.idea.JetFileType
|
import org.jetbrains.kotlin.idea.JetFileType
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
@@ -172,14 +167,14 @@ fun createMoveUsageInfoIfPossible(
|
|||||||
return MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
|
return MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun guessNewFileName(sourceFile: JetFile, declarationsToMove: Collection<JetNamedDeclaration>): String? {
|
public fun guessNewFileName(declarationsToMove: Collection<JetNamedDeclaration>): String? {
|
||||||
assert(sourceFile.getDeclarations().containsAll(declarationsToMove))
|
|
||||||
|
|
||||||
if (declarationsToMove.isEmpty()) return null
|
if (declarationsToMove.isEmpty()) return null
|
||||||
if (sourceFile.getDeclarations().size() == declarationsToMove.size()) return sourceFile.getName()
|
|
||||||
|
|
||||||
val representative = declarationsToMove.firstOrNull { it is JetClassOrObject } ?: declarationsToMove.first()
|
val representative = declarationsToMove.singleOrNull()
|
||||||
return "${representative.getName()}.${JetFileType.EXTENSION}"
|
?: declarationsToMove.filterIsInstance<JetClassOrObject>().singleOrNull()
|
||||||
|
representative?.let { return "${it.name}.${JetFileType.EXTENSION}" }
|
||||||
|
|
||||||
|
return declarationsToMove.first().containingFile.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if successful
|
// returns true if successful
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.refactoring.move
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import com.intellij.codeInsight.TargetElementUtilBase
|
import com.intellij.codeInsight.TargetElementUtilBase
|
||||||
import com.intellij.openapi.editor.Document
|
|
||||||
import com.intellij.openapi.editor.EditorFactory
|
import com.intellij.openapi.editor.EditorFactory
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
@@ -41,16 +40,18 @@ import org.jetbrains.kotlin.idea.core.refactoring.createKotlinFile
|
|||||||
import org.jetbrains.kotlin.idea.jsonUtils.getNullableString
|
import org.jetbrains.kotlin.idea.jsonUtils.getNullableString
|
||||||
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.changePackage.KotlinChangePackageRefactoring
|
import org.jetbrains.kotlin.idea.refactoring.move.changePackage.KotlinChangePackageRefactoring
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*
|
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.DeferredJetFileKotlinMoveTarget
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.JetFileKotlinMoveTarget
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsOptions
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsProcessor
|
||||||
|
import org.jetbrains.kotlin.idea.search.allScope
|
||||||
|
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
|
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||||
import org.jetbrains.kotlin.idea.search.allScope
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.test.JetTestUtils
|
import org.jetbrains.kotlin.test.JetTestUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -248,8 +249,7 @@ enum class MoveAction {
|
|||||||
val moveTarget = config.getNullableString("targetPackage")?.let { packageName ->
|
val moveTarget = config.getNullableString("targetPackage")?.let { packageName ->
|
||||||
DeferredJetFileKotlinMoveTarget(project, FqName(packageName)) {
|
DeferredJetFileKotlinMoveTarget(project, FqName(packageName)) {
|
||||||
val moveDestination = MultipleRootsMoveDestination(PackageWrapper(mainFile.getManager(), packageName))
|
val moveDestination = MultipleRootsMoveDestination(PackageWrapper(mainFile.getManager(), packageName))
|
||||||
createKotlinFile(guessNewFileName(mainFile as JetFile, listOf(elementToMove))!!,
|
createKotlinFile(guessNewFileName(listOf(elementToMove))!!, moveDestination.getTargetDirectory(mainFile))
|
||||||
moveDestination.getTargetDirectory(mainFile))
|
|
||||||
}
|
}
|
||||||
} ?: config.getString("targetFile").let { filePath ->
|
} ?: config.getString("targetFile").let { filePath ->
|
||||||
JetFileKotlinMoveTarget(PsiManager.getInstance(project).findFile(rootDir.findFileByRelativePath(filePath)!!) as JetFile)
|
JetFileKotlinMoveTarget(PsiManager.getInstance(project).findFile(rootDir.findFileByRelativePath(filePath)!!) as JetFile)
|
||||||
|
|||||||
Reference in New Issue
Block a user