Minor: clean up copy refactoring

This commit is contained in:
Dmitry Gridin
2019-07-02 21:09:11 +07:00
parent 1a9abaeb2a
commit 7c547d8c5a
2 changed files with 78 additions and 106 deletions
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 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.
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.refactoring.copy
@@ -53,9 +42,9 @@ import kotlin.math.max
// Based on com.intellij.refactoring.copy.CopyClassDialog
class CopyKotlinDeclarationDialog(
declaration: KtNamedDeclaration,
private val defaultTargetDirectory: PsiDirectory?,
private val project: Project
declaration: KtNamedDeclaration,
private val defaultTargetDirectory: PsiDirectory?,
private val project: Project
) : DialogWrapper(project, true) {
private val informationLabel = JLabel()
private val classNameField = EditorTextField("")
@@ -76,18 +65,19 @@ class CopyKotlinDeclarationDialog(
get() = ((destinationComboBox.comboBox.selectedItem as? DirectoryChooser.ItemWrapper)?.directory ?: originalFile).sourceRoot
init {
informationLabel.text = RefactoringBundle.message("copy.class.copy.0.1", UsageViewUtil.getType(declaration), UsageViewUtil.getLongName(declaration))
informationLabel.text =
RefactoringBundle.message("copy.class.copy.0.1", UsageViewUtil.getType(declaration), UsageViewUtil.getLongName(declaration))
informationLabel.font = informationLabel.font.deriveFont(Font.BOLD)
init()
destinationComboBox.setData(
project,
defaultTargetDirectory,
Pass { setErrorText(it, destinationComboBox) },
packageNameField.childComponent
project,
defaultTargetDirectory,
Pass { setErrorText(it, destinationComboBox) },
packageNameField.childComponent
)
classNameField.setText(UsageViewUtil.getShortName(declaration))
classNameField.text = UsageViewUtil.getShortName(declaration)
classNameField.selectAll()
}
@@ -97,7 +87,8 @@ class CopyKotlinDeclarationDialog(
override fun createNorthPanel(): JComponent? {
val qualifiedName = qualifiedName
packageNameField = PackageNameReferenceEditorCombo(qualifiedName, project, RECENTS_KEY, RefactoringBundle.message("choose.destination.package"))
packageNameField =
PackageNameReferenceEditorCombo(qualifiedName, project, RECENTS_KEY, RefactoringBundle.message("choose.destination.package"))
packageNameField.setTextFieldPreferredWidth(max(qualifiedName.length + 5, 40))
packageLabel.text = RefactoringBundle.message("destination.package")
packageLabel.labelFor = packageNameField
@@ -111,12 +102,12 @@ class CopyKotlinDeclarationDialog(
val panel = JPanel(BorderLayout())
panel.add(openInEditorCheckBox, BorderLayout.EAST)
return FormBuilder.createFormBuilder()
.addComponent(informationLabel)
.addLabeledComponent(RefactoringBundle.message("copy.files.new.name.label"), classNameField, UIUtil.LARGE_VGAP)
.addLabeledComponent(packageLabel, packageNameField)
.addLabeledComponent(label, destinationComboBox)
.addComponent(panel)
.panel
.addComponent(informationLabel)
.addLabeledComponent(RefactoringBundle.message("copy.files.new.name.label"), classNameField, UIUtil.LARGE_VGAP)
.addLabeledComponent(packageLabel, packageNameField)
.addLabeledComponent(label, destinationComboBox)
.addComponent(panel)
.panel
}
private val qualifiedName: String
@@ -144,8 +135,7 @@ class CopyKotlinDeclarationDialog(
try {
targetDirectory = destinationComboBox.selectDirectory(PackageWrapper(manager, packageName), false)
}
catch (e: IncorrectOperationException) {
} catch (e: IncorrectOperationException) {
return e.message
}
@@ -180,6 +170,7 @@ class CopyKotlinDeclarationDialog(
override fun getHelpId() = HelpID.COPY_CLASS
companion object {
@NonNls private val RECENTS_KEY = "CopyKotlinDeclarationDialog.RECENTS_KEY"
@NonNls
private val RECENTS_KEY = "CopyKotlinDeclarationDialog.RECENTS_KEY"
}
}
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 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.
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.refactoring.copy
@@ -66,15 +55,12 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
var Project.newName: String? by UserDataProperty(Key.create("NEW_NAME"))
private fun PsiElement.getCopyableElement() =
parentsWithSelf.firstOrNull { it is KtFile || (it is KtNamedDeclaration && it.parent is KtFile) } as? KtElement
parentsWithSelf.firstOrNull { it is KtFile || (it is KtNamedDeclaration && it.parent is KtFile) } as? KtElement
private fun PsiElement.getDeclarationsToCopy(): List<KtElement> {
val declarationOrFile = getCopyableElement()
return when (declarationOrFile) {
is KtFile -> declarationOrFile.declarations.filterIsInstance<KtNamedDeclaration>().ifEmpty { listOf(declarationOrFile) }
is KtNamedDeclaration -> listOf(declarationOrFile)
else -> emptyList()
}
private fun PsiElement.getDeclarationsToCopy(): List<KtElement> = when (val declarationOrFile = getCopyableElement()) {
is KtFile -> declarationOrFile.declarations.filterIsInstance<KtNamedDeclaration>().ifEmpty { listOf(declarationOrFile) }
is KtNamedDeclaration -> listOf(declarationOrFile)
else -> emptyList()
}
}
@@ -82,8 +68,8 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
private fun getSourceFiles(elements: Array<out PsiElement>): Array<PsiElement>? {
return elements
.map { it.containingFile ?: it as? PsiFileSystemItem ?: return null }
.toTypedArray()
.map { it.containingFile ?: it as? PsiFileSystemItem ?: return null }
.toTypedArray()
}
private fun canCopyFiles(elements: Array<out PsiElement>, fromUpdate: Boolean): Boolean {
@@ -94,11 +80,11 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
private fun canCopyDeclarations(elements: Array<out PsiElement>): Boolean {
val containingFile =
elements
.flatMap { it.getDeclarationsToCopy().ifEmpty { return false } }
.distinctBy { it.containingFile }
.singleOrNull()
?.containingFile ?: return false
elements
.flatMap { it.getDeclarationsToCopy().ifEmpty { return false } }
.distinctBy { it.containingFile }
.singleOrNull()
?.containingFile ?: return false
return containingFile.sourceRoot != null
}
@@ -111,20 +97,18 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
}
private fun getOrCreateTargetFile(
originalFile: KtFile,
targetDirectory: PsiDirectory,
targetFileName: String,
commandName: String
originalFile: KtFile,
targetDirectory: PsiDirectory,
targetFileName: String,
commandName: String
): KtFile? {
val existingFile = targetDirectory.findFile(targetFileName)
if (existingFile == originalFile) return null
if (existingFile != null) {
val policy = getFilePolicy(existingFile, targetFileName, targetDirectory, commandName)
when (policy) {
ExistingFilePolicy.APPEND -> {}
ExistingFilePolicy.OVERWRITE -> runWriteAction { existingFile.delete() }
ExistingFilePolicy.SKIP -> return null
if (existingFile != null) when (getFilePolicy(existingFile, targetFileName, targetDirectory, commandName)) {
ExistingFilePolicy.APPEND -> {
}
ExistingFilePolicy.OVERWRITE -> runWriteAction { existingFile.delete() }
ExistingFilePolicy.SKIP -> return null
}
return runWriteAction {
if (existingFile != null && existingFile.isValid) {
@@ -136,34 +120,33 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
}
private fun getFilePolicy(
existingFile: PsiFile?,
targetFileName: String,
targetDirectory: PsiDirectory,
commandName: String
existingFile: PsiFile?,
targetFileName: String,
targetDirectory: PsiDirectory,
commandName: String
): ExistingFilePolicy {
val isUnitTestMode = ApplicationManager.getApplication().isUnitTestMode
return if (existingFile !is KtFile) {
if (isUnitTestMode) return ExistingFilePolicy.OVERWRITE
val answer = Messages.showOkCancelDialog(
"File $targetFileName already exists in ${targetDirectory.virtualFile.path}",
commandName,
"Overwrite",
"Cancel",
Messages.getQuestionIcon()
"File $targetFileName already exists in ${targetDirectory.virtualFile.path}",
commandName,
"Overwrite",
"Cancel",
Messages.getQuestionIcon()
)
if (answer == Messages.OK) ExistingFilePolicy.OVERWRITE else ExistingFilePolicy.SKIP
}
else {
} else {
if (isUnitTestMode) return ExistingFilePolicy.APPEND
val answer = Messages.showYesNoCancelDialog(
"File $targetFileName already exists in ${targetDirectory.virtualFile.path}",
commandName,
"Append",
"Overwrite",
"Cancel",
Messages.getQuestionIcon()
"File $targetFileName already exists in ${targetDirectory.virtualFile.path}",
commandName,
"Append",
"Overwrite",
"Cancel",
Messages.getQuestionIcon()
)
when (answer) {
Messages.YES -> ExistingFilePolicy.APPEND
@@ -187,7 +170,8 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
val originalFile = elementsToCopy.first().containingFile as KtFile
val initialTargetDirectory = defaultTargetDirectory ?: originalFile.containingDirectory ?: return
val isSingleDeclarationInFile = singleElementToCopy is KtNamedDeclaration && originalFile.declarations.singleOrNull() == singleElementToCopy
val isSingleDeclarationInFile =
singleElementToCopy is KtNamedDeclaration && originalFile.declarations.singleOrNull() == singleElementToCopy
val project = initialTargetDirectory.project
@@ -210,8 +194,7 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
newName = dialog.newName ?: singleElementToCopy.name
targetDirWrapper = dialog.targetDirectory?.toDirectoryWrapper() ?: return
targetSourceRoot = dialog.targetSourceRoot
}
else {
} else {
val dialog = CopyFilesOrDirectoriesDialog(arrayOf(originalFile), initialTargetDirectory, project, false)
if (!dialog.showAndGet()) return
openInEditor = dialog.openInEditor()
@@ -219,8 +202,7 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
targetDirWrapper = dialog.targetDirectory?.toDirectoryWrapper() ?: return
targetSourceRoot = dialog.targetDirectory?.sourceRoot
}
}
else {
} else {
project.newName?.let { newName = it }
}
@@ -229,8 +211,8 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
val internalUsages = runReadAction {
val targetPackageName = targetDirWrapper.getPackageName()
val changeInfo = ContainerChangeInfo(
ContainerInfo.Package(originalFile.packageFqName),
ContainerInfo.Package(FqName(targetPackageName))
ContainerInfo.Package(originalFile.packageFqName),
ContainerInfo.Package(FqName(targetPackageName))
)
elementsToCopy.flatMapTo(LinkedHashSet()) { elementToCopy ->
elementToCopy.getInternalReferencesToUpdateOnPackageNameChange(changeInfo).filter {
@@ -247,7 +229,8 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
project.executeCommand(commandName) {
try {
val targetDirectory = runWriteAction { targetDirWrapper.getOrCreateDirectory(initialTargetDirectory) }
val targetFileName = if (newName?.contains(".") ?: false) newName!! else newName + "." + originalFile.virtualFile.extension
val targetFileName =
if (newName?.contains(".") == true) newName!! else newName + "." + originalFile.virtualFile.extension
val oldToNewElementsMapping = HashMap<PsiElement, PsiElement>()
@@ -271,9 +254,9 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
copiedDeclaration = if (isSingleDeclarationInFile && targetFile is KtFile) {
targetFile.declarations.singleOrNull() as? KtNamedDeclaration
} else null
}
else {
targetFile = getOrCreateTargetFile(originalFile, targetDirectory, targetFileName, commandName) ?: return@executeCommand
} else {
targetFile =
getOrCreateTargetFile(originalFile, targetDirectory, targetFileName, commandName) ?: return@executeCommand
runWriteAction {
val newElements = elementsToCopy.map { targetFile.add(it.copy()) as KtNamedDeclaration }
elementsToCopy.zip(newElements).toMap(oldToNewElementsMapping)
@@ -301,11 +284,9 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
if (openInEditor) {
EditorHelper.openFilesInEditor(arrayOf(targetFile))
}
}
catch (e: IncorrectOperationException) {
} catch (e: IncorrectOperationException) {
Messages.showMessageDialog(project, e.message, RefactoringBundle.message("error.title"), Messages.getErrorIcon())
}
finally {
} finally {
cleanUpInternalUsages(internalUsages + restoredInternalUsages)
}
}
@@ -317,10 +298,10 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
val targetSourceRootPsi = targetSourceRoot?.toPsiDirectory(project)
if (targetSourceRootPsi != null && project == originalFile.project) {
val conflictChecker = MoveConflictChecker(
project,
elementsToCopy,
KotlinDirectoryMoveTarget(FqName.ROOT, targetSourceRootPsi),
originalFile
project,
elementsToCopy,
KotlinDirectoryMoveTarget(FqName.ROOT, targetSourceRootPsi),
originalFile
)
conflictChecker.checkModuleConflictsInDeclarations(internalUsages, conflicts)
conflictChecker.checkVisibilityInDeclarations(conflicts)