| /* |
| * Copyright 2000-2014 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.openapi.wm.impl; |
| |
| import com.intellij.ide.actions.ResizeToolWindowAction; |
| import com.intellij.idea.ActionsBundle; |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.actionSystem.*; |
| import com.intellij.openapi.keymap.Keymap; |
| import com.intellij.openapi.keymap.KeymapManagerListener; |
| import com.intellij.openapi.keymap.ex.KeymapManagerEx; |
| import com.intellij.openapi.project.DumbAware; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.Queryable; |
| import com.intellij.openapi.ui.Splitter; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Disposer; |
| import com.intellij.openapi.util.SystemInfo; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.wm.*; |
| import com.intellij.ui.Gray; |
| import com.intellij.ui.JBColor; |
| import com.intellij.ui.UIBundle; |
| import com.intellij.ui.components.panels.NonOpaquePanel; |
| import com.intellij.ui.content.Content; |
| import com.intellij.util.EventDispatcher; |
| import com.intellij.util.Producer; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.border.Border; |
| import javax.swing.border.EmptyBorder; |
| import java.awt.*; |
| import java.awt.event.*; |
| import java.util.Map; |
| |
| /** |
| * @author Eugene Belyaev |
| * @author Vladimir Kondratyev |
| */ |
| public final class InternalDecorator extends JPanel implements Queryable, TypeSafeDataProvider { |
| |
| private Project myProject; |
| private WindowInfoImpl myInfo; |
| private final ToolWindowImpl myToolWindow; |
| private final MyDivider myDivider; |
| private final EventDispatcher<InternalDecoratorListener> myDispatcher = EventDispatcher.create(InternalDecoratorListener.class); |
| /* |
| * Actions |
| */ |
| private final TogglePinnedModeAction myToggleAutoHideModeAction; |
| private final ToggleDockModeAction myToggleDockModeAction; |
| private final ToggleFloatingModeAction myToggleFloatingModeAction; |
| private final ToggleSideModeAction myToggleSideModeAction; |
| private final ToggleContentUiTypeAction myToggleContentUiTypeAction; |
| |
| private ActionGroup myAdditionalGearActions; |
| /** |
| * Catches all event from tool window and modifies decorator's appearance. |
| */ |
| private final MyKeymapManagerListener myWeakKeymapManagerListener; |
| @NonNls private static final String HIDE_ACTIVE_WINDOW_ACTION_ID = "HideActiveWindow"; |
| @NonNls public static final String TOGGLE_PINNED_MODE_ACTION_ID = "TogglePinnedMode"; |
| @NonNls public static final String TOGGLE_DOCK_MODE_ACTION_ID = "ToggleDockMode"; |
| @NonNls public static final String TOGGLE_FLOATING_MODE_ACTION_ID = "ToggleFloatingMode"; |
| @NonNls public static final String TOGGLE_SIDE_MODE_ACTION_ID = "ToggleSideMode"; |
| @NonNls private static final String TOGGLE_CONTENT_UI_TYPE_ACTION_ID = "ToggleContentUiTypeMode"; |
| |
| private ToolWindowHeader myHeader; |
| |
| InternalDecorator(final Project project, @NotNull WindowInfoImpl info, final ToolWindowImpl toolWindow) { |
| super(new BorderLayout()); |
| myProject = project; |
| myToolWindow = toolWindow; |
| myToolWindow.setDecorator(this); |
| myDivider = new MyDivider(); |
| |
| myToggleFloatingModeAction = new ToggleFloatingModeAction(); |
| myToggleSideModeAction = new ToggleSideModeAction(); |
| myToggleDockModeAction = new ToggleDockModeAction(); |
| myToggleAutoHideModeAction = new TogglePinnedModeAction(); |
| myToggleContentUiTypeAction = new ToggleContentUiTypeAction(); |
| |
| myHeader = new ToolWindowHeader(toolWindow, info, new Producer<ActionGroup>() { |
| @Override |
| public ActionGroup produce() { |
| return createGearPopupGroup(); |
| } |
| }) { |
| @Override |
| protected boolean isActive() { |
| return isFocused(); |
| } |
| |
| @Override |
| protected void hideToolWindow() { |
| fireHidden(); |
| } |
| |
| @Override |
| protected void toolWindowTypeChanged(ToolWindowType type) { |
| fireTypeChanged(type); |
| } |
| |
| @Override |
| protected void sideHidden() { |
| fireHiddenSide(); |
| } |
| }; |
| |
| MyKeymapManagerListener keymapManagerListener = new MyKeymapManagerListener(); |
| final KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx(); |
| myWeakKeymapManagerListener = keymapManagerListener; |
| keymapManager.addWeakListener(keymapManagerListener); |
| |
| init(); |
| |
| apply(info); |
| } |
| |
| public boolean isFocused() { |
| IdeFocusManager fm = IdeFocusManager.getInstance(myProject); |
| Component component = fm.getFocusedDescendantFor(myToolWindow.getComponent()); |
| if (component != null) return true; |
| |
| Component owner = fm.getLastFocusedFor(WindowManager.getInstance().getIdeFrame(myProject)); |
| |
| return owner != null && SwingUtilities.isDescendingFrom(owner, myToolWindow.getComponent()); |
| } |
| |
| /** |
| * Applies specified decoration. |
| */ |
| public final void apply(@NotNull WindowInfoImpl info) { |
| if (Comparing.equal(myInfo, info) || myProject == null || myProject.isDisposed()) { |
| return; |
| } |
| myInfo = info; |
| |
| // Anchor |
| final ToolWindowAnchor anchor = myInfo.getAnchor(); |
| if (info.isSliding()) { |
| myDivider.invalidate(); |
| if (ToolWindowAnchor.TOP == anchor) { |
| add(myDivider, BorderLayout.SOUTH); |
| } |
| else if (ToolWindowAnchor.LEFT == anchor) { |
| add(myDivider, BorderLayout.EAST); |
| } |
| else if (ToolWindowAnchor.BOTTOM == anchor) { |
| add(myDivider, BorderLayout.NORTH); |
| } |
| else if (ToolWindowAnchor.RIGHT == anchor) { |
| add(myDivider, BorderLayout.WEST); |
| } |
| myDivider.setPreferredSize(new Dimension(0, 0)); |
| } |
| else { // docked and floating windows don't have divider |
| remove(myDivider); |
| } |
| |
| validate(); |
| repaint(); |
| |
| |
| // Push "apply" request forward |
| |
| if (myInfo.isFloating() && myInfo.isVisible()) { |
| final FloatingDecorator floatingDecorator = (FloatingDecorator)SwingUtilities.getAncestorOfClass(FloatingDecorator.class, this); |
| if (floatingDecorator != null) { |
| floatingDecorator.apply(myInfo); |
| } |
| } |
| |
| myToolWindow.getContentUI().setType(myInfo.getContentUiType()); |
| setBorder(new InnerPanelBorder(myToolWindow)); |
| } |
| |
| @Override |
| public void calcData(DataKey key, DataSink sink) { |
| if (PlatformDataKeys.TOOL_WINDOW.equals(key)) { |
| sink.put(PlatformDataKeys.TOOL_WINDOW, myToolWindow); |
| } |
| } |
| |
| final void addInternalDecoratorListener(InternalDecoratorListener l) { |
| myDispatcher.addListener(l); |
| } |
| |
| final void removeInternalDecoratorListener(InternalDecoratorListener l) { |
| myDispatcher.removeListener(l); |
| } |
| |
| final void dispose() { |
| removeAll(); |
| KeymapManagerEx.getInstanceEx().removeWeakListener(myWeakKeymapManagerListener); |
| |
| Disposer.dispose(myHeader); |
| myHeader = null; |
| myProject = null; |
| } |
| |
| private void fireAnchorChanged(ToolWindowAnchor anchor) { |
| myDispatcher.getMulticaster().anchorChanged(this, anchor); |
| } |
| |
| private void fireAutoHideChanged(boolean autoHide) { |
| myDispatcher.getMulticaster().autoHideChanged(this, autoHide); |
| } |
| |
| /** |
| * Fires event that "hide" button has been pressed. |
| */ |
| final void fireHidden() { |
| myDispatcher.getMulticaster().hidden(this); |
| } |
| |
| /** |
| * Fires event that "hide" button has been pressed. |
| */ |
| final void fireHiddenSide() { |
| myDispatcher.getMulticaster().hiddenSide(this); |
| } |
| |
| /** |
| * Fires event that user performed click into the title bar area. |
| */ |
| final void fireActivated() { |
| myDispatcher.getMulticaster().activated(this); |
| } |
| |
| private void fireTypeChanged(ToolWindowType type) { |
| myDispatcher.getMulticaster().typeChanged(this, type); |
| } |
| |
| final void fireResized() { |
| myDispatcher.getMulticaster().resized(this); |
| } |
| |
| private void fireSideStatusChanged(boolean isSide) { |
| myDispatcher.getMulticaster().sideStatusChanged(this, isSide); |
| } |
| |
| private void fireContentUiTypeChanges(ToolWindowContentUiType type) { |
| myDispatcher.getMulticaster().contentUiTypeChanges(this, type); |
| } |
| |
| private void init() { |
| enableEvents(AWTEvent.COMPONENT_EVENT_MASK); |
| |
| final JPanel contentPane = new JPanel(new BorderLayout()); |
| contentPane.add(myHeader, BorderLayout.NORTH); |
| |
| JPanel innerPanel = new JPanel(new BorderLayout()); |
| JComponent toolWindowComponent = myToolWindow.getComponent(); |
| innerPanel.add(toolWindowComponent, BorderLayout.CENTER); |
| |
| final NonOpaquePanel inner = new NonOpaquePanel(innerPanel); |
| inner.setBorder(new EmptyBorder(0, 0, 0, 0)); |
| |
| contentPane.add(inner, BorderLayout.CENTER); |
| add(contentPane, BorderLayout.CENTER); |
| if (SystemInfo.isMac) { |
| setBackground(new JBColor(Gray._200, Gray._90)); |
| } |
| |
| // Add listeners |
| registerKeyboardAction(new ActionListener() { |
| @Override |
| public void actionPerformed(final ActionEvent e) { |
| ToolWindowManager.getInstance(myProject).activateEditorComponent(); |
| } |
| }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); |
| } |
| |
| public void setTitleActions(AnAction[] actions) { |
| myHeader.setAdditionalTitleActions(actions); |
| } |
| |
| private class InnerPanelBorder implements Border { |
| |
| private final ToolWindow myWindow; |
| |
| private InnerPanelBorder(ToolWindow window) { |
| myWindow = window; |
| } |
| |
| @Override |
| public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) { |
| if (UIUtil.isUnderDarcula()) { |
| g.setColor(Gray._40); |
| doPaintBorder(c, g, x, y, width, height); |
| } |
| else { |
| g.setColor(UIUtil.getPanelBackground()); |
| doPaintBorder(c, g, x, y, width, height); |
| g.setColor(Gray._155); |
| doPaintBorder(c, g, x, y, width, height); |
| } |
| } |
| |
| private void doPaintBorder(Component c, Graphics g, int x, int y, int width, int height) { |
| Insets insets = getBorderInsets(c); |
| |
| if (insets.top > 0) { |
| UIUtil.drawLine(g, x, y + insets.top - 1, x + width - 1, y + insets.top - 1); |
| UIUtil.drawLine(g, x, y + insets.top, x + width - 1, y + insets.top); |
| } |
| |
| if (insets.left > 0) { |
| UIUtil.drawLine(g, x, y, x, y + height); |
| UIUtil.drawLine(g, x + 1, y, x + 1, y + height); |
| } |
| |
| if (insets.right > 0) { |
| UIUtil.drawLine(g, x + width - 1, y + insets.top, x + width - 1, y + height); |
| UIUtil.drawLine(g, x + width, y + insets.top, x + width, y + height); |
| } |
| |
| if (insets.bottom > 0) { |
| UIUtil.drawLine(g, x, y + height - 1, x + width, y + height - 1); |
| UIUtil.drawLine(g, x, y + height, x + width, y + height); |
| } |
| } |
| |
| @Override |
| public Insets getBorderInsets(final Component c) { |
| if (myProject == null) return new Insets(0, 0, 0, 0); |
| ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject); |
| if (!(toolWindowManager instanceof ToolWindowManagerImpl) |
| || !((ToolWindowManagerImpl)toolWindowManager).isToolWindowRegistered(myInfo.getId()) |
| || myWindow.getType() == ToolWindowType.FLOATING) { |
| return new Insets(0, 0, 0, 0); |
| } |
| ToolWindowAnchor anchor = myWindow.getAnchor(); |
| Component component = myWindow.getComponent(); |
| Container parent = component.getParent(); |
| while(parent != null) { |
| if (parent instanceof Splitter) { |
| Splitter splitter = (Splitter)parent; |
| boolean isFirst = splitter.getFirstComponent() == component; |
| boolean isVertical = splitter.isVertical(); |
| return new Insets(0, |
| anchor == ToolWindowAnchor.RIGHT || (!isVertical && !isFirst) ? 1 : 0, |
| (isVertical && isFirst) ? 1 : 0, |
| anchor == ToolWindowAnchor.LEFT || (!isVertical && isFirst) ? 1 : 0); |
| } |
| component = parent; |
| parent = component.getParent(); |
| } |
| return new Insets(0, anchor == ToolWindowAnchor.RIGHT ? 1 : 0, anchor == ToolWindowAnchor.TOP ? 1 : 0, anchor == ToolWindowAnchor.LEFT ? 1 : 0); |
| } |
| |
| @Override |
| public boolean isBorderOpaque() { |
| return false; |
| } |
| } |
| |
| |
| public final ActionGroup createPopupGroup() { |
| final DefaultActionGroup group = createGearPopupGroup(); |
| |
| group.add(myToggleContentUiTypeAction); |
| |
| final DefaultActionGroup moveGroup = new DefaultActionGroup(UIBundle.message("tool.window.move.to.action.group.name"), true); |
| final ToolWindowAnchor anchor = myInfo.getAnchor(); |
| if (anchor != ToolWindowAnchor.TOP) { |
| final AnAction topAction = new ChangeAnchorAction(UIBundle.message("tool.window.move.to.top.action.name"), ToolWindowAnchor.TOP); |
| moveGroup.add(topAction); |
| } |
| if (anchor != ToolWindowAnchor.LEFT) { |
| final AnAction leftAction = new ChangeAnchorAction(UIBundle.message("tool.window.move.to.left.action.name"), ToolWindowAnchor.LEFT); |
| moveGroup.add(leftAction); |
| } |
| if (anchor != ToolWindowAnchor.BOTTOM) { |
| final AnAction bottomAction = |
| new ChangeAnchorAction(UIBundle.message("tool.window.move.to.bottom.action.name"), ToolWindowAnchor.BOTTOM); |
| moveGroup.add(bottomAction); |
| } |
| if (anchor != ToolWindowAnchor.RIGHT) { |
| final AnAction rightAction = |
| new ChangeAnchorAction(UIBundle.message("tool.window.move.to.right.action.name"), ToolWindowAnchor.RIGHT); |
| moveGroup.add(rightAction); |
| } |
| group.add(moveGroup); |
| |
| DefaultActionGroup resize = new DefaultActionGroup(ActionsBundle.groupText("ResizeToolWindowGroup"), true); |
| resize.add(new ResizeToolWindowAction.Left(myToolWindow, this)); |
| resize.add(new ResizeToolWindowAction.Right(myToolWindow, this)); |
| resize.add(new ResizeToolWindowAction.Up(myToolWindow, this)); |
| resize.add(new ResizeToolWindowAction.Down(myToolWindow, this)); |
| |
| group.add(resize); |
| |
| group.addSeparator(); |
| group.add(new HideAction()); |
| return group; |
| } |
| |
| private DefaultActionGroup createGearPopupGroup() { |
| final DefaultActionGroup group = new DefaultActionGroup(); |
| |
| if (myAdditionalGearActions != null) { |
| addSorted(group, myAdditionalGearActions); |
| group.addSeparator(); |
| } |
| if (myInfo.isDocked()) { |
| group.add(myToggleAutoHideModeAction); |
| group.add(myToggleDockModeAction); |
| group.add(myToggleFloatingModeAction); |
| group.add(myToggleSideModeAction); |
| } |
| else if (myInfo.isFloating()) { |
| group.add(myToggleAutoHideModeAction); |
| group.add(myToggleFloatingModeAction); |
| } |
| else if (myInfo.isSliding()) { |
| group.add(myToggleDockModeAction); |
| group.add(myToggleFloatingModeAction); |
| group.add(myToggleSideModeAction); |
| } |
| return group; |
| } |
| |
| private static void addSorted(DefaultActionGroup main, ActionGroup group) { |
| final AnAction[] children = group.getChildren(null); |
| boolean hadSecondary = false; |
| for (AnAction action : children) { |
| if (group.isPrimary(action)) { |
| main.add(action); |
| } else { |
| hadSecondary = true; |
| } |
| } |
| if (hadSecondary) { |
| main.addSeparator(); |
| for (AnAction action : children) { |
| if (!group.isPrimary(action)) { |
| main.addAction(action).setAsSecondary(true); |
| } |
| } |
| } |
| String separatorText = group.getTemplatePresentation().getText(); |
| if (children.length > 0 && !StringUtil.isEmpty(separatorText)) { |
| main.addAction(new Separator(separatorText), Constraints.FIRST); |
| } |
| } |
| |
| /** |
| * @return tool window associated with the decorator. |
| */ |
| final ToolWindowImpl getToolWindow() { |
| return myToolWindow; |
| } |
| |
| /** |
| * @return last window info applied to the decorator. |
| */ |
| @NotNull |
| final WindowInfoImpl getWindowInfo() { |
| return myInfo; |
| } |
| |
| public int getHeaderHeight() { |
| return myHeader.getPreferredSize().height; |
| } |
| |
| @Override |
| protected final void processComponentEvent(final ComponentEvent e) { |
| super.processComponentEvent(e); |
| if (ComponentEvent.COMPONENT_RESIZED == e.getID()) { |
| fireResized(); |
| } |
| } |
| |
| private final class ChangeAnchorAction extends AnAction implements DumbAware { |
| private final ToolWindowAnchor myAnchor; |
| |
| public ChangeAnchorAction(final String title, final ToolWindowAnchor anchor) { |
| super(title); |
| myAnchor = anchor; |
| } |
| |
| @Override |
| public final void actionPerformed(final AnActionEvent e) { |
| fireAnchorChanged(myAnchor); |
| } |
| } |
| |
| private final class TogglePinnedModeAction extends ToggleAction implements DumbAware { |
| public TogglePinnedModeAction() { |
| copyFrom(ActionManager.getInstance().getAction(TOGGLE_PINNED_MODE_ACTION_ID)); |
| } |
| |
| @Override |
| public final boolean isSelected(final AnActionEvent event) { |
| return !myInfo.isAutoHide(); |
| } |
| |
| @Override |
| public final void setSelected(final AnActionEvent event, final boolean flag) { |
| fireAutoHideChanged(!myInfo.isAutoHide()); |
| } |
| } |
| |
| private final class ToggleDockModeAction extends ToggleAction implements DumbAware { |
| public ToggleDockModeAction() { |
| copyFrom(ActionManager.getInstance().getAction(TOGGLE_DOCK_MODE_ACTION_ID)); |
| } |
| |
| @Override |
| public final boolean isSelected(final AnActionEvent event) { |
| return myInfo.isDocked(); |
| } |
| |
| @Override |
| public final void setSelected(final AnActionEvent event, final boolean flag) { |
| if (myInfo.isDocked()) { |
| fireTypeChanged(ToolWindowType.SLIDING); |
| } |
| else if (myInfo.isSliding()) { |
| fireTypeChanged(ToolWindowType.DOCKED); |
| } |
| } |
| } |
| |
| private final class ToggleFloatingModeAction extends ToggleAction implements DumbAware { |
| public ToggleFloatingModeAction() { |
| copyFrom(ActionManager.getInstance().getAction(TOGGLE_FLOATING_MODE_ACTION_ID)); |
| } |
| |
| @Override |
| public final boolean isSelected(final AnActionEvent event) { |
| return myInfo.isFloating(); |
| } |
| |
| @Override |
| public final void setSelected(final AnActionEvent event, final boolean flag) { |
| if (myInfo.isFloating()) { |
| fireTypeChanged(myInfo.getInternalType()); |
| } |
| else { |
| fireTypeChanged(ToolWindowType.FLOATING); |
| } |
| } |
| } |
| |
| private final class ToggleSideModeAction extends ToggleAction implements DumbAware { |
| public ToggleSideModeAction() { |
| copyFrom(ActionManager.getInstance().getAction(TOGGLE_SIDE_MODE_ACTION_ID)); |
| } |
| |
| @Override |
| public final boolean isSelected(final AnActionEvent event) { |
| return myInfo.isSplit(); |
| } |
| |
| @Override |
| public final void setSelected(final AnActionEvent event, final boolean flag) { |
| fireSideStatusChanged(flag); |
| } |
| |
| @Override |
| public void update(final AnActionEvent e) { |
| super.update(e); |
| } |
| } |
| |
| private final class HideAction extends AnAction implements DumbAware { |
| @NonNls public static final String HIDE_ACTIVE_WINDOW_ACTION_ID = InternalDecorator.HIDE_ACTIVE_WINDOW_ACTION_ID; |
| |
| public HideAction() { |
| copyFrom(ActionManager.getInstance().getAction(HIDE_ACTIVE_WINDOW_ACTION_ID)); |
| getTemplatePresentation().setText(UIBundle.message("tool.window.hide.action.name")); |
| } |
| |
| @Override |
| public final void actionPerformed(final AnActionEvent e) { |
| fireHidden(); |
| } |
| |
| @Override |
| public final void update(final AnActionEvent event) { |
| final Presentation presentation = event.getPresentation(); |
| presentation.setEnabled(myInfo.isVisible()); |
| } |
| } |
| |
| |
| private final class ToggleContentUiTypeAction extends ToggleAction implements DumbAware { |
| private ToggleContentUiTypeAction() { |
| copyFrom(ActionManager.getInstance().getAction(TOGGLE_CONTENT_UI_TYPE_ACTION_ID)); |
| } |
| |
| @Override |
| public boolean isSelected(AnActionEvent e) { |
| return myInfo.getContentUiType() == ToolWindowContentUiType.TABBED; |
| } |
| |
| @Override |
| public void setSelected(AnActionEvent e, boolean state) { |
| fireContentUiTypeChanges(state ? ToolWindowContentUiType.TABBED : ToolWindowContentUiType.COMBO); |
| } |
| } |
| |
| private final class MyDivider extends JPanel { |
| private boolean myDragging; |
| private Point myLastPoint; |
| private Disposable myDisposable; |
| private IdeGlassPane myGlassPane; |
| |
| private final MouseAdapter myListener = new MyMouseAdapter(); |
| |
| @Override |
| public void addNotify() { |
| super.addNotify(); |
| myGlassPane = IdeGlassPaneUtil.find(this); |
| myDisposable = Disposer.newDisposable(); |
| myGlassPane.addMouseMotionPreprocessor(myListener, myDisposable); |
| myGlassPane.addMousePreprocessor(myListener, myDisposable); |
| } |
| |
| @Override |
| public void removeNotify() { |
| super.removeNotify(); |
| if (myDisposable != null && !Disposer.isDisposed(myDisposable)) { |
| Disposer.dispose(myDisposable); |
| } |
| } |
| |
| boolean isInDragZone(MouseEvent e) { |
| final Point p = SwingUtilities.convertMouseEvent(e.getComponent(), e, this).getPoint(); |
| return Math.abs(myInfo.getAnchor().isHorizontal() ? p.y : p.x) < 6; |
| } |
| |
| |
| private class MyMouseAdapter extends MouseAdapter { |
| |
| private void updateCursor(MouseEvent e) { |
| if (isInDragZone(e)) { |
| myGlassPane.setCursor(MyDivider.this.getCursor(), MyDivider.this); |
| e.consume(); |
| } |
| } |
| |
| @Override |
| public void mousePressed(MouseEvent e) { |
| myDragging = isInDragZone(e); |
| updateCursor(e); |
| } |
| |
| @Override |
| public void mouseClicked(MouseEvent e) { |
| updateCursor(e); |
| } |
| |
| @Override |
| public void mouseReleased(MouseEvent e) { |
| updateCursor(e); |
| myDragging = false; |
| } |
| |
| @Override |
| public void mouseMoved(MouseEvent e) { |
| updateCursor(e); |
| } |
| |
| @Override |
| public void mouseDragged(MouseEvent e) { |
| if (!myDragging) return; |
| MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, MyDivider.this); |
| final ToolWindowAnchor anchor = myInfo.getAnchor(); |
| final Point point = event.getPoint(); |
| final Container windowPane = InternalDecorator.this.getParent(); |
| myLastPoint = SwingUtilities.convertPoint(MyDivider.this, point, windowPane); |
| myLastPoint.x = Math.min(Math.max(myLastPoint.x, 0), windowPane.getWidth()); |
| myLastPoint.y = Math.min(Math.max(myLastPoint.y, 0), windowPane.getHeight()); |
| |
| final Rectangle bounds = InternalDecorator.this.getBounds(); |
| if (anchor == ToolWindowAnchor.TOP) { |
| InternalDecorator.this.setBounds(0, 0, bounds.width, myLastPoint.y); |
| } |
| else if (anchor == ToolWindowAnchor.LEFT) { |
| InternalDecorator.this.setBounds(0, 0, myLastPoint.x, bounds.height); |
| } |
| else if (anchor == ToolWindowAnchor.BOTTOM) { |
| InternalDecorator.this.setBounds(0, myLastPoint.y, bounds.width, windowPane.getHeight() - myLastPoint.y); |
| } |
| else if (anchor == ToolWindowAnchor.RIGHT) { |
| InternalDecorator.this.setBounds(myLastPoint.x, 0, windowPane.getWidth() - myLastPoint.x, bounds.height); |
| } |
| InternalDecorator.this.validate(); |
| e.consume(); |
| } |
| } |
| |
| @Override |
| public Cursor getCursor() { |
| final boolean isVerticalCursor = myInfo.isDocked() ? myInfo.getAnchor().isSplitVertically() : myInfo.getAnchor().isHorizontal(); |
| return isVerticalCursor ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR); |
| } |
| } |
| |
| /** |
| * Updates tooltips. |
| */ |
| private final class MyKeymapManagerListener implements KeymapManagerListener { |
| @Override |
| public final void activeKeymapChanged(final Keymap keymap) { |
| if (myHeader != null) { |
| myHeader.updateTooltips(); |
| } |
| } |
| } |
| |
| @Override |
| public void putInfo(@NotNull Map<String, String> info) { |
| info.put("toolWindowTitle", myToolWindow.getTitle()); |
| |
| final Content selection = myToolWindow.getContentManager().getSelectedContent(); |
| if (selection != null) { |
| info.put("toolWindowTab", selection.getTabName()); |
| } |
| } |
| |
| public void setAdditionalGearActions(@Nullable ActionGroup additionalGearActions) { |
| myAdditionalGearActions = additionalGearActions; |
| } |
| } |