IDEA-19061 Integrate the Rearranger-plugin into core-IDEA

New rule editing approach is applied
This commit is contained in:
Denis.Zhdanov
2012-08-15 09:29:13 +04:00
parent 5f0fdf27c7
commit 77637b9e27
21 changed files with 541 additions and 465 deletions
@@ -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());
}
}
@@ -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}.
* <p/>
* Not thread-safe.
*
@@ -34,37 +36,57 @@ import java.util.Set;
*/
public class ArrangementMatcherSettings implements Cloneable {
@NotNull private final Set<ArrangementModifier> 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<ArrangementSettingsNode> myConditions = new ArrayList<ArrangementSettingsNode>();
@NotNull private final Set<Object> myValues = new HashSet<Object>();
@NotNull private final ArrangementSettingsNodeVisitor myAddVisitor = new MyAddVisitor();
@NotNull private final ArrangementSettingsNodeVisitor myRemoveVisitor = new MyRemoveVisitor();
@NotNull
public Set<ArrangementModifier> getModifiers() {
return myModifiers;
public List<ArrangementSettingsNode> 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) {
}
}
}
@@ -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);
}
+1
View File
@@ -25,6 +25,7 @@
<orderEntry type="library" name="Snappy-Java" level="project" />
<orderEntry type="module" module-name="projectModel-impl" exported="" />
<orderEntry type="library" scope="TEST" name="Groovy" level="project" />
<orderEntry type="library" name="swingx" level="project" />
</component>
</module>
@@ -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;
}
@@ -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.
* <p/>
* 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();
@@ -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();
}
@@ -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}.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 8/14/12 9:54 AM
*/
public class ArrangementMatcherRuleEditor extends JPanel {
@NotNull private final Map<Object, ArrangementAtomNodeComponent> myComponents = new HashMap<Object, ArrangementAtomNodeComponent>();
@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<ArrangementSettingType,List<?>> supportedSettings = ArrangementSettingsUtil.buildAvailableOptions(myFilter, null);
addRowIfPossible(ArrangementSettingType.TYPE, supportedSettings, displayManager);
addRowIfPossible(ArrangementSettingType.MODIFIER, supportedSettings, displayManager);
}
private void addRowIfPossible(@NotNull ArrangementSettingType key,
@NotNull Map<ArrangementSettingType, List<?>> 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);
}
}
}
@@ -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);
}
@@ -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<ArrangementSettingType> myMaxWidths = new TObjectIntHashMap<ArrangementSettingType>();
@NotNull private final TObjectIntHashMap<ArrangementSettingType> myMaxWidths = new TObjectIntHashMap<ArrangementSettingType>();
public ArrangementNodeDisplayManager(@NotNull ArrangementStandardSettingsAware filter) {
Map<ArrangementSettingType, List<?>> 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 <T> id type
* @return sorted ids to use (the given list)
*/
@NotNull
public <T> List<T> sort(@NotNull List<T> ids) {
// TODO den implement
return ids;
}
}
@@ -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<ArrangementNodeComponent> myRenderers = new TIntObjectHashMap<ArrangementNodeComponent>();
@NotNull private final List<ArrangementMatcherEditingListener> myListeners = new ArrayList<ArrangementMatcherEditingListener>();
@NotNull private final TreeSelectionModel mySelectionModel = new MySelectionModel();
@NotNull private final TIntObjectHashMap<ArrangementNodeComponent> myRenderers = new TIntObjectHashMap<ArrangementNodeComponent>();
@NotNull private final TIntObjectHashMap<ArrangementMatcherSettings> mySettings =
new TIntObjectHashMap<ArrangementMatcherSettings>();
@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<ArrangementSettingsNode> children = new ArrayList<ArrangementSettingsNode>();
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<HierarchicalArrangementSettingsNode> 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<ArrangementNodeComponent>() {
@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());
}
}
}
}
@@ -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");
}
}
@@ -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<ArrangementSettingType, List<?>> 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<Balloon> balloonRef = new Ref<Balloon>();
ArrangementSettingsNode node = ArrangementSettingsUtil.getSettingsNode(e.getDataContext());
Consumer<ArrangementSettingsAtomNode> consumer = new Consumer<ArrangementSettingsAtomNode>() {
@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);
}
}
}
@@ -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.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 8/13/12 4:15 PM
*/
public class ArrangementAtomEditor extends JPanel {
@NotNull private final Map<Object, Object> myValues = new HashMap<Object, Object>();
@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;
}
}
@@ -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<String, ArrangementAtomEditor> myEditors = new HashMap<String, ArrangementAtomEditor>();
@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<ArrangementSettingType, List<?>> settings,
@NotNull final Consumer<ArrangementSettingsAtomNode> 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<ArrangementSettingType>() {
@Override
public int compare(ArrangementSettingType o1, ArrangementSettingType o2) {
return myDisplayManager.getDisplayValue(o1).compareTo(myDisplayManager.getDisplayValue(o2));
}
});
final Map<Object, ArrangementSettingType> uiText2Type = new HashMap<Object, ArrangementSettingType>();
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<ArrangementSettingType, List<?>> entry : settings.entrySet()) {
List<String> values = new ArrayList<String>();
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;
}
}
@@ -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;
}
@@ -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
@@ -809,9 +809,7 @@
</group>
<group id="Arrangement.RuleEditor.Context.Menu">
<action id="Arrangement.AddNode"
class="com.intellij.application.options.codeStyle.arrangement.action.ArrangementAddAndConditionAction"
icon="AllIcons.General.Add"/>
<!--TODO den implement-->
</group>
</actions>
@@ -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();
}
@@ -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 {
@@ -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;