summaryrefslogtreecommitdiff
path: root/platform/platform-impl/src/com/intellij/openapi/options
diff options
context:
space:
mode:
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/options')
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/CompositeConfigurable.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ConfigurableBase.java98
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ConfigurableUi.java31
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java20
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java54
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/SimpleConfigurable.java52
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java52
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java75
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java12
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java16
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java330
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java442
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java78
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.form41
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.java159
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java211
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java182
18 files changed, 982 insertions, 879 deletions
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/CompositeConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/options/CompositeConfigurable.java
index 0b9e5ade8d29..aaba0fdbaf6b 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/CompositeConfigurable.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/CompositeConfigurable.java
@@ -20,18 +20,21 @@ import java.util.List;
public abstract class CompositeConfigurable<T extends UnnamedConfigurable> extends BaseConfigurable {
private List<T> myConfigurables;
+ @Override
public void reset() {
for (T configurable : getConfigurables()) {
configurable.reset();
}
}
+ @Override
public void apply() throws ConfigurationException {
for (T configurable : getConfigurables()) {
configurable.apply();
}
}
+ @Override
public boolean isModified() {
for (T configurable : getConfigurables()) {
if (configurable.isModified()) {
@@ -41,6 +44,7 @@ public abstract class CompositeConfigurable<T extends UnnamedConfigurable> exten
return false;
}
+ @Override
public void disposeUIResources() {
if (myConfigurables != null) {
for (final T myConfigurable : myConfigurables) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ConfigurableBase.java b/platform/platform-impl/src/com/intellij/openapi/options/ConfigurableBase.java
deleted file mode 100644
index d7c7dca2f19b..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/options/ConfigurableBase.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2000-2014 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.
- */
-package com.intellij.openapi.options;
-
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-public abstract class ConfigurableBase<UI extends ConfigurableUi<S>, S> implements SearchableConfigurable, Configurable.NoScroll {
- private final String id;
- private final String displayName;
- private final String helpTopic;
-
- private UI ui;
-
- protected ConfigurableBase(@NotNull String id, @NotNull String displayName, @Nullable String helpTopic) {
- this.id = id;
- this.displayName = displayName;
- this.helpTopic = helpTopic;
- }
-
- @NotNull
- @Override
- public final String getId() {
- return id;
- }
-
- @Nls
- @Override
- public final String getDisplayName() {
- return displayName;
- }
-
- @Nullable
- @Override
- public final String getHelpTopic() {
- return helpTopic;
- }
-
- @Nullable
- @Override
- public Runnable enableSearch(String option) {
- return null;
- }
-
- @NotNull
- protected abstract S getSettings();
-
- @Override
- public void reset() {
- if (ui != null) {
- ui.reset(getSettings());
- }
- }
-
- @Nullable
- @Override
- public final JComponent createComponent() {
- if (ui == null) {
- ui = createUi();
- }
- return ui.getComponent();
- }
-
- protected abstract UI createUi();
-
- @Override
- public final boolean isModified() {
- return ui != null && ui.isModified(getSettings());
- }
-
- @Override
- public final void apply() {
- if (ui != null) {
- ui.apply(getSettings());
- }
- }
-
- @Override
- public void disposeUIResources() {
- ui = null;
- }
-} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ConfigurableUi.java b/platform/platform-impl/src/com/intellij/openapi/options/ConfigurableUi.java
deleted file mode 100644
index 0ecb19a7ce8e..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/options/ConfigurableUi.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2000-2014 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.
- */
-package com.intellij.openapi.options;
-
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-
-public interface ConfigurableUi<S> {
- void reset(@NotNull S settings);
-
- boolean isModified(@NotNull S settings);
-
- void apply(@NotNull S settings);
-
- @NotNull
- JComponent getComponent();
-} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java
index 323394ad7c94..449a2180e3c1 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.application.impl.ApplicationImpl;
import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.components.ServiceBean;
import com.intellij.openapi.components.SettingsSavingComponent;
+import com.intellij.openapi.components.impl.stores.IApplicationStore;
import com.intellij.openapi.components.impl.stores.StreamProvider;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.containers.ContainerUtil;
@@ -32,21 +33,22 @@ import java.util.Collections;
import java.util.List;
public class SchemesManagerFactoryImpl extends SchemesManagerFactory implements SettingsSavingComponent {
-
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.options.SchemesManagerFactoryImpl");
+ private static final Logger LOG = Logger.getInstance(SchemesManagerFactoryImpl.class);
private final List<SchemesManagerImpl> myRegisteredManagers = ContainerUtil.createLockFreeCopyOnWriteList();
@Override
- public <T extends Scheme, E extends ExternalizableScheme> SchemesManager<T, E> createSchemesManager(final String fileSpec,
- final SchemeProcessor<E> processor,
- final RoamingType roamingType) {
+ public <T extends Scheme, E extends ExternalizableScheme> SchemesManager<T, E> createSchemesManager(@NotNull String fileSpec,
+ @NotNull SchemeProcessor<E> processor,
+ @NotNull RoamingType roamingType) {
final Application application = ApplicationManager.getApplication();
- if (!(application instanceof ApplicationImpl)) return null;
- String baseDirPath = ((ApplicationImpl)application).getStateStore().getStateStorageManager().expandMacros(fileSpec);
-
+ if (!(application instanceof ApplicationImpl)) {
+ return null;
+ }
+ IApplicationStore applicationStore = ((ApplicationImpl)application).getStateStore();
+ String baseDirPath = applicationStore.getStateStorageManager().expandMacros(fileSpec);
if (baseDirPath != null) {
- StreamProvider provider = ((ApplicationImpl)ApplicationManager.getApplication()).getStateStore().getStateStorageManager().getStreamProvider();
+ StreamProvider provider = applicationStore.getStateStorageManager().getStreamProvider();
SchemesManagerImpl<T, E> manager = new SchemesManagerImpl<T, E>(fileSpec, processor, roamingType, provider, new File(baseDirPath));
myRegisteredManagers.add(manager);
return manager;
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java
index 1c7e768c7d83..4ff3ebba1ee9 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java
@@ -34,6 +34,7 @@ import com.intellij.openapi.vfs.VirtualFileAdapter;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.util.Alarm;
+import com.intellij.util.SmartList;
import com.intellij.util.UniqueFileNamesProvider;
import com.intellij.util.containers.HashSet;
import com.intellij.util.text.UniqueNameGenerator;
@@ -51,7 +52,7 @@ import java.io.IOException;
import java.util.*;
public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme> extends AbstractSchemesManager<T, E> {
- private static final Logger LOG = Logger.getInstance("#" + SchemesManagerFactoryImpl.class.getName());
+ private static final Logger LOG = Logger.getInstance(SchemesManagerFactoryImpl.class);
@NonNls private static final String DEFAULT_EXT = ".xml";
@@ -292,12 +293,13 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
}
}
+ @NotNull
private Collection<E> readSchemesFromProviders() {
- Collection<E> result = new ArrayList<E>();
if (myProvider == null || !myProvider.isEnabled()) {
- return result;
+ return Collections.emptyList();
}
+ Collection<E> result = new SmartList<E>();
for (String subPath : myProvider.listSubFiles(myFileSpec, myRoamingType)) {
if (!subPath.equals(DELETED_XML)) {
try {
@@ -305,6 +307,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
if (subDocument != null) {
E scheme = readScheme(subDocument);
boolean fileRenamed = false;
+ assert scheme != null;
T existing = findSchemeByName(scheme.getName());
if (existing != null && existing instanceof ExternalizableScheme) {
String currentFileName = ((ExternalizableScheme)existing).getExternalInfo().getCurrentFileName();
@@ -315,7 +318,6 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
}
}
String fileName = checkFileNameIsFree(subPath, scheme.getName());
-
if (!fileRenamed && !fileName.equals(subPath)) {
deleteServerFiles(subPath);
}
@@ -325,7 +327,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
}
}
catch (Exception e) {
- LOG.info("Cannot load data from IDEAServer: " + e.getLocalizedMessage());
+ LOG.info("Cannot load data from stream provider: " + e.getLocalizedMessage());
}
}
}
@@ -347,21 +349,22 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
});
}
- private String checkFileNameIsFree(final String subPath, final String schemeName) {
+ @NotNull
+ private String checkFileNameIsFree(@NotNull String subPath, @NotNull String schemeName) {
for (Scheme scheme : mySchemes) {
if (scheme instanceof ExternalizableScheme) {
- ExternalInfo externalInfo = ((ExternalizableScheme)scheme).getExternalInfo();
- String name = externalInfo.getCurrentFileName();
- if (name != null) {
- String fileName = name + mySchemeExtension;
- if (fileName.equals(subPath) && !Comparing.equal(schemeName, scheme.getName())) {
- return createUniqueFileName(collectAllFileNames(), UniqueFileNamesProvider.convertName(schemeName));
+ String name = ((ExternalizableScheme)scheme).getExternalInfo().getCurrentFileName();
+ if (name != null &&
+ !schemeName.equals(scheme.getName()) &&
+ subPath.length() == (name.length() + mySchemeExtension.length()) &&
+ subPath.startsWith(name) &&
+ subPath.endsWith(mySchemeExtension)) {
+ return UniqueNameGenerator.generateUniqueName(UniqueFileNamesProvider.convertName(schemeName), collectAllFileNames());
/*VirtualFile oldFile = myVFSBaseDir.findChild(subPath);
if (oldFile != null) {
oldFile.copy(this, myVFSBaseDir, uniqueFileName + EXT);
}
externalInfo.setCurrentFileName(uniqueFileName);*/
- }
}
}
}
@@ -369,8 +372,9 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
return subPath;
}
+ @NotNull
private Collection<String> collectAllFileNames() {
- HashSet<String> result = new HashSet<String>();
+ Set<String> result = new THashSet<String>();
for (T scheme : mySchemes) {
if (scheme instanceof ExternalizableScheme) {
ExternalInfo externalInfo = ((ExternalizableScheme)scheme).getExternalInfo();
@@ -382,10 +386,6 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
return result;
}
- private static String createUniqueFileName(final Collection<String> strings, final String schemeName) {
- return UniqueNameGenerator.generateUniqueName(schemeName, strings);
- }
-
private void loadScheme(final E scheme, boolean forceAdd, final String name) {
if (scheme != null && (!myDeletedNames.contains(scheme.getName()) || forceAdd)) {
T existing = findSchemeByName(scheme.getName());
@@ -469,13 +469,6 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
}
final E scheme = readScheme(document);
if (scheme != null) {
- if (scheme.getName() == null) {
- String suggestedName = FileUtil.getNameWithoutExtension(file.getName());
- if (!"_".equals(suggestedName)) {
- scheme.setName(suggestedName);
- }
- }
-
loadScheme(scheme, forceAdd, file.getName());
result.add(scheme);
}
@@ -653,8 +646,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
result = new SharedSchemeData(original, name, user, description);
}
else {
- Document original = subDocument;
- result = new SharedSchemeData(original, name, null, null);
+ result = new SharedSchemeData(subDocument, name, null, null);
}
return result;
}
@@ -673,8 +665,8 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
return false;
}
- private String getFileFullPath(final String subPath) {
- return myFileSpec + "/" + subPath;
+ private String getFileFullPath(@NotNull String subPath) {
+ return myFileSpec + '/' + subPath;
}
@Override
@@ -843,9 +835,9 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
deleteServerFiles(fileName);
}
- private void deleteServerFiles(final String fileName) {
+ private void deleteServerFiles(@NotNull String path) {
if (myProvider != null && myProvider.isEnabled()) {
- StorageUtil.deleteContent(myProvider, getFileFullPath(fileName), myRoamingType);
+ StorageUtil.delete(myProvider, getFileFullPath(path), myRoamingType);
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/SimpleConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/options/SimpleConfigurable.java
deleted file mode 100644
index 9812165932a2..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/options/SimpleConfigurable.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2000-2014 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.
- */
-package com.intellij.openapi.options;
-
-import com.intellij.openapi.util.Getter;
-import com.intellij.util.ReflectionUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-public final class SimpleConfigurable<UI extends ConfigurableUi<S>, S> extends ConfigurableBase<UI, S> {
- private final Class<UI> uiClass;
- private final Getter<S> settingsGetter;
-
- private SimpleConfigurable(@NotNull String id, @NotNull String displayName, @Nullable String helpTopic, @NotNull Class<UI> uiClass, @NotNull Getter<S> settingsGetter) {
- super(id, displayName, helpTopic);
-
- this.uiClass = uiClass;
- this.settingsGetter = settingsGetter;
- }
-
- public static <UI extends ConfigurableUi<S>, S> SimpleConfigurable<UI, S> create(@NotNull String id, @NotNull String displayName, @Nullable String helpTopic, @NotNull Class<UI> uiClass, @NotNull Getter<S> settingsGetter) {
- return new SimpleConfigurable<UI, S>(id, displayName, helpTopic, uiClass, settingsGetter);
- }
-
- public static <UI extends ConfigurableUi<S>, S> SimpleConfigurable<UI, S> create(@NotNull String id, @NotNull String displayName, @NotNull Class<UI> uiClass, @NotNull Getter<S> settingsGetter) {
- return create(id, displayName, id, uiClass, settingsGetter);
- }
-
- @NotNull
- @Override
- protected S getSettings() {
- return settingsGetter.get();
- }
-
- @Override
- protected UI createUi() {
- return ReflectionUtil.newInstance(uiClass);
- }
-} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
index 5f8dc0e890df..3b67a3478368 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
@@ -165,10 +165,6 @@ public class ConfigurableWrapper implements SearchableConfigurable {
return myEp;
}
- public String getGroupId() {
- return myEp.groupId;
- }
-
public String getParentId() {
return myEp.parentId;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java
index 96cc9e451185..c80a222ffd96 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 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.
@@ -17,7 +17,10 @@
package com.intellij.openapi.options.ex;
import com.intellij.ide.ui.search.SearchUtil;
+import com.intellij.openapi.ui.GraphicsConfig;
+import com.intellij.ui.ColorUtil;
import com.intellij.ui.components.JBTabbedPane;
+import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
@@ -27,6 +30,7 @@ import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.Kernel;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -64,17 +68,19 @@ public class GlassPanel extends JComponent {
final Point leftPoint = SwingUtilities.convertPoint(myPanel, new Point(visibleRect.x, visibleRect.y), surfaceComponent);
Area innerPanel = new Area(new Rectangle2D.Double(leftPoint.x, leftPoint.y, visibleRect.width, visibleRect.height));
Area mask = new Area(screen);
-
+ ArrayList<JComponent> components = new ArrayList<JComponent>();
for (JComponent lightComponent : myLightComponents) {
- final Area area = getComponentArea(surfaceComponent, lightComponent);
+ final Area area = getComponentArea(surfaceComponent, lightComponent, 1);
if (area == null) continue;
+ components.add(lightComponent);
if (lightComponent instanceof JLabel) {
final JLabel label = (JLabel)lightComponent;
final Component labelFor = label.getLabelFor();
if (labelFor instanceof JComponent) {
- final Area labelForArea = getComponentArea(surfaceComponent, (JComponent)labelFor);
+ final Area labelForArea = getComponentArea(surfaceComponent, (JComponent)labelFor, 1);
if (labelForArea != null) {
+ components.add((JComponent)labelFor);
area.add(labelForArea);
}
}
@@ -86,19 +92,32 @@ public class GlassPanel extends JComponent {
Graphics2D g2 = (Graphics2D)g;
- Color shieldColor = new Color(0.0f, 0.0f, 0.0f, 0.15f);
+ Color shieldColor = new Color(0.0f, 0.0f, 0.0f, 0.20f);
Color boundsColor = Color.gray;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(shieldColor);
g2.fill(mask);
- g2.setColor(boundsColor);
- g2.draw(mask);
+ g2.setColor(ColorUtil.toAlpha(Color.orange, 25));
+ GraphicsConfig config = GraphicsUtil.setupAAPainting(g2);
+ for (int i = 2; i > 0; i--) {
+ g2.setStroke(new BasicStroke(i));
+ Area arrr = new Area();
+ for (JComponent component : components) {
+ Area area = getComponentArea(surfaceComponent, component, i-1);
+ if (area != null) {
+ arrr.add(area);
+ }
+ }
+ g2.draw(arrr);
+ }
+
+ config.restore();
}
}
@Nullable
- private Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent) {
+ private Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent, int offset) {
if (!lightComponent.isShowing()) return null;
final Point panelPoint = SwingUtilities.convertPoint(lightComponent, new Point(0, 0), surfaceComponent);
@@ -115,12 +134,17 @@ public class GlassPanel extends JComponent {
int hInset = isWithBorder ? 7 : isLabelFromTabbedPane ? 20 : 7;
int vInset = isWithBorder ? 1 : isLabelFromTabbedPane ? 10 : 5;
- final Area area = new Area(new RoundRectangle2D.Double(x - hInset + insetsToIgnore.left,
- y - vInset + insetsToIgnore.top,
- lightComponent.getWidth() + hInset * 2 - insetsToIgnore.right - insetsToIgnore.left,
- lightComponent.getHeight() + vInset * 2 - insetsToIgnore.top - insetsToIgnore.bottom,
- 6, 6));
- return area;
+ hInset += offset;
+ vInset += offset;
+ int xCoord = x - hInset + insetsToIgnore.left;
+ int yCoord = y - vInset + insetsToIgnore.top;
+ int width = lightComponent.getWidth() + hInset * 2 - insetsToIgnore.right - insetsToIgnore.left;
+ int height = lightComponent.getHeight() + vInset * 2 - insetsToIgnore.top - insetsToIgnore.bottom;
+ return new Area(new RoundRectangle2D.Double(xCoord,
+ yCoord,
+ width,
+ height,
+ Math.min(height, 30), Math.min(height, 30)));
}
protected static Kernel getBlurKernel(int blurSize) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java
index f1411cf3551d..e3404ec017cd 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java
@@ -17,15 +17,21 @@ package com.intellij.openapi.options.ex;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurableGroup;
+import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.OptionsBundle;
import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.util.text.StringUtil;
+import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
+import javax.swing.JComponent;
-public final class MixedConfigurableGroup implements ConfigurableGroup {
+public final class MixedConfigurableGroup implements SearchableConfigurable, ConfigurableGroup {
private final String myGroupId;
private Configurable[] myConfigurables;
@@ -34,6 +40,7 @@ public final class MixedConfigurableGroup implements ConfigurableGroup {
myConfigurables = (configurables != null)
? configurables.toArray(new Configurable[configurables.size()])
: new Configurable[0];
+ Arrays.sort(myConfigurables, COMPARATOR);
}
private MixedConfigurableGroup(String groupId, HashMap<String, ArrayList<Configurable>> configurables) {
@@ -41,6 +48,45 @@ public final class MixedConfigurableGroup implements ConfigurableGroup {
}
@Override
+ public JComponent createComponent() {
+ return null;
+ }
+
+ @Override
+ public boolean isModified() {
+ return false;
+ }
+
+ @Override
+ public void apply() throws ConfigurationException {
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void disposeUIResources() {
+ myConfigurables = null;
+ }
+
+ @Override
+ public Runnable enableSearch(String option) {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public String getId() {
+ return "configurable.group." + myGroupId;
+ }
+
+ @Override
+ public String getHelpTopic() {
+ return "configurable.group." + myGroupId + ".help.topic";
+ }
+
+ @Override
public String getDisplayName() {
return OptionsBundle.message("configurable.group." + myGroupId + ".settings.display.name");
}
@@ -60,7 +106,7 @@ public final class MixedConfigurableGroup implements ConfigurableGroup {
for (Configurable configurable : configurables) {
String groupId = null;
if (configurable instanceof ConfigurableWrapper) {
- groupId = ((ConfigurableWrapper)configurable).getGroupId();
+ groupId = ((ConfigurableWrapper)configurable).getExtensionPoint().groupId;
}
ArrayList<Configurable> list = map.get(groupId);
if (list == null) {
@@ -70,7 +116,7 @@ public final class MixedConfigurableGroup implements ConfigurableGroup {
}
ArrayList<Configurable> buildList = map.get("build");
if (buildList != null) {
- NodeConfigurable buildTools = new NodeConfigurable("build.tools");
+ NodeConfigurable buildTools = new NodeConfigurable("build.tools", 1000);
buildTools.add(find("MavenSettings", buildList.iterator()));
buildTools.add(find("reference.settingsdialog.project.gradle", buildList.iterator()));
buildTools.add(find("reference.settingsdialog.project.gant", buildList.iterator()));
@@ -106,4 +152,27 @@ public final class MixedConfigurableGroup implements ConfigurableGroup {
}
return null;
}
+
+ public static int getGroupWeight(Configurable configurable) {
+ if (configurable instanceof NodeConfigurable) {
+ return ((NodeConfigurable)configurable).getGroupWeight();
+ }
+ if (configurable instanceof ConfigurableWrapper) {
+ return ((ConfigurableWrapper)configurable).getExtensionPoint().groupWeight;
+ }
+ return 0;
+ }
+
+ private static final Comparator<Configurable> COMPARATOR = new Comparator<Configurable>() {
+ @Override
+ public int compare(Configurable configurable1, Configurable configurable2) {
+ if (configurable1 == null || configurable2 == null) {
+ return configurable2 != null ? -1 : configurable1 != null ? 1 : 0;
+ }
+ int weight1 = getGroupWeight(configurable1);
+ int weight2 = getGroupWeight(configurable2);
+ return weight1 > weight2 ? -1 : weight1 < weight2 ? 1 : StringUtil.naturalCompare(configurable1.getDisplayName(),
+ configurable2.getDisplayName());
+ }
+ };
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java
index 6571c7a63746..609943d02943 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java
@@ -27,9 +27,15 @@ import java.util.ArrayList;
public final class NodeConfigurable extends SearchableConfigurable.Parent.Abstract {
private final ArrayList<Configurable> myConfigurables = new ArrayList<Configurable>();
private final String myId;
+ private final int myWeight;
- public NodeConfigurable(@NotNull String id) {
+ public NodeConfigurable(@NotNull String id, int weight) {
myId = id;
+ myWeight = weight;
+ }
+
+ public int getGroupWeight() {
+ return myWeight;
}
public void add(Configurable configurable) {
@@ -48,13 +54,13 @@ public final class NodeConfigurable extends SearchableConfigurable.Parent.Abstra
@NotNull
@Override
public String getId() {
- return myId;
+ return "node.configurable." + myId;
}
@Nullable
@Override
public String getHelpTopic() {
- return myId;
+ return "node.configurable." + myId + ".help.topic";
}
@Nls
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java
index 80144d230eaf..def0dd16a2d2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java
@@ -46,7 +46,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
private Component myParentComponent;
private Configurable myConfigurable;
private JComponent myCenterPanel;
- private String myDimensionKey;
+ private final String myDimensionKey;
private final boolean myShowApplyButton;
private boolean myChangesWereApplied;
@@ -134,6 +134,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
return displayName.replaceAll("\n", " ");
}
+ @Override
protected String getDimensionServiceKey() {
if (myDimensionKey == null) {
return super.getDimensionServiceKey();
@@ -143,6 +144,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
}
}
+ @Override
@NotNull
protected Action[] createActions() {
List<Action> actions = new ArrayList<Action>();
@@ -157,6 +159,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
return actions.toArray(new Action[actions.size()]);
}
+ @Override
protected void doHelpAction() {
HelpManager.getInstance().invokeHelp(myConfigurable.getHelpTopic());
}
@@ -169,6 +172,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
super.doCancelAction();
}
+ @Override
protected void doOKAction() {
try {
if (myConfigurable.isModified()) myConfigurable.apply();
@@ -201,10 +205,11 @@ public class SingleConfigurableEditor extends DialogWrapper {
public ApplyAction() {
super(CommonBundle.getApplyButtonText());
final Runnable updateRequest = new Runnable() {
+ @Override
public void run() {
- if (!SingleConfigurableEditor.this.isShowing()) return;
+ if (!isShowing()) return;
try {
- ApplyAction.this.setEnabled(myConfigurable != null && myConfigurable.isModified());
+ setEnabled(myConfigurable != null && myConfigurable.isModified());
}
catch (IndexNotReadyException ignored) {
}
@@ -214,6 +219,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
// invokeLater necessary to make sure dialog is already shown so we calculate modality state correctly.
SwingUtilities.invokeLater(new Runnable() {
+ @Override
public void run() {
addUpdateRequest(updateRequest);
}
@@ -224,6 +230,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
myUpdateAlarm.addRequest(updateRequest, 500, ModalityState.stateForComponent(getWindow()));
}
+ @Override
public void actionPerformed(ActionEvent event) {
if (myPerformAction) return;
try {
@@ -248,11 +255,13 @@ public class SingleConfigurableEditor extends DialogWrapper {
}
}
+ @Override
protected JComponent createCenterPanel() {
myCenterPanel = myConfigurable.createComponent();
return myCenterPanel;
}
+ @Override
public JComponent getPreferredFocusedComponent() {
if (myConfigurable instanceof BaseConfigurable) {
JComponent preferred = ((BaseConfigurable)myConfigurable).getPreferredFocusedComponent();
@@ -261,6 +270,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
return IdeFocusTraversalPolicy.getPreferredFocusedComponent(myCenterPanel);
}
+ @Override
public void dispose() {
super.dispose();
myConfigurable.disposeUIResources();
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java
new file mode 100644
index 000000000000..c38bf6ff2033
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2000-2014 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.
+ */
+package com.intellij.openapi.options.newEditor;
+
+import com.intellij.CommonBundle;
+import com.intellij.ide.ui.search.SearchUtil;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.openapi.actionSystem.DataProvider;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.help.HelpManager;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurableGroup;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.ActionCallback;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.Gray;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.JBColor;
+import com.intellij.ui.border.CustomLineBorder;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Konstantin Bulenkov
+ */
+public class IdeSettingsDialog extends DialogWrapper implements DataProvider {
+ private Project myProject;
+ private ConfigurableGroup[] myGroups;
+ private Configurable myPreselected;
+ private OptionsEditor myEditor;
+
+ private ApplyAction myApplyAction;
+ public static final String DIMENSION_KEY = "OptionsEditor";
+ @NonNls static final String LAST_SELECTED_CONFIGURABLE = "options.lastSelected";
+
+ /**
+ * This constructor should be eliminated after the new modality approach
+ * will have been checked. See a {@code Registry} key ide.perProjectModality
+ *
+ * @deprecated
+ */
+ public IdeSettingsDialog(Project project, ConfigurableGroup[] groups,
+ @Nullable Configurable preselectedConfigurable, boolean applicationModalIfPossible) {
+ super(project, true, applicationModalIfPossible);
+ init(project, groups, preselectedConfigurable != null ? preselectedConfigurable : findLastSavedConfigurable(groups, project));
+ }
+
+ /**
+ * This constructor should be eliminated after the new modality approach
+ * will have been checked. See a {@code Registry} key ide.perProjectModality
+ *
+ * @deprecated
+ */
+ public IdeSettingsDialog(Project project, ConfigurableGroup[] groups,
+ @NotNull String preselectedConfigurableDisplayName, boolean applicationModalIfPossible) {
+ super(project, true, applicationModalIfPossible);
+ init(project, groups, getPreselectedByDisplayName(groups, preselectedConfigurableDisplayName, project));
+ }
+
+ public IdeSettingsDialog(Project project, ConfigurableGroup[] groups, @Nullable Configurable preselectedConfigurable) {
+ super(project, true);
+ init(project, groups, preselectedConfigurable != null ? preselectedConfigurable : findLastSavedConfigurable(groups, project));
+ }
+
+ public IdeSettingsDialog(Project project, ConfigurableGroup[] groups, @NotNull String preselectedConfigurableDisplayName) {
+ super(project, true);
+ init(project, groups, getPreselectedByDisplayName(groups, preselectedConfigurableDisplayName, project));
+ }
+
+ @Nullable
+ @Override
+ protected Border createContentPaneBorder() {
+ return IdeBorderFactory.createEmptyBorder(0);
+ }
+
+ private void init(final Project project, final ConfigurableGroup[] groups, @Nullable final Configurable preselected) {
+ myProject = project;
+ myGroups = groups;
+ myPreselected = preselected;
+
+ setTitle(CommonBundle.settingsTitle());
+
+ init();
+ }
+
+ @Nullable
+ private static Configurable getPreselectedByDisplayName(final ConfigurableGroup[] groups, final String preselectedConfigurableDisplayName,
+ final Project project) {
+ Configurable result = findPreselectedByDisplayName(preselectedConfigurableDisplayName, groups);
+
+ return result == null ? findLastSavedConfigurable(groups, project) : result;
+ }
+
+ @Override
+ public boolean isTypeAheadEnabled() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createSouthPanel() {
+ final JComponent panel = super.createSouthPanel();
+ CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153.withAlpha(128), Gray._100.withAlpha(128)), 1, 0, 0, 0);
+ panel.setBorder(new CompoundBorder(line, new EmptyBorder(8, 12, 8, 12)));
+ return panel;
+ }
+
+ protected JComponent createCenterPanel() {
+ myEditor = new OptionsEditor(myProject, myGroups, myPreselected);
+ myEditor.getContext().addColleague(new OptionsEditorColleague.Adapter() {
+ @Override
+ public ActionCallback onModifiedAdded(final Configurable configurable) {
+ updateStatus();
+ return new ActionCallback.Done();
+ }
+
+ @Override
+ public ActionCallback onModifiedRemoved(final Configurable configurable) {
+ updateStatus();
+ return new ActionCallback.Done();
+ }
+
+ @Override
+ public ActionCallback onErrorsChanged() {
+ updateStatus();
+ return new ActionCallback.Done();
+ }
+ });
+ Disposer.register(myDisposable, myEditor);
+ return myEditor;
+ }
+
+ public boolean updateStatus() {
+ myApplyAction.setEnabled(myEditor.canApply());
+
+ final Map<Configurable, ConfigurationException> errors = myEditor.getContext().getErrors();
+ if (errors.size() == 0) {
+ setErrorText(null);
+ }
+ else {
+ String text = "Changes were not applied because of an error";
+
+ final String errorMessage = getErrorMessage(errors);
+ if (errorMessage != null) {
+ text += "<br>" + errorMessage;
+ }
+
+ setErrorText(text);
+ }
+
+ return errors.size() == 0;
+ }
+
+ @Nullable
+ private static String getErrorMessage(final Map<Configurable, ConfigurationException> errors) {
+ final Collection<ConfigurationException> values = errors.values();
+ final ConfigurationException[] exceptions = values.toArray(new ConfigurationException[values.size()]);
+ if (exceptions.length > 0) {
+ return exceptions[0].getMessage();
+ }
+ return null;
+ }
+
+ @Override
+ protected String getDimensionServiceKey() {
+ return DIMENSION_KEY;
+ }
+
+ @Override
+ protected void doOKAction() {
+ myEditor.flushModifications();
+
+ if (myEditor.canApply()) {
+ myEditor.apply();
+ if (!updateStatus()) return;
+ }
+
+ saveCurrentConfigurable();
+
+ ApplicationManager.getApplication().saveAll();
+
+ super.doOKAction();
+ }
+
+
+ private void saveCurrentConfigurable() {
+ final Configurable current = myEditor.getContext().getCurrentConfigurable();
+ if (current == null) return;
+
+ final PropertiesComponent props = PropertiesComponent.getInstance(myProject);
+
+ if (current instanceof SearchableConfigurable) {
+ props.setValue(LAST_SELECTED_CONFIGURABLE, ((SearchableConfigurable)current).getId());
+ }
+ else {
+ props.setValue(LAST_SELECTED_CONFIGURABLE, current.getClass().getName());
+ }
+ }
+
+ @Nullable
+ private static Configurable findLastSavedConfigurable(ConfigurableGroup[] groups, final Project project) {
+ final String id = PropertiesComponent.getInstance(project).getValue(LAST_SELECTED_CONFIGURABLE);
+ if (id == null) return null;
+
+ return findConfigurableInGroups(id, groups);
+ }
+
+ @Nullable
+ private static Configurable findConfigurableInGroups(String id, Configurable.Composite... groups) {
+ // avoid unnecessary group expand: check top-level configurables in all groups before looking at children
+ for (Configurable.Composite group : groups) {
+ final Configurable[] configurables = group.getConfigurables();
+ for (Configurable c : configurables) {
+ if (c instanceof SearchableConfigurable && id.equals(((SearchableConfigurable)c).getId())) {
+ return c;
+ }
+ else if (id.equals(c.getClass().getName())) {
+ return c;
+ }
+ }
+ }
+ for (Configurable.Composite group : groups) {
+ final Configurable[] configurables = group.getConfigurables();
+ for (Configurable c : configurables) {
+ if (c instanceof Configurable.Composite) {
+ Configurable result = findConfigurableInGroups(id, (Configurable.Composite)c);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static Configurable findPreselectedByDisplayName(final String preselectedConfigurableDisplayName, ConfigurableGroup[] groups) {
+ final List<Configurable> all = SearchUtil.expand(groups);
+ for (Configurable each : all) {
+ if (preselectedConfigurableDisplayName.equals(each.getDisplayName())) return each;
+ }
+ return null;
+ }
+
+ @Override
+ public void doCancelAction(final AWTEvent source) {
+ if (source instanceof KeyEvent || source instanceof ActionEvent) {
+ if (myEditor.getContext().isHoldingFilter()) {
+ myEditor.clearFilter();
+ return;
+ }
+ }
+
+ super.doCancelAction(source);
+ }
+
+ @Override
+ public void doCancelAction() {
+ saveCurrentConfigurable();
+ super.doCancelAction();
+ }
+
+ @NotNull
+ @Override
+ protected Action[] createActions() {
+ myApplyAction = new ApplyAction();
+ return new Action[]{getOKAction(), getCancelAction(), myApplyAction, getHelpAction()};
+ }
+
+ @Override
+ protected void doHelpAction() {
+ final String topic = myEditor.getHelpTopic();
+ if (topic != null) {
+ HelpManager.getInstance().invokeHelp(topic);
+ }
+ }
+
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myEditor.getPreferredFocusedComponent();
+ }
+
+ public Object getData(@NonNls String dataId) {
+ if (OptionsEditor.KEY.is(dataId)) {
+ return myEditor;
+ }
+ return null;
+ }
+
+ private class ApplyAction extends AbstractAction {
+ public ApplyAction() {
+ super(CommonBundle.getApplyButtonText());
+ setEnabled(false);
+ }
+
+ public void actionPerformed(final ActionEvent e) {
+ myEditor.apply();
+ myEditor.revalidate();
+ myEditor.repaint();
+ }
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java
index 271539f038a0..c2119596a06e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java
@@ -15,9 +15,12 @@
*/
package com.intellij.openapi.options.newEditor;
-import com.intellij.ide.ui.search.ConfigurableHit;
+import com.intellij.AbstractBundle;
+import com.intellij.CommonBundle;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.ui.laf.darcula.ui.DarculaTextBorder;
+import com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI;
import com.intellij.ide.ui.search.SearchUtil;
-import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.internal.statistic.UsageTrigger;
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
@@ -36,18 +39,18 @@ import com.intellij.openapi.ui.*;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.EdtRunnable;
+import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeGlassPaneUtil;
-import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.LightColors;
+import com.intellij.ui.OnePixelSplitter;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SearchTextField;
+import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.navigation.History;
import com.intellij.ui.navigation.Place;
-import com.intellij.ui.speedSearch.ElementFilter;
import com.intellij.ui.treeStructure.SimpleNode;
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
import com.intellij.util.ui.UIUtil;
@@ -61,7 +64,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import javax.swing.event.DocumentEvent;
+import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
@@ -77,23 +80,18 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
@NonNls private static final String MAIN_SPLITTER_PROPORTION = "options.splitter.main.proportions";
@NonNls private static final String DETAILS_SPLITTER_PROPORTION = "options.splitter.details.proportions";
- @NonNls private static final String SEARCH_VISIBLE = "options.searchVisible";
-
@NonNls private static final String NOT_A_NEW_COMPONENT = "component.was.already.instantiated";
- private final Project myProject;
-
- private final OptionsEditorContext myContext;
-
private final History myHistory = new History(this);
private final OptionsTree myTree;
private final SettingsTreeView myTreeView;
- private final MySearchField mySearch;
+ private final SearchTextField mySearch;
private final Splitter myMainSplitter;
//[back/forward] JComponent myToolbarComponent;
- private final DetailsComponent myOwnDetails = new DetailsComponent().setEmptyContentText("Select configuration element in the tree to edit its settings");
+ private final DetailsComponent myOwnDetails =
+ new DetailsComponent().setEmptyContentText("Select configuration element in the tree to edit its settings");
private final ContentWrapper myContentWrapper = new ContentWrapper();
@@ -101,30 +99,54 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
private final Map<Configurable, ActionCallback> myConfigurable2LoadCallback = new HashMap<Configurable, ActionCallback>();
private final MergingUpdateQueue myModificationChecker;
- private final ConfigurableGroup[] myGroups;
private final SpotlightPainter mySpotlightPainter = new SpotlightPainter();
private final MergingUpdateQueue mySpotlightUpdate;
private final LoadingDecorator myLoadingDecorator;
- private final Filter myFilter;
+ private final SettingsFilter myFilter;
private final Wrapper mySearchWrapper = new Wrapper();
private final JPanel myLeftSide;
- private boolean myFilterDocumentWasChanged;
//[back/forward] private ActionToolbar myToolbar;
private Window myWindow;
private final PropertiesComponent myProperties;
private volatile boolean myDisposed;
+ private final KeyListener myTreeKeyListener = new KeyListener() {
+ @Override
+ public void keyPressed(KeyEvent event) {
+ keyTyped(event);
+ }
+
+ @Override
+ public void keyReleased(KeyEvent event) {
+ keyTyped(event);
+ }
+
+ @Override
+ public void keyTyped(KeyEvent event) {
+ Object source = event.getSource();
+ if (source instanceof JTree) {
+ JTree tree = (JTree)source;
+ if (tree.getInputMap().get(KeyStroke.getKeyStrokeForEvent(event)) == null) {
+ myFilter.myDocumentWasChanged = false;
+ try {
+ mySearch.keyEventToTextField(event);
+ }
+ finally {
+ if (myFilter.myDocumentWasChanged && !isFilterFieldVisible()) {
+ setFilterFieldVisible(true, false, false);
+ }
+ }
+ }
+ }
+ }
+ };
+
public OptionsEditor(Project project, ConfigurableGroup[] groups, Configurable preselectedConfigurable) {
- myProject = project;
- myGroups = groups;
myProperties = PropertiesComponent.getInstance(project);
- myFilter = new Filter();
- myContext = new OptionsEditorContext(myFilter);
-
mySearch = new MySearchField() {
@Override
protected void onTextKeyEvent(final KeyEvent e) {
@@ -137,67 +159,53 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
}
};
- mySearch.getTextEditor().addMouseListener(new MouseAdapter() {
- @Override
- public void mousePressed(MouseEvent e) {
- boolean hasText = mySearch.getText().length() > 0;
- if (!myContext.isHoldingFilter() && hasText) {
- myFilter.reenable();
- }
-
- if (!isSearchFieldFocused() && hasText) {
- mySearch.selectText();
- }
- }
- });
-
- final KeyListener listener = new KeyListener() {
+ myFilter = new SettingsFilter(project, groups, mySearch) {
@Override
- public void keyTyped(KeyEvent event) {
- myFilterDocumentWasChanged = false;
- try {
- mySearch.keyEventToTextField(event);
- }
- finally {
- if (myFilterDocumentWasChanged && !isFilterFieldVisible()) {
- setFilterFieldVisible(true, false, false);
- }
+ Configurable getConfigurable(SimpleNode node) {
+ if (node instanceof OptionsTree.EditorNode) {
+ return ((OptionsTree.EditorNode)node).getConfigurable();
}
+ return SettingsTreeView.getConfigurable(node);
}
@Override
- public void keyPressed(KeyEvent event) {
- keyTyped(event);
+ SimpleNode findNode(Configurable configurable) {
+ return myTreeView != null
+ ? myTreeView.findNode(configurable)
+ : myTree.findNodeFor(configurable);
}
@Override
- public void keyReleased(KeyEvent event) {
- keyTyped(event);
+ void updateSpotlight(boolean now) {
+ if (!now) {
+ mySpotlightUpdate.queue(new Update(this) {
+ @Override
+ public void run() {
+ if (!mySpotlightPainter.updateForCurrentConfigurable()) {
+ updateSpotlight(false);
+ }
+ }
+ });
+ }
+ else if (!mySpotlightPainter.updateForCurrentConfigurable()) {
+ updateSpotlight(false);
+ }
}
};
- if (Registry.is("ide.file.settings.tree.new")) {
- myTreeView = new SettingsTreeView(listener, getContext(), groups);
+
+ if (Registry.is("ide.new.settings.dialog")) {
+ myTreeView = new SettingsTreeView(myFilter, groups);
+ myTreeView.myTree.addKeyListener(myTreeKeyListener);
myTree = null;
}
else {
myTreeView = null;
- myTree = new OptionsTree(myProject, groups, getContext()) {
- @Override
- protected void onTreeKeyEvent(final KeyEvent e) {
- listener.keyTyped(e);
- }
- };
+ myTree = new OptionsTree(myFilter, groups);
+ myTree.addKeyListener(myTreeKeyListener);
}
getContext().addColleague(myTreeView != null ? myTreeView : myTree);
Disposer.register(this, myTreeView != null ? myTreeView : myTree);
- mySearch.addDocumentListener(new DocumentAdapter() {
- @Override
- protected void textChanged(DocumentEvent e) {
- myFilter.update(e.getType(), true, false);
- }
- });
-
/* [back/forward]
final DefaultActionGroup toolbarActions = new DefaultActionGroup();
@@ -246,7 +254,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
setLayout(new BorderLayout());
- myMainSplitter = new Splitter(false);
+ myMainSplitter = Registry.is("ide.new.settings.dialog") ? new OnePixelSplitter(false) : new Splitter(false);
myMainSplitter.setFirstComponent(myLeftSide);
myLoadingDecorator = new LoadingDecorator(myOwnDetails.getComponent(), this, 150);
@@ -264,13 +272,9 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
mySpotlightUpdate = new MergingUpdateQueue("OptionsSpotlight", 200, false, this, this, this);
if (preselectedConfigurable != null) {
- if (myTreeView != null) {
- myTreeView.select(preselectedConfigurable);
- }
- else {
- myTree.select(preselectedConfigurable);
- }
- } else {
+ selectInTree(preselectedConfigurable);
+ }
+ else {
if (myTreeView != null) {
myTreeView.selectFirst();
}
@@ -322,6 +326,12 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
});
}
+ private ActionCallback selectInTree(Configurable configurable) {
+ return myTreeView != null
+ ? myTreeView.select(configurable)
+ : myTree.select(configurable);
+ }
+
/** @see #select(com.intellij.openapi.options.Configurable) */
@Deprecated
public ActionCallback select(Class<? extends Configurable> configurableClass) {
@@ -354,18 +364,17 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
}
public ActionCallback select(Configurable configurable) {
- if (StringUtil.isEmpty(mySearch.getText())) {
+ if (myFilter.getFilterText().isEmpty()) {
return select(configurable, "");
- } else {
- return myFilter.refilterFor(mySearch.getText(), true, true);
+ }
+ else {
+ return myFilter.update(true, true);
}
}
public ActionCallback select(Configurable configurable, final String text) {
- myFilter.refilterFor(text, false, true);
- return myTreeView != null
- ? myTreeView.select(configurable)
- : myTree.select(configurable);
+ myFilter.update(text, false, true);
+ return selectInTree(configurable);
}
private float readProportion(final float defaultValue, final String propertyName) {
@@ -390,7 +399,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
if (configurable == null) {
myOwnDetails.setContent(null);
- updateSpotlight(true);
+ myFilter.updateSpotlight(true);
checkModified(oldConfigurable);
result.setDone();
@@ -417,7 +426,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
if (myTreeView != null) {
myOwnDetails.forProject(myTreeView.findConfigurableProject(configurable));
}
- else if (Registry.is("ide.file.settings.order.new")) {
+ else if (Registry.is("ide.new.settings.dialog")) {
myOwnDetails.forProject(myTree.getConfigurableProject(configurable));
}
@@ -430,7 +439,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
myLoadingDecorator.stopLoading();
- updateSpotlight(false);
+ myFilter.updateSpotlight(false);
checkModified(oldConfigurable);
checkModified(configurable);
@@ -480,7 +489,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
((ApplicationEx)app).runEdtSafeAction(new Runnable() {
@Override
public void run() {
- if (myProject.isDisposed()) {
+ if (myFilter.myProject.isDisposed()) {
result.setRejected();
}
else {
@@ -537,26 +546,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
return result;
}
-
- private void updateSpotlight(boolean now) {
- if (now) {
- final boolean success = mySpotlightPainter.updateForCurrentConfigurable();
- if (!success) {
- updateSpotlight(false);
- }
- } else {
- mySpotlightUpdate.queue(new Update(this) {
- @Override
- public void run() {
- final boolean success = mySpotlightPainter.updateForCurrentConfigurable();
- if (!success) {
- updateSpotlight(false);
- }
- }
- });
- }
- }
-
private String[] getBannerText(Configurable configurable) {
if (myTreeView != null) {
return myTreeView.getPathNames(configurable);
@@ -712,7 +701,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
@Override
public boolean isEnabled() {
- return myContext.isModified(myConfigurable) || getContext().getErrors().containsKey(myConfigurable);
+ return myFilter.myContext.isModified(myConfigurable) || getContext().getErrors().containsKey(myConfigurable);
}
}
@@ -849,12 +838,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
getContext().fireErrorsChanged(errors, null);
if (!errors.isEmpty()) {
- if (myTreeView != null) {
- myTreeView.select(errors.keySet().iterator().next());
- }
- else {
- myTree.select(errors.keySet().iterator().next());
- }
+ selectInTree(errors.keySet().iterator().next());
}
}
@@ -868,7 +852,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
}
public JComponent getPreferredFocusedComponent() {
- return mySearch;//myTree.getTree();
+ return myTreeView != null ? myTreeView.myTree : mySearch;//myTree.getTree();
}
@Override
@@ -876,145 +860,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
return new Dimension(1200, 768);
}
- private class Filter extends ElementFilter.Active.Impl<SimpleNode> {
-
- SearchableOptionsRegistrar myIndex = SearchableOptionsRegistrar.getInstance();
- Set<Configurable> myFiltered = null;
- ConfigurableHit myHits;
-
- boolean myUpdateEnabled = true;
- private Configurable myLastSelected;
-
- @Override
- public boolean shouldBeShowing(final SimpleNode value) {
- if (myFiltered == null) return true;
-
- if (value instanceof OptionsTree.EditorNode) {
- final OptionsTree.EditorNode node = (OptionsTree.EditorNode)value;
- return myFiltered.contains(node.getConfigurable()) || isChildOfNameHit(node);
- }
-
- return SettingsTreeView.isFiltered(myFiltered, myHits, value);
- }
-
- private boolean isChildOfNameHit(OptionsTree.EditorNode node) {
- if (myHits != null) {
- OptionsTree.Base eachParent = node;
- while (eachParent != null) {
- if (eachParent instanceof OptionsTree.EditorNode) {
- final OptionsTree.EditorNode eachEditorNode = (OptionsTree.EditorNode)eachParent;
- if (myHits.getNameFullHits().contains(eachEditorNode.myConfigurable)) return true;
- }
- eachParent = (OptionsTree.Base)eachParent.getParent();
- }
-
- return false;
- }
-
- return false;
- }
-
- public ActionCallback refilterFor(String text, boolean adjustSelection, final boolean now) {
- try {
- myUpdateEnabled = false;
- mySearch.setText(text);
- }
- finally {
- myUpdateEnabled = true;
- }
-
- return update(DocumentEvent.EventType.CHANGE, adjustSelection, now);
- }
-
- public void clearTemporary() {
- myContext.setHoldingFilter(false);
- updateSpotlight(false);
- }
-
- public void reenable() {
- myContext.setHoldingFilter(true);
- updateSpotlight(false);
- }
-
- public ActionCallback update(DocumentEvent.EventType type, boolean adjustSelection, boolean now) {
- if (!myUpdateEnabled) return new ActionCallback.Rejected();
-
- final String text = mySearch.getText();
- if (getFilterText().length() == 0) {
- myContext.setHoldingFilter(false);
- myFiltered = null;
- } else {
- myContext.setHoldingFilter(true);
- myHits = myIndex.getConfigurables(myGroups, type, myFiltered, text, myProject);
- myFiltered = myHits.getAll();
- }
-
- if (myFiltered != null && myFiltered.isEmpty()) {
- mySearch.getTextEditor().setBackground(LightColors.RED);
- } else {
- mySearch.getTextEditor().setBackground(UIUtil.getTextFieldBackground());
- }
-
-
- final Configurable current = getContext().getCurrentConfigurable();
-
- boolean shouldMoveSelection = true;
-
- if (myHits != null && (myHits.getNameFullHits().contains(current) || myHits.getContentHits().contains(current))) {
- shouldMoveSelection = false;
- }
-
- if (shouldMoveSelection && type != DocumentEvent.EventType.INSERT && (myFiltered == null || myFiltered.contains(current))) {
- shouldMoveSelection = false;
- }
-
- Configurable toSelect = adjustSelection ? current : null;
- if (shouldMoveSelection && myHits != null) {
- if (!myHits.getNameHits().isEmpty()) {
- toSelect = suggestToSelect(myHits.getNameHits(), myHits.getNameFullHits());
- } else if (!myHits.getContentHits().isEmpty()) {
- toSelect = suggestToSelect(myHits.getContentHits(), null);
- }
- }
-
- updateSpotlight(false);
-
- if ((myFiltered == null || !myFiltered.isEmpty()) && toSelect == null && myLastSelected != null) {
- toSelect = myLastSelected;
- myLastSelected = null;
- }
-
- if (toSelect == null && current != null) {
- myLastSelected = current;
- }
-
- SimpleNode node = !adjustSelection ? null : myTreeView != null ? myTreeView.findNode(toSelect) : myTree.findNodeFor(toSelect);
- final ActionCallback callback = fireUpdate(node, adjustSelection, now);
-
- myFilterDocumentWasChanged = true;
-
- return callback;
- }
-
- private boolean isEmptyParent(Configurable configurable) {
- return configurable instanceof SearchableConfigurable.Parent && !((SearchableConfigurable.Parent)configurable).hasOwnContent();
- }
-
- @Nullable
- private Configurable suggestToSelect(Set<Configurable> set, Set<Configurable> fullHits) {
- Configurable candidate = null;
- for (Configurable each : set) {
- if (fullHits != null && fullHits.contains(each)) return each;
- if (!isEmptyParent(each) && candidate == null) {
- candidate = each;
- }
- }
-
- return candidate;
- }
-
- }
-
@Override
public ActionCallback navigateTo(@Nullable final Place place, final boolean requestFocus) {
final Configurable config = (Configurable)place.getPath("configurable");
@@ -1022,15 +867,10 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
final ActionCallback result = new ActionCallback();
- myFilter.refilterFor(filter, false, true).doWhenDone(new Runnable() {
+ myFilter.update(filter, false, true).doWhenDone(new Runnable() {
@Override
public void run() {
- if (myTreeView != null) {
- myTreeView.select(config).notifyWhenDone(result);
- }
- else {
- myTree.select(config).notifyWhenDone(result);
- }
+ selectInTree(config).notifyWhenDone(result);
}
});
@@ -1041,7 +881,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
public void queryPlace(@NotNull final Place place) {
final Configurable current = getContext().getCurrentConfigurable();
place.putPath("configurable", current);
- place.putPath("filter", getFilterText());
+ place.putPath("filter", myFilter.getFilterText());
if (current instanceof Place.Navigator) {
((Place.Navigator)current).queryPlace(place);
@@ -1060,7 +900,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
myProperties.setValue(MAIN_SPLITTER_PROPORTION, String.valueOf(myMainSplitter.getProportion()));
myProperties.setValue(DETAILS_SPLITTER_PROPORTION, String.valueOf(myContentWrapper.myLastSplitterProportion));
- myProperties.setValue(SEARCH_VISIBLE, Boolean.valueOf(isFilterFieldVisible()).toString());
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
@@ -1087,7 +926,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
}
public OptionsEditorContext getContext() {
- return myContext;
+ return myFilter.myContext;
}
private class MyColleague extends OptionsEditorColleague.Adapter {
@@ -1137,7 +976,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
final MouseEvent me = (MouseEvent)event;
if (SwingUtilities.isDescendingFrom(me.getComponent(), SwingUtilities.getWindowAncestor(myContentWrapper)) || isPopupOverEditor(me.getComponent())) {
queueModificationCheck();
- myFilter.clearTemporary();
+ myFilter.setHoldingFilter(false);
}
}
else if (event.getID() == KeyEvent.KEY_PRESSED || event.getID() == KeyEvent.KEY_RELEASED) {
@@ -1175,6 +1014,23 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
private MySearchField() {
super(false);
addKeyListener(new KeyAdapter() {});
+ if (Registry.is("ide.new.settings.dialog")) {
+ final JTextField editor = getTextEditor();
+ if (!SystemInfo.isMac) {
+ editor.putClientProperty("JTextField.variant", "search");
+ if (!(editor.getUI() instanceof DarculaTextFieldUI)) {
+ editor.setUI((DarculaTextFieldUI)DarculaTextFieldUI.createUI(editor));
+ editor.setBorder(new DarculaTextBorder());
+ }
+ }
+ setBackground(UIUtil.getSidePanelColor());
+ setBorder(new EmptyBorder(5, 10, 2, 10));
+ }
+ }
+
+ @Override
+ protected boolean isSearchControlUISupported() {
+ return true;
}
@Override
@@ -1236,7 +1092,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
return ApplicationManager.getApplication().isUnitTestMode();
}
- String text = getFilterText();
+ String text = myFilter.getFilterText();
try {
final boolean sameText =
@@ -1263,14 +1119,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
myVisible = true;//myContext.isHoldingFilter();
runnable.run();
- boolean pushFilteringFurther = true;
- if (sameText) {
- pushFilteringFurther = false;
- } else {
- if (myFilter.myHits != null) {
- pushFilteringFurther = !myFilter.myHits.getNameHits().contains(current);
- }
- }
+ boolean pushFilteringFurther = !sameText && !myFilter.contains(current);
final Runnable ownSearch = searchable.enableSearch(text);
if (pushFilteringFurther && ownSearch != null) {
@@ -1295,10 +1144,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
}
}
- private String getFilterText() {
- return mySearch.getText() != null ? mySearch.getText().trim() : "";
- }
-
private static class SearachableWrappper implements SearchableConfigurable {
private final Configurable myConfigurable;
@@ -1366,6 +1211,49 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
abstract void setText(final String[] bannerText);
}
+ /**
+ * Returns default view for the specified configurable.
+ * It uses the configurable identifier to retrieve description.
+ *
+ * @param searchable the configurable that does not have any view
+ * @return default view for the specified configurable
+ */
+ private JComponent createDefaultComponent(SearchableConfigurable searchable) {
+ JPanel box = new JPanel();
+ box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
+ try {
+ box.add(new JLabel(getDefaultDescription(searchable)));
+ }
+ catch (AssertionError error) {
+ return null; // description is not set
+ }
+ if (searchable instanceof Configurable.Composite) {
+ box.add(Box.createVerticalStrut(10));
+ Configurable.Composite composite = (Configurable.Composite)searchable;
+ for (final Configurable configurable : composite.getConfigurables()) {
+ box.add(new LinkLabel(configurable.getDisplayName(), AllIcons.Ide.Link) {
+ @Override
+ public void doClick() {
+ select(configurable, null);
+ }
+ });
+ }
+ }
+ return box;
+ }
+
+ @NotNull
+ private static String getDefaultDescription(SearchableConfigurable configurable) {
+ String key = configurable.getId() + ".settings.description";
+ if (configurable instanceof ConfigurableWrapper) {
+ ConfigurableWrapper wrapper = (ConfigurableWrapper) configurable;
+ ConfigurableEP ep = wrapper.getExtensionPoint();
+ ResourceBundle resourceBundle = AbstractBundle.getResourceBundle(ep.bundle, ep.getPluginDescriptor().getPluginClassLoader());
+ return CommonBundle.message(resourceBundle, key);
+ }
+ return OptionsBundle.message(key);
+ }
+
private class Simple extends ConfigurableContent {
JComponent myComponent;
Configurable myConfigurable;
@@ -1373,7 +1261,9 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
Simple(final Configurable configurable) {
myConfigurable = configurable;
myComponent = configurable.createComponent();
-
+ if (myComponent == null && configurable instanceof SearchableConfigurable) {
+ myComponent = createDefaultComponent((SearchableConfigurable)configurable);
+ }
if (myComponent != null) {
final Object clientProperty = myComponent.getClientProperty(NOT_A_NEW_COMPONENT);
if (clientProperty != null && ApplicationManager.getApplication().isInternal()) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java
index 175b994122ef..aee9e889fdf1 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java
@@ -37,6 +37,7 @@ import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
+import com.intellij.util.ui.tree.WideSelectionTreeUI;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.NotNull;
@@ -49,33 +50,32 @@ import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.TreeUI;
-import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
-import java.awt.event.*;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
public class OptionsTree extends JPanel implements Disposable, OptionsEditorColleague {
- Project myProject;
+ private final SettingsFilter myFilter;
final SimpleTree myTree;
List<ConfigurableGroup> myGroups;
FilteringTreeBuilder myBuilder;
Root myRoot;
- OptionsEditorContext myContext;
Map<Configurable, EditorNode> myConfigurable2Node = new HashMap<Configurable, EditorNode>();
MergingUpdateQueue mySelection;
private final OptionsTree.Renderer myRenderer;
- public OptionsTree(Project project, ConfigurableGroup[] groups, OptionsEditorContext context) {
- myProject = project;
+ public OptionsTree(SettingsFilter filter, ConfigurableGroup... groups) {
+ myFilter = filter;
myGroups = Arrays.asList(groups);
- myContext = context;
-
myRoot = new Root();
final SimpleTreeStructure structure = new SimpleTreeStructure() {
@@ -132,35 +132,8 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
}
}
});
- myTree.addKeyListener(new KeyListener() {
- public void keyTyped(final KeyEvent e) {
- _onTreeKeyEvent(e);
- }
-
- public void keyPressed(final KeyEvent e) {
- _onTreeKeyEvent(e);
- }
-
- public void keyReleased(final KeyEvent e) {
- _onTreeKeyEvent(e);
- }
- });
- }
-
- protected void _onTreeKeyEvent(KeyEvent e) {
- final KeyStroke stroke = KeyStroke.getKeyStrokeForEvent(e);
-
- final Object action = myTree.getInputMap().get(stroke);
- if (action == null) {
- onTreeKeyEvent(e);
- }
- }
-
- protected void onTreeKeyEvent(KeyEvent e) {
-
}
-
ActionCallback select(@Nullable Configurable configurable) {
return queueSelection(configurable);
}
@@ -191,7 +164,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
if (configurable == null) {
myTree.getSelectionModel().clearSelection();
- myContext.fireSelected(null, OptionsTree.this);
+ myFilter.myContext.fireSelected(null, OptionsTree.this);
}
else {
myBuilder.getReady(this).doWhenDone(new Runnable() {
@@ -232,7 +205,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
}
private void fireSelected(Configurable configurable, final ActionCallback callback) {
- myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
+ myFilter.myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
}
@@ -297,7 +270,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
myRendererComponent.setOpaqueActive(false);
mySeparator = new GroupSeparator();
- myRendererComponent.add(Registry.is("ide.file.settings.order.new") ? mySeparator : mySeparatorComponent, BorderLayout.NORTH);
+ myRendererComponent.add(Registry.is("ide.new.settings.dialog") ? mySeparator : mySeparatorComponent, BorderLayout.NORTH);
final NonOpaquePanel content = new NonOpaquePanel(new BorderLayout());
myHandle = new JLabel("", SwingConstants.CENTER);
@@ -401,12 +374,12 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
myTextLabel.setForeground(selected ? UIUtil.getTreeSelectionForeground() : fg);
myTextLabel.setOpaque(selected);
- if (Registry.is("ide.file.settings.order.new")) {
+ if (Registry.is("ide.new.settings.dialog")) {
myTextLabel.setBorder(new EmptyBorder(1,2,1,0));
}
Project project = null;
- if (base != null && Registry.is("ide.file.settings.order.new")) {
+ if (base != null && Registry.is("ide.new.settings.dialog")) {
SimpleNode parent = base.getParent();
if (parent == myRoot) {
project = getConfigurableProject(base); // show icon for top-level nodes
@@ -433,6 +406,9 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
} else {
myProjectIcon.setVisible(false);
}
+ if (Registry.is("ide.new.settings.dialog")) {
+ result.setBackground(selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getSidePanelColor());
+ }
return result;
}
@@ -538,7 +514,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
final List<EditorNode> result = new ArrayList<EditorNode>(kids.length);
for (Configurable child : kids) {
result.add(new EditorNode(parent, child, group));
- myContext.registerKid(configurable, child);
+ myFilter.myContext.registerKid(configurable, child);
}
return result; // TODO: DECIDE IF INNERS SHOULD BE SORTED: sort(result);
}
@@ -602,12 +578,12 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
@Override
boolean isModified() {
- return myContext.getModified().contains(myConfigurable);
+ return myFilter.myContext.getModified().contains(myConfigurable);
}
@Override
boolean isError() {
- return myContext.getErrors().containsKey(myConfigurable);
+ return myFilter.myContext.getErrors().containsKey(myConfigurable);
}
}
@@ -757,7 +733,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
super.processMouseEvent(e);
}
- private class MyTreeUi extends BasicTreeUI {
+ private class MyTreeUi extends WideSelectionTreeUI {
@Override
public void toggleExpandState(final TreePath path) {
@@ -810,7 +786,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
boolean myWasHoldingFilter;
public MyBuilder(SimpleTreeStructure structure) {
- super(OptionsTree.this.myTree, myContext.getFilter(), structure, new WeightBasedComparator(false));
+ super(myTree, myFilter, structure, new WeightBasedComparator(false));
myTree.addTreeExpansionListener(new TreeExpansionListener() {
public void treeExpanded(TreeExpansionEvent event) {
invalidateExpansions();
@@ -835,7 +811,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
@Override
public boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor) {
- return myContext.isHoldingFilter();
+ return myFilter.myContext.isHoldingFilter();
}
@Override
@@ -846,21 +822,21 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
@Override
protected ActionCallback refilterNow(Object preferredSelection, boolean adjustSelection) {
final List<Object> toRestore = new ArrayList<Object>();
- if (myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
+ if (myFilter.myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
myToExpandOnResetFilter = myBuilder.getUi().getExpandedElements();
- } else if (!myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
+ } else if (!myFilter.myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
toRestore.addAll(myToExpandOnResetFilter);
myToExpandOnResetFilter = null;
}
- myWasHoldingFilter = myContext.isHoldingFilter();
+ myWasHoldingFilter = myFilter.myContext.isHoldingFilter();
ActionCallback result = super.refilterNow(preferredSelection, adjustSelection);
myRefilteringNow = true;
return result.doWhenDone(new Runnable() {
public void run() {
myRefilteringNow = false;
- if (!myContext.isHoldingFilter() && getSelectedElements().isEmpty()) {
+ if (!myFilter.myContext.isHoldingFilter() && getSelectedElements().isEmpty()) {
restoreExpandedState(toRestore);
}
}
@@ -968,7 +944,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
public void paint(Graphics g) {
super.paint(g);
- if (Registry.is("ide.file.settings.order.new")) {
+ if (Registry.is("ide.new.settings.dialog")) {
ConfigurableGroup group = getGroup(GroupSeparator.SPACE + mySeparator.getFont().getSize());
if (group != null && group == getGroup(-GroupSeparator.SPACE)) {
mySeparator.configure(group, false);
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.form b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.form
deleted file mode 100644
index bfd8e1f0e416..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.form
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.options.newEditor.PreferencesDialog">
- <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
- <margin top="0" left="0" bottom="0" right="0"/>
- <constraints>
- <xy x="20" y="20" width="500" height="400"/>
- </constraints>
- <properties/>
- <border type="none"/>
- <children>
- <grid id="81fb6" binding="myTopPanel" custom-create="true" layout-manager="BorderLayout" hgap="0" vgap="0">
- <constraints>
- <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
- <preferred-size width="-1" height="50"/>
- </grid>
- </constraints>
- <properties/>
- <border type="none"/>
- <children/>
- </grid>
- <vspacer id="420b1">
- <constraints>
- <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
- </constraints>
- </vspacer>
- <grid id="b87b5" binding="myCenterPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
- <constraints>
- <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties/>
- <border type="none"/>
- <children/>
- </grid>
- <hspacer id="e2eff">
- <constraints>
- <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
- </constraints>
- </hspacer>
- </children>
- </grid>
-</form>
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.java
deleted file mode 100644
index 8ed3527e090a..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/PreferencesDialog.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2000-2013 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.
- */
-package com.intellij.openapi.options.newEditor;
-
-import com.intellij.icons.AllIcons;
-import com.intellij.openapi.options.ConfigurableGroup;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.openapi.util.SystemInfo;
-import com.intellij.ui.Gray;
-import com.intellij.ui.SearchTextField;
-import com.intellij.ui.border.CustomLineBorder;
-import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import javax.swing.border.LineBorder;
-import java.awt.*;
-
-/**
- * @author Konstantin Bulenkov
- */
-public class PreferencesDialog extends DialogWrapper {
- private JPanel myRoot;
- private JPanel myTopPanel;
- private JPanel myCenterPanel;
- private SearchTextField mySearchTextField;
-
- public PreferencesDialog(@Nullable Project project, ConfigurableGroup[] groups) {
- super(project);
- init();
- ((JDialog)getPeer().getWindow()).setUndecorated(true);
- if (SystemInfo.isMac) {
- ((JComponent)((JDialog)getPeer().getWindow()).getContentPane()).setBorder(new EmptyBorder(0, 0, 0, 0));
- }
- else {
- ((JComponent)((JDialog)getPeer().getWindow()).getContentPane()).setBorder(new LineBorder(Gray._140, 1));
- }
-
- setTitle("Preferences");
- }
-
- @Nullable
- @Override
- protected JComponent createCenterPanel() {
- final JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
- panel.setBorder(null);
- panel.add(createApplicationSettings());
- panel.add(createProjectSettings());
- panel.add(createEditorSettings());
- panel.add(createOtherSettings());
- panel.setPreferredSize(new Dimension(700, 370));
- myCenterPanel.add(panel, BorderLayout.CENTER);
- return myRoot;
- }
-
- @Nullable
- @Override
- public JComponent getPreferredFocusedComponent() {
- return mySearchTextField.getTextEditor();
- }
-
- private static JComponent createEditorSettings() {
- final LabeledButtonsPanel panel = new LabeledButtonsPanel("Editor");
- panel.addButton(new PreferenceButton("Editor", AllIcons.Preferences.Editor));
- panel.addButton(new PreferenceButton("Code Style", AllIcons.Preferences.CodeStyle));
- panel.setBackground(Gray._229);
- panel.setBorder(new CustomLineBorder(Gray._223, 0, 0, 1, 0));
- return panel;
- }
-
- private static JComponent createProjectSettings() {
- final LabeledButtonsPanel panel = new LabeledButtonsPanel("Project");
- panel.addButton(new PreferenceButton("Compiler", AllIcons.Preferences.Compiler));
- panel.addButton(new PreferenceButton("Version Control", AllIcons.Preferences.VersionControl));
- panel.addButton(new PreferenceButton("File Colors", AllIcons.Preferences.FileColors));
- panel.addButton(new PreferenceButton("Scopes", AllIcons.Preferences.Editor));
- panel.setBackground(Gray._236);
- panel.setBorder(new CustomLineBorder(Gray._223, 0, 0, 1, 0));
- return panel;
- }
-
- private static JComponent createApplicationSettings() {
- final LabeledButtonsPanel panel = new LabeledButtonsPanel("IDE");
- panel.addButton(new PreferenceButton("Appearance", AllIcons.Preferences.Appearance));
- panel.addButton(new PreferenceButton("General", AllIcons.Preferences.General));
- panel.addButton(new PreferenceButton("Keymap", AllIcons.Preferences.Keymap));
- panel.addButton(new PreferenceButton("File Types", AllIcons.Preferences.FileTypes));
- panel.setBackground(Gray._229);
- panel.setBorder(new CustomLineBorder(Gray._223, 0, 0, 1, 0));
- return panel;
- }
-
- private static JComponent createOtherSettings() {
- final LabeledButtonsPanel panel = new LabeledButtonsPanel("Other");
- panel.addButton(new PreferenceButton("Plugins", AllIcons.Preferences.Plugins));
- panel.addButton(new PreferenceButton("Updates", AllIcons.Preferences.Updates));
- panel.setBackground(Gray._236);
- panel.setBorder(new CustomLineBorder(Gray._223, 0, 0, 1, 0));
- return panel;
- }
-
-
- @Nullable
- @Override
- protected JComponent createSouthPanel() {
- if (SystemInfo.isMac) {
- return null;
- }
- final JComponent panel = super.createSouthPanel();
- if (panel != null) {
- panel.setBorder(new EmptyBorder(5, 5, 10, 20));
- }
- return panel;
- }
-
- private void createUIComponents() {
- myTopPanel = new JPanel(new BorderLayout()) {
- @Override
- protected void paintComponent(Graphics g) {
- ((Graphics2D)g).setPaint(new GradientPaint(0, 0, Gray._206, 0, getHeight() - 1, Gray._172));
- g.fillRect(0, 0, getWidth(), getHeight());
- g.setColor(Gray._145);
- g.drawLine(0, getHeight() - 2, getWidth(), getHeight() - 2);
- g.setColor(Gray._103);
- g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1);
- }
- };
- final JLabel title = new JLabel("Preferences");
- if (!SystemInfo.isMac) {
- title.setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD, 14));
- }
- else {
- title.setFont(new Font("Lucuda Grande", Font.PLAIN, 12));
- }
- title.setHorizontalTextPosition(SwingConstants.CENTER);
- title.setHorizontalAlignment(SwingConstants.CENTER);
- title.setVerticalAlignment(SwingConstants.TOP);
- myTopPanel.add(title, BorderLayout.NORTH);
- mySearchTextField = new SearchTextField();
- mySearchTextField.setOpaque(false);
- myTopPanel.add(mySearchTextField, BorderLayout.EAST);
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java
new file mode 100644
index 000000000000..1885a852c5da
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2000-2014 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.
+ */
+package com.intellij.openapi.options.newEditor;
+
+import com.intellij.ide.ui.search.ConfigurableHit;
+import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurableGroup;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.ActionCallback;
+import com.intellij.ui.DocumentAdapter;
+import com.intellij.ui.LightColors;
+import com.intellij.ui.SearchTextField;
+import com.intellij.ui.speedSearch.ElementFilter;
+import com.intellij.ui.treeStructure.SimpleNode;
+import com.intellij.util.ui.UIUtil;
+
+import javax.swing.event.DocumentEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Set;
+
+abstract class SettingsFilter extends ElementFilter.Active.Impl<SimpleNode> {
+ final OptionsEditorContext myContext = new OptionsEditorContext(this);
+ final Project myProject;
+
+ boolean myDocumentWasChanged;
+
+ private final SearchTextField mySearch;
+ private final ConfigurableGroup[] myGroups;
+
+ private SearchableOptionsRegistrar myRegistrar = SearchableOptionsRegistrar.getInstance();
+ private Set<Configurable> myFiltered;
+ private ConfigurableHit myHits;
+
+ private boolean myUpdateRejected;
+ private Configurable myLastSelected;
+
+ SettingsFilter(Project project, ConfigurableGroup[] groups, SearchTextField search) {
+ myProject = project;
+ myGroups = groups;
+ mySearch = search;
+ mySearch.addDocumentListener(new DocumentAdapter() {
+ @Override
+ protected void textChanged(DocumentEvent event) {
+ update(event.getType(), true, false);
+ }
+ });
+ mySearch.getTextEditor().addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent event) {
+ if (!mySearch.getText().isEmpty()) {
+ if (!myContext.isHoldingFilter()) {
+ setHoldingFilter(true);
+ }
+ if (!mySearch.getTextEditor().isFocusOwner()) {
+ mySearch.selectText();
+ }
+ }
+ }
+ });
+ }
+
+ abstract Configurable getConfigurable(SimpleNode node);
+
+ abstract SimpleNode findNode(Configurable configurable);
+
+ abstract void updateSpotlight(boolean now);
+
+ @Override
+ public boolean shouldBeShowing(SimpleNode node) {
+ if (myFiltered != null) {
+ Configurable configurable = getConfigurable(node);
+ if (configurable != null) {
+ if (!myFiltered.contains(configurable)) {
+ if (myHits != null) {
+ Set<Configurable> configurables = myHits.getNameFullHits();
+ while (node != null) {
+ if (configurable != null) {
+ if (configurables.contains(configurable)) {
+ return true;
+ }
+ }
+ node = node.getParent();
+ configurable = getConfigurable(node);
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ String getFilterText() {
+ String text = mySearch.getText();
+ return text == null ? "" : text.trim();
+ }
+
+ void setHoldingFilter(boolean holding) {
+ myContext.setHoldingFilter(holding);
+ updateSpotlight(false);
+ }
+
+ boolean contains(Configurable configurable) {
+ return myHits != null && myHits.getNameHits().contains(configurable);
+ }
+
+ ActionCallback update(boolean adjustSelection, boolean now) {
+ return update(DocumentEvent.EventType.CHANGE, adjustSelection, now);
+ }
+
+ ActionCallback update(String text, boolean adjustSelection, boolean now) {
+ try {
+ myUpdateRejected = true;
+ mySearch.setText(text);
+ }
+ finally {
+ myUpdateRejected = false;
+ }
+ return update(adjustSelection, now);
+ }
+
+ private ActionCallback update(DocumentEvent.EventType type, boolean adjustSelection, boolean now) {
+ if (myUpdateRejected) {
+ return new ActionCallback.Rejected();
+ }
+ String text = getFilterText();
+ if (text.isEmpty()) {
+ myContext.setHoldingFilter(false);
+ myFiltered = null;
+ }
+ else {
+ myContext.setHoldingFilter(true);
+ myHits = myRegistrar.getConfigurables(myGroups, type, myFiltered, text, myProject);
+ myFiltered = myHits.getAll();
+ }
+ mySearch.getTextEditor().setBackground(myFiltered != null && myFiltered.isEmpty()
+ ? LightColors.RED
+ : UIUtil.getTextFieldBackground());
+
+
+ Configurable current = myContext.getCurrentConfigurable();
+
+ boolean shouldMoveSelection = myHits == null || (
+ !myHits.getNameFullHits().contains(current) &&
+ !myHits.getContentHits().contains(current));
+
+ if (shouldMoveSelection && type != DocumentEvent.EventType.INSERT && (myFiltered == null || myFiltered.contains(current))) {
+ shouldMoveSelection = false;
+ }
+
+ Configurable candidate = adjustSelection ? current : null;
+ if (shouldMoveSelection && myHits != null) {
+ if (!myHits.getNameHits().isEmpty()) {
+ candidate = findConfigurable(myHits.getNameHits(), myHits.getNameFullHits());
+ }
+ else if (!myHits.getContentHits().isEmpty()) {
+ candidate = findConfigurable(myHits.getContentHits(), null);
+ }
+ }
+ updateSpotlight(false);
+
+ if ((myFiltered == null || !myFiltered.isEmpty()) && candidate == null && myLastSelected != null) {
+ candidate = myLastSelected;
+ myLastSelected = null;
+ }
+ if (candidate == null && current != null) {
+ myLastSelected = current;
+ }
+ SimpleNode node = !adjustSelection ? null : findNode(candidate);
+ ActionCallback callback = fireUpdate(node, adjustSelection, now);
+ myDocumentWasChanged = true;
+ return callback;
+ }
+
+ private static Configurable findConfigurable(Set<Configurable> configurables, Set<Configurable> hits) {
+ Configurable candidate = null;
+ for (Configurable configurable : configurables) {
+ if (hits != null && hits.contains(configurable)) {
+ return configurable;
+ }
+ if (candidate == null && !isEmptyParent(configurable)) {
+ candidate = configurable;
+ }
+ }
+ return candidate;
+ }
+
+ private static boolean isEmptyParent(Configurable configurable) {
+ if (configurable instanceof SearchableConfigurable.Parent) {
+ SearchableConfigurable.Parent parent = (SearchableConfigurable.Parent)configurable;
+ return !parent.hasOwnContent();
+ }
+ return false;
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java
index 9269da7ab967..e10367d583bf 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java
@@ -16,7 +16,6 @@
package com.intellij.openapi.options.newEditor;
import com.intellij.icons.AllIcons;
-import com.intellij.ide.ui.search.ConfigurableHit;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.options.*;
@@ -26,55 +25,68 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.*;
-import com.intellij.ui.treeStructure.*;
+import com.intellij.ui.treeStructure.CachingSimpleNode;
+import com.intellij.ui.treeStructure.SimpleNode;
+import com.intellij.ui.treeStructure.SimpleTree;
+import com.intellij.ui.treeStructure.SimpleTreeStructure;
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.ui.ButtonlessScrollBarUI;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
+import com.intellij.util.ui.tree.WideSelectionTreeUI;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.awt.*;
-import java.awt.event.*;
-import java.util.*;
-import java.util.List;
import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.TreeUI;
-import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
+import java.awt.*;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.util.*;
+import java.util.List;
/**
* @author Sergey.Malenkov
*/
final class SettingsTreeView extends JComponent implements Disposable, OptionsEditorColleague {
+ private static final Color NORMAL_NODE = new JBColor(Gray._60, Gray._140);
+ private static final Color WRONG_CONTENT = JBColor.RED;
+ private static final Color MODIFIED_CONTENT = JBColor.BLUE;
+
final SimpleTree myTree;
final FilteringTreeBuilder myBuilder;
- private final OptionsEditorContext myContext;
+ private final SettingsFilter myFilter;
private final MyRoot myRoot;
private final JScrollPane myScroller;
private JLabel mySeparator;
private final MyRenderer myRenderer = new MyRenderer();
private final IdentityHashMap<Configurable, MyNode> myConfigurableToNodeMap = new IdentityHashMap<Configurable, MyNode>();
- private final MergingUpdateQueue myQueue = new MergingUpdateQueue("OptionsTree", 150, false, this, this, this).setRestartTimerOnAdd(true);
+ private final MergingUpdateQueue myQueue = new MergingUpdateQueue("SettingsTreeView", 150, false, this, this, this)
+ .setRestartTimerOnAdd(true);
private Configurable myQueuedConfigurable;
- SettingsTreeView(final KeyListener listener, OptionsEditorContext context, ConfigurableGroup... groups) {
- myContext = context;
+ SettingsTreeView(SettingsFilter filter, ConfigurableGroup... groups) {
+ myFilter = filter;
myRoot = new MyRoot(groups);
-
myTree = new MyTree();
+ myTree.putClientProperty(WideSelectionTreeUI.TREE_TABLE_TREE_KEY, Boolean.TRUE);
+ myTree.setBackground(UIUtil.getSidePanelColor());
myTree.getInputMap().clear();
TreeUtil.installActions(myTree);
@@ -88,8 +100,11 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
myTree.setRootVisible(false);
myTree.setShowsRootHandles(false);
- myScroller = ScrollPaneFactory.createScrollPane(myTree);
- myScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
+ myScroller = ScrollPaneFactory.createScrollPane(myTree, true);
+ myScroller.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent());
+ myScroller.setBackground(UIUtil.getSidePanelColor());
+ myScroller.getViewport().setBackground(UIUtil.getSidePanelColor());
+ myScroller.getVerticalScrollBar().setBackground(UIUtil.getSidePanelColor());
add(myScroller);
myTree.addComponentListener(new ComponentAdapter() {
@@ -116,29 +131,6 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
});
- myTree.addKeyListener(new KeyListener() {
- public void keyTyped(KeyEvent event) {
- if (listener != null && isValid(event)) {
- listener.keyTyped(event);
- }
- }
-
- public void keyPressed(KeyEvent event) {
- if (listener != null && isValid(event)) {
- listener.keyPressed(event);
- }
- }
-
- public void keyReleased(KeyEvent event) {
- if (listener != null && isValid(event)) {
- listener.keyReleased(event);
- }
- }
-
- private boolean isValid(KeyEvent event) {
- return null == myTree.getInputMap().get(KeyStroke.getKeyStrokeForEvent(event));
- }
- });
myBuilder = new MyBuilder(new SimpleTreeStructure.Impl(myRoot));
myBuilder.setFilteringMerge(300, null);
Disposer.register(this, myBuilder);
@@ -158,9 +150,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
return ArrayUtil.toStringArray(path);
}
+ static Configurable getConfigurable(SimpleNode node) {
+ return node instanceof MyNode
+ ? ((MyNode)node).myConfigurable
+ : null;
+ }
+
@Nullable
- SimpleNode findNode(Configurable toSelect) {
- return myConfigurableToNodeMap.get(toSelect);
+ SimpleNode findNode(Configurable configurable) {
+ return myConfigurableToNodeMap.get(configurable);
}
@Nullable
@@ -250,24 +248,6 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
: null;
}
- static boolean isFiltered(Set<Configurable> configurables, ConfigurableHit hits, SimpleNode value) {
- if (value instanceof MyNode && !configurables.contains(((MyNode)value).myConfigurable)) {
- if (hits != null) {
- configurables = hits.getNameFullHits();
- while (value != null) {
- if (value instanceof MyNode) {
- if (configurables.contains(((MyNode)value).myConfigurable)) {
- return true;
- }
- }
- value = value.getParent();
- }
- }
- return false;
- }
- return true;
- }
-
@Override
public void doLayout() {
myScroller.setBounds(0, 0, getWidth(), getHeight());
@@ -277,34 +257,34 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
public void paint(Graphics g) {
super.paint(g);
+ if (0 == myTree.getY()) {
+ return; // separator is not needed without scrolling
+ }
if (mySeparator == null) {
mySeparator = new JLabel();
+ mySeparator.setForeground(NORMAL_NODE);
mySeparator.setFont(UIUtil.getLabelFont());
mySeparator.setFont(getFont().deriveFont(Font.BOLD));
}
- ConfigurableGroup group = findConfigurableGroupAt(0, 5 + mySeparator.getFont().getSize());
- if (group != null && group == findConfigurableGroupAt(0, -5)) {
- int offset = UIUtil.isUnderNativeMacLookAndFeel() ? 1 : 3;
- mySeparator.setBorder(BorderFactory.createEmptyBorder(offset, 18, offset, 3));
+ int height = mySeparator.getPreferredSize().height;
+ ConfigurableGroup group = findConfigurableGroupAt(0, height);
+ if (group != null && group == findConfigurableGroupAt(0, -myRenderer.getSeparatorHeight())) {
+ mySeparator.setBorder(BorderFactory.createEmptyBorder(0, 18, 0, 0));
mySeparator.setText(group.getDisplayName());
Rectangle bounds = myScroller.getViewport().getBounds();
- int height = mySeparator.getPreferredSize().height;
if (bounds.height > height) {
bounds.height = height;
}
g.setColor(myTree.getBackground());
+ g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
if (g instanceof Graphics2D) {
- int h = bounds.height / 4;
- int y = bounds.y + bounds.height - h;
- g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height - h);
+ int h = 4; // gradient height
+ int y = bounds.y + bounds.height;
((Graphics2D)g).setPaint(UIUtil.getGradientPaint(
0, y, g.getColor(),
0, y + h, ColorUtil.toAlpha(g.getColor(), 0)));
- g.fillRect(bounds.x, y, bounds.width, h + h);
- }
- else {
- g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
+ g.fillRect(bounds.x, y, bounds.width, h);
}
mySeparator.setSize(bounds.width - 1, bounds.height);
mySeparator.paint(g.create(bounds.x + 1, bounds.y, bounds.width - 1, bounds.height));
@@ -373,7 +353,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
private void fireSelected(Configurable configurable, ActionCallback callback) {
- myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
+ myFilter.myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
}
@Override
@@ -435,20 +415,21 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
myConfigurable = configurable;
String name = configurable.getDisplayName();
myDisplayName = name != null ? name.replace("\n", " ") : "{ " + configurable.getClass().getSimpleName() + " }";
-
- myConfigurableToNodeMap.put(configurable, this);
}
private MyNode(CachingSimpleNode parent, ConfigurableGroup group) {
super(parent);
myComposite = group;
- myConfigurable = null;
+ myConfigurable = group instanceof Configurable ? (Configurable)group : null;
String name = group.getDisplayName();
myDisplayName = name != null ? name.replace("\n", " ") : "{ " + group.getClass().getSimpleName() + " }";
}
@Override
protected SimpleNode[] buildChildren() {
+ if (myConfigurable != null) {
+ myConfigurableToNodeMap.put(myConfigurable, this);
+ }
if (myComposite == null) {
return NO_CHILDREN;
}
@@ -460,7 +441,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
for (int i = 0; i < configurables.length; i++) {
result[i] = new MyNode(this, configurables[i]);
if (myConfigurable != null) {
- myContext.registerKid(myConfigurable, configurables[i]);
+ myFilter.myContext.registerKid(myConfigurable, configurables[i]);
}
}
return result;
@@ -470,11 +451,6 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
public boolean isAlwaysLeaf() {
return myComposite == null;
}
-
- @Override
- public int getWeight() {
- return WeightBasedComparator.UNDEFINED_WEIGHT;
- }
}
private final class MyRenderer extends GroupedElementsRenderer.Tree {
@@ -490,8 +466,9 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
protected void layout() {
myNodeIcon = new JLabel(" ", SwingConstants.RIGHT);
myProjectIcon = new JLabel(" ", SwingConstants.LEFT);
- myProjectIcon.setOpaque(true);
- myRendererComponent.add(BorderLayout.NORTH, mySeparatorComponent);
+ myNodeIcon.setOpaque(false);
+ myTextLabel.setOpaque(false);
+ myProjectIcon.setOpaque(false);
myRendererComponent.add(BorderLayout.CENTER, myComponent);
myRendererComponent.add(BorderLayout.WEST, myNodeIcon);
myRendererComponent.add(BorderLayout.EAST, myProjectIcon);
@@ -504,22 +481,17 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
boolean leaf,
int row,
boolean focused) {
- myTextLabel.setOpaque(selected);
myTextLabel.setFont(UIUtil.getLabelFont());
-
- String text;
- boolean hasSeparatorAbove = false;
- int preferredForcedWidth = -1;
+ myRendererComponent.setBackground(selected ? UIUtil.getTreeSelectionBackground() : myTree.getBackground());
MyNode node = extractNode(value);
if (node == null) {
- text = value.toString();
+ myTextLabel.setText(value.toString());
}
else {
- text = node.myDisplayName;
+ myTextLabel.setText(node.myDisplayName);
// show groups in bold
if (myRoot == node.getParent()) {
- hasSeparatorAbove = node != myRoot.getChildAt(0);
myTextLabel.setFont(myTextLabel.getFont().deriveFont(Font.BOLD));
}
TreePath path = tree.getPathForRow(row);
@@ -543,18 +515,18 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
forcedWidth = visibleRect.width > 0 ? visibleRect.width - indent : forcedWidth;
}
- preferredForcedWidth = forcedWidth - 4;
+ myRendererComponent.setPrefereedWidth(forcedWidth - 4);
}
- Component result = configureComponent(text, null, null, null, selected, hasSeparatorAbove, null, preferredForcedWidth);
// update font color for modified configurables
+ myTextLabel.setForeground(selected ? UIUtil.getTreeSelectionForeground() : NORMAL_NODE);
if (!selected && node != null) {
Configurable configurable = node.myConfigurable;
if (configurable != null) {
- if (myContext.getErrors().containsKey(configurable)) {
- myTextLabel.setForeground(JBColor.RED);
+ if (myFilter.myContext.getErrors().containsKey(configurable)) {
+ myTextLabel.setForeground(WRONG_CONTENT);
}
- else if (myContext.getModified().contains(configurable)) {
- myTextLabel.setForeground(JBColor.BLUE);
+ else if (myFilter.myContext.getModified().contains(configurable)) {
+ myTextLabel.setForeground(MODIFIED_CONTENT);
}
}
}
@@ -586,7 +558,6 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
myProjectIcon.setToolTipText(OptionsBundle.message(project.isDefault()
? "configurable.default.project.tooltip"
: "configurable.current.project.tooltip"));
- myProjectIcon.setBackground(myTextLabel.getBackground());
myProjectIcon.setVisible(true);
}
else {
@@ -601,9 +572,12 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
else {
myNodeIcon.setIcon(null);
}
- return result;
+ return myRendererComponent;
}
+ int getSeparatorHeight() {
+ return mySeparatorComponent.getParent() == null ? 0 : mySeparatorComponent.getPreferredSize().height;
+ }
public boolean isUnderHandle(Point point) {
Point handlePoint = SwingUtilities.convertPoint(myRendererComponent, point, myNodeIcon);
@@ -720,7 +694,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
super.processMouseEvent(e);
}
- private final class MyTreeUi extends BasicTreeUI {
+ private final class MyTreeUi extends WideSelectionTreeUI {
@Override
public void toggleExpandState(TreePath path) {
@@ -773,7 +747,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
boolean myWasHoldingFilter;
public MyBuilder(SimpleTreeStructure structure) {
- super(myTree, myContext.getFilter(), structure, new WeightBasedComparator(false));
+ super(myTree, myFilter, structure, null);
myTree.addTreeExpansionListener(new TreeExpansionListener() {
public void treeExpanded(TreeExpansionEvent event) {
invalidateExpansions();
@@ -798,7 +772,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
@Override
public boolean isAutoExpandNode(NodeDescriptor nodeDescriptor) {
- return myContext.isHoldingFilter();
+ return myFilter.myContext.isHoldingFilter();
}
@Override
@@ -809,22 +783,22 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
@Override
protected ActionCallback refilterNow(Object preferredSelection, boolean adjustSelection) {
final List<Object> toRestore = new ArrayList<Object>();
- if (myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
+ if (myFilter.myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
myToExpandOnResetFilter = myBuilder.getUi().getExpandedElements();
}
- else if (!myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
+ else if (!myFilter.myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
toRestore.addAll(myToExpandOnResetFilter);
myToExpandOnResetFilter = null;
}
- myWasHoldingFilter = myContext.isHoldingFilter();
+ myWasHoldingFilter = myFilter.myContext.isHoldingFilter();
ActionCallback result = super.refilterNow(preferredSelection, adjustSelection);
myRefilteringNow = true;
return result.doWhenDone(new Runnable() {
public void run() {
myRefilteringNow = false;
- if (!myContext.isHoldingFilter() && getSelectedElements().isEmpty()) {
+ if (!myFilter.myContext.isHoldingFilter() && getSelectedElements().isEmpty()) {
restoreExpandedState(toRestore);
}
}