1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.ide.navigationToolbar;
4 import com.intellij.ide.navigationToolbar.ui.NavBarUIManager;
5 import com.intellij.ide.ui.UISettings;
6 import com.intellij.ide.ui.UISettingsListener;
7 import com.intellij.ide.ui.customization.CustomActionsSchema;
8 import com.intellij.ide.ui.customization.CustomisedActionGroup;
9 import com.intellij.openapi.actionSystem.*;
10 import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
11 import com.intellij.openapi.project.Project;
12 import com.intellij.openapi.wm.IdeRootPaneNorthExtension;
13 import com.intellij.openapi.wm.impl.IdeFrameImpl;
14 import com.intellij.ui.ScrollPaneFactory;
15 import com.intellij.util.ui.JBSwingUtilities;
16 import com.intellij.util.ui.JBUI;
18 import org.jetbrains.annotations.NonNls;
19 import org.jetbrains.annotations.NotNull;
20 import org.jetbrains.annotations.Nullable;
26 * @author Konstantin Bulenkov
28 public final class NavBarRootPaneExtension extends IdeRootPaneNorthExtension {
29 private JComponent myWrapperPanel;
30 @NonNls public static final String NAV_BAR = "NavBar";
31 @SuppressWarnings("StatefulEp")
32 private Project myProject;
33 private NavBarPanel myNavigationBar;
34 private JPanel myRunPanel;
35 private final boolean myNavToolbarGroupExist;
36 private JScrollPane myScrollPane;
38 public NavBarRootPaneExtension(@NotNull Project project) {
41 myProject.getMessageBus().connect().subscribe(UISettingsListener.TOPIC, uiSettings -> {
42 toggleRunPanel(!uiSettings.getShowMainToolbar() && uiSettings.getShowNavigationBar() && !uiSettings.getPresentationMode());
45 myNavToolbarGroupExist = runToolbarExists();
49 public void revalidate() {
50 final UISettings settings = UISettings.getInstance();
51 if (!settings.getShowMainToolbar() && settings.getShowNavigationBar() && !UISettings.getInstance().getPresentationMode()) {
52 toggleRunPanel(false);
58 public IdeRootPaneNorthExtension copy() {
59 return new NavBarRootPaneExtension(myProject);
62 public boolean isMainToolbarVisible() {
63 return !UISettings.getInstance().getPresentationMode() && (UISettings.getInstance().getShowMainToolbar() || !myNavToolbarGroupExist);
66 public static boolean runToolbarExists() {
67 final AnAction correctedAction = CustomActionsSchema.getInstance().getCorrectedAction("NavBarToolBar");
68 return correctedAction instanceof DefaultActionGroup && ((DefaultActionGroup)correctedAction).getChildrenCount() > 0 ||
69 correctedAction instanceof CustomisedActionGroup && ((CustomisedActionGroup)correctedAction).getFirstAction() != null;
74 public JComponent getComponent() {
75 if (myWrapperPanel == null) {
76 myWrapperPanel = new NavBarWrapperPanel(new BorderLayout()) {
78 protected void paintComponent(Graphics g) {
79 super.paintComponent(g);
80 NavBarUIManager.getUI().doPaintWrapperPanel((Graphics2D)g, getBounds(), isMainToolbarVisible());
84 public Insets getInsets() {
85 return NavBarUIManager.getUI().getWrapperPanelInsets(super.getInsets());
89 addNavigationBarPanel(myWrapperPanel);
91 toggleRunPanel(!UISettings.getInstance().getShowMainToolbar() && !UISettings.getInstance().getPresentationMode());
93 return myWrapperPanel;
96 private void addNavigationBarPanel(JComponent wrapperPanel) {
97 wrapperPanel.add(buildNavBarPanel(), BorderLayout.CENTER);
100 public static class NavBarWrapperPanel extends JPanel {
101 public NavBarWrapperPanel(LayoutManager layout) {
107 protected Graphics getComponentGraphics(Graphics graphics) {
108 return JBSwingUtilities.runGlobalCGTransform(this, super.getComponentGraphics(graphics));
112 private static void alignVertically(Container container) {
113 if (container.getComponentCount() == 1) {
114 Component c = container.getComponent(0);
115 Insets insets = container.getInsets();
116 Dimension d = c.getPreferredSize();
117 Rectangle r = container.getBounds();
118 c.setBounds(insets.left, (r.height - d.height - insets.top - insets.bottom) / 2 + insets.top, r.width - insets.left - insets.right, d.height);
122 private void toggleRunPanel(final boolean show) {
123 if (show && myRunPanel == null && runToolbarExists()) {
124 final ActionManager manager = ActionManager.getInstance();
125 AnAction toolbarRunGroup = CustomActionsSchema.getInstance().getCorrectedAction("NavBarToolBar");
127 if (toolbarRunGroup instanceof ActionGroup && myWrapperPanel != null) {
128 final ActionToolbar actionToolbar = manager.createActionToolbar(ActionPlaces.NAVIGATION_BAR_TOOLBAR, (ActionGroup)toolbarRunGroup, true);
129 final JComponent component = actionToolbar.getComponent();
130 myRunPanel = new JPanel(new BorderLayout()) {
132 public void doLayout() {
133 alignVertically(this);
136 myRunPanel.setOpaque(false);
137 myRunPanel.add(component, BorderLayout.CENTER);
138 final boolean needGap = isNeedGap(toolbarRunGroup);
139 myRunPanel.setBorder(JBUI.Borders.emptyLeft(needGap ? 5 : 1));
140 myWrapperPanel.add(myRunPanel, BorderLayout.EAST);
143 else if (!show && myRunPanel != null) {
144 myWrapperPanel.remove(myRunPanel);
149 private boolean isUndocked() {
150 final Window ancestor = SwingUtilities.getWindowAncestor(myWrapperPanel);
151 return (ancestor != null && !(ancestor instanceof IdeFrameImpl))
152 || !UISettings.getInstance().getShowMainToolbar()
153 || !UISettings.getInstance().getPresentationMode();
156 private static boolean isNeedGap(final AnAction group) {
157 final AnAction firstAction = getFirstAction(group);
158 return firstAction instanceof ComboBoxAction;
162 private static AnAction getFirstAction(final AnAction group) {
163 if (group instanceof DefaultActionGroup) {
164 AnAction firstAction = null;
165 for (final AnAction action : ((DefaultActionGroup)group).getChildActionsOrStubs()) {
166 if (action instanceof DefaultActionGroup) {
167 firstAction = getFirstAction(action);
169 else if (action instanceof Separator || action instanceof ActionGroup) {
173 firstAction = action;
177 if (firstAction != null) break;
182 if (group instanceof CustomisedActionGroup) {
183 return ((CustomisedActionGroup)group).getFirstAction();
188 private JComponent buildNavBarPanel() {
189 myNavigationBar = new NavBarPanel(myProject, true);
190 myWrapperPanel.putClientProperty("NavBarPanel", myNavigationBar);
191 myNavigationBar.getModel().setFixedComponent(true);
192 myScrollPane = ScrollPaneFactory.createScrollPane(myNavigationBar);
194 JPanel panel = new JPanel(new BorderLayout()) {
197 protected void paintComponent(Graphics g) {
198 super.paintComponent(g);
199 final Component navBar = myScrollPane;
200 Insets insets = getInsets();
201 Rectangle r = navBar.getBounds();
203 Graphics2D g2d = (Graphics2D) g.create();
204 g2d.translate(r.x, r.y);
209 public void doLayout() {
211 final Rectangle r = getBounds();
212 final Insets insets = getInsets();
214 if (myScrollPane == null) return;
215 final Component navBar = myScrollPane;
217 final Dimension preferredSize = navBar.getPreferredSize();
219 navBar.setBounds(x, (r.height - preferredSize.height) / 2,
220 r.width - insets.left - insets.right, preferredSize.height);
224 public void updateUI() {
227 if (myScrollPane == null || myNavigationBar == null) return;
229 myScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
230 myScrollPane.setHorizontalScrollBar(null);
231 myScrollPane.setBorder(new NavBarBorder());
232 myScrollPane.setOpaque(false);
233 myScrollPane.getViewport().setOpaque(false);
234 myScrollPane.setViewportBorder(null);
235 myNavigationBar.setBorder(null);
239 panel.add(myScrollPane, BorderLayout.CENTER);
245 public void uiSettingsChanged(@NotNull UISettings settings) {
246 if (myNavigationBar == null) {
250 myNavigationBar.updateState(settings.getShowNavigationBar());
251 myWrapperPanel.setVisible(settings.getShowNavigationBar() && !UISettings.getInstance().getPresentationMode());
253 myWrapperPanel.revalidate();
254 myNavigationBar.revalidate();
255 myWrapperPanel.repaint();
257 if (myWrapperPanel.getComponentCount() > 0) {
258 Component c = myWrapperPanel.getComponent(0);
259 if (c instanceof JComponent) {
260 ((JComponent)c).setOpaque(false);
267 public String getKey() {