From 77637b9e27a912b1575cecb496bc4ec2dcccbac7 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Wed, 15 Aug 2012 09:29:13 +0400 Subject: [PATCH] IDEA-19061 Integrate the Rearranger-plugin into core-IDEA New rule editing approach is applied --- .../model/ArrangementSettingsAtomNode.java | 44 +++- .../settings/ArrangementMatcherSettings.java | 76 ++++--- .../ArrangementStandardSettingsAware.java | 10 +- platform/lang-impl/lang-impl.iml | 1 + .../ArrangementAndNodeComponent.java | 9 +- .../ArrangementAtomNodeComponent.java | 45 +++- .../ArrangementMatcherEditingListener.java | 30 +++ .../ArrangementMatcherRuleEditor.java | 110 +++++++++ .../arrangement/ArrangementNodeComponent.java | 9 +- .../ArrangementNodeDisplayManager.java | 30 ++- .../arrangement/ArrangementRuleTree.java | 214 ++++++++++++++---- .../arrangement/ArrangementSettingsPanel.java | 31 ++- .../ArrangementAddAndConditionAction.java | 99 -------- .../editor/ArrangementAtomEditor.java | 99 -------- .../editor/ArrangementNodeEditor.java | 157 ------------- .../com/intellij/ui/treeStructure/Tree.java | 6 +- .../src/messages/ApplicationBundle.properties | 7 +- .../src/idea/LangActions.xml | 4 +- .../openapi/util/text/StringUtil.java | 2 +- .../intellij/util}/ui/MultiRowFlowPanel.java | 22 +- .../gradle/ui/RichTextControlBuilder.java | 1 + 21 files changed, 541 insertions(+), 465 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherEditingListener.java create mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherRuleEditor.java delete mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/ArrangementAddAndConditionAction.java delete mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementAtomEditor.java delete mode 100644 platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementNodeEditor.java rename {plugins/gradle/src/org/jetbrains/plugins/gradle => platform/util/src/com/intellij/util}/ui/MultiRowFlowPanel.java (82%) 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 0dcb683fe0c5..fd5c4a7515bc 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 @@ -27,6 +27,8 @@ public class ArrangementSettingsAtomNode implements ArrangementSettingsNode { @NotNull private final ArrangementSettingType myType; @NotNull private final Object myValue; + + private boolean myInverted; public ArrangementSettingsAtomNode(@NotNull ArrangementSettingType type, @NotNull Object value) { myType = type; @@ -48,8 +50,48 @@ public class ArrangementSettingsAtomNode implements ArrangementSettingsNode { visitor.visit(this); } + public boolean isInverted() { + return myInverted; + } + + public void setInverted(boolean inverted) { + myInverted = inverted; + } + + @Override + public int hashCode() { + int result = myType.hashCode(); + result = 31 * result + myValue.hashCode(); + result = 31 * result + (myInverted ? 1 : 0); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ArrangementSettingsAtomNode node = (ArrangementSettingsAtomNode)o; + + if (myInverted != node.myInverted) { + return false; + } + if (myType != node.myType) { + return false; + } + if (!myValue.equals(node.myValue)) { + return false; + } + + return true; + } + @Override public String toString() { - return myType + ": " + myValue; + return String.format("%s: %s%s", myType.toString().toLowerCase(), myInverted ? "not " : "", myValue.toString().toLowerCase()); } } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementMatcherSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementMatcherSettings.java index 76ae26ceb07f..7b961b80883e 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementMatcherSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/settings/ArrangementMatcherSettings.java @@ -15,17 +15,19 @@ */ package com.intellij.psi.codeStyle.arrangement.settings; -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.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 com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.EnumSet; +import java.util.ArrayList; +import java.util.List; import java.util.Set; /** - * Encapsulates information about {@link ArrangementEntryMatcher standard arrangement match rule settings}. + * Encapsulates information about {@link ArrangementSettingsNode standard arrangement match rule settings}. *

* Not thread-safe. * @@ -34,37 +36,57 @@ import java.util.Set; */ public class ArrangementMatcherSettings implements Cloneable { - @NotNull private final Set myModifiers = EnumSet.noneOf(ArrangementModifier.class); - - @Nullable private ArrangementEntryType myType; - - @Nullable - public ArrangementEntryType getType() { - return myType; - } - - public void setType(@Nullable ArrangementEntryType type) { - myType = type; - } + @NotNull private final List myConditions = new ArrayList(); + @NotNull private final Set myValues = new HashSet(); + @NotNull private final ArrangementSettingsNodeVisitor myAddVisitor = new MyAddVisitor(); + @NotNull private final ArrangementSettingsNodeVisitor myRemoveVisitor = new MyRemoveVisitor(); @NotNull - public Set getModifiers() { - return myModifiers; + public List getConditions() { + return myConditions; } - public boolean addModifier(@NotNull ArrangementModifier modifier) { - return myModifiers.add(modifier); + public boolean addCondition(@NotNull ArrangementSettingsNode condition) { + condition.invite(myAddVisitor); + return myConditions.add(condition); } - public boolean removeModifier(@NotNull ArrangementModifier modifier) { - return myModifiers.remove(modifier); + public boolean removeCondition(@NotNull ArrangementSettingsNode condition) { + condition.invite(myRemoveVisitor); + return myConditions.remove(condition); + } + + public boolean hasCondition(@NotNull Object id) { + return myValues.contains(id); } @Override - protected ArrangementMatcherSettings clone() { + public ArrangementMatcherSettings clone() { ArrangementMatcherSettings result = new ArrangementMatcherSettings(); - result.setType(myType); - result.myModifiers.addAll(myModifiers); + result.myConditions.addAll(myConditions); + result.myValues.addAll(myValues); return result; } + + private class MyAddVisitor implements ArrangementSettingsNodeVisitor { + @Override + public void visit(@NotNull ArrangementSettingsAtomNode node) { + myValues.add(node.getValue()); + } + + @Override + public void visit(@NotNull ArrangementSettingsCompositeNode node) { + } + } + + private class MyRemoveVisitor implements ArrangementSettingsNodeVisitor { + @Override + public void visit(@NotNull ArrangementSettingsAtomNode node) { + myValues.remove(node.getValue()); + } + + @Override + public void visit(@NotNull ArrangementSettingsCompositeNode 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 8fccf61c54ff..5daabda09c0b 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 @@ -21,6 +21,8 @@ import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * // TODO den add doc * Strategy that defines what subset of standard arrangement settings can be used during defining arrangement settings. @@ -31,14 +33,14 @@ import org.jetbrains.annotations.Nullable; public interface ArrangementStandardSettingsAware { // TODO den add doc - boolean isNameFilterEnabled(@Nullable ArrangementMatcherSettings settings); + boolean isNameFilterEnabled(@Nullable ArrangementMatcherSettings current); // TODO den add doc - boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings settings); + boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings current); // TODO den add doc - boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings settings); + boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings current); // TODO den add doc - boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings settings); + boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings current); } diff --git a/platform/lang-impl/lang-impl.iml b/platform/lang-impl/lang-impl.iml index 5f1d275f3f40..9a92b659217a 100644 --- a/platform/lang-impl/lang-impl.iml +++ b/platform/lang-impl/lang-impl.iml @@ -25,6 +25,7 @@ + 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 4bb9c18f6460..268fce33c73b 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 @@ -82,7 +82,14 @@ public class ArrangementAndNodeComponent extends JPanel implements ArrangementNo } @Override - public ArrangementNodeComponent getComponentAt(@NotNull RelativePoint point) { + public void setSelected(boolean selected) { + for (ArrangementNodeComponent component : myComponents) { + component.setSelected(selected); + } + } + + @Override + public ArrangementNodeComponent getNodeComponentAt(@NotNull RelativePoint point) { if (myScreenBounds == null) { return null; } 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 c189e98c95bb..fe7306218160 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 @@ -70,6 +70,10 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent { @Nullable private Dimension mySize; @Nullable private Rectangle myScreenBounds; + + private boolean mySelected; + private boolean myEnabled; + private boolean myInverted; public ArrangementAtomNodeComponent(@NotNull ArrangementNodeDisplayManager manager, @NotNull ArrangementSettingsAtomNode node) { mySettingsNode = node; @@ -89,13 +93,7 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent { JPanel roundBorderPanel = new JPanel(new GridBagLayout()) { @Override public void paint(Graphics g) { - Color color; - if (myScreenBounds != null && myScreenBounds.contains(MouseInfo.getPointerInfo().getLocation())) { - color = UIUtil.getTreeSelectionBackground(); - } - else { - color = UIUtil.getTabbedPaneBackground(); - } + Color color = mySelected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTabbedPaneBackground(); Rectangle bounds = getBounds(); g.setColor(color); g.fillRoundRect(0, 0, bounds.width, bounds.height, arcSize, arcSize); @@ -135,10 +133,39 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent { } @Override - public ArrangementNodeComponent getComponentAt(@NotNull RelativePoint point) { + public ArrangementNodeComponent getNodeComponentAt(@NotNull RelativePoint point) { return (myScreenBounds != null && myScreenBounds.contains(point.getScreenPoint())) ? this : null; } - + + /** + * Instructs current component that it should {@link #getUiComponent() draw} itself according to the given 'selected' state. + * + * @param selected flag that indicates if current component should be drawn as 'selected' + */ + public void setSelected(boolean selected) { + mySelected = selected; + } + + /** + * Instructs current component that it should {@link #getUiComponent() draw} itself according to the given 'enabled' state. + * + * @param enabled flag that indicates if current component should be drawn as 'enabled' + */ + public void setEnabled(boolean enabled) { + myEnabled = enabled; + } + + /** + * Instructs current component that it should {@link #getUiComponent() draw} itself according to the given 'inverted' state. + *

+ * For example, target rule might look like 'public' and inverting it produces 'not public'. + * + * @param inverted flag that indicates if current component should be drawn as 'inverted' + */ + public void setInverted(boolean inverted) { + myInverted = inverted; + } + @Override public String toString() { return myLabel.getText(); 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/ArrangementMatcherEditingListener.java new file mode 100644 index 000000000000..83a6dcd6da53 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherEditingListener.java @@ -0,0 +1,30 @@ +/* + * 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.settings.ArrangementMatcherSettings; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 8/15/12 9:14 AM + */ +public interface ArrangementMatcherEditingListener { + + void startEditing(@NotNull ArrangementMatcherSettings settings); + + void stopEditing(); +} 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 new file mode 100644 index 000000000000..7cad4a2bfc4b --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementMatcherRuleEditor.java @@ -0,0 +1,110 @@ +/* + * 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.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; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Control for managing {@link ArrangementEntryMatcher matching rule conditions}. + *

+ * Not thread-safe. + * + * @author Denis Zhdanov + * @since 8/14/12 9:54 AM + */ +public class ArrangementMatcherRuleEditor extends JPanel { + + @NotNull private final Map myComponents = new HashMap(); + + @NotNull private final ArrangementStandardSettingsAware myFilter; + + public ArrangementMatcherRuleEditor(@NotNull ArrangementStandardSettingsAware filter) { + myFilter = filter; + init(); + } + + private void init() { + setLayout(new GridBagLayout()); + + ArrangementNodeDisplayManager displayManager = new ArrangementNodeDisplayManager(myFilter); + Map> supportedSettings = ArrangementSettingsUtil.buildAvailableOptions(myFilter, null); + addRowIfPossible(ArrangementSettingType.TYPE, supportedSettings, displayManager); + addRowIfPossible(ArrangementSettingType.MODIFIER, supportedSettings, displayManager); + } + + private void addRowIfPossible(@NotNull ArrangementSettingType key, + @NotNull Map> supportedSettings, + @NotNull ArrangementNodeDisplayManager manager) + { + List values = supportedSettings.get(key); + if (values == null || values.isEmpty()) { + return; + } + + add(new JLabel(manager.getDisplayLabel(key)), new GridBag().anchor(GridBagConstraints.WEST)); + JPanel valuesPanel = new MultiRowFlowPanel(FlowLayout.LEFT, 8, 5); + for (Object value : manager.sort(values)) { + ArrangementAtomNodeComponent component = new ArrangementAtomNodeComponent(manager, new ArrangementSettingsAtomNode(key, value)); + myComponents.put(value, component); + valuesPanel.add(component.getUiComponent()); + } + add(valuesPanel, new GridBag().anchor(GridBagConstraints.WEST).weightx(1).fillCellHorizontally().coverLine()); + } + + /** + * 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 + */ + public void updateState(@NotNull ArrangementMatcherSettings settings) { + for (ArrangementEntryType type : ArrangementEntryType.values()) { + ArrangementAtomNodeComponent component = myComponents.get(type); + if (component == null) { + continue; + } + boolean enabled = myFilter.isEnabled(type, settings); + boolean selected = settings.hasCondition(type); + component.setEnabled(enabled); + component.setSelected(selected); + } + for (ArrangementModifier modifier : ArrangementModifier.values()) { + ArrangementAtomNodeComponent component = myComponents.get(modifier); + if (component == null) { + continue; + } + boolean enabled = myFilter.isEnabled(modifier, settings); + boolean selected = settings.hasCondition(modifier); + component.setEnabled(enabled); + component.setSelected(selected); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java index d51d710716a9..a28c4bdc837a 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java @@ -40,11 +40,18 @@ public interface ArrangementNodeComponent { // TODO den add doc @Nullable - ArrangementNodeComponent getComponentAt(@NotNull RelativePoint point); + ArrangementNodeComponent getNodeComponentAt(@NotNull RelativePoint point); // TODO den add doc @Nullable Rectangle getScreenBounds(); void setScreenBounds(@Nullable Rectangle bounds); + + /** + * Instructs current component that it should {@link #getUiComponent() draw} itself according to the given 'selected' state. + * + * @param selected flag that indicates if current component should be drawn as 'selected' + */ + void setSelected(boolean selected); } 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 cf3866182ccf..4c9c8f224026 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 @@ -15,6 +15,7 @@ */ package com.intellij.application.options.codeStyle.arrangement; +import com.intellij.openapi.application.ApplicationBundle; import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType; import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware; @@ -34,9 +35,10 @@ import java.util.Map; * @author Denis Zhdanov * @since 8/9/12 3:02 PM */ +@SuppressWarnings("MethodMayBeStatic") public class ArrangementNodeDisplayManager { - private final TObjectIntHashMap myMaxWidths = new TObjectIntHashMap(); + @NotNull private final TObjectIntHashMap myMaxWidths = new TObjectIntHashMap(); public ArrangementNodeDisplayManager(@NotNull ArrangementStandardSettingsAware filter) { Map> map = ArrangementSettingsUtil.buildAvailableOptions(filter, null); @@ -56,19 +58,26 @@ public class ArrangementNodeDisplayManager { return result; } - @SuppressWarnings("MethodMayBeStatic") @NotNull public String getDisplayValue(@NotNull ArrangementSettingsAtomNode node) { return getDisplayValue(node.getValue()); } - @SuppressWarnings("MethodMayBeStatic") + + @NotNull + public String getDisplayLabel(@NotNull ArrangementSettingType type) { + switch (type) { + case TYPE: return ApplicationBundle.message("arrangement.text.type"); + case MODIFIER: return ApplicationBundle.message("arrangement.text.modifier"); + } + return type.toString().toLowerCase(); + } + @NotNull public String getDisplayValue(@NotNull ArrangementSettingType type) { return type.toString().toLowerCase(); } - @SuppressWarnings("MethodMayBeStatic") @NotNull public String getDisplayValue(@NotNull Object value) { return value.toString().toLowerCase(); @@ -77,4 +86,17 @@ public class ArrangementNodeDisplayManager { public int getMaxWidth(@NotNull ArrangementSettingType type) { return myMaxWidths.get(type); } + + /** + * Asks current manager to sort in-place given arrangement condition ids ('field', 'class', 'method', 'public', 'static', 'final' etc). + * + * @param ids target ids to use + * @param id type + * @return sorted ids to use (the given list) + */ + @NotNull + public List sort(@NotNull List ids) { + // TODO den implement + return ids; + } } 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 2b4a05a2aff7..a7bc75689292 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 @@ -20,15 +20,19 @@ import com.intellij.openapi.actionSystem.DataProvider; 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.settings.ArrangementStandardSettingsAware; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.treeStructure.Tree; import gnu.trove.TIntObjectHashMap; +import gnu.trove.TObjectProcedure; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; import javax.swing.tree.*; import java.awt.*; import java.awt.event.MouseAdapter; @@ -42,23 +46,26 @@ import java.util.List; */ public class ArrangementRuleTree { - @NotNull private final TIntObjectHashMap myRenderers = new TIntObjectHashMap(); + @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 DefaultTreeModel myTreeModel; @NotNull private final ArrangementStandardSettingsAware myFilter; @NotNull private final Tree myTree; @NotNull private final ArrangementNodeDisplayManager myDisplayManager; @NotNull private final ArrangementNodeComponentFactory myFactory; - @Nullable private ArrangementNodeComponent myPrevComponentUnderMouse; + private boolean mySkipSelectionChange; public ArrangementRuleTree(@NotNull ArrangementStandardSettingsAware filter) { myFilter = filter; myDisplayManager = new ArrangementNodeDisplayManager(filter); myFactory = new ArrangementNodeComponentFactory(myDisplayManager); DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - myTreeModel = new DefaultTreeModel(root); - myTree = new Tree(myTreeModel) { + DefaultTreeModel treeModel = new DefaultTreeModel(root); + myTree = new Tree(treeModel) { @Override protected void setExpandedState(TreePath path, boolean state) { // Don't allow node collapse @@ -66,23 +73,46 @@ public class ArrangementRuleTree { super.setExpandedState(path, state); } } - }; - // Don't allow row selection as we're interested in particular row nodes. - myTree.setSelectionModel(null); - myTree.addMouseMotionListener(new MouseAdapter() { @Override - public void mouseMoved(MouseEvent e) { - onMouseMoved(e); + protected boolean isAlwaysPaintRowBackground() { + return false; + } + + @Override + protected void processMouseEvent(MouseEvent e) { + // JTree selects a node on mouse click at the same row (even outside the node bounds). We don't want to support + // such selection because selected nodes are highlighted at the rule tree, so, it produces a 'blink' effect. + mySkipSelectionChange = e.getClickCount() > 0 && getNodeComponentAt(e.getLocationOnScreen()) == null; + try { + super.processMouseEvent(e); + if (mySkipSelectionChange) { + notifyEditingListeners(null); + } + } + finally { + mySkipSelectionChange = false; + } + } + }; + myTree.setSelectionModel(mySelectionModel); + mySelectionModel.addTreeSelectionListener(new TreeSelectionListener() { + @Override + public void valueChanged(TreeSelectionEvent e) { + setSelection(e.getOldLeadSelectionPath(), false); + setSelection(e.getNewLeadSelectionPath(), true); + } + }); + myTree.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + onMouseClicked(e); } }); myTree.putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, new DataProvider() { @Override public Object getData(@NonNls String dataId) { - if (ArrangementSettingsUtil.NODE_COMPONENT.is(dataId)) { - return myPrevComponentUnderMouse; - } - else if (ArrangementSettingsUtil.DISPLAY_MANAGER.is(dataId)) { + if (ArrangementSettingsUtil.DISPLAY_MANAGER.is(dataId)) { return myDisplayManager; } else if (ArrangementSettingsUtil.FILTER.is(dataId)) { @@ -95,24 +125,31 @@ public class ArrangementRuleTree { } }); - // TODO den remove - List children = new ArrayList(); - children.add(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC)); - children.add(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.STATIC)); - children.add(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.FINAL)); + 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)); - HierarchicalArrangementSettingsNode settingsNode = new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode( + 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 )); - ArrangementSettingsCompositeNode modifiers = new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND); - for (ArrangementSettingsNode child : children) { - modifiers.addOperand(child); - } - settingsNode.addChild(new HierarchicalArrangementSettingsNode(modifiers)); - //ArrangementSettingsNode node = ArrangementSettingsUtil.buildTreeStructure(settingsNode); - if (settingsNode != null) { - map(root, settingsNode); - } + 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); expandAll(myTree, new TreePath(root)); myTree.setRootVisible(false); @@ -120,6 +157,24 @@ public class ArrangementRuleTree { myTree.setCellRenderer(new MyCellRenderer()); } + private void setSelection(@Nullable final TreePath path, boolean selected) { + if (path == null) { + return; + } + + for (TreePath p = path; p != null; p = p.getParentPath()) { + int row = myTree.getRowForPath(p); + if (row < 0) { + return; + } + ArrangementNodeComponent component = myRenderers.get(row); + if (component != null) { + component.setSelected(selected); + repaintComponent(component); + } + } + } + private static void expandAll(Tree tree, TreePath parent) { // Traverse children TreeNode node = (TreeNode)parent.getLastPathComponent(); @@ -135,12 +190,50 @@ public class ArrangementRuleTree { tree.expandPath(parent); } - private static void map(@NotNull DefaultMutableTreeNode parentTreeNode, @NotNull HierarchicalArrangementSettingsNode settingsNode) { + private int map(@NotNull DefaultMutableTreeNode parentTreeNode, + @NotNull HierarchicalArrangementSettingsNode settingsNode, + @Nullable ArrangementMatcherSettings template, + int row) + { DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(settingsNode.getCurrent()); parentTreeNode.add(childTreeNode); - for (HierarchicalArrangementSettingsNode node : settingsNode.getChildren()) { - map(childTreeNode, node); + List children = settingsNode.getChildren(); + ArrangementMatcherSettings settings = template == null ? new ArrangementMatcherSettings() : template.clone(); + settings.addCondition(settingsNode.getCurrent()); + if (children.isEmpty()) { + mySettings.put(row, settings); + return row + 1; } + else { + row++; + for (HierarchicalArrangementSettingsNode node : children) { + row = map(childTreeNode, node, settings, row); + } + return row; + } + } + + public void addEditingListener(@NotNull ArrangementMatcherEditingListener listener) { + myListeners.add(listener); + } + + /** + * @return matcher settings for the selected tree row(s) if any; null otherwise + */ + @Nullable + public ArrangementMatcherSettings getActiveSettings() { + TreePath[] paths = mySelectionModel.getSelectionPaths(); + if (paths == null) { + return null; + } + 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; + } + } + return null; } @NotNull @@ -149,7 +242,7 @@ public class ArrangementRuleTree { } @NotNull - private ArrangementNodeComponent getComponent(int row, @NotNull ArrangementSettingsNode node) { + private ArrangementNodeComponent getNodeComponentAt(int row, @NotNull ArrangementSettingsNode node) { ArrangementNodeComponent result = myRenderers.get(row); if (result == null) { myRenderers.put(row, result = myFactory.getComponent(node)); @@ -157,22 +250,25 @@ public class ArrangementRuleTree { return result; } - private void onMouseMoved(@NotNull MouseEvent e) { - ArrangementNodeComponent component = getComponent(e.getLocationOnScreen()); - if (component == myPrevComponentUnderMouse) { + private void onMouseClicked(@NotNull MouseEvent e) { + ArrangementNodeComponent component = getNodeComponentAt(e.getLocationOnScreen()); + if (component != null) { return; } - if (myPrevComponentUnderMouse != null) { - repaintComponent(myPrevComponentUnderMouse); - } - if (component != null) { - repaintComponent(component); - } - myPrevComponentUnderMouse = component; + // Clear selection + mySelectionModel.clearSelection(); + myRenderers.forEachValue(new TObjectProcedure() { + @Override + public boolean execute(ArrangementNodeComponent node) { + node.setSelected(false); + return true; + } + }); + myTree.repaint(); } - + @Nullable - private ArrangementNodeComponent getComponent(Point screenLocation) { + private ArrangementNodeComponent getNodeComponentAt(Point screenLocation) { int low = 0; int high = myTree.getRowCount() - 1; @@ -187,7 +283,7 @@ public class ArrangementRuleTree { return null; } if (bounds.contains(screenLocation)) { - return midVal.getComponentAt(RelativePoint.fromScreen(screenLocation)); + return midVal.getNodeComponentAt(RelativePoint.fromScreen(screenLocation)); } else if (bounds.y > screenLocation.y) { high = mid - 1; @@ -211,6 +307,17 @@ public class ArrangementRuleTree { } } + private void notifyEditingListeners(@Nullable ArrangementMatcherSettings settings) { + for (ArrangementMatcherEditingListener listener : myListeners) { + if (settings == null) { + listener.stopEditing(); + } + else { + listener.startEditing(settings); + } + } + } + private class MyCellRenderer implements TreeCellRenderer { @Override public Component getTreeCellRendererComponent(JTree tree, @@ -222,7 +329,18 @@ public class ArrangementRuleTree { boolean hasFocus) { ArrangementSettingsNode node = (ArrangementSettingsNode)((DefaultMutableTreeNode)value).getUserObject(); - return getComponent(row, node).getUiComponent(); + return getNodeComponentAt(row, node).getUiComponent(); + } + } + + private class MySelectionModel extends DefaultTreeSelectionModel { + + @Override + public void setSelectionPath(TreePath path) { + if (!mySkipSelectionChange) { + super.setSelectionPath(path); + notifyEditingListeners(getActiveSettings()); + } } } } 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 01d9aedcdadc..ad0eb1c52780 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 @@ -21,12 +21,17 @@ import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.highlighter.EditorHighlighter; 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.ui.components.JBScrollPane; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.ui.GridBag; +import org.jdesktop.swingx.JXTaskPane; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; import java.awt.*; /** @@ -41,11 +46,31 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { public ArrangementSettingsPanel(@NotNull CodeStyleSettings settings, @NotNull ArrangementStandardSettingsAware filter) { super(settings); - Tree component = new ArrangementRuleTree(filter).getTreeComponent(); - myContent.add(component, new GridBag().weightx(1).weighty(1).fillCell()); + final ArrangementRuleTree ruleTree = new ArrangementRuleTree(filter); + Tree component = ruleTree.getTreeComponent(); + myContent.add(new JBScrollPane(component), new GridBag().weightx(1).weighty(1).fillCell().coverLine()); CustomizationUtil.installPopupHandler( component, ArrangementConstants.ACTION_GROUP_RULE_EDITOR_CONTEXT_MENU, ArrangementConstants.RULE_EDITOR_PLACE ); + + final JXTaskPane editorPane = new JXTaskPane(ApplicationBundle.message("arrangement.title.editor")); + final ArrangementMatcherRuleEditor ruleEditor = new ArrangementMatcherRuleEditor(filter); + editorPane.add(ruleEditor); + editorPane.setCollapsed(true); + myContent.add(editorPane, new GridBag().weightx(1).fillCellHorizontally().coverLine()); + + ruleTree.addEditingListener(new ArrangementMatcherEditingListener() { + @Override + public void startEditing(@NotNull ArrangementMatcherSettings settings) { + ruleEditor.updateState(settings); + editorPane.setCollapsed(false); + } + + @Override + public void stopEditing() { + editorPane.setCollapsed(true); + } + }); } @Override @@ -77,6 +102,6 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { @Override protected String getTabTitle() { - return ApplicationBundle.message("tab.title.arrangement"); + return ApplicationBundle.message("arrangement.title.settings.tab"); } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/ArrangementAddAndConditionAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/ArrangementAddAndConditionAction.java deleted file mode 100644 index d12fe36e92e0..000000000000 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/ArrangementAddAndConditionAction.java +++ /dev/null @@ -1,99 +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.action; - -import com.intellij.application.options.codeStyle.arrangement.ArrangementNodeDisplayManager; -import com.intellij.application.options.codeStyle.arrangement.ArrangementSettingsUtil; -import com.intellij.application.options.codeStyle.arrangement.editor.ArrangementNodeEditor; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.Ref; -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 com.intellij.ui.awt.RelativePoint; -import com.intellij.util.Consumer; - -import javax.swing.*; -import java.awt.*; -import java.util.List; -import java.util.Map; - -/** - * @author Denis Zhdanov - * @since 8/13/12 11:52 AM - */ -public class ArrangementAddAndConditionAction extends AnAction { - - public ArrangementAddAndConditionAction() { - getTemplatePresentation().setText(ApplicationBundle.message("arrangement.action.add.and.node.text")); - getTemplatePresentation().setDescription(ApplicationBundle.message("arrangement.action.add.and.node.description")); - } - - @Override - public void actionPerformed(AnActionEvent e) { - Map> availableSettings = ArrangementSettingsUtil.buildAvailableOptions(e.getDataContext()); - if (availableSettings.isEmpty()) { - return; - } - ArrangementNodeDisplayManager displayManager = ArrangementSettingsUtil.DISPLAY_MANAGER.getData(e.getDataContext()); - if (displayManager == null) { - return; - } - - Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); - if (project == null) { - return; - } - - JComponent tree = ArrangementSettingsUtil.TREE.getData(e.getDataContext()); - if (tree == null) { - return; - } - - final Ref balloonRef = new Ref(); - ArrangementSettingsNode node = ArrangementSettingsUtil.getSettingsNode(e.getDataContext()); - Consumer consumer = new Consumer() { - @Override - public void consume(ArrangementSettingsAtomNode node) { - // TODO den implement - Balloon balloon = balloonRef.get(); - if (balloon != null) { - balloon.hide(); - } - } - }; - - if (node == null) { - // TODO den implement - } - else { - ArrangementNodeEditor editor = new ArrangementNodeEditor(displayManager, availableSettings, consumer); - editor.applyColorsFrom(tree); - Balloon balloon = JBPopupFactory.getInstance().createBalloonBuilder(editor).setDisposable(project).setHideOnClickOutside(true) - .setFillColor(tree.getBackground()).createBalloon(); - balloonRef.set(balloon); - Point point = MouseInfo.getPointerInfo().getLocation(); - SwingUtilities.convertPointFromScreen(point, tree); - balloon.show(new RelativePoint(tree, point), Balloon.Position.below); - } - } -} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementAtomEditor.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementAtomEditor.java deleted file mode 100644 index 0b469bf582ff..000000000000 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementAtomEditor.java +++ /dev/null @@ -1,99 +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.editor; - -import com.intellij.application.options.codeStyle.arrangement.ArrangementNodeDisplayManager; -import com.intellij.util.ui.GridBag; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * Editor for choosing a single value from a set of predefined values. - *

- * Not thread-safe. - * - * @author Denis Zhdanov - * @since 8/13/12 4:15 PM - */ -public class ArrangementAtomEditor extends JPanel { - - @NotNull private final Map myValues = new HashMap(); - - @NotNull private final Dimension myPrefSize; - @NotNull private final JComboBox myValueBox; - - public ArrangementAtomEditor(@NotNull Collection values, @NotNull ArrangementNodeDisplayManager manager) { - String[] uiValues = new String[values.size()]; - int i = 0; - for (Object value : values) { - String uiValue = manager.getDisplayValue(value); - uiValues[i++] = uiValue; - myValues.put(uiValue, value); - } - Arrays.sort(uiValues); - myValueBox = new JComboBox(uiValues); - setLayout(new GridBagLayout()); - add(myValueBox, new GridBag().anchor(GridBagConstraints.CENTER).weightx(1).fillCellHorizontally()); - - FontMetrics metrics = myValueBox.getFontMetrics(myValueBox.getFont()); - int maxWidth = 0; - String widestText = null; - for (String value : uiValues) { - int width = metrics.stringWidth(value); - if (width > maxWidth) { - widestText = value; - maxWidth = width; - } - } - if (widestText != null) { - myValueBox.setSelectedItem(widestText); - } - myPrefSize = super.getPreferredSize(); - if (uiValues.length > 0) { - myValueBox.setSelectedItem(uiValues[0]); - } - } - - @NotNull - public Object getValue() { - return myValues.get(myValueBox.getSelectedItem()); - } - - public void applyColorsFrom(@NotNull JComponent component) { - myValueBox.setBackground(component.getBackground()); - } - - @Override - public Dimension getMinimumSize() { - return getPreferredSize(); - } - - @Override - public Dimension getMaximumSize() { - return getPreferredSize(); - } - - @Override - public Dimension getPreferredSize() { - return myPrefSize; - } -} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementNodeEditor.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementNodeEditor.java deleted file mode 100644 index 13269c7fa63c..000000000000 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/editor/ArrangementNodeEditor.java +++ /dev/null @@ -1,157 +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.editor; - -import com.intellij.application.options.codeStyle.arrangement.ArrangementNodeDisplayManager; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType; -import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.util.Consumer; -import com.intellij.util.ui.GridBag; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.*; -import java.util.List; - -/** - * // TODO den add doc - * - * @author Denis Zhdanov - * @since 8/13/12 12:33 PM - */ -public class ArrangementNodeEditor extends JPanel { - - @NotNull private final CardLayout myCardLayout = new CardLayout(); - @NotNull private final JPanel myValuePanel = new JPanel(myCardLayout); - @NotNull private final Map myEditors = new HashMap(); - - @NotNull private final ArrangementNodeDisplayManager myDisplayManager; - @NotNull private final JComboBox myTypeComboBox; - @NotNull private final JCheckBox myNegateCheckBox; - @NotNull private final Dimension myPrefSize; - @NotNull private String myCurrentCard; - - public ArrangementNodeEditor(@NotNull ArrangementNodeDisplayManager manager, - @NotNull Map> settings, - @NotNull final Consumer resultProcessor) - { - myDisplayManager = manager; - - setOpaque(false); - setBorder(IdeBorderFactory.createEmptyBorder(0, 8, 0, 8)); - setLayout(new GridBagLayout()); - - myTypeComboBox = new JComboBox(); - ArrangementSettingType[] types = settings.keySet().toArray(new ArrangementSettingType[settings.size()]); - Arrays.sort(types, new Comparator() { - @Override - public int compare(ArrangementSettingType o1, ArrangementSettingType o2) { - return myDisplayManager.getDisplayValue(o1).compareTo(myDisplayManager.getDisplayValue(o2)); - } - }); - - final Map uiText2Type = new HashMap(); - for (ArrangementSettingType type : types) { - String displayValue = myDisplayManager.getDisplayValue(type); - uiText2Type.put(displayValue, type); - myTypeComboBox.addItem(displayValue); - } - myTypeComboBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - myCardLayout.show(myValuePanel, myCurrentCard = e.getItem().toString()); - } - } - }); - add(myTypeComboBox, new GridBag().insets(0, 3, 0, 0)); - - int maxWidth = 0; - String widestCardName = null; - for (Map.Entry> entry : settings.entrySet()) { - List values = new ArrayList(); - for (Object o : entry.getValue()) { - values.add(myDisplayManager.getDisplayValue(o)); - Collections.sort(values); - } - ArrangementAtomEditor atomEditor = new ArrangementAtomEditor(values, manager); - String cardName = myDisplayManager.getDisplayValue(entry.getKey()); - myEditors.put(cardName, atomEditor); - myValuePanel.add(atomEditor, cardName); - Dimension size = atomEditor.getPreferredSize(); - if (maxWidth < size.width) { - widestCardName = cardName; - maxWidth = size.width; - } - } - add(myValuePanel, new GridBag().insets(0, 8, 0, 0).fillCellHorizontally().weightx(1).coverLine()); - - myNegateCheckBox = new JCheckBox(ApplicationBundle.message("arrangement.text.negate")); - add(myNegateCheckBox, new GridBag().insets(0, 0, 0, 0).anchor(GridBagConstraints.WEST).coverLine()); - - JButton okButton = new JButton(AllIcons.Actions.Checked); - okButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ArrangementSettingType type = uiText2Type.get(myTypeComboBox.getSelectedItem()); - Object value = myEditors.get(myCurrentCard).getValue(); - resultProcessor.consume(new ArrangementSettingsAtomNode(type, value)); - } - }); - add(okButton, new GridBag().insets(0, 3, 0, 0).weightx(1).fillCellHorizontally().coverLine()); - - if (widestCardName != null) { - myCardLayout.show(myValuePanel, widestCardName); - myPrefSize = super.getPreferredSize(); - } - else { - myPrefSize = super.getPreferredSize(); - } - - myCardLayout.show(myValuePanel, myCurrentCard = myTypeComboBox.getSelectedItem().toString()); - } - - public void applyColorsFrom(@NotNull JComponent component) { - myTypeComboBox.setBackground(component.getBackground()); - myNegateCheckBox.setBackground(component.getBackground()); - for (ArrangementAtomEditor editor : myEditors.values()) { - editor.applyColorsFrom(component); - } - } - - @Override - public Dimension getMinimumSize() { - return getPreferredSize(); - } - - @Override - public Dimension getMaximumSize() { - return getPreferredSize(); - } - - @Override - public Dimension getPreferredSize() { - return myPrefSize; - } -} diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java index eacc8688fae9..585b492605bd 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java @@ -97,7 +97,7 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith TreeUI actualUI = ui; if (!isCustomUI()) { if (!(ui instanceof WideSelectionTreeUI) && isWideSelection() && !UIUtil.isUnderGTKLookAndFeel()) { - actualUI = new WideSelectionTreeUI(isWideSelection(), !SystemInfo.isMac); + actualUI = new WideSelectionTreeUI(isWideSelection(), isAlwaysPaintRowBackground()); } } super.setUI(actualUI); @@ -140,6 +140,10 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith return true; } + protected boolean isAlwaysPaintRowBackground() { + return !SystemInfo.isMac; + } + public boolean isFileColorsEnabled() { return false; } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index bffd09387de9..949af09c749f 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -550,7 +550,8 @@ desktop.entry.sudo.prompt=Please enter your password to create a desktop entry title.tabs.and.indents=Tabs and Indents # Arrangement -tab.title.arrangement=Arrangement -arrangement.action.add.and.node.text=And -arrangement.action.add.and.node.description=Add 'and' condition +arrangement.title.settings.tab=Arrangement +arrangement.title.editor=Edit rule +arrangement.text.type=Type +arrangement.text.modifier=Modifier arrangement.text.negate=Negate \ No newline at end of file diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 9effb8f41cc9..dd54d46380c3 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -809,9 +809,7 @@ - + diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 30efe25dfb5d..87f0caef6ebf 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -1169,7 +1169,7 @@ public class StringUtil extends StringUtilRt { result.append(item).append(separator); } if (result.length() > 0) { - result.setLength(result.length() - 1); + result.setLength(result.length() - separator.length()); } return result.toString(); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/MultiRowFlowPanel.java b/platform/util/src/com/intellij/util/ui/MultiRowFlowPanel.java similarity index 82% rename from plugins/gradle/src/org/jetbrains/plugins/gradle/ui/MultiRowFlowPanel.java rename to platform/util/src/com/intellij/util/ui/MultiRowFlowPanel.java index 466c9ace9305..5c9cf93394a2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/MultiRowFlowPanel.java +++ b/platform/util/src/com/intellij/util/ui/MultiRowFlowPanel.java @@ -1,6 +1,20 @@ -package org.jetbrains.plugins.gradle.ui; +/* + * 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.util.ui; -import com.intellij.util.ui.UIUtil; import org.intellij.lang.annotations.JdkConstants; import javax.swing.*; @@ -14,8 +28,8 @@ import java.awt.*; * and calculates the height. If the user has an ability to manually change panel size (e.g. indirectly via changing * size of the dialog that serves as a container for the panel), that width is used as a maximum width. * - * @author: Denis Zhdanov - * @since: Jul 28, 2008 + * @author Denis Zhdanov + * @since Jul 28, 2008 */ public class MultiRowFlowPanel extends JPanel { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/RichTextControlBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/RichTextControlBuilder.java index cc3371b08d91..c8378ff9c0bf 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/RichTextControlBuilder.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/RichTextControlBuilder.java @@ -1,6 +1,7 @@ package org.jetbrains.plugins.gradle.ui; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ui.MultiRowFlowPanel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable;