[settings] IJPL-248896 introduce NoAutomaticReset interface for Configurables

A safety escape hatch for plugin developers whose Configurables trigger
external actions (e.g. browser OAuth, native file picker) without a
modal dialog. Configurables implementing NoAutomaticReset are skipped
by SettingsEditor.resetUnmodifiedOnWindowFocus() on Settings focus regain.


(cherry picked from commit 79beee8a0e0da064fdf696a1d05850c117f7065a)

IJ-CR-217470

GitOrigin-RevId: 83a745f8f651d4513129e74e71c87a0e66739133
This commit is contained in:
Aleksandra Olemskaia
2026-08-07 13:34:31 +00:00
committed by intellij-monorepo-bot
parent 8f1da042b2
commit e641f7bffa
3 changed files with 26 additions and 4 deletions
+1
View File
@@ -844,6 +844,7 @@ c:com.intellij.openapi.options.ConfigurationException
- setQuickFix(com.intellij.openapi.options.ConfigurationQuickFix):V
- setQuickFix(java.lang.Runnable):V
- withHtmlMessage():com.intellij.openapi.options.ConfigurationException
com.intellij.openapi.options.NoAutomaticReset
f:com.intellij.openapi.options.OptionsBundle
- com.intellij.DynamicBundle
com.intellij.openapi.options.SearchableConfigurable
@@ -0,0 +1,16 @@
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.options
import org.jetbrains.annotations.ApiStatus
/**
* A marker interface for [Configurable]s that require an explicit user action outside the IDE
* (such as browser-based authorization or a native file picker) before their state can be reset.
*
* When a settings window regains focus, the Settings editor normally resets any configurable that
* was unmodified when focus was lost but now reports `isModified() == true` (e.g. due to a
* background/external change). Implementing this interface opts the configurable out of that
* automatic reset, ensuring that ongoing external interactions are not interrupted.
*/
@ApiStatus.OverrideOnly
interface NoAutomaticReset
@@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.UiDataProvider;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.BackedByPersistentState;
import com.intellij.openapi.options.NoAutomaticReset;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurableGroup;
import com.intellij.openapi.options.ConfigurationException;
@@ -72,7 +73,6 @@ import javax.swing.JPanel;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@@ -704,9 +704,14 @@ public final class SettingsEditor extends AbstractEditor implements UiDataProvid
if (isModified == null) return;
LOG.debug("resetUnmodifiedOnWindowFocus: current=" + current.getDisplayName() + ", leaveState=" + leaveState + ", isModified=" + isModified);
if (leaveState == Boolean.FALSE && isModified) {
LOG.warn("resetUnmodifiedOnWindowFocus: resetting " + current.getDisplayName());
current.reset();
filter.context.fireReset(current);
if (ConfigurableWrapper.cast(NoAutomaticReset.class, current) != null) {
LOG.debug("resetUnmodifiedOnWindowFocus: skipping reset for " + current.getDisplayName() + " (NoAutomaticReset)");
}
else {
LOG.warn("resetUnmodifiedOnWindowFocus: resetting " + current.getDisplayName());
current.reset();
filter.context.fireReset(current);
}
}
detectExternalChangesOnFocusGain();
}