mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Configurable refactoring: build tree of configurable (tested)
This commit is contained in:
+135
-7
@@ -132,35 +132,130 @@ public class ConfigurableExtensionPointUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param project the project used to load application settings
|
||||
* @param configurables a list of settings to process
|
||||
* @return the map of different groups of settings
|
||||
*/
|
||||
public static Map<String, List<Configurable>> groupConfigurables(@NotNull List<Configurable> configurables) {
|
||||
Map<String, Node<ConfigurableWrapper>> tree = ContainerUtil.newHashMap();
|
||||
for (Configurable configurable : configurables) {
|
||||
if (configurable instanceof ConfigurableWrapper) {
|
||||
ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
|
||||
String id = wrapper.getId();
|
||||
Node<ConfigurableWrapper> node = Node.get(tree, id);
|
||||
if (node.myValue != null) {
|
||||
LOG.warn("ignore configurable with duplicated id: " + id);
|
||||
}
|
||||
else {
|
||||
String parentId = wrapper.getParentId();
|
||||
String groupId = wrapper.getExtensionPoint().groupId;
|
||||
if (groupId != null) {
|
||||
if (parentId != null) {
|
||||
LOG.warn("ignore deprecated groupId: " + groupId + " for id: " + id);
|
||||
}
|
||||
else {
|
||||
LOG.warn("use deprecated groupId instead of parentId: " + groupId + " for id: " + id);
|
||||
parentId = groupId;
|
||||
}
|
||||
}
|
||||
if (Node.cyclic(tree, parentId, node)) {
|
||||
LOG.warn("ignore cyclic dependency: " + parentId + " cannot contain " + id);
|
||||
parentId = null;
|
||||
}
|
||||
node.myParent = Node.add(tree, parentId, node);
|
||||
node.myValue = wrapper;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Node.add(tree, null, configurable);
|
||||
}
|
||||
}
|
||||
Map<String, List<Configurable>> map = ContainerUtil.newHashMap();
|
||||
for (String id : tree.keySet().toArray(new String[tree.size()])) {
|
||||
Node<ConfigurableWrapper> node = tree.get(id);
|
||||
if (node != null) {
|
||||
List<Configurable> list = getConfigurables(tree, node);
|
||||
if (list != null) {
|
||||
map.put(id, list);
|
||||
tree.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tree a map that represents a tree of nodes
|
||||
* @param node a current node to process children recursively
|
||||
* @return the list of settings for a group or {@code null} for internal node
|
||||
*/
|
||||
private static List<Configurable> getConfigurables(Map<String, Node<ConfigurableWrapper>> tree, Node<ConfigurableWrapper> node) {
|
||||
List<Configurable> list = ContainerUtil.newArrayListWithCapacity(node.myChildren.size());
|
||||
for (Iterator<Object> iterator = node.myChildren.iterator(); iterator.hasNext(); iterator.remove()) {
|
||||
Object child = iterator.next();
|
||||
if (child instanceof Configurable) {
|
||||
list.add((Configurable)child);
|
||||
}
|
||||
else {
|
||||
@SuppressWarnings("unchecked") // expected type
|
||||
Node<ConfigurableWrapper> value = (Node<ConfigurableWrapper>)child;
|
||||
if (getConfigurables(tree, value) != null) {
|
||||
throw new IllegalStateException("unexpected algorithm state");
|
||||
}
|
||||
list.add(value.myValue);
|
||||
tree.remove(value.myValue.getId());
|
||||
}
|
||||
}
|
||||
if (node.myValue == null) {
|
||||
return list; // for group only
|
||||
}
|
||||
for (Configurable configurable : list) {
|
||||
node.myValue = node.myValue.addChild(configurable);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param project a project used to load project settings or {@code null}
|
||||
* @param withIdeSettings specifies whether to load application settings or not
|
||||
* @param loadComponents specifies whether to load Configurable components or not
|
||||
* @return the list of all available settings according to parameters
|
||||
* @return the list of all valid settings according to parameters
|
||||
*/
|
||||
private static List<Configurable> getAllConfigurables(@Nullable Project project, boolean withIdeSettings, boolean loadComponents) {
|
||||
private static List<Configurable> getConfigurables(@Nullable Project project, boolean withIdeSettings, boolean loadComponents) {
|
||||
List<Configurable> list = ContainerUtil.newArrayList();
|
||||
if (withIdeSettings) {
|
||||
Application application = ApplicationManager.getApplication();
|
||||
if (application != null) {
|
||||
if (loadComponents) {
|
||||
ContainerUtil.addAll(list, application.getComponents(Configurable.class));
|
||||
addValid(list, application.getComponents(Configurable.class), null);
|
||||
}
|
||||
for (ConfigurableEP<Configurable> extension : application.getExtensions(Configurable.APPLICATION_CONFIGURABLE)) {
|
||||
ContainerUtil.addIfNotNull(list, ConfigurableWrapper.wrapConfigurable(extension));
|
||||
addValid(list, ConfigurableWrapper.wrapConfigurable(extension), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (project != null) {
|
||||
if (loadComponents) {
|
||||
ContainerUtil.addAll(list, project.getComponents(Configurable.class));
|
||||
addValid(list, project.getComponents(Configurable.class), project);
|
||||
}
|
||||
for (ConfigurableEP<Configurable> extension : project.getExtensions(Configurable.PROJECT_CONFIGURABLE)) {
|
||||
ContainerUtil.addIfNotNull(list, ConfigurableWrapper.wrapConfigurable(extension));
|
||||
addValid(list, ConfigurableWrapper.wrapConfigurable(extension), project);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void addValid(List<Configurable> list, Configurable configurable, Project project) {
|
||||
if (isValid(configurable, project)) {
|
||||
list.add(configurable);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addValid(List<Configurable> list, Configurable[] configurables, Project project) {
|
||||
for (Configurable configurable : configurables) {
|
||||
addValid(list, configurable, project);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param configurable settings component to validate
|
||||
* @param project current project, default template project or {@code null} for IDE settings
|
||||
@@ -285,4 +380,37 @@ public class ConfigurableExtensionPointUtil {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class that helps to build a tree.
|
||||
*/
|
||||
private static final class Node<V> {
|
||||
List<Object> myChildren = ContainerUtil.newArrayList();
|
||||
Node<V> myParent;
|
||||
V myValue;
|
||||
|
||||
private static <I, V> Node<V> get(Map<I, Node<V>> tree, I id) {
|
||||
Node<V> node = tree.get(id);
|
||||
if (node == null) {
|
||||
node = new Node<V>();
|
||||
tree.put(id, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private static <I, V> Node<V> add(Map<I, Node<V>> tree, I id, Object child) {
|
||||
Node<V> node = get(tree, id);
|
||||
node.myChildren.add(child);
|
||||
return node;
|
||||
}
|
||||
|
||||
private static <I, V> boolean cyclic(Map<I, Node<V>> tree, I id, Node<V> parent) {
|
||||
for (Node<V> node = tree.get(id); node != null; node = node.myParent) {
|
||||
if (node == parent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user