mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
IDEA-308635 respect dialog checkboxes
GitOrigin-RevId: 278a64b223fbcb1ba40f1b4b130cd46904d70e8a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bab4206b8e
commit
da992dce67
@@ -2,7 +2,6 @@ package com.intellij.settingsSync
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import java.util.*
|
||||
|
||||
|
||||
@Internal
|
||||
@@ -18,7 +17,8 @@ sealed class SyncSettingsEvent {
|
||||
sealed class ExclusiveEvent : SyncSettingsEvent()
|
||||
|
||||
class IdeChange(snapshot: SettingsSnapshot) : EventWithSnapshot(snapshot)
|
||||
class CloudChange(snapshot: SettingsSnapshot, val serverVersionId: String?) : EventWithSnapshot(snapshot)
|
||||
class CloudChange(snapshot: SettingsSnapshot, val serverVersionId: String?, val syncSettings: SettingsSyncState? = null)
|
||||
: EventWithSnapshot(snapshot)
|
||||
object MustPushRequest : StandardEvent()
|
||||
object LogCurrentSettings : StandardEvent()
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@ package com.intellij.settingsSync
|
||||
|
||||
import com.intellij.openapi.application.ApplicationInfo
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.components.SettingsCategory
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.util.BuildNumber
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.settingsSync.plugins.SettingsSyncPluginsState
|
||||
import com.intellij.util.SystemProperties
|
||||
import com.intellij.util.xmlb.XmlSerializer
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
@@ -53,6 +56,29 @@ data class SettingsSnapshot(val metaInfo: MetaInfo,
|
||||
fun isDeleted(): Boolean {
|
||||
return metaInfo.isDeleted
|
||||
}
|
||||
|
||||
fun getState(): SettingsSyncState {
|
||||
val fileState = fileStates.firstOrNull {
|
||||
it.file == ("${PathManager.OPTIONS_DIRECTORY}/${SettingsSyncSettings.FILE_SPEC}")
|
||||
} ?: return SettingsSyncStateHolder()
|
||||
|
||||
if (fileState !is FileState.Modified) {
|
||||
return SettingsSyncStateHolder()
|
||||
}
|
||||
try {
|
||||
val componentElement = JDOMUtil.load(fileState.content).getChildren("component")
|
||||
.firstOrNull { it.getAttributeValue("name") == SettingsSyncSettings.COMPONENT_NAME }
|
||||
?: return SettingsSyncStateHolder()
|
||||
val state = XmlSerializer.deserialize(componentElement, SettingsSyncSettings.State::class.java)
|
||||
return SettingsSyncStateHolder(
|
||||
state
|
||||
)
|
||||
}
|
||||
catch (ex: Throwable) {
|
||||
SettingsSyncSettings.LOG.error("Unable to deserialize content of ${SettingsSyncSettings.FILE_SPEC} into object", ex)
|
||||
return SettingsSyncStateHolder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
|
||||
@@ -102,7 +102,7 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
settingsLog.advanceMaster() // merge (preserve) 'ide' changes made by logging existing settings
|
||||
|
||||
val masterPosition = settingsLog.forceWriteToMaster(cloudEvent.snapshot, "Remote changes to initialize settings by data from cloud")
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition)
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition, cloudEvent.syncSettings)
|
||||
|
||||
// normally we set cloud position only after successful push to cloud, but in this case we already take all settings from the cloud,
|
||||
// so no push is needed, and we know the cloud settings state.
|
||||
@@ -127,7 +127,7 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
|
||||
SettingsSyncLocalSettings.getInstance().knownAndAppliedServerId = updateResult.serverVersionId
|
||||
SettingsSyncSettings.getInstance().syncEnabled = true
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition)
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition, null)
|
||||
}
|
||||
is UpdateResult.FileDeletedFromServer -> {
|
||||
SettingsSyncSettings.getInstance().syncEnabled = false
|
||||
@@ -144,7 +144,7 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
settingsLog.setCloudPosition(masterPosition)
|
||||
|
||||
SettingsSyncSettings.getInstance().syncEnabled = true
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition)
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition, null)
|
||||
migration.migrateCategoriesSyncStatus(appConfigPath, SettingsSyncSettings.getInstance())
|
||||
saveIdeSettings()
|
||||
}
|
||||
@@ -333,7 +333,7 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
}
|
||||
|
||||
if (newIdePosition != masterPosition) { // master has advanced further that ide => the ide needs to be updated
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition)
|
||||
pushToIde(settingsLog.collectCurrentSnapshot(), masterPosition, null)
|
||||
}
|
||||
|
||||
if (newCloudPosition != masterPosition || pushRequestMode == MUST_PUSH || pushRequestMode == FORCE_PUSH) {
|
||||
@@ -399,8 +399,8 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
}
|
||||
}
|
||||
|
||||
private fun pushToIde(settingsSnapshot: SettingsSnapshot, targetPosition: SettingsLog.Position) {
|
||||
ideMediator.applyToIde(settingsSnapshot)
|
||||
private fun pushToIde(settingsSnapshot: SettingsSnapshot, targetPosition: SettingsLog.Position, syncSettings: SettingsSyncState?) {
|
||||
ideMediator.applyToIde(settingsSnapshot, syncSettings)
|
||||
settingsLog.setIdePosition(targetPosition)
|
||||
LOG.info("Applied settings to the IDE.")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@ import java.nio.file.Path
|
||||
@ApiStatus.Internal
|
||||
interface SettingsSyncIdeMediator {
|
||||
|
||||
fun applyToIde(snapshot: SettingsSnapshot)
|
||||
/**
|
||||
* @param settings if not null, SettingsSync settings will be taken from this object rather than snapshot
|
||||
*/
|
||||
fun applyToIde(snapshot: SettingsSnapshot, settings: SettingsSyncState?)
|
||||
|
||||
fun activateStreamProvider()
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.settingsSync.SettingsSnapshot.MetaInfo
|
||||
import com.intellij.settingsSync.plugins.SettingsSyncPluginManager
|
||||
import com.intellij.util.io.*
|
||||
import org.jdom.Element
|
||||
import java.io.InputStream
|
||||
import java.nio.file.FileVisitResult
|
||||
import java.nio.file.Files
|
||||
@@ -64,11 +65,17 @@ internal class SettingsSyncIdeMediatorImpl(private val componentStore: Component
|
||||
return roamingType != RoamingType.DISABLED
|
||||
}
|
||||
|
||||
override fun applyToIde(snapshot: SettingsSnapshot) {
|
||||
override fun applyToIde(snapshot: SettingsSnapshot, settings: SettingsSyncState?) {
|
||||
// 1. update SettingsSyncSettings first to apply changes in categories
|
||||
val settingsSyncFileState = snapshot.fileStates.find { it.file == "$OPTIONS_DIRECTORY/${SettingsSyncSettings.FILE_SPEC}" }
|
||||
if (settingsSyncFileState != null) {
|
||||
writeStatesToAppConfig(listOf(settingsSyncFileState))
|
||||
if (settings != null) {
|
||||
LOG.info("applying sync settings from SettingsSyncState")
|
||||
SettingsSyncSettings.getInstance().applyFromState(settings)
|
||||
}
|
||||
else {
|
||||
if (settingsSyncFileState != null) {
|
||||
writeStatesToAppConfig(listOf(settingsSyncFileState))
|
||||
}
|
||||
}
|
||||
|
||||
// 2. update plugins
|
||||
@@ -283,10 +290,9 @@ internal class SettingsSyncIdeMediatorImpl(private val componentStore: Component
|
||||
|
||||
invokeAndWaitIfNeeded {
|
||||
reloadComponents(changedFileSpecs, deletedFileSpecs)
|
||||
if (Registry.getInstance().isRestartNeeded){
|
||||
if (Registry.getInstance().isRestartNeeded) {
|
||||
SettingsSyncEvents.getInstance().fireRestartRequired("registry", SettingsSyncBundle.message("sync.registry.update.message"))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,34 +2,41 @@ package com.intellij.settingsSync
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.settingsSync.SettingsSyncSettings.Companion.COMPONENT_NAME
|
||||
import com.intellij.settingsSync.SettingsSyncSettings.Companion.FILE_SPEC
|
||||
import com.intellij.util.xmlb.annotations.Property
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
@State(name = "SettingsSyncSettings", storages = [Storage(FILE_SPEC)])
|
||||
@State(name = COMPONENT_NAME, storages = [Storage(FILE_SPEC)])
|
||||
@ApiStatus.Internal
|
||||
class SettingsSyncSettings :
|
||||
SimplePersistentStateComponent<SettingsSyncSettings.SettingsSyncSettingsState>(SettingsSyncSettingsState())
|
||||
{
|
||||
class SettingsSyncSettings : SettingsSyncState, SerializablePersistentStateComponent<SettingsSyncSettings.State>(State()) {
|
||||
|
||||
companion object {
|
||||
fun getInstance() = ApplicationManager.getApplication().getService(SettingsSyncSettings::class.java)
|
||||
|
||||
fun getInstance(): SettingsSyncSettings = ApplicationManager.getApplication().getService(SettingsSyncSettings::class.java)
|
||||
val LOG = logger<SettingsSyncSettings>()
|
||||
const val FILE_SPEC = "settingsSync.xml"
|
||||
const val COMPONENT_NAME = "SettingsSyncSettings"
|
||||
}
|
||||
|
||||
var migrationFromOldStorageChecked: Boolean
|
||||
override var migrationFromOldStorageChecked: Boolean
|
||||
get() = state.migrationFromOldStorageChecked
|
||||
set(value) {
|
||||
state.migrationFromOldStorageChecked = value
|
||||
updateState {
|
||||
it.withMigrationFromOldStorageChecked(value)
|
||||
}
|
||||
}
|
||||
|
||||
var syncEnabled
|
||||
override var syncEnabled
|
||||
get() = state.syncEnabled
|
||||
set(value) {
|
||||
state.syncEnabled = value
|
||||
updateState {
|
||||
it.withSyncEnabled(value)
|
||||
}
|
||||
fireSettingsStateChanged(value)
|
||||
}
|
||||
|
||||
@@ -37,65 +44,145 @@ class SettingsSyncSettings :
|
||||
SettingsSyncEvents.getInstance().fireEnabledStateChanged(syncEnabled)
|
||||
}
|
||||
|
||||
fun isCategoryEnabled(category: SettingsCategory) = !state.disabledCategories.contains(category)
|
||||
override fun isCategoryEnabled(category: SettingsCategory) = state.isCategoryEnabled(category)
|
||||
|
||||
fun setCategoryEnabled(category: SettingsCategory, isEnabled: Boolean) {
|
||||
if (isEnabled) {
|
||||
state.disabledCategories.remove(category)
|
||||
}
|
||||
else {
|
||||
if (!state.disabledCategories.contains(category)) {
|
||||
state.disabledCategories.add(category)
|
||||
state.disabledCategories.sort()
|
||||
}
|
||||
override fun setCategoryEnabled(category: SettingsCategory, isEnabled: Boolean) {
|
||||
updateState {
|
||||
it.withCategoryEnabled(category, isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun isSubcategoryEnabled(category: SettingsCategory, subcategoryId: String): Boolean {
|
||||
val disabled = state.disabledSubcategories[category]
|
||||
return disabled == null || !disabled.contains(subcategoryId)
|
||||
override fun isSubcategoryEnabled(category: SettingsCategory, subcategoryId: String) = state.isSubcategoryEnabled(category, subcategoryId)
|
||||
override fun setSubcategoryEnabled(category: SettingsCategory, subcategoryId: String, isEnabled: Boolean) {
|
||||
updateState {
|
||||
it.withSubcategoryEnabled(category, subcategoryId, isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun setSubcategoryEnabled(category: SettingsCategory, subcategoryId: String, isEnabled: Boolean) {
|
||||
val disabledList = state.disabledSubcategories[category]
|
||||
if (isEnabled) {
|
||||
if (disabledList != null) {
|
||||
disabledList.remove(subcategoryId)
|
||||
if (disabledList.isEmpty()) {
|
||||
state.disabledSubcategories.remove(category)
|
||||
}
|
||||
}
|
||||
override val disabledCategories: List<SettingsCategory>
|
||||
get() = state.disabledCategories
|
||||
override val disabledSubcategories: Map<SettingsCategory, List<String>>
|
||||
get() = state.disabledSubcategories
|
||||
|
||||
fun applyFromState(state: SettingsSyncState) {
|
||||
updateState {
|
||||
State(state.disabledCategories, state.disabledSubcategories, state.migrationFromOldStorageChecked, state.syncEnabled)
|
||||
}
|
||||
else {
|
||||
if (disabledList == null) {
|
||||
val newList = ArrayList<String>()
|
||||
newList.add(subcategoryId)
|
||||
state.disabledSubcategories.put(category, newList)
|
||||
}
|
||||
|
||||
data class State(@JvmField val disabledCategories: List<SettingsCategory> = emptyList(),
|
||||
@JvmField val disabledSubcategories: Map<SettingsCategory, List<String>> = emptyMap(),
|
||||
@JvmField @field:Property val migrationFromOldStorageChecked: Boolean = false,
|
||||
@JvmField @field:Property val syncEnabled: Boolean = false) {
|
||||
fun withSyncEnabled(enabled: Boolean): State {
|
||||
return State(disabledCategories, disabledSubcategories, migrationFromOldStorageChecked, enabled)
|
||||
}
|
||||
|
||||
fun withMigrationFromOldStorageChecked(checked: Boolean): State {
|
||||
return State(disabledCategories, disabledSubcategories, checked, syncEnabled)
|
||||
}
|
||||
|
||||
private fun withDisabledCategories(newCategories: List<SettingsCategory>): State {
|
||||
return State(newCategories, disabledSubcategories, migrationFromOldStorageChecked, syncEnabled)
|
||||
}
|
||||
|
||||
fun withCategoryEnabled(category: SettingsCategory, isEnabled: Boolean): State {
|
||||
val newCategories = ArrayList<SettingsCategory>(disabledCategories)
|
||||
if (isEnabled) {
|
||||
newCategories -= category
|
||||
}
|
||||
else {
|
||||
if (!disabledList.contains(subcategoryId)) {
|
||||
disabledList.add(subcategoryId)
|
||||
Collections.sort(disabledList)
|
||||
if (!newCategories.contains(category)) newCategories += category
|
||||
}
|
||||
newCategories.sort()
|
||||
return withDisabledCategories(newCategories)
|
||||
}
|
||||
|
||||
|
||||
private fun withDisabledSubcategories(newSubcategoriesMap: Map<SettingsCategory, List<String>>): State {
|
||||
return State(disabledCategories, newSubcategoriesMap, migrationFromOldStorageChecked, syncEnabled)
|
||||
}
|
||||
|
||||
fun withSubcategoryEnabled(category: SettingsCategory, subcategoryId: String, isEnabled: Boolean): State {
|
||||
val newSubcategoriesMap = HashMap(disabledSubcategories)
|
||||
val subcategoriesList = newSubcategoriesMap[category]
|
||||
if (isEnabled) {
|
||||
if (subcategoriesList != null) {
|
||||
val newSubcategories = ArrayList(subcategoriesList)
|
||||
newSubcategories -= subcategoryId
|
||||
if (newSubcategories.isEmpty()) {
|
||||
newSubcategoriesMap.remove(category)
|
||||
}
|
||||
else {
|
||||
newSubcategoriesMap[category] = newSubcategories
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val newSubcategories = if (subcategoriesList == null) {
|
||||
ArrayList()
|
||||
}
|
||||
else {
|
||||
ArrayList(subcategoriesList)
|
||||
}
|
||||
if (!newSubcategories.contains(subcategoryId)) {
|
||||
newSubcategories += subcategoryId
|
||||
}
|
||||
newSubcategories.sort()
|
||||
newSubcategoriesMap[category] = newSubcategories
|
||||
}
|
||||
return withDisabledSubcategories(newSubcategoriesMap)
|
||||
}
|
||||
state.intIncrementModificationCount()
|
||||
}
|
||||
|
||||
class SettingsSyncSettingsState : BaseState() {
|
||||
var syncEnabled by property(false)
|
||||
fun isCategoryEnabled(category: SettingsCategory) = !disabledCategories.contains(category)
|
||||
|
||||
var disabledCategories by list<SettingsCategory>()
|
||||
var disabledSubcategories by map<SettingsCategory, ArrayList<String>>()
|
||||
|
||||
var migrationFromOldStorageChecked by property(false)
|
||||
|
||||
@TestOnly
|
||||
internal fun reset() {
|
||||
syncEnabled = false
|
||||
disabledCategories = mutableListOf()
|
||||
disabledSubcategories = mutableMapOf()
|
||||
migrationFromOldStorageChecked = false
|
||||
fun isSubcategoryEnabled(category: SettingsCategory, subcategoryId: String): Boolean {
|
||||
val disabled = disabledSubcategories[category]
|
||||
return disabled == null || !disabled.contains(subcategoryId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface SettingsSyncState {
|
||||
fun isCategoryEnabled(category: SettingsCategory): Boolean
|
||||
fun setCategoryEnabled(category: SettingsCategory, isEnabled: Boolean)
|
||||
fun isSubcategoryEnabled(category: SettingsCategory, subcategoryId: String): Boolean
|
||||
fun setSubcategoryEnabled(category: SettingsCategory, subcategoryId: String, isEnabled: Boolean)
|
||||
|
||||
val disabledCategories: List<SettingsCategory>
|
||||
val disabledSubcategories: Map<SettingsCategory, List<String>>
|
||||
|
||||
var syncEnabled: Boolean
|
||||
var migrationFromOldStorageChecked: Boolean
|
||||
}
|
||||
|
||||
class SettingsSyncStateHolder(initState: SettingsSyncSettings.State = SettingsSyncSettings.State()) : SettingsSyncState {
|
||||
@Volatile
|
||||
private var state = initState
|
||||
override fun isCategoryEnabled(category: SettingsCategory) = state.isCategoryEnabled(category)
|
||||
|
||||
override fun setCategoryEnabled(category: SettingsCategory, isEnabled: Boolean) {
|
||||
state = state.withCategoryEnabled(category, isEnabled)
|
||||
}
|
||||
|
||||
override fun isSubcategoryEnabled(category: SettingsCategory, subcategoryId: String) = state.isSubcategoryEnabled(category, subcategoryId)
|
||||
|
||||
override fun setSubcategoryEnabled(category: SettingsCategory, subcategoryId: String, isEnabled: Boolean) {
|
||||
state = state.withSubcategoryEnabled(category, subcategoryId, isEnabled)
|
||||
}
|
||||
|
||||
override val disabledCategories: List<SettingsCategory>
|
||||
get() = state.disabledCategories
|
||||
override val disabledSubcategories: Map<SettingsCategory, List<String>>
|
||||
get() = state.disabledSubcategories
|
||||
override var syncEnabled: Boolean
|
||||
get() = state.syncEnabled
|
||||
set(value) {
|
||||
state = state.withSyncEnabled(value)
|
||||
}
|
||||
override var migrationFromOldStorageChecked: Boolean
|
||||
get() = state.migrationFromOldStorageChecked
|
||||
set(value) {
|
||||
state = state.withMigrationFromOldStorageChecked(value)
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,19 @@ package com.intellij.settingsSync.config
|
||||
import com.intellij.openapi.ui.DialogPanel
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.settingsSync.SettingsSyncBundle.message
|
||||
import org.jetbrains.annotations.Nls
|
||||
import com.intellij.settingsSync.SettingsSyncState
|
||||
import com.intellij.settingsSync.SettingsSyncStateHolder
|
||||
import java.awt.event.ActionEvent
|
||||
import javax.swing.AbstractAction
|
||||
import javax.swing.Action
|
||||
import javax.swing.JComponent
|
||||
|
||||
internal class EnableSettingsSyncDialog
|
||||
private constructor(parent: JComponent, private val remoteSettingsFound: Boolean) : DialogWrapper(parent, false) {
|
||||
internal class EnableSettingsSyncDialog(parent: JComponent, remoteSettings: SettingsSyncState?) : DialogWrapper(parent, false) {
|
||||
|
||||
private lateinit var configPanel: DialogPanel
|
||||
private var dialogResult: Result? = null
|
||||
val syncSettings: SettingsSyncState = remoteSettings ?: SettingsSyncStateHolder()
|
||||
private val remoteSettingsExist: Boolean = remoteSettings != null
|
||||
|
||||
init {
|
||||
title = message("title.settings.sync")
|
||||
@@ -25,22 +27,14 @@ internal class EnableSettingsSyncDialog
|
||||
GET_FROM_SERVER
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun showAndGetResult(parent: JComponent, remoteSettingsFound: Boolean) : Result? {
|
||||
val dialog = EnableSettingsSyncDialog(parent, remoteSettingsFound)
|
||||
dialog.show()
|
||||
return dialog.getResult()
|
||||
}
|
||||
}
|
||||
|
||||
override fun createCenterPanel(): JComponent {
|
||||
configPanel = SettingsSyncPanelFactory.createPanel(message("enable.dialog.select.what.to.sync"))
|
||||
configPanel = SettingsSyncPanelFactory.createPanel(message("enable.dialog.select.what.to.sync"), syncSettings)
|
||||
configPanel.reset()
|
||||
return configPanel
|
||||
}
|
||||
|
||||
override fun createActions(): Array<Action> =
|
||||
if (remoteSettingsFound) arrayOf(cancelAction, SyncLocalSettingsAction(), GetSettingsFromAccountAction())
|
||||
if (remoteSettingsExist) arrayOf(cancelAction, SyncLocalSettingsAction(), GetSettingsFromAccountAction())
|
||||
else {
|
||||
val enableSyncAction = EnableSyncAction()
|
||||
enableSyncAction.putValue(DEFAULT_ACTION, true)
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package com.intellij.settingsSync.config
|
||||
|
||||
import com.intellij.openapi.components.SettingsCategory
|
||||
import com.intellij.openapi.components.SettingsCategory.*
|
||||
import com.intellij.settingsSync.SettingsSyncBundle.message
|
||||
import com.intellij.settingsSync.SettingsSyncSettings
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.util.*
|
||||
|
||||
internal class SettingsCategoryDescriptor(
|
||||
private val category : SettingsCategory,
|
||||
val secondaryGroup: SettingsSyncSubcategoryGroup? = null
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private val DESCRIPTORS : List<SettingsCategoryDescriptor> = listOf(
|
||||
SettingsCategoryDescriptor(UI, SettingsSyncUiGroup()),
|
||||
SettingsCategoryDescriptor(KEYMAP),
|
||||
SettingsCategoryDescriptor(CODE),
|
||||
SettingsCategoryDescriptor(PLUGINS, SettingsSyncPluginsGroup()),
|
||||
SettingsCategoryDescriptor(TOOLS),
|
||||
SettingsCategoryDescriptor(SYSTEM),
|
||||
)
|
||||
|
||||
fun listAll() : List<SettingsCategoryDescriptor> {
|
||||
return DESCRIPTORS
|
||||
}
|
||||
}
|
||||
|
||||
var isSynchronized: Boolean = true
|
||||
|
||||
fun reset() {
|
||||
isSynchronized = SettingsSyncSettings.getInstance().isCategoryEnabled(category)
|
||||
if (secondaryGroup != null) {
|
||||
secondaryGroup.getDescriptors().forEach {
|
||||
it.isSelected = isSynchronized && SettingsSyncSettings.getInstance().isSubcategoryEnabled(category, it.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun apply() {
|
||||
if (secondaryGroup != null) {
|
||||
secondaryGroup.getDescriptors().forEach {
|
||||
// !isSynchronized not store disabled states individually
|
||||
SettingsSyncSettings.getInstance().setSubcategoryEnabled(category, it.id, !isSynchronized || it.isSelected)
|
||||
}
|
||||
}
|
||||
SettingsSyncSettings.getInstance().setCategoryEnabled(category, isSynchronized)
|
||||
}
|
||||
|
||||
fun isModified() : Boolean {
|
||||
if (isSynchronized != SettingsSyncSettings.getInstance().isCategoryEnabled(category)) return true
|
||||
if (secondaryGroup != null && isSynchronized) {
|
||||
secondaryGroup.getDescriptors().forEach {
|
||||
if (it.isSelected != SettingsSyncSettings.getInstance().isSubcategoryEnabled(category, it.id)) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
val name: @Nls String
|
||||
get() {
|
||||
return message("${categoryKey}.name")
|
||||
}
|
||||
|
||||
val description: @Nls String
|
||||
get() {
|
||||
return message("${categoryKey}.description")
|
||||
}
|
||||
|
||||
private val categoryKey: String
|
||||
get() {
|
||||
return "settings.category." + category.name.lowercase(Locale.getDefault())
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,7 @@ internal class SettingsSyncConfigurable : BoundConfigurable(message("title.setti
|
||||
SettingsSyncEvents.getInstance().addListener(object : SettingsSyncEventListener {
|
||||
override fun enabledStateChanged(syncEnabled: Boolean) {
|
||||
listener(invoke())
|
||||
configPanel.reset()
|
||||
}
|
||||
}, disposable!!)
|
||||
}
|
||||
@@ -126,7 +127,7 @@ internal class SettingsSyncConfigurable : BoundConfigurable(message("title.setti
|
||||
}
|
||||
|
||||
override fun createPanel(): DialogPanel {
|
||||
val categoriesPanel = SettingsSyncPanelFactory.createPanel(message("configurable.what.to.sync.label"))
|
||||
val categoriesPanel = SettingsSyncPanelFactory.createPanel(message("configurable.what.to.sync.label"), SettingsSyncSettings.getInstance())
|
||||
val authService = SettingsSyncAuthService.getInstance()
|
||||
val authAvailable = authService.isLoginAvailable()
|
||||
configPanel = panel {
|
||||
@@ -252,8 +253,8 @@ internal class SettingsSyncConfigurable : BoundConfigurable(message("title.setti
|
||||
|
||||
override fun serverStateCheckFinished(updateResult: UpdateResult) {
|
||||
when (updateResult) {
|
||||
NoFileOnServer, FileDeletedFromServer -> showEnableSyncDialog(false)
|
||||
is Success -> showEnableSyncDialog(true)
|
||||
NoFileOnServer, FileDeletedFromServer -> showEnableSyncDialog(null)
|
||||
is Success -> showEnableSyncDialog(updateResult.settingsSnapshot.getState())
|
||||
is Error -> {
|
||||
if (updateResult != SettingsSyncEnabler.State.CANCELLED) {
|
||||
showError(message("notification.title.update.error"), updateResult.message)
|
||||
@@ -278,19 +279,20 @@ internal class SettingsSyncConfigurable : BoundConfigurable(message("title.setti
|
||||
updateStatusInfo()
|
||||
}
|
||||
|
||||
private fun showEnableSyncDialog(remoteSettingsFound: Boolean) {
|
||||
val dialogResult = EnableSettingsSyncDialog.showAndGetResult(configPanel, remoteSettingsFound)
|
||||
private fun showEnableSyncDialog(remoteSettings: SettingsSyncState?) {
|
||||
val dialog = EnableSettingsSyncDialog(configPanel, remoteSettings)
|
||||
dialog.show()
|
||||
val dialogResult = dialog.getResult()
|
||||
if (dialogResult != null) {
|
||||
reset()
|
||||
when (dialogResult) {
|
||||
EnableSettingsSyncDialog.Result.GET_FROM_SERVER -> {
|
||||
syncEnabler.getSettingsFromServer()
|
||||
syncEnabler.getSettingsFromServer(dialog.syncSettings)
|
||||
SettingsSyncEventsStatistics.ENABLED_MANUALLY.log(SettingsSyncEventsStatistics.EnabledMethod.GET_FROM_SERVER)
|
||||
}
|
||||
EnableSettingsSyncDialog.Result.PUSH_LOCAL -> {
|
||||
SettingsSyncSettings.getInstance().syncEnabled = true
|
||||
syncEnabler.pushSettingsToServer()
|
||||
if (remoteSettingsFound) {
|
||||
if (remoteSettings != null) {
|
||||
SettingsSyncEventsStatistics.ENABLED_MANUALLY.log(SettingsSyncEventsStatistics.EnabledMethod.PUSH_LOCAL)
|
||||
}
|
||||
else {
|
||||
@@ -302,6 +304,8 @@ internal class SettingsSyncConfigurable : BoundConfigurable(message("title.setti
|
||||
else {
|
||||
SettingsSyncEventsStatistics.ENABLED_MANUALLY.log(SettingsSyncEventsStatistics.EnabledMethod.CANCELED)
|
||||
}
|
||||
reset()
|
||||
configPanel.reset()
|
||||
}
|
||||
|
||||
companion object DisableResult {
|
||||
|
||||
@@ -34,7 +34,7 @@ internal class SettingsSyncEnabler {
|
||||
}
|
||||
|
||||
|
||||
fun getSettingsFromServer() {
|
||||
fun getSettingsFromServer(syncSettings: SettingsSyncState? = null) {
|
||||
eventDispatcher.multicaster.updateFromServerStarted()
|
||||
val settingsSyncControls = SettingsSyncMain.getInstance().controls
|
||||
object : Task.Modal(null, SettingsSyncBundle.message("enable.sync.get.from.server.progress"), false) {
|
||||
@@ -44,7 +44,7 @@ internal class SettingsSyncEnabler {
|
||||
val result = settingsSyncControls.remoteCommunicator.receiveUpdates()
|
||||
updateResult = result
|
||||
if (result is UpdateResult.Success) {
|
||||
val cloudEvent = SyncSettingsEvent.CloudChange(result.settingsSnapshot, result.serverVersionId)
|
||||
val cloudEvent = SyncSettingsEvent.CloudChange(result.settingsSnapshot, result.serverVersionId, syncSettings)
|
||||
settingsSyncControls.bridge.initialize(SettingsSyncBridge.InitMode.TakeFromServer(cloudEvent))
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ internal class SettingsSyncEnabler {
|
||||
|
||||
fun pushSettingsToServer() {
|
||||
val settingsSyncControls = SettingsSyncMain.getInstance().controls
|
||||
object: Task.Modal(null, SettingsSyncBundle.message("enable.sync.push.to.server.progress"), false) {
|
||||
object : Task.Modal(null, SettingsSyncBundle.message("enable.sync.push.to.server.progress"), false) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
// todo initialization must be modal but pushing to server can be made later
|
||||
settingsSyncControls.bridge.initialize(SettingsSyncBridge.InitMode.PushToServer)
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.intellij.settingsSync.config
|
||||
import com.intellij.openapi.ui.DialogPanel
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.settingsSync.SettingsSyncBundle.message
|
||||
import com.intellij.settingsSync.SettingsSyncState
|
||||
import com.intellij.ui.CheckBoxList
|
||||
import com.intellij.ui.CheckBoxListListener
|
||||
import com.intellij.ui.SeparatorComponent
|
||||
@@ -21,52 +22,51 @@ import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
|
||||
internal object SettingsSyncPanelFactory {
|
||||
fun createPanel(syncLabel: @Nls String): DialogPanel {
|
||||
fun createPanel(syncLabel: @Nls String, state: SettingsSyncState): DialogPanel {
|
||||
return panel {
|
||||
row {
|
||||
label(syncLabel)
|
||||
}
|
||||
|
||||
SettingsCategoryDescriptor.listAll().forEach { descriptor ->
|
||||
descriptor.reset()
|
||||
val categoryHolders = SyncCategoryHolder.createAllForState(state)
|
||||
for (holder in categoryHolders) {
|
||||
indent {
|
||||
row {
|
||||
if (descriptor.secondaryGroup == null) {
|
||||
if (holder.secondaryGroup == null) {
|
||||
checkBox(
|
||||
descriptor.name
|
||||
holder.name
|
||||
)
|
||||
.bindSelected(descriptor::isSynchronized)
|
||||
.onReset { descriptor.reset() }
|
||||
.onApply { descriptor.apply() }
|
||||
.onIsModified { descriptor.isModified() }
|
||||
comment(descriptor.description)
|
||||
.bindSelected(holder::isSynchronized)
|
||||
.onReset { holder.reset() }
|
||||
.onApply { holder.apply() }
|
||||
.onIsModified { holder.isModified() }
|
||||
comment(holder.description)
|
||||
}
|
||||
else {
|
||||
val topCheckBox = ThreeStateCheckBox(descriptor.name)
|
||||
val topCheckBox = ThreeStateCheckBox(holder.name)
|
||||
topCheckBox.isThirdStateEnabled = false
|
||||
cell(topCheckBox)
|
||||
.onReset {
|
||||
descriptor.reset()
|
||||
topCheckBox.state = getGroupState(descriptor)
|
||||
holder.reset()
|
||||
topCheckBox.state = getGroupState(holder)
|
||||
}
|
||||
.onApply {
|
||||
descriptor.isSynchronized = topCheckBox.state != State.NOT_SELECTED
|
||||
descriptor.apply()
|
||||
holder.isSynchronized = topCheckBox.state != State.NOT_SELECTED
|
||||
holder.apply()
|
||||
}
|
||||
.onIsModified { descriptor.isModified() }
|
||||
val c = comment(descriptor.description).visible(!descriptor.description.isEmpty())
|
||||
val subcategoryLink = configureLink(descriptor.secondaryGroup, c.component.font.size2D) {
|
||||
topCheckBox.state = getGroupState(descriptor)
|
||||
descriptor.isSynchronized = topCheckBox.state != State.NOT_SELECTED
|
||||
.onIsModified { holder.isModified() }
|
||||
val c = comment(holder.description).visible(!holder.description.isEmpty())
|
||||
val subcategoryLink = configureLink(holder.secondaryGroup!!, c.component.font.size2D) {
|
||||
topCheckBox.state = getGroupState(holder)
|
||||
holder.isSynchronized = topCheckBox.state != State.NOT_SELECTED
|
||||
}
|
||||
cell(subcategoryLink)
|
||||
.visible(descriptor.secondaryGroup.getDescriptors().size > 1 || !descriptor.secondaryGroup.isComplete())
|
||||
.visible(holder.secondaryGroup!!.getDescriptors().size > 1 || !holder.secondaryGroup!!.isComplete())
|
||||
topCheckBox.addActionListener {
|
||||
descriptor.isSynchronized = topCheckBox.state != State.NOT_SELECTED
|
||||
descriptor.secondaryGroup.getDescriptors().forEach {
|
||||
it.isSelected = descriptor.isSynchronized
|
||||
holder.isSynchronized = topCheckBox.state != State.NOT_SELECTED
|
||||
holder.secondaryGroup!!.getDescriptors().forEach {
|
||||
it.isSelected = holder.isSynchronized
|
||||
}
|
||||
subcategoryLink.isEnabled = descriptor.secondaryGroup.isComplete() || descriptor.isSynchronized
|
||||
subcategoryLink.isEnabled = holder.secondaryGroup!!.isComplete() || holder.isSynchronized
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ internal object SettingsSyncPanelFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGroupState(descriptor: SettingsCategoryDescriptor): State {
|
||||
private fun getGroupState(descriptor: SyncCategoryHolder): State {
|
||||
val group = descriptor.secondaryGroup
|
||||
if (group == null) {
|
||||
return if (descriptor.isSynchronized) State.SELECTED else State.NOT_SELECTED
|
||||
@@ -95,7 +95,7 @@ internal object SettingsSyncPanelFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureLink(group: SettingsSyncSubcategoryGroup,
|
||||
private fun configureLink(group: SyncSubcategoryGroup,
|
||||
fontSize: Float,
|
||||
onCheckBoxChange: () -> Unit): JComponent {
|
||||
val actionLink = ActionLink(message("subcategory.config.link")) {}
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.intellij.settingsSync.config
|
||||
|
||||
import org.jetbrains.annotations.Nls
|
||||
|
||||
internal interface SettingsSyncSubcategoryGroup {
|
||||
internal interface SyncSubcategoryGroup {
|
||||
fun getDescriptors() : List<SettingsSyncSubcategoryDescriptor>
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.intellij.settingsSync.config
|
||||
|
||||
import com.intellij.openapi.components.SettingsCategory
|
||||
import com.intellij.openapi.components.SettingsCategory.*
|
||||
import com.intellij.settingsSync.SettingsSyncState
|
||||
import com.intellij.settingsSync.SettingsSyncBundle.message
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.util.*
|
||||
|
||||
internal class SyncCategoryHolder(
|
||||
val descriptor: Category,
|
||||
private val state: SettingsSyncState
|
||||
) {
|
||||
var isSynchronized: Boolean = state.isCategoryEnabled(descriptor.category)
|
||||
|
||||
val name: @Nls String
|
||||
get() = descriptor.name
|
||||
|
||||
val description: @Nls String
|
||||
get() = descriptor.description
|
||||
|
||||
val secondaryGroup: SyncSubcategoryGroup?
|
||||
get() = descriptor.secondaryGroup
|
||||
|
||||
fun reset() {
|
||||
with(descriptor) {
|
||||
isSynchronized = state.isCategoryEnabled(category)
|
||||
if (secondaryGroup != null) {
|
||||
secondaryGroup.getDescriptors().forEach {
|
||||
it.isSelected = isSynchronized && state.isSubcategoryEnabled(category, it.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun apply() {
|
||||
with(descriptor) {
|
||||
if (secondaryGroup != null) {
|
||||
secondaryGroup.getDescriptors().forEach {
|
||||
// !isSynchronized not store disabled states individually
|
||||
state.setSubcategoryEnabled(category, it.id, !isSynchronized || it.isSelected)
|
||||
}
|
||||
}
|
||||
state.setCategoryEnabled(category, isSynchronized)
|
||||
}
|
||||
}
|
||||
|
||||
fun isModified(): Boolean {
|
||||
with(descriptor) {
|
||||
if (isSynchronized != state.isCategoryEnabled(category)) return true
|
||||
if (secondaryGroup != null && isSynchronized) {
|
||||
secondaryGroup.getDescriptors().forEach {
|
||||
if (it.isSelected != state.isSubcategoryEnabled(category, it.id)) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun createAllForState(state: SettingsSyncState): List<SyncCategoryHolder> {
|
||||
val retval = arrayListOf<SyncCategoryHolder>()
|
||||
for (descriptor in Category.DESCRIPTORS) {
|
||||
retval.add(SyncCategoryHolder(descriptor, state))
|
||||
}
|
||||
return retval
|
||||
}
|
||||
}
|
||||
|
||||
internal class Category(
|
||||
val category: SettingsCategory,
|
||||
val secondaryGroup: SyncSubcategoryGroup? = null
|
||||
) {
|
||||
|
||||
val name: @Nls String
|
||||
get() {
|
||||
return message("${categoryKey}.name")
|
||||
}
|
||||
|
||||
val description: @Nls String
|
||||
get() {
|
||||
return message("${categoryKey}.description")
|
||||
}
|
||||
|
||||
private val categoryKey: String
|
||||
get() {
|
||||
return "settings.category." + category.name.lowercase(Locale.getDefault())
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal val DESCRIPTORS: List<Category> = listOf(
|
||||
Category(UI, SyncUiGroup()),
|
||||
Category(KEYMAP),
|
||||
Category(CODE),
|
||||
Category(PLUGINS, SyncPluginsGroup()),
|
||||
Category(TOOLS),
|
||||
Category(SYSTEM),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nls
|
||||
|
||||
internal const val BUNDLED_PLUGINS_ID = "bundled"
|
||||
|
||||
internal class SettingsSyncPluginsGroup : SettingsSyncSubcategoryGroup {
|
||||
internal class SyncPluginsGroup : SyncSubcategoryGroup {
|
||||
private val storedDescriptors = HashMap<String, SettingsSyncSubcategoryDescriptor>()
|
||||
|
||||
override fun getDescriptors(): List<SettingsSyncSubcategoryDescriptor> {
|
||||
@@ -4,7 +4,7 @@ import com.intellij.settingsSync.SettingsSyncBundle
|
||||
|
||||
const val EDITOR_FONT_SUBCATEGORY_ID = "editorFont"
|
||||
|
||||
internal class SettingsSyncUiGroup : SettingsSyncSubcategoryGroup {
|
||||
internal class SyncUiGroup : SyncSubcategoryGroup {
|
||||
|
||||
private val descriptors = listOf(SettingsSyncSubcategoryDescriptor(SettingsSyncBundle.message("settings.category.ui.editor.font"),
|
||||
EDITOR_FONT_SUBCATEGORY_ID, false, false))
|
||||
@@ -145,7 +145,7 @@ internal class SettingsRepositoryToSettingsSyncMigration {
|
||||
TemplateSettings.getInstance() // Required for live templates to be migrated correctly, see IDEA-303831
|
||||
|
||||
SettingsSyncIdeMediatorImpl(ApplicationManager.getApplication().stateStore as ComponentStoreImpl,
|
||||
PathManager.getConfigDir(), { false }).applyToIde(snapshot)
|
||||
PathManager.getConfigDir(), { false }).applyToIde(snapshot, null)
|
||||
settingsRepositoryMigration.showNotificationAboutUnbundling(executorService)
|
||||
SettingsSyncEventsStatistics.MIGRATED_FROM_SETTINGS_REPOSITORY.log()
|
||||
}
|
||||
|
||||
@@ -13,14 +13,11 @@ import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.junit5.TestDisposable
|
||||
import com.intellij.testFramework.replaceService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.test.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@TestApplication
|
||||
@@ -76,7 +73,7 @@ abstract class BasePluginManagerTest {
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
SettingsSyncSettings.getInstance().syncEnabled = true
|
||||
SettingsSyncSettings.getInstance().loadState(SettingsSyncSettings.SettingsSyncSettingsState())
|
||||
SettingsSyncSettings.getInstance().loadState(SettingsSyncSettings.State())
|
||||
testPluginManager = TestPluginManager()
|
||||
ApplicationManager.getApplication().replaceService(PluginManagerProxy::class.java, testPluginManager, testRootDisposable)
|
||||
testScheduler = TestCoroutineScheduler()
|
||||
|
||||
@@ -13,7 +13,7 @@ internal class MockSettingsSyncIdeMediator : SettingsSyncIdeMediator {
|
||||
|
||||
private var exceptionToThrowOnApply: Exception? = null
|
||||
|
||||
override fun applyToIde(snapshot: SettingsSnapshot) {
|
||||
override fun applyToIde(snapshot: SettingsSnapshot, settings: SettingsSyncState?) {
|
||||
if (exceptionToThrowOnApply != null) {
|
||||
throw exceptionToThrowOnApply!!
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.intellij.settingsSync
|
||||
|
||||
import com.intellij.openapi.components.SettingsCategory
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Instant
|
||||
|
||||
class SettingsSnapshotTest {
|
||||
|
||||
@Test
|
||||
fun `extract dialog state`() {
|
||||
val metaInfo = SettingsSnapshot.MetaInfo(Instant.now(), null)
|
||||
val settingsSyncXmlState = FileState.Modified("options/settingsSync.xml", """
|
||||
<application>
|
||||
<component name="SettingsSyncSettings">
|
||||
<option name="disabledCategories">
|
||||
<list>
|
||||
<option value="TOOLS" />
|
||||
<option value="SYSTEM" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="disabledSubcategories">
|
||||
<map>
|
||||
<entry key="UI">
|
||||
<value>
|
||||
<list>
|
||||
<option value="editorFont" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="PLUGINS">
|
||||
<value>
|
||||
<list>
|
||||
<option value="org.vlang" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="migrationFromOldStorageChecked" value="true" />
|
||||
<option name="syncEnabled" value="true" />
|
||||
</component>
|
||||
</application>
|
||||
""".trimIndent().toByteArray())
|
||||
val snapshot = SettingsSnapshot(metaInfo, setOf(settingsSyncXmlState), null, emptyMap(), emptySet())
|
||||
val state = snapshot.getState()
|
||||
Assertions.assertTrue(state.disabledCategories.containsAll(listOf(SettingsCategory.SYSTEM, SettingsCategory.TOOLS)))
|
||||
Assertions.assertEquals(2,state.disabledCategories.size)
|
||||
Assertions.assertTrue(state.isCategoryEnabled(SettingsCategory.PLUGINS))
|
||||
Assertions.assertTrue(state.isCategoryEnabled(SettingsCategory.UI))
|
||||
Assertions.assertFalse(state.isSubcategoryEnabled(SettingsCategory.UI, "editorFont"))
|
||||
Assertions.assertTrue(state.disabledSubcategories.keys.containsAll(listOf(SettingsCategory.UI, SettingsCategory.PLUGINS)))
|
||||
Assertions.assertTrue(state.syncEnabled)
|
||||
Assertions.assertTrue(state.migrationFromOldStorageChecked)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extract dialog state 2`() {
|
||||
val metaInfo = SettingsSnapshot.MetaInfo(Instant.now(), null)
|
||||
val settingsSyncXmlState = FileState.Modified("options/settingsSync.xml", """
|
||||
<application>
|
||||
<component name="SettingsSyncSettings">
|
||||
<option name="disabledSubcategories">
|
||||
<map>
|
||||
<entry key="PLUGINS">
|
||||
<value>
|
||||
<list>
|
||||
<option value="org.vlang" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</application>
|
||||
""".trimIndent().toByteArray())
|
||||
val snapshot = SettingsSnapshot(metaInfo, setOf(settingsSyncXmlState), null, emptyMap(), emptySet())
|
||||
val state = snapshot.getState()
|
||||
Assertions.assertTrue(state.isCategoryEnabled(SettingsCategory.TOOLS))
|
||||
Assertions.assertTrue(state.isCategoryEnabled(SettingsCategory.PLUGINS))
|
||||
Assertions.assertTrue(state.isCategoryEnabled(SettingsCategory.UI))
|
||||
Assertions.assertTrue(state.isSubcategoryEnabled(SettingsCategory.UI, "editorFont"))
|
||||
Assertions.assertFalse(state.syncEnabled)
|
||||
Assertions.assertFalse(state.migrationFromOldStorageChecked)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,21 +2,26 @@ package com.intellij.settingsSync
|
||||
|
||||
import com.intellij.configurationStore.ChildlessComponentStore
|
||||
import com.intellij.configurationStore.StateStorageManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.RoamingType
|
||||
import com.intellij.openapi.components.SettingsCategory
|
||||
import com.intellij.openapi.components.stateStore
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import com.intellij.testFramework.rules.InMemoryFsRule
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import java.nio.file.Path
|
||||
import java.time.Instant
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.createFile
|
||||
import kotlin.io.path.div
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
@RunWith(JUnit4::class)
|
||||
class SettingsSyncIdeMediatorTest {
|
||||
class SettingsSyncIdeMediatorTest : BasePlatformTestCase() {
|
||||
|
||||
@JvmField @Rule
|
||||
val memoryFs = InMemoryFsRule()
|
||||
@@ -46,4 +51,50 @@ true
|
||||
|
||||
assertEquals(setOf("mytemplate.kt"), visited)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `respect SettingSyncState`() {
|
||||
val rootConfig = memoryFs.fs.getPath("/appconfig")
|
||||
val componentStore = object : ChildlessComponentStore() {
|
||||
override val storageManager: StateStorageManager
|
||||
get() = ApplicationManager.getApplication().stateStore.storageManager
|
||||
|
||||
override fun setPath(path: Path) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
val mediator = SettingsSyncIdeMediatorImpl(componentStore, rootConfig, { true })
|
||||
val metaInfo = SettingsSnapshot.MetaInfo(Instant.now(), null)
|
||||
val settingsSyncXmlState = FileState.Modified("options/settingsSync.xml", """
|
||||
<application>
|
||||
<component name="SettingsSyncSettings">
|
||||
<option name="disabledSubcategories">
|
||||
<map>
|
||||
<entry key="PLUGINS">
|
||||
<value>
|
||||
<list>
|
||||
<option value="org.vlang" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</application>
|
||||
""".trimIndent().toByteArray())
|
||||
val snapshot = SettingsSnapshot(metaInfo, setOf(settingsSyncXmlState), null, emptyMap(), emptySet())
|
||||
val syncState = SettingsSyncStateHolder(SettingsSyncSettings.State())
|
||||
syncState.syncEnabled = true
|
||||
syncState.setCategoryEnabled(SettingsCategory.CODE, false)
|
||||
syncState.setSubcategoryEnabled(SettingsCategory.PLUGINS, "IdeaVIM", false)
|
||||
mediator.applyToIde(snapshot, syncState)
|
||||
Assert.assertTrue(SettingsSyncSettings.getInstance().syncEnabled)
|
||||
Assert.assertFalse(SettingsSyncSettings.getInstance().migrationFromOldStorageChecked)
|
||||
Assert.assertFalse(SettingsSyncSettings.getInstance().isCategoryEnabled(SettingsCategory.CODE))
|
||||
Assert.assertTrue(SettingsSyncSettings.getInstance().isCategoryEnabled(SettingsCategory.UI))
|
||||
Assert.assertTrue(SettingsSyncSettings.getInstance().isCategoryEnabled(SettingsCategory.SYSTEM))
|
||||
|
||||
Assert.assertTrue(SettingsSyncSettings.getInstance().isSubcategoryEnabled(SettingsCategory.PLUGINS, "org.vlang"))
|
||||
Assert.assertFalse(SettingsSyncSettings.getInstance().isSubcategoryEnabled(SettingsCategory.PLUGINS, "IdeaVIM"))
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ internal abstract class SettingsSyncTestBase {
|
||||
configDir = mainDir.resolve("rootconfig").createDirectories()
|
||||
|
||||
SettingsSyncLocalSettings.getInstance().state.reset()
|
||||
SettingsSyncSettings.getInstance().state.reset()
|
||||
SettingsSyncSettings.getInstance().state = SettingsSyncSettings.State()
|
||||
|
||||
remoteCommunicator = if (isTestingAgainstRealCloudServer()) {
|
||||
TestRemoteCommunicator()
|
||||
|
||||
Reference in New Issue
Block a user