diff options
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/options/ex')
6 files changed, 362 insertions, 269 deletions
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java index 429a55b2b809..ca72bf30c541 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java @@ -48,7 +48,7 @@ public class ConfigurableExtensionPointUtil { } } - final Map<String, ConfigurableWrapper> idToConfigurable = new HashMap<String, ConfigurableWrapper>(); + final Map<String, ConfigurableWrapper> idToConfigurable = new LinkedHashMap<String, ConfigurableWrapper>(); for (ConfigurableEP<Configurable> ep : extensions) { final Configurable configurable = ConfigurableWrapper.wrapConfigurable(ep); if (isSuppressed(configurable, filter)) continue; @@ -75,16 +75,13 @@ public class ConfigurableExtensionPointUtil { } } } - //leave only roots (i.e. configurables without parents) - for (final Iterator<String> iterator = idToConfigurable.keySet().iterator(); iterator.hasNext(); ) { - final String key = iterator.next(); - final ConfigurableWrapper wrapper = idToConfigurable.get(key); - final String parentId = wrapper.getParentId(); - if (parentId != null && idToConfigurable.containsKey(parentId)) { - iterator.remove(); // remove only processed parents + // add roots only (i.e. configurables without parents) + for (ConfigurableWrapper wrapper : idToConfigurable.values()) { + String parentId = wrapper.getParentId(); + if (parentId == null || !idToConfigurable.containsKey(parentId)) { + result.add(wrapper); } } - ContainerUtil.addAll(result, idToConfigurable.values()); return result; } @@ -164,7 +161,7 @@ public class ConfigurableExtensionPointUtil { @NotNull private static <T extends Configurable> T findConfigurable(ConfigurableEP<Configurable>[] extensions, Class<T> configurableClass) { for (ConfigurableEP<Configurable> extension : extensions) { - if (extension.providerClass != null || extension.instanceClass != null || extension.implementationClass != null) { + if (extension.canCreateConfigurable()) { final Configurable configurable = extension.createConfigurable(); if (configurableClass.isInstance(configurable)) { return configurableClass.cast(configurable); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableVisitor.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableVisitor.java new file mode 100644 index 000000000000..7d820a255fb3 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableVisitor.java @@ -0,0 +1,144 @@ +/* + * 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.ex; + +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurableGroup; +import com.intellij.openapi.options.SearchableConfigurable; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Sergey.Malenkov + */ +public abstract class ConfigurableVisitor { + public static final ConfigurableVisitor ALL = new ConfigurableVisitor() { + @Override + protected boolean accept(Configurable configurable) { + return true; + } + }; + + protected abstract boolean accept(Configurable configurable); + + public final Configurable find(@NotNull ConfigurableGroup... groups) { + for (ConfigurableGroup group : groups) { + Configurable result = find(group.getConfigurables()); + if (result != null) { + return result; + } + } + return null; + } + + public final Configurable find(@NotNull Configurable... configurables) { + for (Configurable configurable : configurables) { + if (accept(configurable)) { + return configurable; + } + } + for (Configurable configurable : configurables) { + if (configurable instanceof Configurable.Composite) { + Configurable.Composite composite = (Configurable.Composite)configurable; + Configurable result = find(composite.getConfigurables()); + if (result != null) { + return result; + } + } + } + return null; + } + + public final List<Configurable> findAll(@NotNull ConfigurableGroup... groups) { + List<Configurable> list = new ArrayList<Configurable>(); + for (ConfigurableGroup group : groups) { + add(list, group.getConfigurables()); + } + return list; + } + + public final List<Configurable> findAll(@NotNull Configurable... configurables) { + List<Configurable> list = new ArrayList<Configurable>(); + add(list, configurables); + return list; + } + + private void add(List<Configurable> list, Configurable... configurables) { + for (Configurable configurable : configurables) { + if (accept(configurable)) { + list.add(configurable); + } + if (configurable instanceof Configurable.Composite) { + Configurable.Composite composite = (Configurable.Composite)configurable; + add(list, composite.getConfigurables()); + } + } + } + + public static final class ByID extends ConfigurableVisitor { + private final String myID; + + public ByID(@NotNull String id) { + myID = id; + } + + @Override + protected boolean accept(Configurable configurable) { + return myID.equals(getID(configurable)); + } + + public static String getID(Configurable configurable) { + return configurable instanceof SearchableConfigurable + ? ((SearchableConfigurable)configurable).getId() + : configurable.getClass().getName(); + } + } + + public static final class ByName extends ConfigurableVisitor { + private final String myName; + + public ByName(@NotNull String name) { + myName = name; + } + + @Override + protected boolean accept(Configurable configurable) { + return myName.equals(configurable.getDisplayName()); + } + } + + public static final class ByType extends ConfigurableVisitor { + private final Class<? extends Configurable> myType; + + public ByType(@NotNull Class<? extends Configurable> type) { + myType = type; + } + + @Override + protected boolean accept(Configurable configurable) { + if (myType.isInstance(configurable)) { + return true; + } + if (configurable instanceof ConfigurableWrapper) { + ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable; + return myType.isInstance(wrapper.getConfigurable()); + } + return false; + } + } +} 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 3b67a3478368..dd8169e159a7 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 @@ -47,6 +47,9 @@ public class ConfigurableWrapper implements SearchableConfigurable { @Nullable public static <T extends UnnamedConfigurable> T wrapConfigurable(ConfigurableEP<T> ep) { + if (!ep.canCreateConfigurable()) { + return null; + } if (ep.displayName != null || ep.key != null || ep.groupId != null) { T configurable = null; if (ep.providerClass != null) { @@ -55,9 +58,9 @@ public class ConfigurableWrapper implements SearchableConfigurable { return null; // it is allowed to return null from provider } } - return ep.children != null || ep.childrenEPName != null || ep.dynamic - ? (T)new CompositeWrapper(ep, configurable) - : (T)new ConfigurableWrapper(ep, configurable); + return !ep.dynamic && ep.children == null && ep.childrenEPName == null + ? (T)new ConfigurableWrapper(ep, configurable) + : (T)new CompositeWrapper(ep, configurable); } else { return ep.createConfigurable(); @@ -157,7 +160,16 @@ public class ConfigurableWrapper implements SearchableConfigurable { @NotNull @Override public String getId() { - return myEp.id == null ? myEp.instanceClass == null ? myEp.providerClass : myEp.instanceClass : myEp.id; + if (myEp.id != null) { + return myEp.id; + } + UnnamedConfigurable configurable = getConfigurable(); + if (configurable instanceof SearchableConfigurable) { + return ((SearchableConfigurable)configurable).getId(); + } + return myEp.instanceClass != null + ? myEp.instanceClass + : myEp.providerClass; } @NotNull 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 deleted file mode 100644 index e3404ec017cd..000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java +++ /dev/null @@ -1,178 +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.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 SearchableConfigurable, ConfigurableGroup { - private final String myGroupId; - private Configurable[] myConfigurables; - - private MixedConfigurableGroup(String groupId, ArrayList<Configurable> configurables) { - myGroupId = groupId; - 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) { - this(groupId, configurables.remove(groupId)); - } - - @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"); - } - - @Override - public String getShortName() { - return getDisplayName(); - } - - @Override - public Configurable[] getConfigurables() { - return myConfigurables; - } - - public static ConfigurableGroup[] getGroups(Configurable... configurables) { - HashMap<String, ArrayList<Configurable>> map = new HashMap<String, ArrayList<Configurable>>(); - for (Configurable configurable : configurables) { - String groupId = null; - if (configurable instanceof ConfigurableWrapper) { - groupId = ((ConfigurableWrapper)configurable).getExtensionPoint().groupId; - } - ArrayList<Configurable> list = map.get(groupId); - if (list == null) { - map.put(groupId, list = new ArrayList<Configurable>()); - } - list.add(configurable); - } - ArrayList<Configurable> buildList = map.get("build"); - if (buildList != null) { - 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())); - if (buildTools.getConfigurables() != null) { - buildList.add(0, buildTools); - } - } - ArrayList<ConfigurableGroup> groups = new ArrayList<ConfigurableGroup>(map.size()); - groups.add(new MixedConfigurableGroup("appearance", map)); - groups.add(new MixedConfigurableGroup("editor", map)); - groups.add(new MixedConfigurableGroup("project", map)); - groups.add(new MixedConfigurableGroup("build", map)); - groups.add(new MixedConfigurableGroup("language", map)); - groups.add(new MixedConfigurableGroup("tools", map)); - ConfigurableGroup other = new MixedConfigurableGroup(null, map); - for(Entry<String, ArrayList<Configurable>>entry: map.entrySet()){ - groups.add(new MixedConfigurableGroup(entry.getKey(), entry.getValue())); - } - groups.add(other); - return groups.toArray(new ConfigurableGroup[groups.size()]); - } - - private static Configurable find(String id, Iterator<Configurable> iterator) { - while (iterator.hasNext()) { - Configurable configurable = iterator.next(); - if (configurable instanceof SearchableConfigurable) { - SearchableConfigurable sc = (SearchableConfigurable)configurable; - if (id.equals(sc.getId())) { - iterator.remove(); - return configurable; - } - } - } - 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 deleted file mode 100644 index 609943d02943..000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java +++ /dev/null @@ -1,77 +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.ex; - -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.OptionsBundle; -import com.intellij.openapi.options.SearchableConfigurable; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -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, int weight) { - myId = id; - myWeight = weight; - } - - public int getGroupWeight() { - return myWeight; - } - - public void add(Configurable configurable) { - if (configurable != null) { - super.disposeUIResources(); - myConfigurables.add(configurable); - } - } - - @Override - public void disposeUIResources() { - super.disposeUIResources(); - myConfigurables.clear(); - } - - @NotNull - @Override - public String getId() { - return "node.configurable." + myId; - } - - @Nullable - @Override - public String getHelpTopic() { - return "node.configurable." + myId + ".help.topic"; - } - - @Nls - @Override - public String getDisplayName() { - return OptionsBundle.message("node.configurable." + myId + ".display.name"); - } - - @Override - protected Configurable[] buildConfigurables() { - int size = myConfigurables.size(); - return size == 0 ? null : myConfigurables.toArray(new Configurable[size]); - } -} diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/SortedConfigurableGroup.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/SortedConfigurableGroup.java new file mode 100644 index 000000000000..3d87b7679359 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/SortedConfigurableGroup.java @@ -0,0 +1,195 @@ +/* + * 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.ex; + +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurableGroup; +import com.intellij.openapi.options.OptionsBundle; +import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +/** + * @author Sergey.Malenkov + */ +public final class SortedConfigurableGroup + extends SearchableConfigurable.Parent.Abstract + implements SearchableConfigurable, ConfigurableGroup, Configurable.NoScroll { + + public static ConfigurableGroup getGroup(Configurable... configurables) { + SortedConfigurableGroup root = new SortedConfigurableGroup("root"); + HashMap<String, SortedConfigurableGroup> map = new HashMap<String, SortedConfigurableGroup>(); + map.put("root", root); + for (Configurable configurable : configurables) { + int weight = 0; + String groupId = null; + if (configurable instanceof ConfigurableWrapper) { + ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable; + weight = wrapper.getExtensionPoint().groupWeight; + groupId = wrapper.getExtensionPoint().groupId; + } + SortedConfigurableGroup composite = map.get(groupId); + if (composite == null) { + composite = new SortedConfigurableGroup(groupId); + map.put(groupId, composite); + } + composite.add(weight, configurable); + } + // process supported groups + root.add(60, map.remove("appearance")); + root.add(50, map.remove("editor")); + root.add(40, map.remove("project")); + SortedConfigurableGroup build = map.remove("build"); + if (build == null) { + build = map.remove("build.tools"); + } + else { + build.add(1000, map.remove("build.tools")); + } + root.add(30, build); + root.add(20, map.remove("language")); + root.add(10, map.remove("tools")); + root.add(-10, map.remove(null)); + // process unsupported groups + if (1 < map.size()) { + for (SortedConfigurableGroup group : map.values()) { + if (root != group) { + group.myDisplayName = "Category: " + group.myGroupId; + root.add(0, group); + } + } + } + return root; + } + + private final ArrayList<WeightConfigurable> myList = new ArrayList<WeightConfigurable>(); + private final String myGroupId; + private String myDisplayName; + + private SortedConfigurableGroup(String groupId) { + myGroupId = groupId; + } + + public SortedConfigurableGroup(Configurable... configurables) { + myGroupId = "root"; + // create groups from configurations + HashMap<String, SortedConfigurableGroup> map = new HashMap<String, SortedConfigurableGroup>(); + map.put(myGroupId, this); + for (Configurable configurable : configurables) { + int weight = 0; + String groupId = null; + if (configurable instanceof ConfigurableWrapper) { + ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable; + weight = wrapper.getExtensionPoint().groupWeight; + groupId = wrapper.getExtensionPoint().groupId; + } + SortedConfigurableGroup composite = map.get(groupId); + if (composite == null) { + composite = new SortedConfigurableGroup(groupId); + map.put(groupId, composite); + } + composite.add(weight, configurable); + } + // process supported groups + add(60, map.remove("appearance")); + add(50, map.remove("editor")); + add(40, map.remove("project")); + SortedConfigurableGroup build = map.remove("build"); + if (build == null) { + build = map.remove("build.tools"); + } + else { + build.add(1000, map.remove("build.tools")); + } + add(30, build); + add(20, map.remove("language")); + add(10, map.remove("tools")); + add(-10, map.remove(null)); + // process unsupported groups + if (1 < map.size()) { + for (SortedConfigurableGroup group : map.values()) { + if (this != group) { + group.myDisplayName = "Category: " + group.myGroupId; + add(0, group); + } + } + } + } + + private void add(int weight, Configurable configurable) { + if (configurable != null) { + myList.add(new WeightConfigurable(configurable, weight)); + } + } + + @Override + protected Configurable[] buildConfigurables() { + Collections.sort(myList); + int length = myList.size(); + Configurable[] result = new Configurable[length]; + for (int i = 0; i < result.length; i++) { + result[i] = myList.get(i).myConfigurable; + } + myList.clear(); + return result; + } + + @NotNull + @Override + public String getId() { + return "configurable.group." + myGroupId; + } + + @Nullable + @Override + public String getHelpTopic() { + return "configurable.group." + myGroupId + ".help.topic"; + } + + @Nls + @Override + public String getDisplayName() { + return myDisplayName != null ? myDisplayName : OptionsBundle.message("configurable.group." + myGroupId + ".settings.display.name"); + } + + @Override + public String getShortName() { + return getDisplayName(); + } + + private static final class WeightConfigurable implements Comparable<WeightConfigurable> { + private final Configurable myConfigurable; + private final int myWeight; + + private WeightConfigurable(@NotNull Configurable configurable, int weight) { + myConfigurable = configurable; + myWeight = weight; + } + + @Override + public int compareTo(@NotNull WeightConfigurable pair) { + return myWeight > pair.myWeight ? -1 : + myWeight < pair.myWeight ? 1 : + StringUtil.naturalCompare(myConfigurable.getDisplayName(), pair.myConfigurable.getDisplayName()); + } + } +} |