diff options
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java')
-rw-r--r-- | platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java | 305 |
1 files changed, 145 insertions, 160 deletions
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java index e10367d583bf..817a042c9bc9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java @@ -20,7 +20,7 @@ import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.openapi.Disposable; import com.intellij.openapi.options.*; import com.intellij.openapi.options.ex.ConfigurableWrapper; -import com.intellij.openapi.options.ex.NodeConfigurable; +import com.intellij.openapi.options.ex.SortedConfigurableGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; @@ -49,6 +49,7 @@ import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.plaf.TreeUI; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import java.awt.*; @@ -63,6 +64,7 @@ import java.util.List; * @author Sergey.Malenkov */ final class SettingsTreeView extends JComponent implements Disposable, OptionsEditorColleague { + private static final String NODE_ICON = "settings.tree.view.icon"; private static final Color NORMAL_NODE = new JBColor(Gray._60, Gray._140); private static final Color WRONG_CONTENT = JBColor.RED; private static final Color MODIFIED_CONTENT = JBColor.BLUE; @@ -74,8 +76,9 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd private final MyRoot myRoot; private final JScrollPane myScroller; private JLabel mySeparator; - private final MyRenderer myRenderer = new MyRenderer(); private final IdentityHashMap<Configurable, MyNode> myConfigurableToNodeMap = new IdentityHashMap<Configurable, MyNode>(); + private final IdentityHashMap<UnnamedConfigurable, ConfigurableWrapper> myConfigurableToWrapperMap + = new IdentityHashMap<UnnamedConfigurable, ConfigurableWrapper>(); private final MergingUpdateQueue myQueue = new MergingUpdateQueue("SettingsTreeView", 150, false, this, this, this) .setRestartTimerOnAdd(true); @@ -96,9 +99,10 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd myTree.setRowHeight(-1); myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - myTree.setCellRenderer(myRenderer); + myTree.setCellRenderer(new MyRenderer()); myTree.setRootVisible(false); myTree.setShowsRootHandles(false); + myTree.setExpandableItemsEnabled(false); myScroller = ScrollPaneFactory.createScrollPane(myTree, true); myScroller.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent()); @@ -139,7 +143,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd @NotNull String[] getPathNames(Configurable configurable) { ArrayDeque<String> path = new ArrayDeque<String>(); - MyNode node = myConfigurableToNodeMap.get(configurable); + MyNode node = findNode(configurable); while (node != null) { path.push(node.myDisplayName); SimpleNode parent = node.getParent(); @@ -157,8 +161,9 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } @Nullable - SimpleNode findNode(Configurable configurable) { - return myConfigurableToNodeMap.get(configurable); + MyNode findNode(Configurable configurable) { + ConfigurableWrapper wrapper = myConfigurableToWrapperMap.get(configurable); + return myConfigurableToNodeMap.get(wrapper != null ? wrapper : configurable); } @Nullable @@ -180,6 +185,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd if (configurable instanceof ConfigurableWrapper) { ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable; configurable = wrapper.getConfigurable(); + myConfigurableToWrapperMap.put(configurable, wrapper); } if (type.isInstance(configurable)) { return type.cast(configurable); @@ -194,7 +200,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable; return wrapper.getExtensionPoint().getProject(); } - return findConfigurableProject(myConfigurableToNodeMap.get(configurable)); + return findConfigurableProject(findNode(configurable)); } @Nullable @@ -214,15 +220,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } @Nullable - private ConfigurableGroup findConfigurableGroupAt(int x, int y) { + private String findGroupNameAt(int x, int y) { TreePath path = myTree.getClosestPathForLocation(x - myTree.getX(), y - myTree.getY()); while (path != null) { MyNode node = extractNode(path); if (node == null) { return null; } - if (node.myComposite instanceof ConfigurableGroup) { - return (ConfigurableGroup)node.myComposite; + if (myRoot == node.getParent()) { + return node.myDisplayName; } path = path.getParentPath(); } @@ -267,10 +273,10 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd mySeparator.setFont(getFont().deriveFont(Font.BOLD)); } int height = mySeparator.getPreferredSize().height; - ConfigurableGroup group = findConfigurableGroupAt(0, height); - if (group != null && group == findConfigurableGroupAt(0, -myRenderer.getSeparatorHeight())) { + String group = findGroupNameAt(0, height); + if (group != null && group.equals(findGroupNameAt(0, 0))) { mySeparator.setBorder(BorderFactory.createEmptyBorder(0, 18, 0, 0)); - mySeparator.setText(group.getDisplayName()); + mySeparator.setText(group); Rectangle bounds = myScroller.getViewport().getBounds(); if (bounds.height > height) { @@ -319,7 +325,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd public void run() { if (configurable != myQueuedConfigurable) return; - MyNode editorNode = myConfigurableToNodeMap.get(configurable); + MyNode editorNode = findNode(configurable); FilteringTreeStructure.FilteringNode editorUiNode = myBuilder.getVisibleNodeFor(editorNode); if (editorUiNode == null) return; @@ -353,7 +359,8 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } private void fireSelected(Configurable configurable, ActionCallback callback) { - myFilter.myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable()); + ConfigurableWrapper wrapper = myConfigurableToWrapperMap.get(configurable); + myFilter.myContext.fireSelected(wrapper != null ? wrapper : configurable, this).doWhenProcessed(callback.createSetDoneRunnable()); } @Override @@ -396,11 +403,13 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd if (myGroups == null || myGroups.length == 0) { return NO_CHILDREN; } - SimpleNode[] result = new SimpleNode[myGroups.length]; - for (int i = 0; i < myGroups.length; i++) { - result[i] = new MyNode(this, myGroups[i]); + ArrayList<MyNode> list = new ArrayList<MyNode>(); + for (ConfigurableGroup group : myGroups) { + for (Configurable configurable : group.getConfigurables()) { + list.add(new MyNode(this, configurable, 0)); + } } - return result; + return list.toArray(new SimpleNode[list.size()]); } } @@ -408,21 +417,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd private final Configurable.Composite myComposite; private final Configurable myConfigurable; private final String myDisplayName; + private final int myLevel; - private MyNode(CachingSimpleNode parent, Configurable configurable) { + private MyNode(CachingSimpleNode parent, Configurable configurable, int level) { super(parent); myComposite = configurable instanceof Configurable.Composite ? (Configurable.Composite)configurable : null; myConfigurable = configurable; String name = configurable.getDisplayName(); myDisplayName = name != null ? name.replace("\n", " ") : "{ " + configurable.getClass().getSimpleName() + " }"; - } - - private MyNode(CachingSimpleNode parent, ConfigurableGroup group) { - super(parent); - myComposite = group; - myConfigurable = group instanceof Configurable ? (Configurable)group : null; - String name = group.getDisplayName(); - myDisplayName = name != null ? name.replace("\n", " ") : "{ " + group.getClass().getSimpleName() + " }"; + myLevel = level; } @Override @@ -439,7 +442,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } SimpleNode[] result = new SimpleNode[configurables.length]; for (int i = 0; i < configurables.length; i++) { - result[i] = new MyNode(this, configurables[i]); + result[i] = new MyNode(this, configurables[i], myLevel + 1); if (myConfigurable != null) { myFilter.myContext.registerKid(myConfigurable, configurables[i]); } @@ -453,25 +456,17 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } } - private final class MyRenderer extends GroupedElementsRenderer.Tree { - private JLabel myNodeIcon; - private JLabel myProjectIcon; - - protected JComponent createItemComponent() { - myTextLabel = new ErrorLabel(); - return myTextLabel; - } + private final class MyRenderer extends JPanel implements TreeCellRenderer { + private final JLabel myTextLabel = new ErrorLabel(); + private final JLabel myNodeIcon = new JLabel(" ", SwingConstants.RIGHT); + private final JLabel myProjectIcon = new JLabel(" ", SwingConstants.LEFT); - @Override - protected void layout() { - myNodeIcon = new JLabel(" ", SwingConstants.RIGHT); - myProjectIcon = new JLabel(" ", SwingConstants.LEFT); - myNodeIcon.setOpaque(false); - myTextLabel.setOpaque(false); - myProjectIcon.setOpaque(false); - myRendererComponent.add(BorderLayout.CENTER, myComponent); - myRendererComponent.add(BorderLayout.WEST, myNodeIcon); - myRendererComponent.add(BorderLayout.EAST, myProjectIcon); + public MyRenderer() { + super(new BorderLayout()); + myNodeIcon.setName(NODE_ICON); + add(BorderLayout.CENTER, myTextLabel); + add(BorderLayout.WEST, myNodeIcon); + add(BorderLayout.EAST, myProjectIcon); } public Component getTreeCellRendererComponent(JTree tree, @@ -482,7 +477,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd int row, boolean focused) { myTextLabel.setFont(UIUtil.getLabelFont()); - myRendererComponent.setBackground(selected ? UIUtil.getTreeSelectionBackground() : myTree.getBackground()); + setPreferredSize(null); MyNode node = extractNode(value); if (node == null) { @@ -494,28 +489,19 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd if (myRoot == node.getParent()) { myTextLabel.setFont(myTextLabel.getFont().deriveFont(Font.BOLD)); } - TreePath path = tree.getPathForRow(row); - if (path == null) { - if (value instanceof DefaultMutableTreeNode) { - path = new TreePath(((DefaultMutableTreeNode)value).getPath()); - } - } - int forcedWidth = 2000; - if (path != null && tree.isVisible()) { - Rectangle visibleRect = tree.getVisibleRect(); - - int nestingLevel = tree.isRootVisible() ? path.getPathCount() - 1 : path.getPathCount() - 2; - - int left = UIUtil.getTreeLeftChildIndent(); - int right = UIUtil.getTreeRightChildIndent(); - + if (tree.isVisible()) { + int indent = node.myLevel * (UIUtil.getTreeLeftChildIndent() + UIUtil.getTreeRightChildIndent()); Insets treeInsets = tree.getInsets(); - - int indent = (left + right) * nestingLevel + (treeInsets != null ? treeInsets.left + treeInsets.right : 0); - - forcedWidth = visibleRect.width > 0 ? visibleRect.width - indent : forcedWidth; + if (treeInsets != null) { + indent += treeInsets.left + treeInsets.right; + } + int visibleWidth = tree.getVisibleRect().width; + if (visibleWidth > indent) { + Dimension size = getPreferredSize(); + size.width = visibleWidth - indent; + //setPreferredSize(size); + } } - myRendererComponent.setPrefereedWidth(forcedWidth - 4); } // update font color for modified configurables myTextLabel.setForeground(selected ? UIUtil.getTreeSelectionForeground() : NORMAL_NODE); @@ -537,15 +523,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd if (parent instanceof MyNode) { if (myRoot == parent.getParent()) { project = findConfigurableProject(node); // show icon for top-level nodes - if (node.myConfigurable instanceof NodeConfigurable) { // special case for custom subgroups (build.tools) - Configurable[] configurables = ((NodeConfigurable)node.myConfigurable).getConfigurables(); + if (node.myConfigurable instanceof SortedConfigurableGroup) { // special case for custom subgroups (build.tools) + Configurable[] configurables = ((SortedConfigurableGroup)node.myConfigurable).getConfigurables(); if (configurables != null) { // assume that all configurables have the same project project = findConfigurableProject(configurables[0]); } } } - else if (((MyNode)parent).myConfigurable instanceof NodeConfigurable) { - if (((MyNode)node.getParent()).myConfigurable instanceof NodeConfigurable) { + else if (((MyNode)parent).myConfigurable instanceof SortedConfigurableGroup) { + if (((MyNode)node.getParent()).myConfigurable instanceof SortedConfigurableGroup) { project = findConfigurableProject(node); // special case for custom subgroups } } @@ -564,25 +550,20 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd myProjectIcon.setVisible(false); } // configure node icon - if (value instanceof DefaultMutableTreeNode) { - DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value; - TreePath treePath = new TreePath(treeNode.getPath()); - myNodeIcon.setIcon(myTree.getHandleIcon(treeNode, treePath)); - } - else { - myNodeIcon.setIcon(null); + Icon nodeIcon = null; + if (node != null) { + if (0 == node.getChildCount()) { + nodeIcon = myTree.getEmptyHandle(); + } + else if (value instanceof DefaultMutableTreeNode) { + DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value; + nodeIcon = myTree.isExpanded(new TreePath(treeNode.getPath())) + ? myTree.getExpandedHandle() + : myTree.getCollapsedHandle(); + } } - return myRendererComponent; - } - - int getSeparatorHeight() { - return mySeparatorComponent.getParent() == null ? 0 : mySeparatorComponent.getPreferredSize().height; - } - - public boolean isUnderHandle(Point point) { - Point handlePoint = SwingUtilities.convertPoint(myRendererComponent, point, myNodeIcon); - Rectangle bounds = myNodeIcon.getBounds(); - return bounds.x < handlePoint.x && bounds.getMaxX() >= handlePoint.x; + myNodeIcon.setIcon(nodeIcon); + return this; } } @@ -616,11 +597,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd @Override public void setUI(TreeUI ui) { - TreeUI actualUI = ui; - if (!(ui instanceof MyTreeUi)) { - actualUI = new MyTreeUi(); - } - super.setUI(actualUI); + super.setUI(ui instanceof MyTreeUi ? ui : new MyTreeUi()); } @Override @@ -659,84 +636,92 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } @Override - protected void processMouseEvent(MouseEvent e) { + protected void processMouseEvent(MouseEvent event) { MyTreeUi ui = (MyTreeUi)myTree.getUI(); - boolean toggleNow = MouseEvent.MOUSE_RELEASED == e.getID() - && UIUtil.isActionClick(e, MouseEvent.MOUSE_RELEASED) - && !ui.isToggleEvent(e); - - if (toggleNow || MouseEvent.MOUSE_PRESSED == e.getID()) { - TreePath path = getPathForLocation(e.getX(), e.getY()); - if (path != null) { - Rectangle bounds = getPathBounds(path); - if (bounds != null && path.getLastPathComponent() instanceof DefaultMutableTreeNode) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); - boolean selected = isPathSelected(path); - boolean expanded = isExpanded(path); - Component comp = - myRenderer.getTreeCellRendererComponent(this, node, selected, expanded, node.isLeaf(), getRowForPath(path), isFocusOwner()); - - comp.setBounds(bounds); - comp.validate(); - - Point point = new Point(e.getX() - bounds.x, e.getY() - bounds.y); - if (myRenderer.isUnderHandle(point)) { - if (toggleNow) { - ui.toggleExpandState(path); - } - e.consume(); - return; - } - } - } + if (!ui.processMouseEvent(event)) { + super.processMouseEvent(event); } - - super.processMouseEvent(e); } + } - private final class MyTreeUi extends WideSelectionTreeUI { + private static final class MyTreeUi extends WideSelectionTreeUI { + boolean processMouseEvent(MouseEvent event) { + if (super.tree instanceof SimpleTree) { + SimpleTree tree = (SimpleTree)super.tree; - @Override - public void toggleExpandState(TreePath path) { - super.toggleExpandState(path); - } + boolean toggleNow = MouseEvent.MOUSE_RELEASED == event.getID() + && UIUtil.isActionClick(event, MouseEvent.MOUSE_RELEASED) + && !isToggleEvent(event); - @Override - public boolean isToggleEvent(MouseEvent event) { - return super.isToggleEvent(event); + if (toggleNow || MouseEvent.MOUSE_PRESSED == event.getID()) { + Component component = tree.getDeepestRendererComponentAt(event.getX(), event.getY()); + if (component != null && NODE_ICON.equals(component.getName())) { + if (toggleNow) { + toggleExpandState(tree.getPathForLocation(event.getX(), event.getY())); + } + event.consume(); + return true; + } + } } + return false; + } - @Override - protected boolean shouldPaintExpandControl(TreePath path, - int row, - boolean isExpanded, - boolean hasBeenExpanded, - boolean isLeaf) { - return false; - } + @Override + protected boolean shouldPaintExpandControl(TreePath path, + int row, + boolean isExpanded, + boolean hasBeenExpanded, + boolean isLeaf) { + return false; + } - @Override - protected void paintHorizontalPartOfLeg(Graphics g, - Rectangle clipBounds, - Insets insets, - Rectangle bounds, - TreePath path, - int row, - boolean isExpanded, - boolean hasBeenExpanded, - boolean isLeaf) { + @Override + protected void paintHorizontalPartOfLeg(Graphics g, + Rectangle clipBounds, + Insets insets, + Rectangle bounds, + TreePath path, + int row, + boolean isExpanded, + boolean hasBeenExpanded, + boolean isLeaf) { - } + } - @Override - protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) { - } + @Override + protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) { + } - @Override - public void paint(Graphics g, JComponent c) { - GraphicsUtil.setupAntialiasing(g); - super.paint(g, c); + @Override + public void paint(Graphics g, JComponent c) { + GraphicsUtil.setupAntialiasing(g); + super.paint(g, c); + } + + @Override + protected void paintRow(Graphics g, + Rectangle clipBounds, + Insets insets, + Rectangle bounds, + TreePath path, + int row, + boolean isExpanded, + boolean hasBeenExpanded, + boolean isLeaf) { + if (tree != null) { + int width = tree.getWidth(); + Container parent = tree.getParent(); + if (parent instanceof JViewport) { + JViewport viewport = (JViewport)parent; + width = viewport.getWidth() - viewport.getViewPosition().x; + } + width -= bounds.x; + if (bounds.width < width) { + bounds.width = width; + } } + super.paintRow(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); } } |