From 339d8e021b166af59809efa59e36d3eef65b9908 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Wed, 15 Aug 2012 16:55:58 +0400 Subject: [PATCH] IDEA-19061 Integrate the Rearranger-plugin into core-IDEA 1. Adding ability to modify arrangement rules; 2. Refactoring; --- .../codeStyle/arrangement/JavaRearranger.java | 82 ++++++-- ...rrangementRuleEditingModelBuilderTest.java | 79 ++++++++ .../arrangement/ArrangementUtil.java | 38 +++- .../model/ArrangementSettingsAtomNode.java | 1 + .../ArrangementSettingsCompositeNode.java | 12 +- .../model/ArrangementSettingsNode.java | 1 + .../settings/ArrangementSettingsGrouper.java | 50 +++++ .../ArrangementStandardSettingsAware.java | 9 +- .../DefaultArrangementSettingsGrouper.java | 36 ++++ .../group/ArrangementSettingsNodeGrouper.java | 25 --- .../ArrangementAndNodeComponent.java | 2 +- .../ArrangementAtomNodeComponent.java | 5 +- .../arrangement/ArrangementConfigUtil.java | 116 ++++++++++++ .../ArrangementMatcherRuleEditor.java | 104 ++++++---- .../ArrangementNodeDisplayManager.java | 2 +- ...va => ArrangementRuleEditingListener.java} | 5 +- .../ArrangementRuleEditingModel.java | 51 +++++ .../ArrangementRuleEditingModelBuilder.java | 71 +++++++ .../ArrangementRuleEditingModelImpl.java | 56 ++++++ .../arrangement/ArrangementRuleTree.java | 129 +++++-------- .../arrangement/ArrangementSettingsPanel.java | 17 +- .../arrangement/ArrangementSettingsUtil.java | 177 ------------------ 22 files changed, 708 insertions(+), 360 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilderTest.java create mode 100644 platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementSettingsGrouper.java create mode 100644 platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/DefaultArrangementSettingsGrouper.java delete mode 100644 platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/group/ArrangementSettingsNodeGrouper.java create mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java rename platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/{ArrangementMatcherEditingListener.java => ArrangementRuleEditingListener.java} (79%) create mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModel.java create mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java create mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java delete mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsUtil.java diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java index 1d5bc8561a98..21489bafd61f 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java @@ -16,11 +16,13 @@ package com.intellij.psi.codeStyle.arrangement; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings; +import com.intellij.psi.codeStyle.arrangement.model.*; +import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettingsGrouper; import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType; import org.jetbrains.annotations.NotNull; @@ -32,7 +34,9 @@ import java.util.*; * @author Denis Zhdanov * @since 7/20/12 2:31 PM */ -public class JavaRearranger implements Rearranger, ArrangementStandardSettingsAware { +public class JavaRearranger implements Rearranger, ArrangementStandardSettingsAware, + ArrangementSettingsGrouper +{ // Type @NotNull private static final Set SUPPORTED_TYPES = EnumSet.of( @@ -80,35 +84,87 @@ public class JavaRearranger implements Rearranger, } @Override - public boolean isNameFilterEnabled(@Nullable ArrangementMatcherSettings settings) { + public boolean isNameFilterEnabled(@Nullable ArrangementSettingsNode current) { // TODO den implement return true; } @Override - public boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings settings) { + public boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementSettingsNode current) { return SUPPORTED_TYPES.contains(type); } @Override - public boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings settings) { - if (settings == null) { + public boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementSettingsNode current) { + if (current == null) { return SUPPORTED_MODIFIERS.contains(modifier); } - Object key = NO_TYPE; - for (ArrangementEntryType type : ArrangementEntryType.values()) { - if (settings.hasCondition(type)) { - key = type; - break; + + final Ref typeRef = new Ref(); + current.invite(new ArrangementSettingsNodeVisitor() { + @Override + public void visit(@NotNull ArrangementSettingsAtomNode node) { + if (node.getType() == ArrangementSettingType.TYPE) { + typeRef.set(node.getValue()); + } } - } + + @Override + public void visit(@NotNull ArrangementSettingsCompositeNode node) { + for (ArrangementSettingsNode n : node.getOperands()) { + if (typeRef.get() != null) { + return; + } + n.invite(this); + } + } + }); + Object key = typeRef.get() == null ? NO_TYPE : typeRef.get(); Set modifiers = MODIFIERS_BY_TYPE.get(key); return modifiers != null && modifiers.contains(modifier); } @Override - public boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings settings) { + public boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementSettingsNode current) { // TODO den implement return true; } + + @NotNull + @Override + public HierarchicalArrangementSettingsNode group(@NotNull ArrangementSettingsNode node) { + final Ref result = new Ref(); + node.invite(new ArrangementSettingsNodeVisitor() { + @Override + public void visit(@NotNull ArrangementSettingsAtomNode node) { + result.set(new HierarchicalArrangementSettingsNode(node)); + } + + @Override + public void visit(@NotNull ArrangementSettingsCompositeNode node) { + ArrangementSettingsNode typeNode = null; + for (ArrangementSettingsNode n : node.getOperands()) { + if (n instanceof ArrangementSettingsAtomNode && ((ArrangementSettingsAtomNode)n).getType() == ArrangementSettingType.TYPE) { + typeNode = n; + break; + } + } + if (typeNode == null) { + result.set(new HierarchicalArrangementSettingsNode(node)); + } + else { + HierarchicalArrangementSettingsNode parent = new HierarchicalArrangementSettingsNode(typeNode); + ArrangementSettingsCompositeNode compositeWithoutType = new ArrangementSettingsCompositeNode(node.getOperator()); + for (ArrangementSettingsNode n : node.getOperands()) { + if (n != typeNode) { + compositeWithoutType.addOperand(n); + } + } + parent.addChild(new HierarchicalArrangementSettingsNode(compositeWithoutType)); + result.set(parent); + } + } + }); + return result.get(); + } } diff --git a/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilderTest.java b/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilderTest.java new file mode 100644 index 000000000000..509aa3ba2aa9 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilderTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2012 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.application.options.codeStyle.arrangement; + +import com.intellij.psi.codeStyle.arrangement.ArrangementUtil; +import com.intellij.psi.codeStyle.arrangement.JavaRearranger; +import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; +import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.NotNull; +import org.junit.Before; +import org.junit.Test; + +import javax.swing.tree.DefaultMutableTreeNode; + +import static com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier.PUBLIC; +import static com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier.STATIC; +import static org.junit.Assert.assertEquals; + +/** + * @author Denis Zhdanov + * @since 08/15/2012 + */ +public class ArrangementRuleEditingModelBuilderTest { + + @NotNull private ArrangementRuleEditingModelBuilder myBuilder; + @NotNull private DefaultMutableTreeNode myRoot; + @NotNull private TIntObjectHashMap myRowMappings; + @NotNull private JavaRearranger myGrouper; + + @Before + public void setUp() { + myBuilder = new ArrangementRuleEditingModelBuilder(); + myRoot = new DefaultMutableTreeNode(); + myRowMappings = new TIntObjectHashMap(); + myGrouper = new JavaRearranger(); + } + + @Test + public void mapToTheSameLayer() { + build(ArrangementUtil.and(atom(PUBLIC), atom(STATIC))); + // TODO den uncomment + //assertEquals(1, myRowMappings.size()); + } + + private void build(@NotNull ArrangementSettingsNode node) { + myBuilder.build(node, myRoot, myGrouper, myRowMappings); + } + + private static ArrangementSettingsAtomNode atom(@NotNull Object condition) { + final ArrangementSettingType type; + if (condition instanceof ArrangementEntryType) { + type = ArrangementSettingType.TYPE; + } + else if (condition instanceof ArrangementModifier) { + type = ArrangementSettingType.MODIFIER; + } + else { + throw new IllegalArgumentException(String.format("Unexpected condition of class %s: %s", condition.getClass(), condition)); + } + return new ArrangementSettingsAtomNode(type, condition); + } +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java index 520407ba89ba..f2da39c54bf4 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java @@ -16,10 +16,15 @@ package com.intellij.psi.codeStyle.arrangement; import com.intellij.lang.Language; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher; import com.intellij.psi.codeStyle.arrangement.match.CompositeArrangementEntryMatcher; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsCompositeNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNodeVisitor; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -108,17 +113,48 @@ public class ArrangementUtil { } //endregion - //region Matchers composition + //region Rule composition + + @NotNull + public static ArrangementSettingsNode and(@NotNull ArrangementSettingsNode... nodes) { + final ArrangementSettingsCompositeNode result = new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND); + final ArrangementSettingsNodeVisitor visitor = new ArrangementSettingsNodeVisitor() { + @Override + public void visit(@NotNull ArrangementSettingsAtomNode node) { + result.addOperand(node); + } + + @Override + public void visit(@NotNull ArrangementSettingsCompositeNode node) { + if (node.getOperator() == ArrangementSettingsCompositeNode.Operator.AND) { + for (ArrangementSettingsNode operand : node.getOperands()) { + operand.invite(this); + } + } + else { + result.addOperand(node); + } + } + }; + for (ArrangementSettingsNode node : nodes) { + node.invite(visitor); + } + return result; + } + + // TODO den remove @NotNull public static ArrangementEntryMatcher or(@NotNull ArrangementEntryMatcher... matchers) { return combine(CompositeArrangementEntryMatcher.Operator.OR, matchers); } + // TODO den remove @NotNull public static ArrangementEntryMatcher and(@NotNull ArrangementEntryMatcher... matchers) { return combine(CompositeArrangementEntryMatcher.Operator.AND, matchers); } + // TODO den remove @NotNull private static ArrangementEntryMatcher combine(@NotNull CompositeArrangementEntryMatcher.Operator operator, @NotNull ArrangementEntryMatcher... matchers) diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsAtomNode.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsAtomNode.java index 95751e6ffb8b..22a75c58888e 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsAtomNode.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsAtomNode.java @@ -90,6 +90,7 @@ public class ArrangementSettingsAtomNode implements ArrangementSettingsNode { return true; } + @NotNull @Override public ArrangementSettingsAtomNode clone() { ArrangementSettingsAtomNode result = new ArrangementSettingsAtomNode(myType, myValue); diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsCompositeNode.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsCompositeNode.java index 5144eeb985b8..4e36aeae7d27 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsCompositeNode.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsCompositeNode.java @@ -16,11 +16,10 @@ package com.intellij.psi.codeStyle.arrangement.model; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.Set; /** * // TODO den add doc @@ -30,7 +29,7 @@ import java.util.List; */ public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode { - @NotNull private final List myOperands = new ArrayList(); + @NotNull private final Set myOperands = new HashSet(); @NotNull private final Operator myOperator; public ArrangementSettingsCompositeNode(@NotNull Operator operator) { @@ -38,7 +37,7 @@ public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode } @NotNull - public List getOperands() { + public Set getOperands() { return myOperands; } @@ -57,6 +56,7 @@ public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode visitor.visit(this); } + @NotNull @Override public ArrangementSettingsCompositeNode clone() { ArrangementSettingsCompositeNode result = new ArrangementSettingsCompositeNode(myOperator); @@ -70,7 +70,7 @@ public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode public String toString() { return StringUtil.join(myOperands, myOperator == Operator.AND ? " and " : " or "); } - + public enum Operator { AND, OR } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsNode.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsNode.java index 3759a39877d8..a8b55607966d 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsNode.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/model/ArrangementSettingsNode.java @@ -27,5 +27,6 @@ public interface ArrangementSettingsNode extends Cloneable { void invite(@NotNull ArrangementSettingsNodeVisitor visitor); + @NotNull ArrangementSettingsNode clone(); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementSettingsGrouper.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementSettingsGrouper.java new file mode 100644 index 000000000000..33c2c671c7b7 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementSettingsGrouper.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2012 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.psi.codeStyle.arrangement.settings; + +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode; +import org.jetbrains.annotations.NotNull; + +/** + * Strategy which hints on how arrangement settings should be grouped at the UI. + *

+ * Implementations of this interface are expected to be thread-safe. + * + * @author Denis Zhdanov + * @since 8/15/12 4:21 PM + */ +public interface ArrangementSettingsGrouper { + + /** + * Allows to answer if and how should be grouped given settings. + *

+ * Example: given settings node is a composite 'AND' node with the following conditions: + * 'type: field; modifier: public; modifier: static; modifier: final'. We might want to show it like below: + *

+   *   field
+   *     |
+   *      ---public---static---final
+   * 
+ * That means that we'll return a {@link HierarchicalArrangementSettingsNode} with condition 'type: field' and + * a single child node with composite 'AND' condition 'modifier: public; modifier: static; modifier: final'. + * + * @param node settings node which conditions should be grouped + * @return grouping-aware node + */ + @NotNull + HierarchicalArrangementSettingsNode group(@NotNull ArrangementSettingsNode node); +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementStandardSettingsAware.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementStandardSettingsAware.java index 5daabda09c0b..ea02bbd5b155 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementStandardSettingsAware.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementStandardSettingsAware.java @@ -17,6 +17,7 @@ package com.intellij.psi.codeStyle.arrangement.settings; import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,14 +34,14 @@ import java.util.List; public interface ArrangementStandardSettingsAware { // TODO den add doc - boolean isNameFilterEnabled(@Nullable ArrangementMatcherSettings current); + boolean isNameFilterEnabled(@Nullable ArrangementSettingsNode current); // TODO den add doc - boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings current); + boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementSettingsNode current); // TODO den add doc - boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings current); + boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementSettingsNode current); // TODO den add doc - boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings current); + boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementSettingsNode current); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/DefaultArrangementSettingsGrouper.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/DefaultArrangementSettingsGrouper.java new file mode 100644 index 000000000000..a7aa312165e7 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/DefaultArrangementSettingsGrouper.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2012 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.psi.codeStyle.arrangement.settings; + +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 8/15/12 4:23 PM + */ +public class DefaultArrangementSettingsGrouper implements ArrangementSettingsGrouper { + + @NotNull public static final DefaultArrangementSettingsGrouper INSTANCE = new DefaultArrangementSettingsGrouper(); + + @NotNull + @Override + public HierarchicalArrangementSettingsNode group(@NotNull ArrangementSettingsNode node) { + // Don't group. + return new HierarchicalArrangementSettingsNode(node); + } +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/group/ArrangementSettingsNodeGrouper.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/group/ArrangementSettingsNodeGrouper.java deleted file mode 100644 index 18a70476651d..000000000000 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/group/ArrangementSettingsNodeGrouper.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2000-2012 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.psi.codeStyle.arrangement.settings.group; - -/** - * // TODO den add doc - * - * @author Denis Zhdanov - * @since 8/8/12 12:29 PM - */ -public interface ArrangementSettingsNodeGrouper { -} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java index 268fce33c73b..182bc092ba4e 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java @@ -135,7 +135,7 @@ public class ArrangementAndNodeComponent extends JPanel implements ArrangementNo @Override public void paint(Graphics g) { - Point point = ArrangementSettingsUtil.getLocationOnScreen(this); + Point point = ArrangementConfigUtil.getLocationOnScreen(this); if (point != null) { Rectangle bounds = getBounds(); myScreenBounds = new Rectangle(point.x, point.y, bounds.width, bounds.height); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java index 9c8e714a61ed..1e2b1cf43702 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java @@ -16,7 +16,6 @@ package com.intellij.application.options.codeStyle.arrangement; import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; -import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.ui.GridBag; @@ -40,7 +39,7 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent { @NotNull private final JPanel myRenderer = new JPanel(new GridBagLayout()) { @Override public void paint(Graphics g) { - Point point = ArrangementSettingsUtil.getLocationOnScreen(this); + Point point = ArrangementConfigUtil.getLocationOnScreen(this); if (point != null) { Rectangle bounds = myRenderer.getBounds(); myScreenBounds = new Rectangle(point.x, point.y, bounds.width, bounds.height); @@ -114,7 +113,7 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent { @NotNull @Override - public ArrangementSettingsNode getSettingsNode() { + public ArrangementSettingsAtomNode getSettingsNode() { return mySettingsNode; } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java new file mode 100644 index 000000000000..3fb162408e1e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConfigUtil.java @@ -0,0 +1,116 @@ +/* + * Copyright 2000-2012 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.application.options.codeStyle.arrangement; + +import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; +import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings; +import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.*; +import java.util.List; + +/** + * Contains various utility methods to be used during showing arrangement settings. + *

+ * Thread-safe. + * + * @author Denis Zhdanov + * @since 8/8/12 9:14 AM + */ +public class ArrangementConfigUtil { + + private ArrangementConfigUtil() { + } + + /** + * Allows to answer what new settings are available for a particular {@link ArrangementMatcherSettings arrangement matcher rules}. + * + * @param filter filter to use + * @param settings object that encapsulates information about current arrangement matcher settings + * @return map which contains information on what new new settings are available at the current situation + */ + @NotNull + public static Map> buildAvailableOptions(@NotNull ArrangementStandardSettingsAware filter, + @Nullable ArrangementSettingsNode settings) + { + Map> result = new EnumMap>(ArrangementSettingType.class); + processData(filter, settings, result, ArrangementSettingType.TYPE, ArrangementEntryType.values()); + processData(filter, settings, result, ArrangementSettingType.MODIFIER, ArrangementModifier.values()); + return result; + } + + private static void processData(@NotNull ArrangementStandardSettingsAware filter, + @Nullable ArrangementSettingsNode settings, + @NotNull Map> result, + @NotNull ArrangementSettingType type, + @NotNull T[] values) + { + List data = null; + for (T v : values) { + if (!isEnabled(v, filter, settings)) { + continue; + } + if (data == null) { + data = new ArrayList(); + } + data.add(v); + } + if (data != null) { + result.put(type, data); + } + } + + public static boolean isEnabled(@NotNull Object conditionId, + @NotNull ArrangementStandardSettingsAware filter, + @Nullable ArrangementSettingsNode settings) + { + if (conditionId instanceof ArrangementEntryType) { + return filter.isEnabled((ArrangementEntryType)conditionId, settings); + } + else if (conditionId instanceof ArrangementModifier) { + return filter.isEnabled((ArrangementModifier)conditionId, settings); + } + else { + return false; + } + } + + @Nullable + public static Point getLocationOnScreen(@NotNull JComponent component) { + int dx = 0; + int dy = 0; + for (Container c = component; c != null; c = c.getParent()) { + if (c.isShowing()) { + Point locationOnScreen = c.getLocationOnScreen(); + locationOnScreen.translate(dx, dy); + return locationOnScreen; + } + else { + Point location = c.getLocation(); + dx += location.x; + dy += location.y; + } + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherRuleEditor.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherRuleEditor.java index 77add416e8db..7744f149a1ad 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherRuleEditor.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherRuleEditor.java @@ -16,11 +16,8 @@ package com.intellij.application.options.codeStyle.arrangement; import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher; -import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; -import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType; import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings; import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; import com.intellij.util.ui.GridBag; import com.intellij.util.ui.MultiRowFlowPanel; @@ -29,6 +26,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.*; import java.util.List; @@ -47,18 +46,25 @@ public class ArrangementMatcherRuleEditor extends JPanel { new HashMap(); @NotNull private final ArrangementStandardSettingsAware myFilter; + @Nullable private ArrangementRuleEditingModel myModel; public ArrangementMatcherRuleEditor(@NotNull ArrangementStandardSettingsAware filter, @NotNull ArrangementNodeDisplayManager displayManager) { myFilter = filter; init(displayManager); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + onMouseClicked(e); + } + }); } private void init(@NotNull ArrangementNodeDisplayManager displayManager) { setLayout(new GridBagLayout()); - Map> supportedSettings = ArrangementSettingsUtil.buildAvailableOptions(myFilter, null); + Map> supportedSettings = ArrangementConfigUtil.buildAvailableOptions(myFilter, null); addRowIfPossible(ArrangementSettingType.TYPE, supportedSettings, displayManager); addRowIfPossible(ArrangementSettingType.MODIFIER, supportedSettings, displayManager); } @@ -78,7 +84,7 @@ public class ArrangementMatcherRuleEditor extends JPanel { myComponents.put(value, component); valuesPanel.add(component.getUiComponent()); } - + int top = ArrangementAtomNodeComponent.PADDING; add(new JLabel(manager.getDisplayLabel(key) + ":"), new GridBag().anchor(GridBagConstraints.NORTHWEST).insets(top, 0, 0, 0)); add(valuesPanel, new GridBag().anchor(GridBagConstraints.WEST).weightx(1).fillCellHorizontally().coverLine()); @@ -89,52 +95,68 @@ public class ArrangementMatcherRuleEditor extends JPanel { * Asks current editor to refresh its state in accordance with the given arguments (e.g. when new rule is selected and * we want to show only available conditions). * - * @param settings current rule settings if defined; null as an indication that no settings should be active + * @param model current rule settings model if defined; null as an indication that no settings should be active */ - public void updateState(@Nullable ArrangementMatcherSettings settings) { - for (ArrangementEntryType type : ArrangementEntryType.values()) { - ArrangementAtomNodeComponent component = myComponents.get(type); - if (component == null) { - continue; - } - boolean enabled; - boolean selected; - if (settings == null) { - enabled = false; - selected = false; - } - else { - enabled = myFilter.isEnabled(type, settings); - selected = settings.hasCondition(type); - } - component.setEnabled(enabled); - component.setSelected(selected); + public void updateState(@Nullable ArrangementRuleEditingModel model) { + myModel = model; + + // Reset state. + for (ArrangementAtomNodeComponent component : myComponents.values()) { + component.setEnabled(false); + component.setSelected(false); } - for (ArrangementModifier modifier : ArrangementModifier.values()) { - ArrangementAtomNodeComponent component = myComponents.get(modifier); - if (component == null) { - continue; + + if (model == null) { + return; + } + + Map> available = ArrangementConfigUtil.buildAvailableOptions(myFilter, model.getSettingsNode()); + for (Collection ids : available.values()) { + for (Object id : ids) { + ArrangementAtomNodeComponent component = myComponents.get(id); + if (component != null) { + component.setEnabled(true); + component.setSelected(model.hasCondition(id)); + } } - boolean enabled; - boolean selected; - if (settings == null) { - enabled = false; - selected = false; - } - else { - enabled = myFilter.isEnabled(modifier, settings); - selected = settings.hasCondition(modifier); - } - component.setEnabled(enabled); - component.setSelected(selected); } repaint(); } - + public void applyBackground(@NotNull Color color) { setBackground(color); for (JComponent component : myColoredComponents) { component.setBackground(color); } } + + private void onMouseClicked(@NotNull MouseEvent e) { + if (myModel == null) { + return; + } + ArrangementAtomNodeComponent component = getNodeComponentAt(e.getLocationOnScreen()); + if (component == null) { + return; + } + ArrangementSettingsAtomNode settingsNode = component.getSettingsNode(); + boolean remove = myModel.hasCondition(settingsNode.getValue()); + component.setSelected(!remove); + if (remove) { + myModel.removeAndCondition(settingsNode); + } + else { + myModel.addAndCondition(settingsNode); + } + } + + @Nullable + private ArrangementAtomNodeComponent getNodeComponentAt(@NotNull Point screenPoint) { + for (ArrangementAtomNodeComponent component : myComponents.values()) { + Rectangle screenBounds = component.getScreenBounds(); + if (screenBounds != null && screenBounds.contains(screenPoint)) { + return component; + } + } + return null; + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeDisplayManager.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeDisplayManager.java index 2f7322ddf6d5..e1cc76fa682e 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeDisplayManager.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeDisplayManager.java @@ -49,7 +49,7 @@ public class ArrangementNodeDisplayManager { @NotNull ArrangementStandardSettingsRepresentationAware representationManager) { myRepresentationManager = representationManager; - Map> map = ArrangementSettingsUtil.buildAvailableOptions(filter, null); + Map> map = ArrangementConfigUtil.buildAvailableOptions(filter, null); for (Map.Entry> entry : map.entrySet()) { myMaxWidths.put(entry.getKey(), maxWidth(entry.getValue())); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherEditingListener.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingListener.java similarity index 79% rename from platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherEditingListener.java rename to platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingListener.java index 83a6dcd6da53..2993e37eb9f0 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherEditingListener.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingListener.java @@ -15,16 +15,15 @@ */ package com.intellij.application.options.codeStyle.arrangement; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings; import org.jetbrains.annotations.NotNull; /** * @author Denis Zhdanov * @since 8/15/12 9:14 AM */ -public interface ArrangementMatcherEditingListener { +public interface ArrangementRuleEditingListener { - void startEditing(@NotNull ArrangementMatcherSettings settings); + void startEditing(@NotNull ArrangementRuleEditingModel settings); void stopEditing(); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModel.java new file mode 100644 index 000000000000..2bb5749ca681 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModel.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2012 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.application.options.codeStyle.arrangement; + +import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; +import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import org.jetbrains.annotations.NotNull; + +/** + * Combines and encapsulates information about arrangement matcher rules representation (tree nodes) and + * underlying {@link ArrangementSettingsNode data model}. + *

+ * Implementations of this interface are not obliged to be thread-safe. + * + * @author Denis Zhdanov + * @since 8/15/12 1:04 PM + */ +public interface ArrangementRuleEditingModel { + + @NotNull + ArrangementSettingsNode getSettingsNode(); + + /** + * Allows to answer if current model has a registered condition for the given key. A key is expected to be one of the standard + * keys, e.g. {@link ArrangementEntryType type}, {@link ArrangementModifier modifier} etc. + * + * @param key target key + * @return true if current model has a registered mapping for the given key; + * false otherwise + */ + boolean hasCondition(@NotNull Object key); + + void addAndCondition(@NotNull ArrangementSettingsAtomNode node); + + void removeAndCondition(@NotNull ArrangementSettingsNode node); +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java new file mode 100644 index 000000000000..d982ff8f8889 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelBuilder.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2012 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.application.options.codeStyle.arrangement; + +import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettingsGrouper; +import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsRepresentationAware; +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.NotNull; + +import javax.swing.tree.DefaultMutableTreeNode; + +/** + * Holds glue logic between arrangement settings and their representation - + * '{@link ArrangementSettingsNode} -> {@link ArrangementRuleEditingModel}' + *

+ * Thread-safe. + * + * @author Denis Zhdanov + * @since 8/15/12 2:50 PM + */ +public class ArrangementRuleEditingModelBuilder { + + /** + * Does the following: + *

+   * 
    + *
  1. + * {@link HierarchicalArrangementSettingsNode Groups} given {@link ArrangementSettingsNode settings} using + * the given {@link ArrangementStandardSettingsRepresentationAware#group(ArrangementSettingsNode) strategy}; + *
  2. + *
  3. + * Build {@link DefaultMutableTreeNode tree nodes} for the {@link HierarchicalArrangementSettingsNode groiping-aware nodes} + * and register them within the target tree structure (denoted by the given settings root element); + *
  4. + *
  5. + * Build necessary {@link ArrangementRuleEditingModel editing models} and store them at the given container (a key is a node row); + *
  6. + *
+ *
+ * + * @param setting target settings to process + * @param root UI tree settings root to use + * @param grouper strategy that knows how to + * {@link ArrangementStandardSettingsRepresentationAware#getDisplayValue(ArrangementModifier) group} setting + * nodes for UI representation + * @param rowMappings container to hold built {@link ArrangementRuleEditingModel editing models} (UI tree row numbers are used as keys) + */ + public void build(@NotNull ArrangementSettingsNode setting, + @NotNull DefaultMutableTreeNode root, + @NotNull ArrangementSettingsGrouper grouper, + @NotNull TIntObjectHashMap rowMappings) + { + HierarchicalArrangementSettingsNode grouped = grouper.group(setting); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java new file mode 100644 index 000000000000..650309c8a40e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImpl.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2012 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.application.options.codeStyle.arrangement; + +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 8/15/12 2:40 PM + */ +public class ArrangementRuleEditingModelImpl implements ArrangementRuleEditingModel { + + @NotNull private ArrangementSettingsNode mySettingsNode; + + public ArrangementRuleEditingModelImpl(@NotNull ArrangementSettingsNode node) { + mySettingsNode = node; + } + + @NotNull + @Override + public ArrangementSettingsNode getSettingsNode() { + return mySettingsNode; + } + + @Override + public boolean hasCondition(@NotNull Object key) { + // TODO den implement + return false; + } + + @Override + public void addAndCondition(@NotNull ArrangementSettingsAtomNode node) { + // TODO den implement + } + + @Override + public void removeAndCondition(@NotNull ArrangementSettingsNode node) { + // TODO den implement + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java index 6a9d9e26123d..c2f9452132ec 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java @@ -17,8 +17,11 @@ package com.intellij.application.options.codeStyle.arrangement; import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; -import com.intellij.psi.codeStyle.arrangement.model.*; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsCompositeNode; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; +import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettingsGrouper; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.treeStructure.Tree; import gnu.trove.TIntObjectHashMap; @@ -43,18 +46,20 @@ import java.util.List; */ public class ArrangementRuleTree { - @NotNull private final List myListeners = new ArrayList(); - @NotNull private final TreeSelectionModel mySelectionModel = new MySelectionModel(); - @NotNull private final TIntObjectHashMap myRenderers = new TIntObjectHashMap(); - @NotNull private final TIntObjectHashMap mySettings = - new TIntObjectHashMap(); + @NotNull private final List myListeners = new ArrayList(); + @NotNull private final TreeSelectionModel mySelectionModel = new MySelectionModel(); - @NotNull private final Tree myTree; - @NotNull private final ArrangementNodeComponentFactory myFactory; + @NotNull private final TIntObjectHashMap myRenderers = + new TIntObjectHashMap(); + @NotNull private final TIntObjectHashMap myModels = + new TIntObjectHashMap(); + + @NotNull private final Tree myTree; + @NotNull private final ArrangementNodeComponentFactory myFactory; private boolean mySkipSelectionChange; - public ArrangementRuleTree(@NotNull ArrangementNodeDisplayManager displayManager) { + public ArrangementRuleTree(@NotNull ArrangementSettingsGrouper grouper, @NotNull ArrangementNodeDisplayManager displayManager) { myFactory = new ArrangementNodeComponentFactory(displayManager); DefaultMutableTreeNode root = new DefaultMutableTreeNode(); DefaultTreeModel treeModel = new DefaultTreeModel(root); @@ -102,32 +107,23 @@ public class ArrangementRuleTree { onMouseClicked(e); } }); - - ArrangementSettingsCompositeNode constants = new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND); - constants.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC)); - constants.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.STATIC)); - constants.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.FINAL)); - - ArrangementSettingsCompositeNode privateFields = new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND); - privateFields.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE)); - - HierarchicalArrangementSettingsNode fields = new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode( - ArrangementSettingType.TYPE, ArrangementEntryType.FIELD - )); - fields.addChild(new HierarchicalArrangementSettingsNode(constants)); - fields.addChild(new HierarchicalArrangementSettingsNode(privateFields)); - int row = map(root, fields, null, 0); - - HierarchicalArrangementSettingsNode methods = new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode( - ArrangementSettingType.TYPE, ArrangementEntryType.METHOD - )); - methods.addChild(new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode( - ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC - ))); - methods.addChild(new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode( - ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE - ))); - map(root, methods, null, row); + + List rules = new ArrayList(); + rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.FIELD)) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC)) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.STATIC)) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.FINAL))); + rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.FIELD)) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE))); + rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.METHOD)) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC))); + rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.METHOD)) + .addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE))); + map(root, rules, grouper); expandAll(myTree, new TreePath(root)); myTree.setRootVisible(false); @@ -168,58 +164,37 @@ public class ArrangementRuleTree { tree.expandPath(parent); } - private int map(@NotNull DefaultMutableTreeNode parentTreeNode, - @NotNull HierarchicalArrangementSettingsNode settingsNode, - @Nullable ArrangementSettingsCompositeNode template, - int row) + private void map(@NotNull DefaultMutableTreeNode root, + @NotNull List settings, + @NotNull ArrangementSettingsGrouper grouper) { - DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(settingsNode.getCurrent()); - parentTreeNode.add(childTreeNode); - List children = settingsNode.getChildren(); - if (children.isEmpty()) { - ArrangementMatcherSettings settings = new ArrangementMatcherSettings(); - ArrangementSettingsNode condition; - if (template == null) { - condition = settingsNode.getCurrent(); - } - else { - condition = template.clone().addOperand(settingsNode.getCurrent()); - } - settings.addCondition(condition); - mySettings.put(row, settings); - return row + 1; - } - else { - row++; - ArrangementSettingsCompositeNode newTemplate = - template == null ? new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND) - : template.clone(); - newTemplate.addOperand(settingsNode.getCurrent()); - for (HierarchicalArrangementSettingsNode node : children) { - row = map(childTreeNode, node, newTemplate, row); - } - return row; + ArrangementRuleEditingModelBuilder builder = new ArrangementRuleEditingModelBuilder(); + for (ArrangementSettingsNode setting : settings) { + builder.build(setting, root, grouper, myModels); } } - public void addEditingListener(@NotNull ArrangementMatcherEditingListener listener) { + public void addEditingListener(@NotNull ArrangementRuleEditingListener listener) { myListeners.add(listener); } /** - * @return matcher settings for the selected tree row(s) if any; null otherwise + * @return matcher model for the selected tree row(s) if any; null otherwise */ @Nullable - public ArrangementMatcherSettings getActiveSettings() { + public ArrangementRuleEditingModel getActiveModel() { TreePath[] paths = mySelectionModel.getSelectionPaths(); if (paths == null) { return null; } + + // There is a possible case that particular settings node is represented on multiple rows and that non-leaf nodes are served + // for more than one rule. No model is registered for them then and we want just to skip them. for (int i = paths.length - 1; i >= 0; i--) { int row = myTree.getRowForPath(paths[i]); - ArrangementMatcherSettings settings = mySettings.get(row); - if (settings != null) { - return settings; + ArrangementRuleEditingModel model = myModels.get(row); + if (model != null) { + return model; } } return null; @@ -296,13 +271,13 @@ public class ArrangementRuleTree { } } - private void notifyEditingListeners(@Nullable ArrangementMatcherSettings settings) { - for (ArrangementMatcherEditingListener listener : myListeners) { - if (settings == null) { + private void notifyEditingListeners(@Nullable ArrangementRuleEditingModel model) { + for (ArrangementRuleEditingListener listener : myListeners) { + if (model == null) { listener.stopEditing(); } else { - listener.startEditing(settings); + listener.startEditing(model); } } } @@ -328,7 +303,7 @@ public class ArrangementRuleTree { public void setSelectionPath(TreePath path) { if (!mySkipSelectionChange) { super.setSelectionPath(path); - notifyEditingListeners(getActiveSettings()); + notifyEditingListeners(getActiveModel()); } } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java index 1e963eb3cc41..a29343689220 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java @@ -22,10 +22,7 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.util.Ref; import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsRepresentationAware; -import com.intellij.psi.codeStyle.arrangement.settings.DefaultArrangementSettingsRepresentationManager; +import com.intellij.psi.codeStyle.arrangement.settings.*; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.ui.GridBag; @@ -54,8 +51,12 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { representationManager = (ArrangementStandardSettingsRepresentationAware)filter; } ArrangementNodeDisplayManager displayManager = new ArrangementNodeDisplayManager(filter, representationManager); + ArrangementSettingsGrouper grouper = DefaultArrangementSettingsGrouper.INSTANCE; + if (filter instanceof ArrangementSettingsGrouper) { + grouper = (ArrangementSettingsGrouper)filter; + } - final ArrangementRuleTree ruleTree = new ArrangementRuleTree(displayManager); + final ArrangementRuleTree ruleTree = new ArrangementRuleTree(grouper, displayManager); Tree component = ruleTree.getTreeComponent(); myContent.add(new JBScrollPane(component), new GridBag().weightx(1).weighty(1).fillCell().coverLine()); CustomizationUtil.installPopupHandler( @@ -78,10 +79,10 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { } } }); - ruleTree.addEditingListener(new ArrangementMatcherEditingListener() { + ruleTree.addEditingListener(new ArrangementRuleEditingListener() { @Override - public void startEditing(@NotNull ArrangementMatcherSettings settings) { - ruleEditor.updateState(settings); + public void startEditing(@NotNull ArrangementRuleEditingModel model) { + ruleEditor.updateState(model); resetEditor.set(Boolean.FALSE); try { editorPane.setCollapsed(false); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsUtil.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsUtil.java deleted file mode 100644 index 82f4b89a4c81..000000000000 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsUtil.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2000-2012 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.application.options.codeStyle.arrangement; - -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.DataKey; -import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType; -import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier; -import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType; -import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode; -import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings; -import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.util.*; -import java.util.List; - -/** - * // TODO den add doc - * - * @author Denis Zhdanov - * @since 8/8/12 9:14 AM - */ -public class ArrangementSettingsUtil { - - public static final DataKey NODE_COMPONENT = DataKey.create("Arrangement.Rule.Editor.Node.Component"); - public static final DataKey FILTER = DataKey.create("Arrangement.Rule.Editor.Settings.Filter"); - public static final DataKey DISPLAY_MANAGER = DataKey.create("Arrangement.Rule.Editor.Display.Manager"); - public static final DataKey SETTINGS = DataKey.create("Arrangement.Rule.Editor.Matcher.Settings"); - public static final DataKey TREE = DataKey.create("Arrangement.Rule.Editor.Tree"); - - private static final EntryTypeHelper ENTRY_TYPE_HELPER = new EntryTypeHelper(); - private static final ModifierHelper MODIFIER_HELPER = new ModifierHelper(); - - private ArrangementSettingsUtil() { - } - - @Nullable - public static ArrangementSettingsNode getSettingsNode(@NotNull DataContext context) { - ArrangementNodeComponent nodeComponent = NODE_COMPONENT.getData(context); - return nodeComponent == null ? null : nodeComponent.getSettingsNode(); - } - - @Nullable - public static HierarchicalArrangementSettingsNode buildTreeStructure(@NotNull ArrangementSettingsNode modelNode) { - // TODO den implement - return new HierarchicalArrangementSettingsNode(modelNode); - } - - /** - * Serves for the same purposes as {@link #buildAvailableOptions(ArrangementStandardSettingsAware, ArrangementMatcherSettings)} but - * retrieves necessary information from the given context. - * - * @param context target information holder - * @return map which contains information on what new new settings are available at the current situation - */ - @NotNull - public static Map> buildAvailableOptions(@NotNull DataContext context) { - ArrangementStandardSettingsAware filter = FILTER.getData(context); - if (filter == null) { - return Collections.emptyMap(); - } - - return buildAvailableOptions(filter, SETTINGS.getData(context)); - } - - /** - * Allows to answer what new settings are available for a particular {@link ArrangementMatcherSettings arrangement matcher rules}. - * - * @param filter filter to use - * @param settings object that encapsulates information about current arrangement matcher settings - * @return map which contains information on what new new settings are available at the current situation - */ - @NotNull - public static Map> buildAvailableOptions(@NotNull ArrangementStandardSettingsAware filter, - @Nullable ArrangementMatcherSettings settings) - { - Map> result = new EnumMap>(ArrangementSettingType.class); - processData(filter, settings, result, ArrangementEntryType.values(), ENTRY_TYPE_HELPER); - processData(filter, settings, result, ArrangementModifier.values(), MODIFIER_HELPER); - return result; - } - - private static void processData(@NotNull ArrangementStandardSettingsAware filter, - @Nullable ArrangementMatcherSettings settings, - Map> result, - @NotNull T[] values, - @NotNull Helper helper) - { - List data = null; - for (T v : values) { - if (!helper.isEnabled(v, filter, settings)) { - continue; - } - if (data == null) { - data = new ArrayList(); - } - data.add(v); - } - if (data != null) { - result.put(helper.getType(), data); - } - } - - @Nullable - public static Point getLocationOnScreen(@NotNull JComponent component) { - int dx = 0; - int dy = 0; - for (Container c = component; c != null; c = c.getParent()) { - if (c.isShowing()) { - Point locationOnScreen = c.getLocationOnScreen(); - locationOnScreen.translate(dx, dy); - return locationOnScreen; - } - else { - Point location = c.getLocation(); - dx += location.x; - dy += location.y; - } - } - return null; - } - - private interface Helper { - @NotNull ArrangementSettingType getType(); - boolean isEnabled(@NotNull T data, @NotNull ArrangementStandardSettingsAware filter, @Nullable ArrangementMatcherSettings settings); - } - - private static class EntryTypeHelper implements Helper { - @NotNull - @Override - public ArrangementSettingType getType() { - return ArrangementSettingType.TYPE; - } - - @Override - public boolean isEnabled(@NotNull ArrangementEntryType data, - @NotNull ArrangementStandardSettingsAware filter, - @Nullable ArrangementMatcherSettings settings) - { - return filter.isEnabled(data, settings); - } - } - - private static class ModifierHelper implements Helper { - @NotNull - @Override - public ArrangementSettingType getType() { - return ArrangementSettingType.MODIFIER; - } - - @Override - public boolean isEnabled(@NotNull ArrangementModifier data, - @NotNull ArrangementStandardSettingsAware filter, - @Nullable ArrangementMatcherSettings settings) - { - return filter.isEnabled(data, settings); - } - } -}