IDEA-112485 Shortcut to maximize toolwindow

This commit is contained in:
Vassiliy.Kudryashov
2014-11-17 01:22:07 +03:00
parent 5ecd12f274
commit 2ab625ca9a
12 changed files with 218 additions and 47 deletions
@@ -37,6 +37,8 @@ import java.awt.event.MouseEvent;
* @author Vladimir Kondratyev
*/
public class ThreeComponentsSplitter extends JPanel implements Disposable {
public static final int MIN_SIZE = 48;
private int myDividerWidth;
/**
* /------/
@@ -189,14 +191,22 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
else {
firstCompontSize = getFirstSize();
lastComponentSize = getLastSize();
int sizeLack = firstCompontSize + lastComponentSize - (componentSize - dividersCount * dividerWidth);
int sizeLack = firstCompontSize + lastComponentSize - (componentSize - dividersCount * dividerWidth - MIN_SIZE);
if (sizeLack > 0) {
// Lacking size. Reduce first component's size, inner -> empty
firstCompontSize -= sizeLack;
innerComponentSize = 0;
// Lacking size. Reduce first & last component's size, inner -> MIN_SIZE
double firstSizeRatio = (double)firstCompontSize / (firstCompontSize + lastComponentSize);
if (firstCompontSize > 0) {
firstCompontSize -= sizeLack * firstSizeRatio;
firstCompontSize = Math.max(MIN_SIZE, firstCompontSize);
}
if (lastComponentSize > 0) {
lastComponentSize -= sizeLack * (1 - firstSizeRatio);
lastComponentSize = Math.max(MIN_SIZE, lastComponentSize);
}
innerComponentSize = MIN_SIZE;
}
else {
innerComponentSize = componentSize - dividersCount * dividerWidth - getFirstSize() - getLastSize();
innerComponentSize = Math.max(MIN_SIZE, componentSize - dividersCount * dividerWidth - getFirstSize() - getLastSize());
}
if (!innerVisible()) {
@@ -395,6 +405,29 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
return lastVisible() ? myLastSize : 0;
}
public int getMinSize(boolean first) {
return getMinSize(first? myFirstComponent : myLastComponent);
}
public int getMaxSize(boolean first) {
final int size = getOrientation() ? this.getHeight() : this.getWidth();
return size - (first? myLastSize: myFirstSize) - MIN_SIZE;
}
private int getMinSize(JComponent component) {
if (isHonorMinimumSize()) {
if (component != null && myFirstComponent != null && myFirstComponent.isVisible() && myLastComponent != null && myLastComponent.isVisible()) {
if (getOrientation()) {
return component.getMinimumSize().height;
}
else {
return component.getMinimumSize().width;
}
}
}
return MIN_SIZE;
}
@Override
public void dispose() {
myLastComponent = null;
@@ -633,23 +666,24 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
myGlassPane.setCursor(getResizeCursor(), myListener);
myPoint = SwingUtilities.convertPoint(this, e.getPoint(), ThreeComponentsSplitter.this);
final int size = getOrientation() ? ThreeComponentsSplitter.this.getHeight() : ThreeComponentsSplitter.this.getWidth();
if (getOrientation()) {
if (getHeight() > 0 || myDividerZone > 0) {
if (size > 0 || myDividerZone > 0) {
if (myIsFirst) {
setFirstSize(Math.max(getMinSize(myFirstComponent), myPoint.y));
setFirstSize(Math.min(size - myLastSize - MIN_SIZE, Math.max(getMinSize(myFirstComponent), myPoint.y)));
}
else {
setLastSize(Math.max(getMinSize(myLastComponent), ThreeComponentsSplitter.this.getHeight() - myPoint.y - getDividerWidth()));
setLastSize(Math.min(size - myFirstSize - MIN_SIZE, Math.max(getMinSize(myLastComponent), size - myPoint.y - getDividerWidth())));
}
}
}
else {
if (getWidth() > 0 || myDividerZone > 0) {
if (size > 0 || myDividerZone > 0) {
if (myIsFirst) {
setFirstSize(Math.max(getMinSize(myFirstComponent), myPoint.x));
setFirstSize(Math.min(size - myLastSize - MIN_SIZE, Math.max(getMinSize(myFirstComponent), myPoint.x)));
}
else {
setLastSize(Math.max(getMinSize(myLastComponent), ThreeComponentsSplitter.this.getWidth() - myPoint.x - getDividerWidth()));
setLastSize(Math.min(size - myFirstSize - MIN_SIZE, Math.max(getMinSize(myLastComponent), size - myPoint.x - getDividerWidth())));
}
}
}
@@ -670,20 +704,6 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
}
}
private int getMinSize(JComponent component) {
if (isHonorMinimumSize()) {
if (component != null && myFirstComponent != null && myFirstComponent.isVisible() && myLastComponent != null && myLastComponent.isVisible()) {
if (getOrientation()) {
return component.getMinimumSize().height;
}
else {
return component.getMinimumSize().width;
}
}
}
return 0;
}
protected void processMouseEvent(MouseEvent e) {
super.processMouseEvent(e);
if (!isShowing()) {
@@ -154,4 +154,8 @@ public abstract class ToolWindowManager {
@Nullable
public abstract Balloon getToolWindowBalloon(String id);
public abstract boolean isMaximized(@NotNull ToolWindow wnd);
public abstract void setMaximized(@NotNull ToolWindow wnd, boolean maximized);
}
@@ -402,6 +402,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
resize.add(new ResizeToolWindowAction.Right(myToolWindow, this));
resize.add(new ResizeToolWindowAction.Up(myToolWindow, this));
resize.add(new ResizeToolWindowAction.Down(myToolWindow, this));
resize.add(ActionManager.getInstance().getAction("MaximizeToolWindow"));
group.add(resize);
@@ -0,0 +1,60 @@
/*
* 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.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import org.jetbrains.annotations.NotNull;
public class MaximizeToolWindowAction extends AnAction {
public MaximizeToolWindowAction() {
super();
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getProject();
if (project == null || project.isDisposed()) return;
ToolWindow toolWindow = e.getData(PlatformDataKeys.TOOL_WINDOW);
if (toolWindow == null) return;
ToolWindowManager manager = ToolWindowManager.getInstance(project);
manager.setMaximized(toolWindow, !manager.isMaximized(toolWindow));
}
@Override
public void update(@NotNull AnActionEvent e) {
e.getPresentation().setEnabled(true);
Project project = e.getProject();
if (project == null || project.isDisposed()) {
e.getPresentation().setEnabled(false);
return;
}
ToolWindow toolWindow = e.getData(PlatformDataKeys.TOOL_WINDOW);
if (toolWindow == null) {
e.getPresentation().setEnabled(false);
return;
}
ToolWindowManager manager = ToolWindowManager.getInstance(project);
e.getPresentation().setText(manager.isMaximized(toolWindow) ?
ActionsBundle.message("action.ResizeToolWindowMaximize.text.alternative") :
ActionsBundle.message("action.ResizeToolWindowMaximize.text"));
}
}
@@ -25,9 +25,11 @@ import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
import com.intellij.openapi.actionSystem.impl.*;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.ui.InplaceButton;
@@ -210,6 +212,12 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS
};
}
void switchMaximizedState(Project project) {
if (project == null || project.isDisposed()) return;
ToolWindowManager mgr = ToolWindowManager.getInstance(project);
mgr.setMaximized(myToolWindow, !mgr.isMaximized(myToolWindow));
}
@Override
public void uiSettingsChanged(UISettings source) {
clearCaches();
@@ -198,6 +198,15 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx {
return null;
}
@Override
public boolean isMaximized(@NotNull ToolWindow wnd) {
return false;
}
@Override
public void setMaximized(@NotNull ToolWindow wnd, boolean maximized) {
}
@Override
public void initToolWindow(@NotNull ToolWindowEP bean) {
@@ -120,6 +120,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
private final FileEditorManager myFileEditorManager;
private final LafManager myLafManager;
private final Map<String, Balloon> myWindow2Balloon = new HashMap<String, Balloon>();
private Pair<String, Integer> myMaximizedToolwindowSize = null;
private KeyState myCurrentState = KeyState.waiting;
private final Alarm myWaiterForSecondPress = new Alarm();
@@ -1982,6 +1983,16 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
myToolWindowsPane.stretchWidth(toolWindow, value);
}
@Override
public boolean isMaximized(@NotNull ToolWindow wnd) {
return myToolWindowsPane.isMaximized(wnd);
}
@Override
public void setMaximized(@NotNull ToolWindow wnd, boolean maximized) {
myToolWindowsPane.setMaximized(wnd, maximized);
}
public void stretchHeight(ToolWindowImpl toolWindow, int value) {
myToolWindowsPane.stretchHeight(toolWindow, value);
}
@@ -22,20 +22,27 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.ui.ThreeComponentsSplitter;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.IdeGlassPaneUtil;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.openapi.wm.ex.ToolWindowEx;
import com.intellij.openapi.wm.impl.commands.FinalizableCommand;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.components.JBLayeredPane;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.FadeInFadeOut;
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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
@@ -58,6 +65,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable {
private final HashMap<StripeButton, WindowInfoImpl> myButton2Info;
private final HashMap<InternalDecorator, WindowInfoImpl> myDecorator2Info;
private final HashMap<String, Float> myId2SplitProportion;
private Pair<ToolWindow, Integer> myMaximizedProportion = null;
/**
* This panel is the layered pane where all sliding tool windows are located. The DEFAULT
* layer contains splitters. The PALETTE layer contains all sliding tool windows.
@@ -192,6 +200,24 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable {
super.addNotify();
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
UISettings.getInstance().addUISettingsListener(myUISettingsListener, myDisposable);
IdeGlassPaneUtil.find(this).addMousePreprocessor(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2 && e.getModifiersEx() == 0) {
e = SwingUtilities.convertMouseEvent(e.getComponent(), e, ToolWindowsPane.this);
Component component = SwingUtilities.getDeepestComponentAt(ToolWindowsPane.this, e.getX(), e.getY());
Component header = component == null ? null : UIUtil.findParentByCondition((JComponent)component, new Condition<Component>() {
@Override
public boolean value(Component component) {
return component instanceof ToolWindowHeader;
}
});
if (header instanceof ToolWindowHeader) {
((ToolWindowHeader)header).switchMaximizedState(myFrame.getProject());
}
}
}
}, this);
}
}
@@ -490,7 +516,21 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable {
}
private void stretch(ToolWindow wnd, int value) {
if (!wnd.isVisible()) return;
Pair<Resizer, Component> pair = findResizerAndComponent(wnd);
if (pair == null) return;
boolean vertical = wnd.getAnchor() == ToolWindowAnchor.TOP || wnd.getAnchor() == ToolWindowAnchor.BOTTOM;
int actualSize = (vertical ? pair.second.getHeight() : pair.second.getWidth()) + value;
boolean first = wnd.getAnchor() == ToolWindowAnchor.LEFT || wnd.getAnchor() == ToolWindowAnchor.TOP;
int maxValue = vertical ? myVerticalSplitter.getMaxSize(first) : myHorizontalSplitter.getMaxSize(first);
int minValue = vertical ? myVerticalSplitter.getMinSize(first) : myHorizontalSplitter.getMinSize(first);;
pair.first.setSize(Math.max(minValue, Math.min(maxValue, actualSize)));
}
@Nullable
private Pair<Resizer, Component> findResizerAndComponent(ToolWindow wnd) {
if (!wnd.isVisible()) return null;
Resizer resizer = null;
Component cmp = null;
@@ -534,26 +574,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable {
}
}
if (resizer == null) return;
int currentValue = wnd.getAnchor().isHorizontal() ? cmp.getHeight() : cmp.getWidth();
int actualSize = currentValue + value;
int minValue =
wnd.getAnchor().isHorizontal() ? ((ToolWindowEx)wnd).getDecorator().getHeaderHeight() : 16 + myHorizontalSplitter.getDividerWidth();
int maxValue = wnd.getAnchor().isHorizontal() ? myLayeredPane.getHeight() : myLayeredPane.getWidth();
if (actualSize < minValue) {
actualSize = minValue;
}
if (actualSize > maxValue) {
actualSize = maxValue;
}
resizer.setSize(actualSize);
return resizer != null ? Pair.create(resizer, cmp) : null;
}
private void updateLayout() {
@@ -598,6 +619,27 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable {
}
}
public boolean isMaximized(@NotNull ToolWindow wnd) {
return myMaximizedProportion != null && myMaximizedProportion.first == wnd;
}
public void setMaximized(@NotNull ToolWindow wnd, boolean maximized) {
Pair<Resizer, Component> resizerAndComponent = findResizerAndComponent(wnd);
if (resizerAndComponent == null) return;
if (!maximized) {
ToolWindow maximizedWindow = myMaximizedProportion.first;
assert maximizedWindow == wnd;
resizerAndComponent.first.setSize(myMaximizedProportion.second);
myMaximizedProportion = null;
} else {
int size = wnd.getAnchor().isHorizontal() ? resizerAndComponent.second.getHeight() : resizerAndComponent.second.getWidth();
stretch(wnd, Short.MAX_VALUE);
myMaximizedProportion = Pair.create(wnd, size);
}
doLayout();
}
interface Resizer {
void setSize(int size);
@@ -842,6 +842,9 @@ action.ResizeToolWindowUp.text=Stretch to Top
action.ResizeToolWindowUp.description=Resize active tool window to the top
action.ResizeToolWindowDown.text=Stretch to Bottom
action.ResizeToolWindowDown.description=Resize active tool window to the bottom
action.ResizeToolWindowMaximize.text=Maximize tool window
action.ResizeToolWindowMaximize.text.alternative=Restore tool window size
action.ResizeToolWindowMaximize.description=Maximize tool widow
action.IncrementWindowWidth.text=Increment Width
action.DecrementWindowWidth.text=Decrement Width
action.IncrementWindowHeight.text=Increment Height
@@ -774,6 +774,9 @@
<action id="ResizeToolWindowDown">
<keyboard-shortcut first-keystroke="control shift DOWN"/>
</action>
<action id="MaximizeToolWindow">
<keyboard-shortcut first-keystroke="control shift QUOTE"/>
</action>
<action id="HideSideWindows"/>
<action id="ShowPopupMenu">
<keyboard-shortcut first-keystroke="CONTEXT_MENU"/>
@@ -355,6 +355,7 @@
<action id="HideAllWindows" class="com.intellij.ide.actions.HideAllToolWindowsAction"/>
<action id="CloseActiveTab" class="com.intellij.ide.actions.CloseActiveTabAction"/>
<action id="JumpToLastWindow" class="com.intellij.ide.actions.JumpToLastWindowAction"/>
<action id="MaximizeToolWindow" class="com.intellij.openapi.wm.impl.MaximizeToolWindowAction"/>
<separator/>
<action id="TogglePinnedMode" class="com.intellij.ide.actions.TogglePinnedModeAction"/>
<action id="ToggleDockMode" class="com.intellij.ide.actions.ToggleDockModeAction"/>
@@ -654,6 +654,15 @@ public class Mock {
return null;
}
@Override
public boolean isMaximized(@NotNull ToolWindow wnd) {
return false;
}
@Override
public void setMaximized(@NotNull ToolWindow wnd, boolean maximized) {
}
@Override
public void notifyByBalloon(@NotNull final String toolWindowId, @NotNull final MessageType type, @NotNull final String htmlBody) {
}