mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] KTIJ-35016 Introduce observable UI settings for move refactoring
Settings allow sharing UI state between dependent move model parts. This is necessary for conditional rendering of widgets. For example, simultaneous move of expects with actuals needs a slightly customized UI. GitOrigin-RevId: 722cc642ec192990113b866fa38a70c97f8ac323
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c8a4b34bd2
commit
c9d485e340
+38
-8
@@ -2,6 +2,9 @@
|
||||
package org.jetbrains.kotlin.idea.k2.refactoring.move.ui
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.observable.properties.AtomicBooleanProperty
|
||||
import com.intellij.openapi.observable.properties.MutableBooleanProperty
|
||||
import com.intellij.openapi.observable.properties.ObservableBooleanProperty
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.util.NlsContexts
|
||||
@@ -38,7 +41,11 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
/**
|
||||
* @see K2MoveDescriptor
|
||||
*/
|
||||
sealed class K2MoveModel {
|
||||
sealed class K2MoveModel(observableUiSettings: ObservableUiSettings) : K2MoveModelObservableSettings {
|
||||
init {
|
||||
observableUiSettings.registerK2MoveModelSettings(this)
|
||||
}
|
||||
|
||||
abstract val project: Project
|
||||
|
||||
abstract val source: K2MoveSourceModel<*>
|
||||
@@ -81,6 +88,18 @@ sealed class K2MoveModel {
|
||||
}
|
||||
}
|
||||
|
||||
override val mppDeclarationsObservable: ObservableBooleanProperty
|
||||
get() = mppDeclarations.observableProperty
|
||||
|
||||
override val searchForTextObservable: ObservableBooleanProperty
|
||||
get() = searchForText.observableProperty
|
||||
|
||||
override val searchInCommentsObservable: ObservableBooleanProperty
|
||||
get() = searchInComments.observableProperty
|
||||
|
||||
override val searchReferencesObservable: ObservableBooleanProperty
|
||||
get() = searchReferences.observableProperty
|
||||
|
||||
enum class Setting(private val text: @NlsContexts.Checkbox String) {
|
||||
SEARCH_FOR_TEXT(KotlinBundle.message("search.for.text.occurrences")) {
|
||||
override var state: Boolean
|
||||
@@ -124,12 +143,16 @@ sealed class K2MoveModel {
|
||||
};
|
||||
|
||||
abstract var state: Boolean
|
||||
// lazy prevents service access from constructor
|
||||
internal val observableProperty: MutableBooleanProperty by lazy { AtomicBooleanProperty(state) }
|
||||
|
||||
fun createComboBox(panel: Panel, enabled: Boolean = true) {
|
||||
panel.row {
|
||||
val checkBox = checkBox(text).enabled(enabled)
|
||||
if (enabled) {
|
||||
checkBox.bindSelected(::state)
|
||||
// bind doesn't register state changes before dialog confirmation, but the UI should be updated on all state changes
|
||||
checkBox.onChanged { observableProperty.set(it.isSelected) }
|
||||
} else {
|
||||
checkBox.selected(false)
|
||||
}
|
||||
@@ -145,8 +168,9 @@ sealed class K2MoveModel {
|
||||
override val source: K2MoveSourceModel.FileSource,
|
||||
override val target: K2MoveTargetModel.SourceDirectory,
|
||||
override val inSourceRoot: Boolean,
|
||||
override val moveCallBack: MoveCallback? = null
|
||||
) : K2MoveModel() {
|
||||
observableUiSettings: ObservableUiSettings,
|
||||
override val moveCallBack: MoveCallback? = null,
|
||||
) : K2MoveModel(observableUiSettings) {
|
||||
private fun PsiFile.isAlreadyInTarget(): Boolean {
|
||||
return parent == target.directory && when (this) {
|
||||
is PsiJavaFile -> packageName == target.pkgName.asString()
|
||||
@@ -192,8 +216,9 @@ sealed class K2MoveModel {
|
||||
override val source: K2MoveSourceModel.ElementSource,
|
||||
override val target: K2MoveTargetModel,
|
||||
override val inSourceRoot: Boolean,
|
||||
observableUiSettings: ObservableUiSettings,
|
||||
override val moveCallBack: MoveCallback? = null
|
||||
) : K2MoveModel() {
|
||||
) : K2MoveModel(observableUiSettings) {
|
||||
private fun isValidFileRefactoring(fileName: String): Boolean {
|
||||
fun KtFile.isTargetFile(): Boolean {
|
||||
return containingDirectory == target.directory
|
||||
@@ -307,6 +332,7 @@ sealed class K2MoveModel {
|
||||
}
|
||||
val inSourceRoot = isInSourceRoot(project, elementsToMove, targetContainer)
|
||||
val explicitPkgMoveFqName = findExplicitPkgMoveFqName(elementsToMove)
|
||||
val observableUiSettings = ObservableUiSettingsImpl()
|
||||
|
||||
return when {
|
||||
(elementsToMove.all { it is KtFile } && targetContainer is PsiDirectory)
|
||||
@@ -321,22 +347,23 @@ sealed class K2MoveModel {
|
||||
pkgName = pkg,
|
||||
directory = targetContainer,
|
||||
explicitPkgMoveFqName = explicitPkgMoveFqName,
|
||||
observableUiSettings = observableUiSettings,
|
||||
)
|
||||
} else { // no default target is provided, happens when invoking refactoring via keyboard instead of drag-and-drop
|
||||
val file = elementsToMove.firstOrNull { it.containingFile != null }?.containingFile
|
||||
?: error("No default target found")
|
||||
val directory = file.containingDirectory ?: error("No default target found")
|
||||
val pkgName = elementsToMove.firstIsInstanceOrNull<KtElement>()?.containingKtFile?.packageFqName ?: FqName.ROOT
|
||||
K2MoveTargetModel.SourceDirectory(pkgName, directory, explicitPkgMoveFqName = null)
|
||||
K2MoveTargetModel.SourceDirectory(pkgName, directory, explicitPkgMoveFqName = null, observableUiSettings)
|
||||
}
|
||||
Files(project, source, target, inSourceRoot, moveCallBack)
|
||||
Files(project, source, target, inSourceRoot, observableUiSettings, moveCallBack)
|
||||
}
|
||||
|
||||
targetContainer is KtFile || targetContainer.isSingleClassContainer() || isSingleFileMove(elementsToMove) -> {
|
||||
val source = K2MoveSourceModel.ElementSource(declarationsFromFiles.toSet())
|
||||
val targetFile = targetContainer?.containingFile
|
||||
val target = if (targetFile is KtFile) {
|
||||
K2MoveTargetModel.File(targetFile)
|
||||
K2MoveTargetModel.File(targetFile, observableUiSettings)
|
||||
} else if (targetContainer is PsiDirectory) {
|
||||
val pkg = targetContainer.getFqNameWithImplicitPrefixOrRoot()
|
||||
K2MoveTargetModel.File(
|
||||
@@ -344,6 +371,7 @@ sealed class K2MoveModel {
|
||||
pkg = pkg,
|
||||
directory = targetContainer,
|
||||
explicitPkgMoveFqName = explicitPkgMoveFqName,
|
||||
observableUiSettings = observableUiSettings,
|
||||
)
|
||||
} else { // no default target is provided, happens when invoking refactoring via keyboard instead of drag-and-drop
|
||||
val firstElem = elementsToMove.firstOrNull() as KtElement
|
||||
@@ -352,7 +380,8 @@ sealed class K2MoveModel {
|
||||
K2MoveTargetModel.Declarations(
|
||||
defaultDirectory = psiDirectory,
|
||||
defaultPkgName = containingFile.packageFqName,
|
||||
defaultFileName = findSourceFileNameByMovedElements(elementsToMove)
|
||||
defaultFileName = findSourceFileNameByMovedElements(elementsToMove),
|
||||
observableUiSettings = observableUiSettings,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -361,6 +390,7 @@ sealed class K2MoveModel {
|
||||
source = source,
|
||||
target = target,
|
||||
inSourceRoot = inSourceRoot,
|
||||
observableUiSettings = observableUiSettings,
|
||||
moveCallBack = moveCallBack
|
||||
)
|
||||
}
|
||||
|
||||
+25
-8
@@ -46,6 +46,8 @@ sealed interface K2MoveTargetModel {
|
||||
|
||||
val explicitPkgMoveFqName: FqName?
|
||||
|
||||
val observableUiSettings: ObservableUiSettings
|
||||
|
||||
/**
|
||||
* Creates a [K2MoveTargetDescriptor] from this model.
|
||||
* @param kmpSourceRoot source KMP directory that corresponds to the base [directory] in a different source set.
|
||||
@@ -60,6 +62,7 @@ sealed interface K2MoveTargetModel {
|
||||
override var pkgName: FqName,
|
||||
override var directory: PsiDirectory,
|
||||
override val explicitPkgMoveFqName: FqName?,
|
||||
override val observableUiSettings: ObservableUiSettings,
|
||||
) : K2MoveTargetModel {
|
||||
private val initialDirectory = directory
|
||||
|
||||
@@ -147,7 +150,8 @@ sealed interface K2MoveTargetModel {
|
||||
pkgName: FqName,
|
||||
directory: PsiDirectory,
|
||||
explicitPkgMoveFqName: FqName?,
|
||||
) : SourceDirectoryChooser(pkgName, directory, explicitPkgMoveFqName) {
|
||||
observableUiSettings: ObservableUiSettings,
|
||||
) : SourceDirectoryChooser(pkgName, directory, explicitPkgMoveFqName, observableUiSettings) {
|
||||
override fun toDescriptor(kmpSourceRoot: PsiDirectory?): K2MoveTargetDescriptor.Directory {
|
||||
return K2MoveTargetDescriptor.Directory(
|
||||
pkgName = pkgName,
|
||||
@@ -167,7 +171,8 @@ sealed interface K2MoveTargetModel {
|
||||
pkg: FqName,
|
||||
directory: PsiDirectory,
|
||||
explicitPkgMoveFqName: FqName?,
|
||||
) : SourceDirectoryChooser(pkg, directory, explicitPkgMoveFqName) {
|
||||
observableUiSettings: ObservableUiSettings,
|
||||
) : SourceDirectoryChooser(pkg, directory, explicitPkgMoveFqName, observableUiSettings) {
|
||||
var fileName: String = fileName
|
||||
protected set
|
||||
|
||||
@@ -221,8 +226,13 @@ sealed interface K2MoveTargetModel {
|
||||
}
|
||||
}
|
||||
|
||||
class File(fileName: String, pkg: FqName, directory: PsiDirectory, explicitPkgMoveFqName: FqName?) :
|
||||
FileChooser(fileName, pkg, directory, explicitPkgMoveFqName) {
|
||||
class File(
|
||||
fileName: String,
|
||||
pkg: FqName,
|
||||
directory: PsiDirectory,
|
||||
explicitPkgMoveFqName: FqName?,
|
||||
observableUiSettings: ObservableUiSettings,
|
||||
) : FileChooser(fileName, pkg, directory, explicitPkgMoveFqName, observableUiSettings) {
|
||||
override fun toDescriptor(kmpSourceRoot: PsiDirectory?): K2MoveTargetDescriptor.File =
|
||||
K2MoveTargetDescriptor.File(
|
||||
fileName = fileName,
|
||||
@@ -242,8 +252,9 @@ sealed interface K2MoveTargetModel {
|
||||
class Declarations(
|
||||
defaultDirectory: PsiDirectory,
|
||||
defaultPkgName: FqName,
|
||||
defaultFileName: String
|
||||
) : FileChooser(defaultFileName, defaultPkgName, defaultDirectory, explicitPkgMoveFqName = null) {
|
||||
defaultFileName: String,
|
||||
observableUiSettings: ObservableUiSettings,
|
||||
) : FileChooser(defaultFileName, defaultPkgName, defaultDirectory, explicitPkgMoveFqName = null, observableUiSettings) {
|
||||
private val propertyGraph = PropertyGraph()
|
||||
|
||||
private val destinationClassProperty = propertyGraph.property<KtClassOrObject?>(null)
|
||||
@@ -354,9 +365,15 @@ sealed interface K2MoveTargetModel {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun File(file: KtFile): File {
|
||||
fun File(file: KtFile, observableUiSettings: ObservableUiSettings): File {
|
||||
val directory = file.containingDirectory ?: error("No containing directory was found")
|
||||
return File(file.name, file.packageFqName, directory, null)
|
||||
return File(
|
||||
fileName = file.name,
|
||||
pkg = file.packageFqName,
|
||||
directory = directory,
|
||||
explicitPkgMoveFqName = null,
|
||||
observableUiSettings = observableUiSettings,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.refactoring.move.ui
|
||||
|
||||
import com.intellij.openapi.observable.properties.ObservableBooleanProperty
|
||||
|
||||
interface ObservableUiSettings : K2MoveModelObservableSettings {
|
||||
fun registerK2MoveModelSettings(settings: K2MoveModelObservableSettings)
|
||||
}
|
||||
|
||||
interface K2MoveModelObservableSettings {
|
||||
val searchReferencesObservable: ObservableBooleanProperty
|
||||
val searchForTextObservable: ObservableBooleanProperty
|
||||
val searchInCommentsObservable: ObservableBooleanProperty
|
||||
val mppDeclarationsObservable: ObservableBooleanProperty
|
||||
}
|
||||
|
||||
internal class ObservableUiSettingsImpl : ObservableUiSettings {
|
||||
private lateinit var k2MoveModelSettings: K2MoveModelObservableSettings
|
||||
|
||||
override val searchReferencesObservable: ObservableBooleanProperty
|
||||
get() = k2MoveModelSettings.searchReferencesObservable
|
||||
override val searchForTextObservable: ObservableBooleanProperty
|
||||
get() = k2MoveModelSettings.searchForTextObservable
|
||||
override val searchInCommentsObservable: ObservableBooleanProperty
|
||||
get() = k2MoveModelSettings.searchInCommentsObservable
|
||||
override val mppDeclarationsObservable: ObservableBooleanProperty
|
||||
get() = k2MoveModelSettings.mppDeclarationsObservable
|
||||
|
||||
override fun registerK2MoveModelSettings(settings: K2MoveModelObservableSettings) {
|
||||
k2MoveModelSettings = settings
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user