diff options
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java')
-rw-r--r-- | platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java | 129 |
1 files changed, 120 insertions, 9 deletions
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java index e0ab24815ece..175b994122ef 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java @@ -23,6 +23,7 @@ import com.intellij.openapi.options.ConfigurableGroup; import com.intellij.openapi.options.OptionsBundle; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.ex.ConfigurableWrapper; +import com.intellij.openapi.options.ex.NodeConfigurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; @@ -116,10 +117,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl } }); - final JScrollPane scrolls = ScrollPaneFactory.createScrollPane(myTree); - scrolls.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); - - add(scrolls, BorderLayout.CENTER); + add(new StickySeparator(myTree), BorderLayout.CENTER); mySelection = new MergingUpdateQueue("OptionsTree", 150, false, this, this, this).setRestartTimerOnAdd(true); myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { @@ -290,7 +288,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl } class Renderer extends GroupedElementsRenderer.Tree { - + private GroupSeparator mySeparator; private JLabel myProjectIcon; private JLabel myHandle; @@ -298,7 +296,8 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl protected void layout() { myRendererComponent.setOpaqueActive(false); - myRendererComponent.add(mySeparatorComponent, BorderLayout.NORTH); + mySeparator = new GroupSeparator(); + myRendererComponent.add(Registry.is("ide.file.settings.order.new") ? mySeparator : mySeparatorComponent, BorderLayout.NORTH); final NonOpaquePanel content = new NonOpaquePanel(new BorderLayout()); myHandle = new JLabel("", SwingConstants.CENTER); @@ -325,7 +324,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl JComponent result; Color fg = UIUtil.getTreeTextForeground(); - + mySeparator.configure(null, false); final Base base = extractNode(value); if (base instanceof EditorNode) { @@ -335,6 +334,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl final DefaultMutableTreeNode prevValue = ((DefaultMutableTreeNode)value).getPreviousSibling(); if (prevValue == null || prevValue instanceof LoadingNode) { group = editor.getGroup(); + mySeparator.configure(group, false); } else { final Base prevBase = extractNode(prevValue); @@ -342,6 +342,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl final EditorNode prevEditor = (EditorNode)prevBase; if (prevEditor.getGroup() != editor.getGroup()) { group = editor.getGroup(); + mySeparator.configure(group, true); } } } @@ -404,8 +405,25 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl myTextLabel.setBorder(new EmptyBorder(1,2,1,0)); } - Project project = getConfigurableProject(base); - if (project != null && Registry.is("ide.file.settings.order.new")) { + Project project = null; + if (base != null && Registry.is("ide.file.settings.order.new")) { + SimpleNode parent = base.getParent(); + if (parent == myRoot) { + project = getConfigurableProject(base); // show icon for top-level nodes + if (base.getConfigurable() instanceof NodeConfigurable) { // special case for custom subgroups (build.tools) + Configurable[] configurables = ((NodeConfigurable)base.getConfigurable()).getConfigurables(); + if (configurables != null) { // assume that all configurables have the same project + project = getConfigurableProject(configurables[0]); + } + } + } + else if (parent instanceof Base && ((Base)parent).getConfigurable() instanceof NodeConfigurable) { + if (((Base)base.getParent()).getConfigurable() instanceof NodeConfigurable) { + project = getConfigurableProject(base); // special case for custom subgroups + } + } + } + if (project != null) { myProjectIcon.setBackground(selected ? getSelectionBackground() : getBackground()); myProjectIcon.setIcon(selected ? AllIcons.General.ProjectConfigurableSelected : AllIcons.General.ProjectConfigurable); myProjectIcon.setVisible(true); @@ -903,4 +921,97 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl } return getConfigurableProject(node.getParent()); } + + private static final class GroupSeparator extends JLabel { + public static final int SPACE = 10; + + public GroupSeparator() { + setFont(UIUtil.getLabelFont()); + setFont(getFont().deriveFont(Font.BOLD)); + } + + public void configure(ConfigurableGroup group, boolean isSpaceNeeded) { + if (group == null) { + setVisible(false); + } + else { + setVisible(true); + int bottom = UIUtil.isUnderNativeMacLookAndFeel() ? 1 : 3; + int top = isSpaceNeeded + ? bottom + SPACE + : bottom; + setBorder(BorderFactory.createEmptyBorder(top, 3, bottom, 3)); + setText(group.getDisplayName()); + } + } + } + + private static final class StickySeparator extends JComponent { + private final SimpleTree myTree; + private final JScrollPane myScroller; + private final GroupSeparator mySeparator; + + public StickySeparator(SimpleTree tree) { + myTree = tree; + myScroller = ScrollPaneFactory.createScrollPane(myTree); + myScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + mySeparator = new GroupSeparator(); + add(myScroller); + } + + @Override + public void doLayout() { + myScroller.setBounds(0, 0, getWidth(), getHeight()); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + + if (Registry.is("ide.file.settings.order.new")) { + ConfigurableGroup group = getGroup(GroupSeparator.SPACE + mySeparator.getFont().getSize()); + if (group != null && group == getGroup(-GroupSeparator.SPACE)) { + mySeparator.configure(group, false); + + Rectangle bounds = myScroller.getViewport().getBounds(); + int height = mySeparator.getPreferredSize().height; + if (bounds.height > height) { + bounds.height = height; + } + g.setColor(myTree.getBackground()); + if (g instanceof Graphics2D) { + int h = bounds.height / 3; + int y = bounds.y + bounds.height - h; + g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height - h); + ((Graphics2D)g).setPaint(UIUtil.getGradientPaint( + 0, y, g.getColor(), + 0, y + h, ColorUtil.toAlpha(g.getColor(), 0))); + g.fillRect(bounds.x, y, bounds.width, h); + } + else { + g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); + } + mySeparator.setSize(bounds.width - 1, bounds.height); + mySeparator.paint(g.create(bounds.x + 1, bounds.y, bounds.width - 1, bounds.height)); + } + } + } + + private ConfigurableGroup getGroup(int offset) { + TreePath path = myTree.getClosestPathForLocation(-myTree.getX(), -myTree.getY() + offset); + SimpleNode node = myTree.getNodeFor(path); + if (node instanceof FilteringTreeStructure.FilteringNode) { + Object delegate = ((FilteringTreeStructure.FilteringNode)node).getDelegate(); + while (delegate instanceof EditorNode) { + EditorNode editor = (EditorNode)delegate; + ConfigurableGroup group = editor.getGroup(); + if (group != null) { + return group; + } + delegate = editor.getParent(); + } + } + return null; + } + } } |