diff options
Diffstat (limited to 'platform/platform-impl/src/com/intellij/designer/LightToolWindow.java')
-rw-r--r-- | platform/platform-impl/src/com/intellij/designer/LightToolWindow.java | 562 |
1 files changed, 562 insertions, 0 deletions
diff --git a/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java b/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java new file mode 100644 index 000000000000..ce3cb33deb90 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java @@ -0,0 +1,562 @@ +/* + * 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.designer; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; +import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ThreeComponentsSplitter; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.wm.*; +import com.intellij.openapi.wm.ex.ToolWindowEx; +import com.intellij.openapi.wm.impl.AnchoredButton; +import com.intellij.openapi.wm.impl.InternalDecorator; +import com.intellij.openapi.wm.impl.StripeButtonUI; +import com.intellij.openapi.wm.impl.content.ToolWindowContentUi; +import com.intellij.ui.*; +import com.intellij.ui.components.panels.Wrapper; +import com.intellij.ui.tabs.TabsUtil; +import com.intellij.util.ui.EmptyIcon; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; + +/** + * @author Alexander Lobas + */ +public class LightToolWindow extends JPanel { + public static final String LEFT_MIN_KEY = "left"; + public static final String RIGHT_MIN_KEY = "right"; + public static final int MINIMIZE_WIDTH = 25; + private static final String IGNORE_WIDTH_KEY = "ignore_width"; + + private final LightToolWindowContent myContent; + private final JComponent myFocusedComponent; + private final ThreeComponentsSplitter myContentSplitter; + private ToolWindowAnchor myAnchor; + private final Project myProject; + private final LightToolWindowManager myManager; + private final PropertiesComponent myPropertiesComponent; + private boolean myShowContent; + private final String myShowStateKey; + private int myCurrentWidth; + private final String myWidthKey; + private final JPanel myMinimizeComponent; + private final AnchoredButton myMinimizeButton; + + private final TogglePinnedModeAction myToggleAutoHideModeAction = new TogglePinnedModeAction(); + private final ToggleDockModeAction myToggleDockModeAction = new ToggleDockModeAction(); + private final ToggleFloatingModeAction myToggleFloatingModeAction = new ToggleFloatingModeAction(); + private final ToggleSideModeAction myToggleSideModeAction = new ToggleSideModeAction(); + + private final ComponentListener myWidthListener = new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + int width = isLeft() ? myContentSplitter.getFirstSize() : myContentSplitter.getLastSize(); + if (width > 0 && width != myCurrentWidth && myContentSplitter.getInnerComponent().getClientProperty(IGNORE_WIDTH_KEY) == null) { + myCurrentWidth = width; + myPropertiesComponent.setValue(myWidthKey, Integer.toString(width)); + } + } + }; + + public LightToolWindow(@NotNull LightToolWindowContent content, + @NotNull String title, + @NotNull Icon icon, + @NotNull JComponent component, + @NotNull JComponent focusedComponent, + @NotNull ThreeComponentsSplitter contentSplitter, + @Nullable ToolWindowAnchor anchor, + @NotNull LightToolWindowManager manager, + @NotNull Project project, + @NotNull PropertiesComponent propertiesComponent, + @NotNull String key, + int defaultWidth, + @Nullable AnAction[] actions) { + super(new BorderLayout()); + myContent = content; + myFocusedComponent = focusedComponent; + myContentSplitter = contentSplitter; + myAnchor = anchor; + myProject = project; + myManager = manager; + myPropertiesComponent = propertiesComponent; + + myShowStateKey = LightToolWindowManager.EDITOR_MODE + key + ".SHOW"; + myWidthKey = LightToolWindowManager.EDITOR_MODE + key + ".WIDTH"; + + HeaderPanel header = new HeaderPanel(); + header.setLayout(new BorderLayout()); + add(header, BorderLayout.NORTH); + + JLabel titleLabel = new JLabel(title); + titleLabel.setBorder(IdeBorderFactory.createEmptyBorder(2, 5, 2, 10)); + titleLabel.setFont(UIUtil.getLabelFont(UIUtil.FontSize.SMALL)); + header.add(titleLabel, BorderLayout.CENTER); + + JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0)); + actionPanel.setBorder(IdeBorderFactory.createEmptyBorder(3, 0, 2, 0)); + actionPanel.setOpaque(false); + header.add(actionPanel, BorderLayout.EAST); + + if (actions != null) { + for (AnAction action : actions) { + addAction(actionPanel, action); + } + + actionPanel.add(new JLabel(AllIcons.General.Divider)); + } + + addAction(actionPanel, new GearAction()); + addAction(actionPanel, new HideAction()); + + JPanel contentWrapper = new JPanel(new BorderLayout()); + contentWrapper.setBorder(IdeBorderFactory.createBorder(SideBorder.TOP)); + contentWrapper.add(component, BorderLayout.CENTER); + + add(contentWrapper, BorderLayout.CENTER); + + addMouseListener(new MouseAdapter() { + public void mouseReleased(final MouseEvent e) { + IdeFocusManager.getInstance(myProject).requestFocus(myFocusedComponent, true); + } + }); + + addMouseListener(new PopupHandler() { + public void invokePopup(Component component, int x, int y) { + showGearPopup(component, x, y); + } + }); + + myMinimizeButton = new AnchoredButton(title, icon) { + @Override + public void updateUI() { + setUI(StripeButtonUI.createUI(this)); + setFont(UIUtil.getLabelFont(UIUtil.FontSize.SMALL)); + } + + @Override + public int getMnemonic2() { + return 0; + } + + @Override + public ToolWindowAnchor getAnchor() { + return myAnchor; + } + }; + myMinimizeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + myMinimizeButton.setSelected(false); + updateContent(true, true); + } + }); + myMinimizeButton.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); + myMinimizeButton.setFocusable(false); + + myMinimizeButton.setRolloverEnabled(true); + myMinimizeButton.setOpaque(false); + + myMinimizeComponent = new JPanel() { + @Override + public void doLayout() { + Dimension size = myMinimizeButton.getPreferredSize(); + myMinimizeButton.setBounds(0, 0, getWidth(), size.height); + } + }; + myMinimizeComponent.add(myMinimizeButton); + + configureBorder(); + configureWidth(defaultWidth); + updateContent(myPropertiesComponent.getBoolean(myShowStateKey, true), false); + } + + private void configureBorder() { + int borderStyle = isLeft() ? SideBorder.RIGHT : SideBorder.LEFT; + setBorder(IdeBorderFactory.createBorder(borderStyle)); + myMinimizeComponent.setBorder(IdeBorderFactory.createBorder(borderStyle)); + } + + private void configureWidth(int defaultWidth) { + myCurrentWidth = myPropertiesComponent.getOrInitInt(myWidthKey, defaultWidth); + updateWidth(); + myContentSplitter.getInnerComponent().addComponentListener(myWidthListener); + } + + private void updateWidth() { + if (isLeft()) { + myContentSplitter.setFirstSize(myCurrentWidth); + } + else { + myContentSplitter.setLastSize(myCurrentWidth); + } + } + + public void updateAnchor(ToolWindowAnchor newAnchor) { + JComponent minimizeParent = myContentSplitter.getInnerComponent(); + minimizeParent.putClientProperty(IGNORE_WIDTH_KEY, Boolean.TRUE); + + if (myShowContent) { + Object oldWindow = isLeft() ? myContentSplitter.getFirstComponent() : myContentSplitter.getLastComponent(); + if (oldWindow == this) { + setContentComponent(null); + } + } + else { + String key = getMinKey(); + if (minimizeParent.getClientProperty(key) == myMinimizeComponent) { + minimizeParent.putClientProperty(key, null); + } + minimizeParent.putClientProperty(isLeft() ? RIGHT_MIN_KEY : LEFT_MIN_KEY, myMinimizeComponent); + minimizeParent.revalidate(); + } + + myAnchor = newAnchor; + configureBorder(); + updateWidth(); + + if (myShowContent) { + setContentComponent(this); + } + + minimizeParent.putClientProperty(IGNORE_WIDTH_KEY, null); + } + + private void updateContent(boolean show, boolean flag) { + myShowContent = show; + + String key = getMinKey(); + + JComponent minimizeParent = myContentSplitter.getInnerComponent(); + + if (show) { + minimizeParent.putClientProperty(key, null); + minimizeParent.remove(myMinimizeComponent); + } + + setContentComponent(show ? this : null); + + if (!show) { + minimizeParent.putClientProperty(key, myMinimizeComponent); + minimizeParent.add(myMinimizeComponent); + } + + minimizeParent.revalidate(); + + if (flag) { + myPropertiesComponent.setValue(myShowStateKey, Boolean.toString(show)); + } + } + + private void setContentComponent(JComponent component) { + if (isLeft()) { + myContentSplitter.setFirstComponent(component); + } + else { + myContentSplitter.setLastComponent(component); + } + } + + public void dispose() { + JComponent minimizeParent = myContentSplitter.getInnerComponent(); + minimizeParent.removeComponentListener(myWidthListener); + + setContentComponent(null); + myContent.dispose(); + + if (!myShowContent) { + minimizeParent.putClientProperty(getMinKey(), null); + minimizeParent.remove(myMinimizeComponent); + minimizeParent.revalidate(); + } + } + + private String getMinKey() { + return isLeft() ? LEFT_MIN_KEY : RIGHT_MIN_KEY; + } + + public Object getContent() { + return myContent; + } + + private boolean isLeft() { + return myAnchor == ToolWindowAnchor.LEFT; + } + + private boolean isActive() { + IdeFocusManager fm = IdeFocusManager.getInstance(myProject); + Component component = fm.getFocusedDescendantFor(this); + if (component != null) { + return true; + } + Component owner = fm.getLastFocusedFor(WindowManager.getInstance().getIdeFrame(myProject)); + return owner != null && SwingUtilities.isDescendingFrom(owner, this); + } + + private void addAction(JPanel actionPanel, AnAction action) { + actionPanel.add(new ActionButton(action)); + } + + private DefaultActionGroup createGearPopupGroup() { + DefaultActionGroup group = new DefaultActionGroup(); + + group.add(myManager.createGearActions()); + group.addSeparator(); + + ToolWindowType type = myManager.getToolWindow().getType(); + if (type == ToolWindowType.DOCKED) { + group.add(myToggleAutoHideModeAction); + group.add(myToggleDockModeAction); + group.add(myToggleFloatingModeAction); + group.add(myToggleSideModeAction); + } + else if (type == ToolWindowType.FLOATING) { + group.add(myToggleAutoHideModeAction); + group.add(myToggleFloatingModeAction); + } + else if (type == ToolWindowType.SLIDING) { + group.add(myToggleDockModeAction); + group.add(myToggleFloatingModeAction); + } + + return group; + } + + private void showGearPopup(Component component, int x, int y) { + ActionPopupMenu popupMenu = + ((ActionManagerImpl)ActionManager.getInstance()) + .createActionPopupMenu(ToolWindowContentUi.POPUP_PLACE, createGearPopupGroup(), new MenuItemPresentationFactory(true)); + popupMenu.getComponent().show(component, x, y); + } + + private class GearAction extends AnAction { + public GearAction() { + Presentation presentation = getTemplatePresentation(); + presentation.setIcon(AllIcons.General.Gear); + presentation.setHoveredIcon(AllIcons.General.GearHover); + } + + @Override + public void actionPerformed(AnActionEvent e) { + int x = 0; + int y = 0; + InputEvent inputEvent = e.getInputEvent(); + if (inputEvent instanceof MouseEvent) { + x = ((MouseEvent)inputEvent).getX(); + y = ((MouseEvent)inputEvent).getY(); + } + + showGearPopup(inputEvent.getComponent(), x, y); + } + } + + private class HideAction extends AnAction { + public HideAction() { + Presentation presentation = getTemplatePresentation(); + presentation.setText(UIBundle.message("tool.window.hide.action.name")); + if (isLeft()) { + presentation.setIcon(AllIcons.General.HideLeftPart); + presentation.setHoveredIcon(AllIcons.General.HideLeftPartHover); + } + else { + presentation.setIcon(AllIcons.General.HideRightPart); + presentation.setHoveredIcon(AllIcons.General.HideRightPartHover); + } + } + + @Override + public void actionPerformed(AnActionEvent e) { + updateContent(false, true); + } + } + + private class TogglePinnedModeAction extends ToggleAction { + public TogglePinnedModeAction() { + copyFrom(ActionManager.getInstance().getAction(InternalDecorator.TOGGLE_PINNED_MODE_ACTION_ID)); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return !myManager.getToolWindow().isAutoHide(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + ToolWindow window = myManager.getToolWindow(); + window.setAutoHide(!window.isAutoHide()); + myManager.setEditorMode(null); + } + } + + private class ToggleDockModeAction extends ToggleAction { + public ToggleDockModeAction() { + copyFrom(ActionManager.getInstance().getAction(InternalDecorator.TOGGLE_DOCK_MODE_ACTION_ID)); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return myManager.getToolWindow().getType() == ToolWindowType.DOCKED; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + ToolWindow window = myManager.getToolWindow(); + ToolWindowType type = window.getType(); + if (type == ToolWindowType.DOCKED) { + window.setType(ToolWindowType.SLIDING, null); + } + else if (type == ToolWindowType.SLIDING) { + window.setType(ToolWindowType.DOCKED, null); + } + myManager.setEditorMode(null); + } + } + + private class ToggleFloatingModeAction extends ToggleAction { + public ToggleFloatingModeAction() { + copyFrom(ActionManager.getInstance().getAction(InternalDecorator.TOGGLE_FLOATING_MODE_ACTION_ID)); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return myManager.getToolWindow().getType() == ToolWindowType.FLOATING; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + ToolWindow window = myManager.getToolWindow(); + ToolWindowType type = window.getType(); + if (type == ToolWindowType.FLOATING) { + window.setType(((ToolWindowEx)window).getInternalType(), null); + } + else { + window.setType(ToolWindowType.FLOATING, null); + } + myManager.setEditorMode(null); + } + } + + private class ToggleSideModeAction extends ToggleAction { + public ToggleSideModeAction() { + copyFrom(ActionManager.getInstance().getAction(InternalDecorator.TOGGLE_SIDE_MODE_ACTION_ID)); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return myManager.getToolWindow().isSplitMode(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + myManager.getToolWindow().setSplitMode(state, null); + myManager.setEditorMode(null); + } + } + + private class ActionButton extends Wrapper implements ActionListener { + private final AnAction myAction; + + public ActionButton(AnAction action) { + myAction = action; + + Presentation presentation = action.getTemplatePresentation(); + InplaceButton button = new InplaceButton(KeymapUtil.createTooltipText(presentation.getText(), action), EmptyIcon.ICON_16, this) { + @Override + public boolean isActive() { + return LightToolWindow.this.isActive(); + } + }; + button.setHoveringEnabled(!SystemInfo.isMac); + setContent(button); + + Icon icon = presentation.getIcon(); + Icon hoveredIcon = presentation.getHoveredIcon(); + button.setIcons(icon, icon, hoveredIcon == null ? icon : hoveredIcon); + } + + @Override + public void actionPerformed(ActionEvent e) { + InputEvent inputEvent = e.getSource() instanceof InputEvent ? (InputEvent)e.getSource() : null; + myAction.actionPerformed(AnActionEvent.createFromInputEvent(myAction, inputEvent, ActionPlaces.UNKNOWN)); + } + } + + private class HeaderPanel extends JPanel { + private BufferedImage myActiveImage; + private BufferedImage myImage; + + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + return new Dimension(size.width, TabsUtil.getTabsHeight()); + } + + @Override + public Dimension getMinimumSize() { + Dimension size = super.getMinimumSize(); + return new Dimension(size.width, TabsUtil.getTabsHeight()); + } + + protected void _paintComponent(Graphics g) { // XXX: visual artifacts on linux + Rectangle r = getBounds(); + + Image image; + if (isActive()) { + if (myActiveImage == null || myActiveImage.getHeight() != r.height) { + myActiveImage = drawToBuffer(true, r.height); + } + image = myActiveImage; + } + else { + if (myImage == null || myImage.getHeight() != r.height) { + myImage = drawToBuffer(false, r.height); + } + image = myImage; + } + + Graphics2D g2d = (Graphics2D)g; + Rectangle clipBounds = g2d.getClip().getBounds(); + for (int x = clipBounds.x; x < clipBounds.x + clipBounds.width; x += 150) { + g2d.drawImage(image, x, 0, null); + } + } + + protected boolean isActive() { + return LightToolWindow.this.isActive(); + } + } + + private static BufferedImage drawToBuffer(boolean active, int height) { + final int width = 150; + + BufferedImage image = UIUtil.createImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + UIUtil.drawHeader(g, 0, width, height, active, true, false, false); + g.dispose(); + + return image; + } +}
\ No newline at end of file |