diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt index 66648fa9181..14b7b244595 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt @@ -35,9 +35,11 @@ fun Project.projectScope(): GlobalSearchScope = GlobalSearchScope.projectScope(t fun PsiFile.fileScope(): GlobalSearchScope = GlobalSearchScope.fileScope(this) +fun GlobalSearchScope.restrictToKotlinSources() = GlobalSearchScope.getScopeRestrictedByFileTypes(this, KotlinFileType.INSTANCE) + fun SearchScope.restrictToKotlinSources(): SearchScope { return when (this) { - is GlobalSearchScope -> GlobalSearchScope.getScopeRestrictedByFileTypes(this, KotlinFileType.INSTANCE) + is GlobalSearchScope -> restrictToKotlinSources() is LocalSearchScope -> { val ktElements = scope.filter { it.containingFile is KtFile } when (ktElements.size) { diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java b/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java index 833d0087f19..7adb4d0b343 100644 --- a/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java +++ b/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java @@ -34,6 +34,10 @@ public class KtFileTreeNode extends PsiFileNode { super(project, value, viewSettings); } + public final KtFile getKtFile() { + return (KtFile) getValue(); + } + @Override public Collection getChildrenImpl() { KtFile file = (KtFile) getValue(); diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties b/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties index 8216695cc67..4a5f90f2f6f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/KotlinRefactoringBundle.properties @@ -35,7 +35,6 @@ column.name.val.var=Val/Var refactoring.move.specifc.element=Move {0} {1} refactoring.move.selected.elements=Move selected elements -refactoring.move.top.level.declaration.file.title=Choose Destination File refactoring.move.non.kotlin.file=Target must be a Kotlin file package.private.0.will.no.longer.be.accessible.from.1=Package-private {0} will no longer be accessible from {1} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java index f804f5b4db5..8ef465eea0f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java @@ -19,15 +19,11 @@ package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.fileChooser.FileChooserDescriptor; -import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.JavaProjectRootsUtil; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Pass; @@ -70,6 +66,7 @@ import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPan import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable; import org.jetbrains.kotlin.idea.refactoring.move.MoveUtilsKt; import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*; +import org.jetbrains.kotlin.idea.refactoring.ui.KotlinFileChooserDialog; import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtFile; @@ -139,8 +136,6 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog { initMemberInfo(elementsToMove, sourceFiles); updateControls(); - - pack(); } private static List getSourceFiles(@NotNull Collection elementsToMove) { @@ -337,12 +332,36 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog { @NotNull Set elementsToMove, @NotNull List sourceFiles ) { - FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor() - .withRoots(ProjectRootManager.getInstance(myProject).getContentRoots()) - .withTreeRootVisible(true); + final PsiDirectory sourceDir = sourceFiles.get(0).getParent(); + assert sourceDir != null : sourceFiles.get(0).getVirtualFile().getPath(); - String title = KotlinRefactoringBundle.message("refactoring.move.top.level.declaration.file.title"); - fileChooser.addBrowseFolderListener(title, null, myProject, descriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); + fileChooser.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + KotlinFileChooserDialog dialog = new KotlinFileChooserDialog("Choose Containing File", myProject); + + File targetFile = new File(getTargetFilePath()); + PsiFile targetPsiFile = JetRefactoringUtilKt.toPsiFile(targetFile, myProject); + if (targetPsiFile instanceof KtFile) { + dialog.select((KtFile) targetPsiFile); + } + else { + PsiDirectory targetDir = JetRefactoringUtilKt.toPsiDirectory(targetFile.getParentFile(), myProject); + if (targetDir == null) { + targetDir = sourceDir; + } + dialog.selectDirectory(targetDir); + } + + dialog.showDialog(); + KtFile selectedFile = dialog.isOK() ? dialog.getSelected() : null; + if (selectedFile != null) { + fileChooser.setText(selectedFile.getVirtualFile().getPath()); + } + } + } + ); String initialTargetPath = targetFile != null @@ -561,8 +580,11 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog { } File targetDir = targetFile.getParentFile(); - final PsiDirectory psiDirectory = JetRefactoringUtilKt.toPsiDirectory(targetDir, myProject); - assert psiDirectory != null : "No directory found: " + targetDir.getPath(); + final PsiDirectory psiDirectory = targetDir != null ? JetRefactoringUtilKt.toPsiDirectory(targetDir, myProject) : null; + if (psiDirectory == null) { + setErrorText("No directory found for file: " + targetFile.getPath()); + return null; + } PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(psiDirectory); if (psiPackage == null) { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/ui/KotlinFileChooserDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/ui/KotlinFileChooserDialog.kt new file mode 100644 index 00000000000..97d4ef15ae4 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/ui/KotlinFileChooserDialog.kt @@ -0,0 +1,62 @@ +/* + * 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.ui + +import com.intellij.ide.util.AbstractTreeClassChooserDialog +import com.intellij.ide.util.gotoByName.GotoFileModel +import com.intellij.openapi.project.Project +import com.intellij.psi.search.FilenameIndex +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.idea.projectView.KtClassOrObjectTreeNode +import org.jetbrains.kotlin.idea.projectView.KtFileTreeNode +import org.jetbrains.kotlin.idea.search.projectScope +import org.jetbrains.kotlin.idea.search.restrictToKotlinSources +import org.jetbrains.kotlin.psi.KtFile +import javax.swing.tree.DefaultMutableTreeNode + +class KotlinFileChooserDialog( + title: String, + project: Project +) : AbstractTreeClassChooserDialog( + title, + project, + project.projectScope().restrictToKotlinSources(), + KtFile::class.java, + null, + null, + null, + false, + false +) { + override fun getSelectedFromTreeUserObject(node: DefaultMutableTreeNode): KtFile? { + val userObject = node.userObject + return when (userObject) { + is KtFileTreeNode -> userObject.ktFile + is KtClassOrObjectTreeNode -> { + val containingFile = userObject.value.getContainingKtFile() + if (containingFile.declarations.size == 1) containingFile else null + } + else -> null + } + } + + override fun getClassesByName(name: String, checkBoxState: Boolean, pattern: String, searchScope: GlobalSearchScope): List { + return FilenameIndex.getFilesByName(project, name, searchScope).filterIsInstance() + } + + override fun createChooseByNameModel() = GotoFileModel(this.project) +} \ No newline at end of file