| /* |
| * Copyright 2000-2013 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.ide.ui.laf.darcula.ui; |
| |
| import sun.awt.SunToolkit; |
| import sun.swing.SwingUtilities2; |
| |
| import javax.accessibility.AccessibleContext; |
| import javax.swing.*; |
| import javax.swing.border.EmptyBorder; |
| import javax.swing.plaf.UIResource; |
| import java.awt.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.WindowAdapter; |
| import java.awt.event.WindowEvent; |
| import java.awt.event.WindowListener; |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.util.List; |
| |
| /** |
| * @author Konstantin Bulenkov |
| */ |
| public class DarculaTitlePane extends JComponent { |
| private static final int IMAGE_HEIGHT = 16; |
| private static final int IMAGE_WIDTH = 16; |
| |
| private PropertyChangeListener myPropertyChangeListener; |
| private JMenuBar myMenuBar; |
| private Action myCloseAction; |
| private Action myIconifyAction; |
| private Action myRestoreAction; |
| private Action myMaximizeAction; |
| private JButton myToggleButton; |
| private JButton myIconifyButton; |
| private JButton myCloseButton; |
| private Icon myMaximizeIcon; |
| private Icon myMinimizeIcon; |
| private Image mySystemIcon; |
| private WindowListener myWindowListener; |
| private Window myWindow; |
| private JRootPane myRootPane; |
| private int myState; |
| private DarculaRootPaneUI rootPaneUI; |
| |
| |
| private Color myInactiveBackground = UIManager.getColor("inactiveCaption"); |
| private Color myInactiveForeground = UIManager.getColor("inactiveCaptionText"); |
| private Color myInactiveShadow = UIManager.getColor("inactiveCaptionBorder"); |
| private Color myActiveBackground = null; |
| private Color myActiveForeground = null; |
| private Color myActiveShadow = null; |
| |
| public DarculaTitlePane(JRootPane root, DarculaRootPaneUI ui) { |
| this.myRootPane = root; |
| rootPaneUI = ui; |
| |
| myState = -1; |
| |
| installSubcomponents(); |
| determineColors(); |
| installDefaults(); |
| |
| setLayout(createLayout()); |
| } |
| |
| private void uninstall() { |
| uninstallListeners(); |
| myWindow = null; |
| removeAll(); |
| } |
| |
| private void installListeners() { |
| if (myWindow != null) { |
| myWindowListener = createWindowListener(); |
| myWindow.addWindowListener(myWindowListener); |
| myPropertyChangeListener = createWindowPropertyChangeListener(); |
| myWindow.addPropertyChangeListener(myPropertyChangeListener); |
| } |
| } |
| |
| private void uninstallListeners() { |
| if (myWindow != null) { |
| myWindow.removeWindowListener(myWindowListener); |
| myWindow.removePropertyChangeListener(myPropertyChangeListener); |
| } |
| } |
| |
| private WindowListener createWindowListener() { |
| return new WindowHandler(); |
| } |
| |
| private PropertyChangeListener createWindowPropertyChangeListener() { |
| return new PropertyChangeHandler(); |
| } |
| |
| public JRootPane getRootPane() { |
| return myRootPane; |
| } |
| |
| private int getWindowDecorationStyle() { |
| return getRootPane().getWindowDecorationStyle(); |
| } |
| |
| public void addNotify() { |
| super.addNotify(); |
| |
| uninstallListeners(); |
| |
| myWindow = SwingUtilities.getWindowAncestor(this); |
| if (myWindow != null) { |
| if (myWindow instanceof Frame) { |
| setState(((Frame)myWindow).getExtendedState()); |
| } |
| else { |
| setState(0); |
| } |
| setActive(myWindow.isActive()); |
| installListeners(); |
| updateSystemIcon(); |
| } |
| } |
| |
| public void removeNotify() { |
| super.removeNotify(); |
| |
| uninstallListeners(); |
| myWindow = null; |
| } |
| |
| private void installSubcomponents() { |
| int decorationStyle = getWindowDecorationStyle(); |
| if (decorationStyle == JRootPane.FRAME) { |
| createActions(); |
| myMenuBar = createMenuBar(); |
| add(myMenuBar); |
| createButtons(); |
| add(myIconifyButton); |
| add(myToggleButton); |
| add(myCloseButton); |
| } |
| else if (decorationStyle == JRootPane.PLAIN_DIALOG || |
| decorationStyle == JRootPane.INFORMATION_DIALOG || |
| decorationStyle == JRootPane.ERROR_DIALOG || |
| decorationStyle == JRootPane.COLOR_CHOOSER_DIALOG || |
| decorationStyle == JRootPane.FILE_CHOOSER_DIALOG || |
| decorationStyle == JRootPane.QUESTION_DIALOG || |
| decorationStyle == JRootPane.WARNING_DIALOG) { |
| createActions(); |
| createButtons(); |
| add(myCloseButton); |
| } |
| } |
| |
| private void determineColors() { |
| switch (getWindowDecorationStyle()) { |
| case JRootPane.FRAME: |
| myActiveBackground = UIManager.getColor("activeCaption"); |
| myActiveForeground = UIManager.getColor("activeCaptionText"); |
| myActiveShadow = UIManager.getColor("activeCaptionBorder"); |
| break; |
| case JRootPane.ERROR_DIALOG: |
| myActiveBackground = UIManager.getColor("OptionPane.errorDialog.titlePane.background"); |
| myActiveForeground = UIManager.getColor("OptionPane.errorDialog.titlePane.foreground"); |
| myActiveShadow = UIManager.getColor("OptionPane.errorDialog.titlePane.shadow"); |
| break; |
| case JRootPane.QUESTION_DIALOG: |
| case JRootPane.COLOR_CHOOSER_DIALOG: |
| case JRootPane.FILE_CHOOSER_DIALOG: |
| myActiveBackground = UIManager.getColor("OptionPane.questionDialog.titlePane.background"); |
| myActiveForeground = UIManager.getColor("OptionPane.questionDialog.titlePane.foreground"); |
| myActiveShadow = UIManager.getColor("OptionPane.questionDialog.titlePane.shadow"); |
| break; |
| case JRootPane.WARNING_DIALOG: |
| myActiveBackground = UIManager.getColor("OptionPane.warningDialog.titlePane.background"); |
| myActiveForeground = UIManager.getColor("OptionPane.warningDialog.titlePane.foreground"); |
| myActiveShadow = UIManager.getColor("OptionPane.warningDialog.titlePane.shadow"); |
| break; |
| case JRootPane.PLAIN_DIALOG: |
| case JRootPane.INFORMATION_DIALOG: |
| default: |
| myActiveBackground = UIManager.getColor("activeCaption"); |
| myActiveForeground = UIManager.getColor("activeCaptionText"); |
| myActiveShadow = UIManager.getColor("activeCaptionBorder"); |
| break; |
| } |
| } |
| |
| private void installDefaults() { |
| setFont(UIManager.getFont("InternalFrame.titleFont", getLocale())); |
| } |
| |
| |
| protected JMenuBar createMenuBar() { |
| myMenuBar = new SystemMenuBar(); |
| myMenuBar.setFocusable(false); |
| myMenuBar.setBorderPainted(true); |
| myMenuBar.add(createMenu()); |
| return myMenuBar; |
| } |
| |
| private void close() { |
| Window window = getWindow(); |
| |
| if (window != null) { |
| window.dispatchEvent(new WindowEvent( |
| window, WindowEvent.WINDOW_CLOSING)); |
| } |
| } |
| |
| private void iconify() { |
| Frame frame = getFrame(); |
| if (frame != null) { |
| frame.setExtendedState(myState | Frame.ICONIFIED); |
| } |
| } |
| |
| private void maximize() { |
| Frame frame = getFrame(); |
| if (frame != null) { |
| frame.setExtendedState(myState | Frame.MAXIMIZED_BOTH); |
| } |
| } |
| |
| private void restore() { |
| Frame frame = getFrame(); |
| |
| if (frame == null) { |
| return; |
| } |
| |
| if ((myState & Frame.ICONIFIED) != 0) { |
| frame.setExtendedState(myState & ~Frame.ICONIFIED); |
| } |
| else { |
| frame.setExtendedState(myState & ~Frame.MAXIMIZED_BOTH); |
| } |
| } |
| |
| private void createActions() { |
| myCloseAction = new CloseAction(); |
| if (getWindowDecorationStyle() == JRootPane.FRAME) { |
| myIconifyAction = new IconifyAction(); |
| myRestoreAction = new RestoreAction(); |
| myMaximizeAction = new MaximizeAction(); |
| } |
| } |
| |
| private JMenu createMenu() { |
| JMenu menu = new JMenu(""); |
| if (getWindowDecorationStyle() == JRootPane.FRAME) { |
| addMenuItems(menu); |
| } |
| return menu; |
| } |
| |
| private void addMenuItems(JMenu menu) { |
| menu.add(myRestoreAction); |
| menu.add(myIconifyAction); |
| if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { |
| menu.add(myMaximizeAction); |
| } |
| |
| menu.add(new JSeparator()); |
| |
| menu.add(myCloseAction); |
| } |
| |
| private static JButton createButton(String accessibleName, Icon icon, Action action) { |
| JButton button = new JButton(); |
| button.setFocusPainted(false); |
| button.setFocusable(false); |
| button.setOpaque(true); |
| button.putClientProperty("paintActive", Boolean.TRUE); |
| button.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName); |
| button.setBorder(new EmptyBorder(0, 0, 0, 0)); |
| button.setText(null); |
| button.setAction(action); |
| button.setIcon(icon); |
| return button; |
| } |
| |
| private void createButtons() { |
| myCloseButton = createButton("Close", UIManager.getIcon("InternalFrame.closeIcon"), myCloseAction); |
| |
| if (getWindowDecorationStyle() == JRootPane.FRAME) { |
| myMaximizeIcon = UIManager.getIcon("InternalFrame.maximizeIcon"); |
| myMinimizeIcon = UIManager.getIcon("InternalFrame.minimizeIcon"); |
| |
| myIconifyButton = createButton("Iconify", UIManager.getIcon("InternalFrame.iconifyIcon"), myIconifyAction); |
| myToggleButton = createButton("Maximize", myMaximizeIcon, myRestoreAction); |
| } |
| } |
| |
| private LayoutManager createLayout() { |
| return new TitlePaneLayout(); |
| } |
| |
| private void setActive(boolean active) { |
| myCloseButton.putClientProperty("paintActive", Boolean.valueOf(active)); |
| |
| if (getWindowDecorationStyle() == JRootPane.FRAME) { |
| myIconifyButton.putClientProperty("paintActive", Boolean.valueOf(active)); |
| myToggleButton.putClientProperty("paintActive", Boolean.valueOf(active)); |
| } |
| |
| getRootPane().repaint(); |
| } |
| |
| private void setState(int state) { |
| setState(state, false); |
| } |
| |
| private void setState(int state, boolean updateRegardless) { |
| Window wnd = getWindow(); |
| |
| if (wnd != null && getWindowDecorationStyle() == JRootPane.FRAME) { |
| if (myState == state && !updateRegardless) { |
| return; |
| } |
| Frame frame = getFrame(); |
| |
| if (frame != null) { |
| JRootPane rootPane = getRootPane(); |
| |
| if (((state & Frame.MAXIMIZED_BOTH) != 0) && |
| (rootPane.getBorder() == null || |
| (rootPane.getBorder() instanceof UIResource)) && |
| frame.isShowing()) { |
| rootPane.setBorder(null); |
| } |
| else if ((state & Frame.MAXIMIZED_BOTH) == 0) { |
| // This is a croak, if state becomes bound, this can |
| // be nuked. |
| rootPaneUI.installBorder(rootPane); |
| } |
| if (frame.isResizable()) { |
| if ((state & Frame.MAXIMIZED_BOTH) != 0) { |
| updateToggleButton(myRestoreAction, myMinimizeIcon); |
| myMaximizeAction.setEnabled(false); |
| myRestoreAction.setEnabled(true); |
| } |
| else { |
| updateToggleButton(myMaximizeAction, myMaximizeIcon); |
| myMaximizeAction.setEnabled(true); |
| myRestoreAction.setEnabled(false); |
| } |
| if (myToggleButton.getParent() == null || |
| myIconifyButton.getParent() == null) { |
| add(myToggleButton); |
| add(myIconifyButton); |
| revalidate(); |
| repaint(); |
| } |
| myToggleButton.setText(null); |
| } |
| else { |
| myMaximizeAction.setEnabled(false); |
| myRestoreAction.setEnabled(false); |
| if (myToggleButton.getParent() != null) { |
| remove(myToggleButton); |
| revalidate(); |
| repaint(); |
| } |
| } |
| } |
| else { |
| // Not contained in a Frame |
| myMaximizeAction.setEnabled(false); |
| myRestoreAction.setEnabled(false); |
| myIconifyAction.setEnabled(false); |
| remove(myToggleButton); |
| remove(myIconifyButton); |
| revalidate(); |
| repaint(); |
| } |
| myCloseAction.setEnabled(true); |
| myState = state; |
| } |
| } |
| |
| private void updateToggleButton(Action action, Icon icon) { |
| myToggleButton.setAction(action); |
| myToggleButton.setIcon(icon); |
| myToggleButton.setText(null); |
| } |
| |
| private Frame getFrame() { |
| Window window = getWindow(); |
| |
| if (window instanceof Frame) { |
| return (Frame)window; |
| } |
| return null; |
| } |
| |
| private Window getWindow() { |
| return myWindow; |
| } |
| |
| private String getTitle() { |
| Window w = getWindow(); |
| |
| if (w instanceof Frame) { |
| return ((Frame)w).getTitle(); |
| } |
| else if (w instanceof Dialog) { |
| return ((Dialog)w).getTitle(); |
| } |
| return null; |
| } |
| |
| public void paintComponent(Graphics g) { |
| if (getFrame() != null) { |
| setState(getFrame().getExtendedState()); |
| } |
| JRootPane rootPane = getRootPane(); |
| Window window = getWindow(); |
| boolean leftToRight = (window == null) ? |
| rootPane.getComponentOrientation().isLeftToRight() : |
| window.getComponentOrientation().isLeftToRight(); |
| boolean isSelected = (window == null) ? true : window.isActive(); |
| int width = getWidth(); |
| int height = getHeight(); |
| |
| Color background; |
| Color foreground; |
| Color darkShadow; |
| |
| if (isSelected) { |
| background = myActiveBackground; |
| foreground = myActiveForeground; |
| darkShadow = myActiveShadow; |
| } |
| else { |
| background = myInactiveBackground; |
| foreground = myInactiveForeground; |
| darkShadow = myInactiveShadow; |
| } |
| |
| g.setColor(background); |
| g.fillRect(0, 0, width, height); |
| |
| g.setColor(darkShadow); |
| g.drawLine(0, height - 1, width, height - 1); |
| g.drawLine(0, 0, 0, 0); |
| g.drawLine(width - 1, 0, width - 1, 0); |
| |
| int xOffset = leftToRight ? 5 : width - 5; |
| |
| if (getWindowDecorationStyle() == JRootPane.FRAME) { |
| xOffset += leftToRight ? IMAGE_WIDTH + 5 : -IMAGE_WIDTH - 5; |
| } |
| |
| String theTitle = getTitle(); |
| if (theTitle != null) { |
| FontMetrics fm = SwingUtilities2.getFontMetrics(rootPane, g); |
| |
| g.setColor(foreground); |
| |
| int yOffset = ((height - fm.getHeight()) / 2) + fm.getAscent(); |
| |
| Rectangle rect = new Rectangle(0, 0, 0, 0); |
| if (myIconifyButton != null && myIconifyButton.getParent() != null) { |
| rect = myIconifyButton.getBounds(); |
| } |
| int titleW; |
| |
| if (leftToRight) { |
| if (rect.x == 0) { |
| rect.x = window.getWidth() - window.getInsets().right - 2; |
| } |
| titleW = rect.x - xOffset - 4; |
| theTitle = SwingUtilities2.clipStringIfNecessary( |
| rootPane, fm, theTitle, titleW); |
| } |
| else { |
| titleW = xOffset - rect.x - rect.width - 4; |
| theTitle = SwingUtilities2.clipStringIfNecessary( |
| rootPane, fm, theTitle, titleW); |
| xOffset -= SwingUtilities2.stringWidth(rootPane, fm, theTitle); |
| } |
| int titleLength = SwingUtilities2.stringWidth(rootPane, fm, theTitle); |
| SwingUtilities2.drawString(rootPane, g, theTitle, xOffset, yOffset); |
| xOffset += leftToRight ? titleLength + 5 : -5; |
| } |
| } |
| |
| private class CloseAction extends AbstractAction { |
| public CloseAction() { |
| super(UIManager.getString("DarculaTitlePane.closeTitle", getLocale())); |
| } |
| |
| public void actionPerformed(ActionEvent e) { |
| close(); |
| } |
| } |
| |
| |
| private class IconifyAction extends AbstractAction { |
| public IconifyAction() { |
| super(UIManager.getString("DarculaTitlePane.iconifyTitle", getLocale())); |
| } |
| |
| public void actionPerformed(ActionEvent e) { |
| iconify(); |
| } |
| } |
| |
| |
| private class RestoreAction extends AbstractAction { |
| public RestoreAction() { |
| super(UIManager.getString |
| ("DarculaTitlePane.restoreTitle", getLocale())); |
| } |
| |
| public void actionPerformed(ActionEvent e) { |
| restore(); |
| } |
| } |
| |
| |
| private class MaximizeAction extends AbstractAction { |
| public MaximizeAction() { |
| super(UIManager.getString("DarculaTitlePane.maximizeTitle", getLocale())); |
| } |
| |
| public void actionPerformed(ActionEvent e) { |
| maximize(); |
| } |
| } |
| |
| |
| private class SystemMenuBar extends JMenuBar { |
| public void paint(Graphics g) { |
| if (isOpaque()) { |
| g.setColor(getBackground()); |
| g.fillRect(0, 0, getWidth(), getHeight()); |
| } |
| |
| if (mySystemIcon != null) { |
| g.drawImage(mySystemIcon, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null); |
| } |
| else { |
| Icon icon = UIManager.getIcon("InternalFrame.icon"); |
| |
| if (icon != null) { |
| icon.paintIcon(this, g, 0, 0); |
| } |
| } |
| } |
| |
| public Dimension getMinimumSize() { |
| return getPreferredSize(); |
| } |
| |
| public Dimension getPreferredSize() { |
| Dimension size = super.getPreferredSize(); |
| |
| return new Dimension(Math.max(IMAGE_WIDTH, size.width), |
| Math.max(size.height, IMAGE_HEIGHT)); |
| } |
| } |
| |
| private class TitlePaneLayout implements LayoutManager { |
| public void addLayoutComponent(String name, Component c) { |
| } |
| |
| public void removeLayoutComponent(Component c) { |
| } |
| |
| public Dimension preferredLayoutSize(Container c) { |
| int height = computeHeight(); |
| //noinspection SuspiciousNameCombination |
| return new Dimension(height, height); |
| } |
| |
| public Dimension minimumLayoutSize(Container c) { |
| return preferredLayoutSize(c); |
| } |
| |
| private int computeHeight() { |
| FontMetrics fm = myRootPane.getFontMetrics(getFont()); |
| int fontHeight = fm.getHeight(); |
| fontHeight += 7; |
| int iconHeight = 0; |
| if (getWindowDecorationStyle() == JRootPane.FRAME) { |
| iconHeight = IMAGE_HEIGHT; |
| } |
| |
| return Math.max(fontHeight, iconHeight); |
| } |
| |
| public void layoutContainer(Container c) { |
| boolean leftToRight = (myWindow == null) ? |
| getRootPane().getComponentOrientation().isLeftToRight() : |
| myWindow.getComponentOrientation().isLeftToRight(); |
| |
| int w = getWidth(); |
| int x; |
| int y = 3; |
| int spacing; |
| int buttonHeight; |
| int buttonWidth; |
| |
| if (myCloseButton != null && myCloseButton.getIcon() != null) { |
| buttonHeight = myCloseButton.getIcon().getIconHeight(); |
| buttonWidth = myCloseButton.getIcon().getIconWidth(); |
| } |
| else { |
| buttonHeight = IMAGE_HEIGHT; |
| buttonWidth = IMAGE_WIDTH; |
| } |
| |
| |
| x = leftToRight ? w : 0; |
| |
| spacing = 5; |
| x = leftToRight ? spacing : w - buttonWidth - spacing; |
| if (myMenuBar != null) { |
| myMenuBar.setBounds(x, y, buttonWidth, buttonHeight); |
| } |
| |
| x = leftToRight ? w : 0; |
| spacing = 4; |
| x += leftToRight ? -spacing - buttonWidth : spacing; |
| if (myCloseButton != null) { |
| myCloseButton.setBounds(x, y, buttonWidth, buttonHeight); |
| } |
| |
| if (!leftToRight) x += buttonWidth; |
| |
| if (getWindowDecorationStyle() == JRootPane.FRAME) { |
| if (Toolkit.getDefaultToolkit().isFrameStateSupported( |
| Frame.MAXIMIZED_BOTH)) { |
| if (myToggleButton.getParent() != null) { |
| spacing = 10; |
| x += leftToRight ? -spacing - buttonWidth : spacing; |
| myToggleButton.setBounds(x, y, buttonWidth, buttonHeight); |
| if (!leftToRight) { |
| x += buttonWidth; |
| } |
| } |
| } |
| |
| if (myIconifyButton != null && myIconifyButton.getParent() != null) { |
| spacing = 2; |
| x += leftToRight ? -spacing - buttonWidth : spacing; |
| myIconifyButton.setBounds(x, y, buttonWidth, buttonHeight); |
| if (!leftToRight) { |
| x += buttonWidth; |
| } |
| } |
| } |
| } |
| } |
| |
| |
| private class PropertyChangeHandler implements PropertyChangeListener { |
| public void propertyChange(PropertyChangeEvent pce) { |
| String name = pce.getPropertyName(); |
| |
| if ("resizable".equals(name) || "state".equals(name)) { |
| Frame frame = getFrame(); |
| |
| if (frame != null) { |
| setState(frame.getExtendedState(), true); |
| } |
| if ("resizable".equals(name)) { |
| getRootPane().repaint(); |
| } |
| } |
| else if ("title".equals(name)) { |
| repaint(); |
| } |
| else if ("componentOrientation" == name) { |
| revalidate(); |
| repaint(); |
| } |
| else if ("iconImage" == name) { |
| updateSystemIcon(); |
| revalidate(); |
| repaint(); |
| } |
| } |
| } |
| |
| private void updateSystemIcon() { |
| Window window = getWindow(); |
| if (window == null) { |
| mySystemIcon = null; |
| return; |
| } |
| |
| List<Image> icons = window.getIconImages(); |
| assert icons != null; |
| |
| if (icons.size() == 0) { |
| mySystemIcon = null; |
| } else if (icons.size() == 1) { |
| mySystemIcon = icons.get(0); |
| } else { |
| mySystemIcon = SunToolkit.getScaledIconImage(icons, IMAGE_WIDTH, IMAGE_HEIGHT); |
| } |
| } |
| |
| private class WindowHandler extends WindowAdapter { |
| public void windowActivated(WindowEvent ev) { |
| setActive(true); |
| } |
| |
| public void windowDeactivated(WindowEvent ev) { |
| setActive(false); |
| } |
| } |
| } |