Move: Show file dialog if all elements to be moved are KtFile

This commit is contained in:
Alexey Sedunov
2017-03-30 20:47:10 +03:00
parent 64a2fa2d6b
commit 691322e406
4 changed files with 102 additions and 51 deletions
@@ -30,14 +30,15 @@ import com.intellij.util.containers.MultiMap
import com.intellij.util.text.UniqueNameGenerator
import org.jetbrains.kotlin.psi.KtFile
class MoveFilesWithDeclarationsProcessor(
class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor (
project: Project,
private val sourceFiles: List<KtFile>,
private val targetDirectory: PsiDirectory,
private val targetFileName: String?,
searchInComments: Boolean,
searchInNonJavaFiles: Boolean,
moveCallback: MoveCallback?
moveCallback: MoveCallback?,
prepareSuccessfulCallback: Runnable = EmptyRunnable.INSTANCE
) : MoveFilesOrDirectoriesProcessor(project,
sourceFiles.toTypedArray<PsiElement>(),
targetDirectory,
@@ -45,7 +46,7 @@ class MoveFilesWithDeclarationsProcessor(
searchInComments,
searchInNonJavaFiles,
moveCallback,
EmptyRunnable.INSTANCE) {
prepareSuccessfulCallback) {
override fun getCommandName(): String {
return if (targetFileName != null) "Move " + sourceFiles.single().name else "Move"
}
@@ -29,10 +29,13 @@ import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.move.MoveCallback
import com.intellij.refactoring.move.MoveHandlerDelegate
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesImpl
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
import com.intellij.refactoring.util.CommonRefactoringUtil
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.refactoring.move.invokeMoveFilesOrDirectoriesRefactoring
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesDialog
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
@@ -100,6 +103,22 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
return true
}
if (elements.all { it is KtFile }) {
val initialTargetElement = when {
targetContainer is PsiPackage || targetContainer is PsiDirectory -> targetContainer
container is PsiPackage || container is PsiDirectory -> container
else -> null
}
val initialTargetDirectory = MoveFilesOrDirectoriesUtil.resolveToDirectory(project, initialTargetElement)
val dialog = KotlinAwareMoveFilesOrDirectoriesDialog(project) {
invokeMoveFilesOrDirectoriesRefactoring(it, project, elements, initialTargetDirectory, callback)
}
dialog.setData(elements, initialTargetDirectory, "refactoring.moveFile")
dialog.show()
return true
}
when (container) {
is PsiDirectory, is PsiPackage, is KtFile -> {
val targetPackageName = MoveClassesOrPackagesImpl.getInitialTargetPackageName(targetContainer, elements)
@@ -54,9 +54,12 @@ class KotlinMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandler() {
override fun doMove(project: Project, elements: Array<out PsiElement>, targetContainer: PsiElement?, callback: MoveCallback?) {
if (!(targetContainer == null || targetContainer is PsiDirectory || targetContainer is PsiDirectoryContainer)) return
moveFilesOrDirectories(project, adjustForMove(project, elements, targetContainer) ?: return, targetContainer) {
callback?.refactoringCompleted()
}
moveFilesOrDirectories(
project,
adjustForMove(project, elements, targetContainer) ?: return,
targetContainer,
callback?.let { MoveCallback { it.refactoringCompleted() } }
)
}
override fun tryToMove(element: PsiElement, project: Project, dataContext: DataContext?, reference: PsiReference?, editor: Editor?): Boolean {
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.Key
import com.intellij.psi.*
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
import com.intellij.refactoring.move.MoveCallback
import com.intellij.refactoring.move.MoveHandler
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
@@ -48,6 +49,7 @@ import org.jetbrains.kotlin.idea.codeInsight.shorten.addDelayedImportRequest
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
import org.jetbrains.kotlin.idea.refactoring.isInJavaSourceRoot
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveFilesWithDeclarationsProcessor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesDialog
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
@@ -406,12 +408,81 @@ fun postProcessMoveUsages(usages: Collection<UsageInfo>,
var KtFile.updatePackageDirective: Boolean? by UserDataProperty(Key.create("UPDATE_PACKAGE_DIRECTIVE"))
fun invokeMoveFilesOrDirectoriesRefactoring(
moveDialog: KotlinAwareMoveFilesOrDirectoriesDialog?,
project: Project,
elements: Array<out PsiElement>,
initialTargetDirectory: PsiDirectory?,
moveCallback: MoveCallback?
) {
fun closeDialog() {
moveDialog?.close(DialogWrapper.CANCEL_EXIT_CODE)
}
project.executeCommand(MoveHandler.REFACTORING_NAME) {
val selectedDir = if (moveDialog != null) moveDialog.targetDirectory else initialTargetDirectory
val updatePackageDirective = (moveDialog as? KotlinAwareMoveFilesOrDirectoriesDialog)?.updatePackageDirective
try {
val choice = if (elements.size > 1 || elements[0] is PsiDirectory) intArrayOf(-1) else null
val elementsToMove = elements.filterNot {
it is PsiFile
&& runWriteAction { CopyFilesOrDirectoriesHandler.checkFileExist(selectedDir, choice, it, it.name, "Move") }
}
elementsToMove.forEach {
MoveFilesOrDirectoriesUtil.checkMove(it, selectedDir!!)
if (it is KtFile && it.isInJavaSourceRoot()) {
it.updatePackageDirective = updatePackageDirective
}
}
val enableSearchReferences = elements.any { ProjectRootsUtil.isInProjectSource(it) }
if (elementsToMove.isNotEmpty()) {
@Suppress("UNCHECKED_CAST")
val processor = if (elementsToMove.all { it is KtFile } && selectedDir != null) {
MoveFilesWithDeclarationsProcessor(
project,
elementsToMove as List<KtFile>,
selectedDir,
null,
false,
false,
moveCallback,
Runnable(::closeDialog)
)
}
else {
MoveFilesOrDirectoriesProcessor(
project,
elementsToMove.toTypedArray(),
selectedDir,
enableSearchReferences,
false,
false,
moveCallback,
Runnable(::closeDialog)
)
}
processor.run()
}
else {
closeDialog()
}
}
catch (e: IncorrectOperationException) {
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.message, "refactoring.moveFile", project)
}
}
}
// Mostly copied from MoveFilesOrDirectoriesUtil.doMove()
fun moveFilesOrDirectories(
project: Project,
elements: Array<PsiElement>,
targetElement: PsiElement?,
moveCallback: (() -> Unit)? = null
moveCallback: MoveCallback? = null
) {
elements.forEach { if (it !is PsiFile && it !is PsiDirectory) throw IllegalArgumentException("unexpected element type: " + it) }
@@ -421,50 +492,7 @@ fun moveFilesOrDirectories(
val initialTargetDirectory = MoveFilesOrDirectoriesUtil.getInitialTargetDirectory(targetDirectory, elements)
fun doRun(moveDialog: KotlinAwareMoveFilesOrDirectoriesDialog?) {
fun closeDialog() {
moveDialog?.close(DialogWrapper.CANCEL_EXIT_CODE)
}
project.executeCommand(MoveHandler.REFACTORING_NAME) {
val selectedDir = if (moveDialog != null) moveDialog.targetDirectory else initialTargetDirectory
val updatePackageDirective = (moveDialog as? KotlinAwareMoveFilesOrDirectoriesDialog)?.updatePackageDirective
try {
val choice = if (elements.size > 1 || elements[0] is PsiDirectory) intArrayOf(-1) else null
val elementsToMove = elements.filterNot {
it is PsiFile
&& runWriteAction { CopyFilesOrDirectoriesHandler.checkFileExist(selectedDir, choice, it, it.name, "Move") }
}
elementsToMove.forEach {
MoveFilesOrDirectoriesUtil.checkMove(it, selectedDir!!)
if (it is KtFile && it.isInJavaSourceRoot()) {
it.updatePackageDirective = updatePackageDirective
}
}
val enableSearchReferences = elements.any { ProjectRootsUtil.isInProjectSource(it) }
if (elementsToMove.isNotEmpty()) {
MoveFilesOrDirectoriesProcessor(
project,
elementsToMove.toTypedArray(),
selectedDir,
enableSearchReferences,
false,
false,
moveCallback,
::closeDialog
).run()
}
else {
closeDialog()
}
}
catch (e: IncorrectOperationException) {
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.message, "refactoring.moveFile", project)
}
}
invokeMoveFilesOrDirectoriesRefactoring(moveDialog, project, elements, initialTargetDirectory, moveCallback)
}
if (ApplicationManager.getApplication().isUnitTestMode) {