forbid calling ensureContentInitialized explicitly, reduce usages of isActive

GitOrigin-RevId: 9f446f83a81e5d750d6344cae1a45f0ac8033b6f
This commit is contained in:
Vladimir Krivosheev
2020-01-13 12:39:24 +00:00
committed by intellij-monorepo-bot
parent d0ac9c47aa
commit fff4e71169
18 changed files with 472 additions and 500 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.externalSystem.util;
import com.intellij.build.*;
@@ -86,7 +86,6 @@ import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
import com.intellij.openapi.wm.impl.ToolWindowImpl;
import com.intellij.pom.Navigatable;
import com.intellij.pom.NonNavigatable;
import com.intellij.util.ArrayUtil;
@@ -107,10 +106,7 @@ import java.util.function.Supplier;
import static com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings.SyncType.*;
import static com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.doWriteAction;
/**
* @author Denis Zhdanov
*/
public class ExternalSystemUtil {
public final class ExternalSystemUtil {
private static final Logger LOG = Logger.getInstance(ExternalSystemUtil.class);
@NotNull private static final Map<String, String> RUNNER_IDS = new HashMap<>();
@@ -185,16 +181,7 @@ public class ExternalSystemUtil {
@Nullable
public static ToolWindow ensureToolWindowContentInitialized(@NotNull Project project, @NotNull ProjectSystemId externalSystemId) {
final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
if (toolWindowManager == null) return null;
final ToolWindow toolWindow = toolWindowManager.getToolWindow(externalSystemId.getReadableName());
if (toolWindow == null) return null;
if (toolWindow instanceof ToolWindowImpl) {
((ToolWindowImpl)toolWindow).ensureContentInitialized();
}
return toolWindow;
return ToolWindowManager.getInstance(project).getToolWindow(externalSystemId.getReadableName());
}
/**
@@ -282,9 +269,9 @@ public class ExternalSystemUtil {
}
}
@Nullable
@NotNull
private static String extractDetails(@NotNull Throwable e) {
final Throwable unwrapped = RemoteUtil.unwrap(e);
Throwable unwrapped = RemoteUtil.unwrap(e);
if (unwrapped instanceof ExternalSystemException) {
return ((ExternalSystemException)unwrapped).getOriginalReason();
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.ui;
import com.intellij.icons.AllIcons;
@@ -474,18 +474,15 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
*
*/
public void setFirstComponent(@Nullable JComponent component) {
if (myFirstComponent != component) {
if (myFirstComponent != null) {
remove(myFirstComponent);
}
myFirstComponent = component;
updateComponentTreeUI(myFirstComponent);
if (myFirstComponent != null) {
add(myFirstComponent);
myFirstComponent.invalidate();
}
if (myFirstComponent == component) {
return;
}
if (myFirstComponent != null) {
remove(myFirstComponent);
}
myFirstComponent = component;
doAddComponent(component);
}
@Nullable
@@ -493,25 +490,20 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
return myLastComponent;
}
/**
* Sets component which is located as the "second" split area. The method doesn't validate and
* repaint the splitter.
*
*/
public void setLastComponent(@Nullable JComponent component) {
if (myLastComponent != component) {
if (myLastComponent != null) {
remove(myLastComponent);
}
myLastComponent = component;
updateComponentTreeUI(myLastComponent);
if (myLastComponent != null) {
add(myLastComponent);
myLastComponent.invalidate();
}
if (myLastComponent == component) {
return;
}
if (myLastComponent != null) {
remove(myLastComponent);
}
myLastComponent = component;
doAddComponent(component);
}
@Nullable
@@ -519,10 +511,12 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
return myInnerComponent;
}
private static void updateComponentTreeUI(@Nullable JComponent component) {
UIUtil.uiTraverser(component).postOrderDfsTraversal().
filter(c -> c instanceof JComponent).
forEach(c -> ((JComponent)c).updateUI());
private static void updateComponentTreeUI(@Nullable JComponent rootComponent) {
for (Component component : UIUtil.uiTraverser(rootComponent).postOrderDfsTraversal()) {
if (component instanceof JComponent) {
((JComponent)component).updateUI();
}
}
}
/**
@@ -537,13 +531,15 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
if (myInnerComponent != null) {
remove(myInnerComponent);
}
myInnerComponent = component;
updateComponentTreeUI(myInnerComponent);
doAddComponent(component);
}
if (myInnerComponent != null) {
add(myInnerComponent);
myInnerComponent.invalidate();
private void doAddComponent(@Nullable JComponent component) {
if (component != null) {
updateComponentTreeUI(component);
add(component);
component.invalidate();
}
}
@@ -637,11 +633,6 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
}
private void _processMouseMotionEvent(MouseEvent e) {
MouseEvent event = getTargetEvent(e);
if (event == null) {
myGlassPane.setCursor(null, myListener);
return;
}
processMouseMotionEvent(event);
if (event.isConsumed()) {
e.consume();
@@ -650,11 +641,6 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
private void _processMouseEvent(MouseEvent e) {
MouseEvent event = getTargetEvent(e);
if (event == null) {
myGlassPane.setCursor(null, myListener);
return;
}
processMouseEvent(event);
if (event.isConsumed()) {
e.consume();
@@ -664,7 +650,7 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
private final MouseAdapter myListener = new MyMouseAdapter();
private MouseEvent getTargetEvent(MouseEvent e) {
private MouseEvent getTargetEvent(@NotNull MouseEvent e) {
return SwingUtilities.convertMouseEvent(e.getComponent(), e, this);
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.ui.content;
import com.intellij.ide.dnd.DnDTarget;
@@ -50,17 +50,16 @@ public interface Content extends UserDataHolder, ComponentContainer {
void setTabName(String tabName);
String getTabName();
void setToolwindowTitle(String toolwindowTitle);
String getToolwindowTitle();
void setToolwindowTitle(String toolwindowTitle);
Disposable getDisposer();
void setDisposer(@NotNull Disposable disposer);
void setShouldDisposeContent(boolean value);
boolean shouldDisposeContent();
String getDescription();
void setDescription(String description);
@@ -7,18 +7,17 @@ import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.ui.Splitter;
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.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.ui.ComponentWithMnemonics;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.paint.LinePainter2D;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NonNls;
@@ -41,30 +40,43 @@ import java.util.Map;
*/
public final class InternalDecorator extends JPanel implements Queryable, DataProvider, ComponentWithMnemonics {
private final ToolWindowImpl toolWindow;
private final MyDivider myDivider;
private final JPanel divider;
private IdeGlassPane glassPane;
private Disposable disposable;
private final MouseAdapter myListener = new MyMouseListener();
private boolean isDragging;
/**
* Catches all event from tool window and modifies decorator's appearance.
*/
static final String HIDE_ACTIVE_WINDOW_ACTION_ID = "HideActiveWindow";
//See ToolWindowViewModeAction and ToolWindowMoveAction
// see ToolWindowViewModeAction and ToolWindowMoveAction
public static final String TOGGLE_DOCK_MODE_ACTION_ID = "ToggleDockMode";
public static final String TOGGLE_FLOATING_MODE_ACTION_ID = "ToggleFloatingMode";
public static final String TOGGLE_SIDE_MODE_ACTION_ID = "ToggleSideMode";
private final ToolWindowHeader header;
InternalDecorator(@NotNull ToolWindowImpl toolWindow) {
InternalDecorator(@NotNull ToolWindowImpl toolWindow, @NotNull ToolWindowContentUi contentUi) {
super(new BorderLayout());
this.toolWindow = toolWindow;
myDivider = new MyDivider();
divider = new JPanel() {
@NotNull
@Override
public Cursor getCursor() {
WindowInfo info = InternalDecorator.this.toolWindow.getWindowInfo();
boolean isVerticalCursor = info.getType() == ToolWindowType.DOCKED ? info.getAnchor().isSplitVertically() : info.getAnchor().isHorizontal();
return isVerticalCursor ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
}
};
setFocusable(false);
setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
header = new ToolWindowHeader(toolWindow, () -> toolWindow.createPopupGroup(true)) {
header = new ToolWindowHeader(toolWindow, contentUi, () -> toolWindow.createPopupGroup(true)) {
@Override
protected boolean isActive() {
return toolWindow.isActive();
@@ -83,6 +95,8 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
if (SystemInfo.isMac) {
setBackground(new JBColor(Gray._200, Gray._90));
}
setBorder(new InnerPanelBorder(toolWindow));
}
@Override
@@ -90,38 +104,22 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
return toolWindow.getId();
}
public boolean isFocused(@NotNull JFrame frame) {
IdeFocusManager focusManager = toolWindow.getToolWindowManager().getFocusManager();
JComponent toolWindowComponent = toolWindow.getComponentIfInitialized();
if (toolWindowComponent == null) {
return false;
}
Component component = focusManager.getFocusedDescendantFor(toolWindowComponent);
if (component != null) {
return true;
}
Component owner = focusManager.getLastFocusedFor(frame);
return owner != null && SwingUtilities.isDescendingFrom(owner, toolWindowComponent);
}
void applyWindowInfo(@NotNull WindowInfo info) {
// Anchor
ToolWindowAnchor anchor = info.getAnchor();
if (info.isSliding()) {
myDivider.invalidate();
if (ToolWindowAnchor.TOP == anchor) {
add(myDivider, BorderLayout.SOUTH);
divider.invalidate();
if (anchor == ToolWindowAnchor.TOP) {
add(divider, BorderLayout.SOUTH);
}
else if (ToolWindowAnchor.LEFT == anchor) {
add(myDivider, BorderLayout.EAST);
else if (anchor == ToolWindowAnchor.LEFT) {
add(divider, BorderLayout.EAST);
}
else if (ToolWindowAnchor.BOTTOM == anchor) {
add(myDivider, BorderLayout.NORTH);
else if (anchor == ToolWindowAnchor.BOTTOM) {
add(divider, BorderLayout.NORTH);
}
else if (ToolWindowAnchor.RIGHT == anchor) {
add(myDivider, BorderLayout.WEST);
else if (anchor == ToolWindowAnchor.RIGHT) {
add(divider, BorderLayout.WEST);
}
divider.setPreferredSize(new Dimension(0, 0));
}
@@ -130,9 +128,6 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
remove(divider);
}
validate();
repaint();
// push "apply" request forward
if (info.isFloating()) {
FloatingDecorator floatingDecorator = (FloatingDecorator)SwingUtilities.getAncestorOfClass(FloatingDecorator.class, this);
@@ -140,9 +135,6 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
floatingDecorator.apply(info);
}
}
toolWindow.getContentUI().setType(info.getContentUiType());
setBorder(new InnerPanelBorder(toolWindow, info));
}
@Nullable
@@ -154,14 +146,6 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
return null;
}
void addContentComponent(boolean dumbAware, @NotNull ContentManager contentManager) {
JComponent toolWindowComponent = contentManager.getComponent();
if (!dumbAware) {
toolWindowComponent = DumbService.getInstance(toolWindow.getToolWindowManager().getProject()).wrapGently(toolWindowComponent, toolWindow.getDisposable());
}
add(toolWindowComponent, BorderLayout.CENTER);
}
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT && pressed) {
@@ -185,16 +169,13 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
private static final class InnerPanelBorder implements Border {
@NotNull
private final ToolWindowImpl window;
@NotNull
private final WindowInfo windowInfo;
private InnerPanelBorder(@NotNull ToolWindowImpl window, @NotNull WindowInfo windowInfo) {
private InnerPanelBorder(@NotNull ToolWindowImpl window) {
this.window = window;
this.windowInfo = windowInfo;
}
@Override
public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
public void paintBorder(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height) {
g.setColor(JBColor.border());
doPaintBorder(c, g, x, y, width, height);
}
@@ -227,6 +208,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
@Override
public Insets getBorderInsets(@NotNull Component c) {
ToolWindowManagerImpl toolWindowManager = window.getToolWindowManager();
WindowInfo windowInfo = window.getWindowInfo();
if (toolWindowManager.getProject().isDisposed() ||
!toolWindowManager.isToolWindowRegistered(window.getId()) || windowInfo.getType() == ToolWindowType.FLOATING || windowInfo.getType() == ToolWindowType.WINDOWED) {
return JBUI.emptyInsets();
@@ -280,103 +262,95 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
header.setVisible(value);
}
private final class MyDivider extends JPanel {
private boolean myDragging;
private Disposable myDisposable;
private IdeGlassPane myGlassPane;
@Override
public void addNotify() {
super.addNotify();
private final MouseAdapter myListener = new MyMouseAdapter();
glassPane = IdeGlassPaneUtil.find(this);
disposable = Disposer.newDisposable();
glassPane.addMouseMotionPreprocessor(myListener, disposable);
glassPane.addMousePreprocessor(myListener, disposable);
}
@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();
Disposable disposable = this.disposable;
if (disposable != null && !Disposer.isDisposed(disposable)) {
this.disposable = null;
Disposer.dispose(disposable);
}
}
private final class MyMouseListener extends MouseAdapter {
private boolean isInDragZone(@NotNull MouseEvent e) {
Point point = new Point(e.getPoint());
SwingUtilities.convertPointToScreen(point, e.getComponent());
if ((toolWindow.getWindowInfo().getAnchor().isHorizontal() ? point.y : point.x) == 0) {
return false;
}
SwingUtilities.convertPointFromScreen(point, divider);
return Math.abs(toolWindow.getWindowInfo().getAnchor().isHorizontal() ? point.y : point.x) < 6;
}
private void updateCursor(@NotNull MouseEvent event, boolean isInDragZone) {
if (isInDragZone) {
glassPane.setCursor(divider.getCursor(), divider);
event.consume();
}
}
@Override
public void removeNotify() {
super.removeNotify();
if (myDisposable != null && !Disposer.isDisposed(myDisposable)) {
Disposer.dispose(myDisposable);
}
public void mousePressed(@NotNull MouseEvent e) {
isDragging = isInDragZone(e);
updateCursor(e, isDragging);
}
boolean isInDragZone(MouseEvent e) {
Point p = SwingUtilities.convertMouseEvent(e.getComponent(), e, this).getPoint();
return Math.abs(toolWindow.getWindowInfo().getAnchor().isHorizontal() ? p.y : p.x) < 6;
}
private final 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 = toolWindow.getAnchor();
final Point point = event.getPoint();
final Container windowPane = InternalDecorator.this.getParent();
Point lastPoint = SwingUtilities.convertPoint(MyDivider.this, point, windowPane);
lastPoint.x = Math.min(Math.max(lastPoint.x, 0), windowPane.getWidth());
lastPoint.y = Math.min(Math.max(lastPoint.y, 0), windowPane.getHeight());
final Rectangle bounds = InternalDecorator.this.getBounds();
if (anchor == ToolWindowAnchor.TOP) {
InternalDecorator.this.setBounds(0, 0, bounds.width, lastPoint.y);
}
else if (anchor == ToolWindowAnchor.LEFT) {
InternalDecorator.this.setBounds(0, 0, lastPoint.x, bounds.height);
}
else if (anchor == ToolWindowAnchor.BOTTOM) {
InternalDecorator.this.setBounds(0, lastPoint.y, bounds.width, windowPane.getHeight() - lastPoint.y);
}
else if (anchor == ToolWindowAnchor.RIGHT) {
InternalDecorator.this.setBounds(lastPoint.x, 0, windowPane.getWidth() - lastPoint.x, bounds.height);
}
InternalDecorator.this.validate();
e.consume();
}
}
@NotNull
@Override
public Cursor getCursor() {
WindowInfo info = toolWindow.getWindowInfo();
boolean isVerticalCursor = info.getType() == ToolWindowType.DOCKED ? info.getAnchor().isSplitVertically() : info.getAnchor().isHorizontal();
return isVerticalCursor ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
public void mouseClicked(@NotNull MouseEvent e) {
updateCursor(e, isInDragZone(e));
}
@Override
public void mouseReleased(@NotNull MouseEvent e) {
updateCursor(e, isInDragZone(e));
isDragging = false;
}
@Override
public void mouseMoved(@NotNull MouseEvent e) {
updateCursor(e, isDragging || isInDragZone(e));
}
@Override
public void mouseDragged(@NotNull MouseEvent e) {
if (!isDragging) {
return;
}
ToolWindowAnchor anchor = toolWindow.getAnchor();
Container windowPane = InternalDecorator.this.getParent();
Point lastPoint = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), windowPane);
lastPoint.x = Math.min(Math.max(lastPoint.x, 0), windowPane.getWidth());
lastPoint.y = Math.min(Math.max(lastPoint.y, 0), windowPane.getHeight());
Rectangle bounds = InternalDecorator.this.getBounds();
if (anchor == ToolWindowAnchor.TOP) {
InternalDecorator.this.setBounds(0, 0, bounds.width, lastPoint.y);
}
else if (anchor == ToolWindowAnchor.LEFT) {
InternalDecorator.this.setBounds(0, 0, lastPoint.x, bounds.height);
}
else if (anchor == ToolWindowAnchor.BOTTOM) {
InternalDecorator.this.setBounds(0, lastPoint.y, bounds.width, windowPane.getHeight() - lastPoint.y);
}
else if (anchor == ToolWindowAnchor.RIGHT) {
InternalDecorator.this.setBounds(lastPoint.x, 0, windowPane.getWidth() - lastPoint.x, bounds.height);
}
InternalDecorator.this.validate();
e.consume();
}
}
@@ -384,7 +358,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
public void putInfo(@NotNull Map<String, String> info) {
info.put("toolWindowTitle", toolWindow.getTitle());
final Content selection = toolWindow.getContentManager().getSelectedContent();
Content selection = toolWindow.getContentManager().getSelectedContent();
if (selection != null) {
info.put("toolWindowTab", selection.getTabName());
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl;
import com.intellij.featureStatistics.FeatureUsageTracker;
@@ -313,7 +313,7 @@ public final class StripeButton extends AnchoredButton implements DataProvider {
}
void apply(@NotNull WindowInfo info) {
setSelected(info.isVisible() || info.isActive());
setSelected(info.isVisible());
updateState(toolWindow);
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl;
import com.intellij.icons.AllIcons;
@@ -13,12 +13,14 @@ import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.ui.DoubleClickListener;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.UIBundle;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.layout.migLayout.MigLayoutBuilderKt;
import com.intellij.ui.layout.migLayout.patched.MigLayout;
import com.intellij.ui.tabs.impl.MorePopupAware;
import com.intellij.ui.tabs.impl.SingleHeightTabs;
import com.intellij.util.ui.*;
import com.intellij.util.ui.accessibility.AccessibleContextUtil;
import net.miginfocom.swing.MigLayout;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.ConstraintParser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,6 +37,7 @@ import java.util.function.Supplier;
* @author pegov
*/
public abstract class ToolWindowHeader extends JPanel implements UISettingsListener, DataProvider {
@NotNull private final ToolWindowContentUi contentUi;
@NotNull private final Supplier<? extends ActionGroup> myGearProducer;
@NotNull
@@ -50,20 +53,19 @@ public abstract class ToolWindowHeader extends JPanel implements UISettingsListe
private ActionToolbar myToolbarWest;
private final JPanel myWestPanel;
ToolWindowHeader(@NotNull ToolWindowImpl toolWindow, @NotNull Supplier<? extends ActionGroup> gearProducer) {
ToolWindowHeader(@NotNull ToolWindowImpl toolWindow, @NotNull ToolWindowContentUi contentUi, @NotNull Supplier<? extends ActionGroup> gearProducer) {
super(new MigLayout(MigLayoutBuilderKt.createLayoutConstraints(0, 0).noVisualPadding().fill(), ConstraintParser.parseColumnConstraints("[grow][pref!]")));
this.contentUi = contentUi;
myGearProducer = gearProducer;
AccessibleContextUtil.setName(this, "Tool Window Header");
myToolWindow = toolWindow;
setLayout(new MigLayout("novisualpadding, ins 0, gap 0, fill", "[grow][pref!]"));
myWestPanel = new NonOpaquePanel(new MigLayout("filly, novisualpadding, ins 0, gap 0"));
add(myWestPanel, "grow");
myWestPanel.add(toolWindow.getContentUI().getTabComponent(), "growy");
ToolWindowContentUi.initMouseListeners(myWestPanel, toolWindow.getContentUI(), true);
myWestPanel = contentUi.getTabComponent();
add(myWestPanel, new CC().grow());
ToolWindowContentUi.initMouseListeners(myWestPanel, contentUi, true);
ActionManager actionManager = ActionManager.getInstance();
AnAction tabListAction = actionManager.getAction("TabList");
@@ -83,8 +85,7 @@ public abstract class ToolWindowHeader extends JPanel implements UISettingsListe
myWestPanel.addMouseListener(new PopupHandler() {
@Override
public void invokePopup(final Component comp, final int x, final int y) {
toolWindow.getContentUI()
.showContextMenu(comp, x, y, toolWindow.getPopupGroup(), toolWindow.getContentManager().getSelectedContent());
contentUi.showContextMenu(comp, x, y, toolWindow.getPopupGroup(), contentUi.getContentManager().getSelectedContent());
}
});
myWestPanel.addMouseListener(new MouseAdapter() {
@@ -139,7 +140,7 @@ public abstract class ToolWindowHeader extends JPanel implements UISettingsListe
@Override
public Object getData(@NotNull String dataId) {
if (MorePopupAware.KEY.is(dataId) && myToolWindow instanceof ToolWindowImpl) {
return ((ToolWindowImpl)myToolWindow).getContentUI().getData(dataId);
return contentUi.getData(dataId);
}
return null;
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl
import com.intellij.icons.AllIcons
@@ -10,10 +10,10 @@ import com.intellij.notification.EventLog
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.ex.ActionUtil
import com.intellij.openapi.actionSystem.impl.ActionManagerImpl
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.util.ActionCallback
import com.intellij.openapi.util.BusyObject
import com.intellij.openapi.util.Disposer
@@ -22,18 +22,22 @@ import com.intellij.openapi.wm.ex.ToolWindowEx
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi
import com.intellij.ui.LayeredIcon
import com.intellij.ui.UIBundle
import com.intellij.ui.content.Content
import com.intellij.ui.content.ContentManager
import com.intellij.ui.content.ContentManagerListener
import com.intellij.ui.content.impl.ContentImpl
import com.intellij.ui.content.impl.ContentManagerImpl
import com.intellij.ui.scale.JBUIScale
import com.intellij.util.ui.UIUtil
import com.intellij.util.ui.update.Activatable
import com.intellij.util.ui.update.UiNotifyConnector
import java.awt.BorderLayout
import java.awt.Component
import java.awt.Rectangle
import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent
import java.awt.event.InputEvent
import java.util.*
import javax.swing.Icon
import javax.swing.JComponent
import javax.swing.JLabel
@@ -45,7 +49,7 @@ private val LOG = logger<ToolWindowImpl>()
class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManagerImpl,
val id: String,
private val canCloseContent: Boolean,
private val canWorkInDumbMode: Boolean,
private val dumbAware: Boolean,
component: JComponent?,
private val parentDisposable: Disposable,
windowInfo: WindowInfo,
@@ -56,16 +60,14 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
var windowInfo: WindowInfo = windowInfo
private set
private val contentUi by lazy {
ToolWindowContentUi(this)
}
private var contentUi: ToolWindowContentUi? = null
private var decorator: InternalDecorator? = null
private var hideOnEmptyContent = false
var isPlaceholderMode = false
private val pendingContentManagerListeners: List<ContentManagerListener>? = null
private var pendingContentManagerListeners: MutableList<ContentManagerListener>? = null
private val showing = object : BusyObject.Impl() {
override fun isReady(): Boolean {
@@ -82,36 +84,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
internal var icon: ToolWindowIcon? = null
private val contentManager = lazy {
val contentManager = ContentManagerImpl(contentUi, canCloseContent, toolWindowManager.project, parentDisposable)
val contentComponent = contentManager.component
InternalDecorator.installFocusTraversalPolicy(contentComponent, LayoutFocusTraversalPolicy())
Disposer.register(parentDisposable, UiNotifyConnector(contentComponent, object : Activatable {
override fun showNotify() {
showing.onReady()
}
}))
val decorator = InternalDecorator(this)
this.decorator = decorator
decorator.applyWindowInfo(windowInfo)
decorator.addComponentListener(object : ComponentAdapter() {
override fun componentResized(e: ComponentEvent) {
toolWindowManager.resized(e.component as InternalDecorator)
}
})
decorator.addContentComponent(canWorkInDumbMode, contentManager)
toolWindowFocusWatcher = ToolWindowManagerImpl.ToolWindowFocusWatcher(this, contentManager.component)
// after init, as it was before contentManager creation was changed to be lazy
pendingContentManagerListeners?.let { list ->
for (listener in list) {
contentManager.addContentManagerListener(listener)
}
}
contentManager
createContentManager()
}
init {
@@ -123,13 +96,67 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
}
internal fun getOrCreateDecoratorComponent(): JComponent {
ensureContentManagerInitialized()
return decorator!!
}
private fun createContentManager(): ContentManagerImpl {
val contentUi = ToolWindowContentUi(this, windowInfo.contentUiType)
this.contentUi = contentUi
val contentManager = ContentManagerImpl(contentUi, canCloseContent, toolWindowManager.project, parentDisposable)
addContentNotInHierarchyComponents(contentUi)
val contentComponent = contentManager.component
InternalDecorator.installFocusTraversalPolicy(contentComponent, LayoutFocusTraversalPolicy())
Disposer.register(parentDisposable, UiNotifyConnector(contentComponent, object : Activatable {
override fun showNotify() {
showing.onReady()
}
}))
val decorator = InternalDecorator(this, contentUi)
this.decorator = decorator
var decoratorChild = contentManager.component
if (!dumbAware) {
decoratorChild = DumbService.getInstance(toolWindowManager.project).wrapGently(decoratorChild, parentDisposable)
}
decorator.add(decoratorChild, BorderLayout.CENTER)
decorator.applyWindowInfo(windowInfo)
decorator.addComponentListener(object : ComponentAdapter() {
override fun componentResized(e: ComponentEvent) {
toolWindowManager.resized(e.component as InternalDecorator)
}
})
toolWindowFocusWatcher = ToolWindowManagerImpl.ToolWindowFocusWatcher(this, contentComponent)
// after init, as it was before contentManager creation was changed to be lazy
pendingContentManagerListeners?.let { list ->
pendingContentManagerListeners = null
for (listener in list) {
contentManager.addContentManagerListener(listener)
}
}
return contentManager
}
internal fun applyWindowInfo(info: WindowInfo) {
if (windowInfo == info) {
return
}
windowInfo = info
decorator?.applyWindowInfo(info)
val decorator = decorator
contentUi?.setType(info.contentUiType)
if (decorator != null) {
decorator.applyWindowInfo(info)
decorator.validate()
decorator.repaint()
}
}
val decoratorComponent: JComponent?
@@ -142,6 +169,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
toolWindowFocusWatcher?.setFocusedComponentImpl(component)
}
@Deprecated(message = "Do not use.", level = DeprecationLevel.ERROR)
fun getContentUI() = contentUi
override fun getDisposable() = parentDisposable
@@ -164,19 +192,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
override fun isActive(): Boolean {
ApplicationManager.getApplication().assertIsDispatchThread()
val frameHelper = toolWindowManager.getFrame() ?: return false
val frame = frameHelper.frame
if (!frame.isActive || toolWindowManager.isEditorComponentActive) {
return false
}
val actionManager = ActionManager.getInstance()
if (actionManager is ActionManagerImpl && !actionManager.isActionPopupStackEmpty && !actionManager.isToolWindowContextMenuVisible) {
return false
}
else {
return windowInfo.isActive || (windowInfo.isVisible && (decorator?.isFocused(frameHelper.frame) ?: false))
}
return windowInfo.isVisible && decorator != null && toolWindowManager.activeToolWindowId == id
}
override fun getReady(requestor: Any): ActionCallback {
@@ -262,27 +278,22 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
override fun getDecorator() = decorator!!
val isFocused: Boolean
get() {
return decorator?.isFocused(toolWindowManager.getFrame()?.frame ?: return false) ?: false
}
override fun setAdditionalGearActions(value: ActionGroup?) {
additionalGearActions = value
}
override fun setTitleActions(vararg actions: AnAction) {
contentManager.value
createContentIfNeeded()
decorator!!.setTitleActions(actions)
}
override fun setTabActions(vararg actions: AnAction) {
contentManager.value
createContentIfNeeded()
decorator!!.setTabActions(actions)
}
fun setTabDoubleClickActions(vararg actions: AnAction) {
contentUi.setTabDoubleClickActions(*actions)
contentUi?.setTabDoubleClickActions(*actions)
}
override fun setAvailable(available: Boolean, runnable: Runnable?) {
@@ -321,7 +332,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
override fun getContentManager(): ContentManager {
ensureContentInitialized()
createContentIfNeeded()
return contentManager.value
}
@@ -329,6 +340,12 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
if (contentManager.isInitialized()) {
contentManager.value.addContentManagerListener(listener)
}
else {
if (pendingContentManagerListeners == null) {
pendingContentManagerListeners = arrayListOf()
}
pendingContentManagerListeners!!.add(listener)
}
}
fun canCloseContents() = canCloseContent
@@ -414,19 +431,36 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
override fun isDisposed() = contentManager.isInitialized() && contentManager.value.isDisposed
fun ensureContentInitialized() {
val currentContentFactory = contentFactory
if (currentContentFactory != null) {
// clear it first to avoid SOE
this.contentFactory = null
if (contentManager.isInitialized()) {
contentManager.value.removeAllContents(false)
}
contentManager.value
currentContentFactory.createToolWindowContent(toolWindowManager.project, this)
private fun ensureContentManagerInitialized() {
contentManager.value
}
internal fun scheduleContentInitializationIfNeeded() {
if (contentFactory != null) {
// todo use lazy loading (e.g. JBLoadingPanel)
createContentIfNeeded()
}
}
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated("Do not use. Tool window content will be initialized automatically.", level = DeprecationLevel.ERROR)
fun ensureContentInitialized() {
createContentIfNeeded()
}
internal fun createContentIfNeeded() {
val currentContentFactory = contentFactory ?: return
// clear it first to avoid SOE
this.contentFactory = null
if (contentManager.isInitialized()) {
contentManager.value.removeAllContents(false)
}
else {
ensureContentManagerInitialized()
}
currentContentFactory.createToolWindowContent(toolWindowManager.project, this)
}
override fun getHelpId() = helpId
override fun setHelpId(value: String) {
@@ -434,9 +468,8 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
override fun showContentPopup(inputEvent: InputEvent) {
// create before access contentUi
val contentManager = contentManager.value
ToolWindowContentUi.toggleContentPopup(contentUi, contentManager)
// called only when tool window is already opened, so, content should be already created
ToolWindowContentUi.toggleContentPopup(contentUi!!, contentManager.value)
}
@JvmOverloads
@@ -524,7 +557,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
private inner class ResizeActionGroup : ActionGroup(ActionsBundle.groupText("ResizeToolWindowGroup"), true), DumbAware {
private val children by lazy<Array<AnAction>> {
// force creation
contentManager.value
createContentIfNeeded()
val component = decorator
val toolWindow = this@ToolWindowImpl
arrayOf(
@@ -558,7 +591,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
override fun update(e: AnActionEvent) {
hadSeveralContents = hadSeveralContents || getContentManager().contentCount > 1
hadSeveralContents = hadSeveralContents || (contentManager.isInitialized() && contentManager.value.contentCount > 1)
super.update(e)
e.presentation.isVisible = hadSeveralContents
}
@@ -596,4 +629,31 @@ private fun addSorted(main: DefaultActionGroup, group: ActionGroup) {
if (children.isNotEmpty() && !separatorText.isNullOrEmpty()) {
main.addAction(Separator(separatorText), Constraints.FIRST)
}
}
private fun addContentNotInHierarchyComponents(contentUi: ToolWindowContentUi) {
UIUtil.putClientProperty(contentUi.component, UIUtil.NOT_IN_HIERARCHY_COMPONENTS, object : Iterable<JComponent> {
override fun iterator(): Iterator<JComponent> {
val contentManager = contentUi.contentManager ?: return Collections.emptyIterator()
if (contentManager.contentCount == 0) {
return Collections.emptyIterator()
}
return contentManager.contents
.asSequence()
.mapNotNull { content: Content ->
var last: JComponent? = null
var parent: Component? = content.component
while (parent != null) {
if (parent === contentUi.component || parent !is JComponent) {
return@mapNotNull null
}
last = parent
parent = parent.getParent()
}
last
}
.iterator()
}
})
}
@@ -50,7 +50,6 @@ import com.intellij.openapi.wm.ex.ToolWindowManagerEx
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
import com.intellij.openapi.wm.ex.WindowManagerEx
import com.intellij.openapi.wm.impl.commands.RequestFocusInToolWindowCommand
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi
import com.intellij.ui.BalloonImpl
import com.intellij.ui.ComponentUtil
import com.intellij.ui.GuiUtils
@@ -628,9 +627,6 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
if (parent is InternalDecorator) {
return parent.toolWindow.id
}
else if (parent is ToolWindowContentUi) {
return parent.toolWindowId
}
parent = parent.parent
}
@@ -781,7 +777,7 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
private fun doHide(entry: ToolWindowEntry, info: WindowInfoImpl, dirtyMode: Boolean, hideSide: Boolean = false, moveFocus: Boolean = true): Boolean {
// info.isActive is not reliable (not set to false on focus lost)
val wasActive = entry.toolWindow.isFocused
val wasActive = entry.toolWindow.isActive
if (!wasActive && !info.isVisible) {
return false
@@ -862,8 +858,6 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
}
private fun doShowWindow(entry: ToolWindowEntry, info: WindowInfo, dirtyMode: Boolean) {
entry.toolWindow.ensureContentInitialized()
if (entry.readOnlyWindowInfo.type == ToolWindowType.FLOATING) {
addFloatingDecorator(entry, info)
}
@@ -906,12 +900,14 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
}
}
toolWindowPane!!.addDecorator(entry.toolWindow.decoratorComponent!!, info, dirtyMode, this)
toolWindowPane!!.addDecorator(entry.toolWindow.getOrCreateDecoratorComponent(), info, dirtyMode, this)
// remove tool window from the SideStack
if (isStackEnabled) {
sideStack.remove(entry.id)
}
}
entry.toolWindow.scheduleContentInitializationIfNeeded()
}
override fun registerToolWindow(task: RegisterToolWindowTask): ToolWindowImpl {
@@ -1388,7 +1384,7 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
private fun hideIfNeededAndShowAfterTask(entry: ToolWindowEntry, info: WindowInfoImpl, task: () -> Unit) {
val wasVisible = entry.readOnlyWindowInfo.isVisible
val wasFocused = entry.toolWindow.isFocused
val wasFocused = entry.toolWindow.isActive
if (wasVisible) {
doHide(entry, info, dirtyMode = true, moveFocus = false)
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl.content;
import com.intellij.openapi.ui.popup.ListPopup;
@@ -34,7 +34,7 @@ final class ComboContentLayout extends ContentLayout {
@Override
public void layout() {
Rectangle bounds = myUi.getBounds();
Rectangle bounds = myUi.getTabComponent().getBounds();
Dimension idSize = isIdVisible() ? myIdLabel.getPreferredSize() : JBUI.emptySize();
int eachX = 0;
@@ -70,9 +70,6 @@ final class ComboContentLayout extends ContentLayout {
g.drawLine(r.width - 1, 0, r.width - 1, r.height);
}
@Override
public void paintChildren(Graphics g) { }
@Override
public void update() {
updateIdLabel(myIdLabel);
@@ -81,17 +78,17 @@ final class ComboContentLayout extends ContentLayout {
@Override
public void rebuild() {
myUi.removeAll();
myUi.getTabComponent().removeAll();
myUi.add(myIdLabel);
myUi.getTabComponent().add(myIdLabel);
ToolWindowContentUi.initMouseListeners(myIdLabel, myUi, true);
myUi.add(myComboLabel);
myUi.getTabComponent().add(myComboLabel);
ToolWindowContentUi.initMouseListeners(myComboLabel, myUi, false);
}
boolean isToDrawCombo() {
ContentManager manager = myUi.contentManager;
ContentManager manager = myUi.getContentManager();
return manager != null && manager.getContentCount() > 1;
}
@@ -1,8 +1,9 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl.content;
import com.intellij.ui.Gray;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.ScreenReader;
@@ -44,7 +45,7 @@ final class ContentComboLabel extends BaseLabel {
@Override
public void keyPressed(KeyEvent e) {
if (e.getModifiers() == 0 && e.getKeyCode() == KeyEvent.VK_SPACE) {
ToolWindowContentUi.toggleContentPopup(myUi, myUi.contentManager);
ToolWindowContentUi.toggleContentPopup(myUi, myUi.getContentManager());
}
super.keyPressed(e);
}
@@ -57,7 +58,7 @@ final class ContentComboLabel extends BaseLabel {
super.processMouseEvent(e);
if (UIUtil.isActionClick(e)) {
ToolWindowContentUi.toggleContentPopup(myUi, myUi.contentManager);
ToolWindowContentUi.toggleContentPopup(myUi, myUi.getContentManager());
}
}
@@ -109,7 +110,8 @@ final class ContentComboLabel extends BaseLabel {
@Nullable
@Override
public Content getContent() {
return myUi.contentManager == null ? null : myUi.contentManager.getSelectedContent();
ContentManager contentManager = myUi.getContentManager();
return contentManager == null ? null : contentManager.getSelectedContent();
}
@Override
@@ -145,7 +147,7 @@ final class ContentComboLabel extends BaseLabel {
@Override
public boolean doAccessibleAction(int index) {
if (index == 0) {
ToolWindowContentUi.toggleContentPopup(myUi, myUi.contentManager);
ToolWindowContentUi.toggleContentPopup(myUi, myUi.getContentManager());
return true;
}
else {
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl.content;
import com.intellij.openapi.ui.popup.ListPopup;
@@ -13,8 +13,6 @@ import javax.swing.*;
import java.awt.*;
abstract class ContentLayout {
static final int TAB_ARC = 2;
ToolWindowContentUi myUi;
BaseLabel myIdLabel;
@@ -30,8 +28,6 @@ abstract class ContentLayout {
public abstract void paintComponent(Graphics g);
public abstract void paintChildren(Graphics g);
public abstract void update();
public abstract void rebuild();
@@ -54,7 +50,7 @@ abstract class ContentLayout {
}
private String getTitleSuffix() {
ContentManager manager = myUi.contentManager;
ContentManager manager = myUi.getContentManager();
switch (manager == null ? 0 : manager.getContentCount()) {
case 0:
return null;
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl.content;
import com.intellij.ide.DataManager;
@@ -23,7 +23,6 @@ import com.intellij.util.ui.TimedDeadzone;
import com.intellij.util.ui.UIUtilities;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
@@ -105,7 +104,6 @@ class ContentTabLabel extends BaseLabel {
}
String toolText = icon.getTooltip();
if (toolText != null && !toolText.isEmpty()) {
IdeTooltip tooltip = new IdeTooltip(this, icon.getCenterPoint(), new JLabel(toolText));
currentIconTooltip = new CurrentTooltip(IdeTooltipManager.getInstance().show(tooltip, false, false), icon);
@@ -118,7 +116,6 @@ class ContentTabLabel extends BaseLabel {
IdeTooltip tooltip = new IdeTooltip(this, getMousePosition(), new JLabel(myText));
currentIconTooltip = new CurrentTooltip(IdeTooltipManager.getInstance().show(tooltip, false, false), null);
}
}
private void hideCurrentTooltip() {
@@ -130,15 +127,12 @@ class ContentTabLabel extends BaseLabel {
private final BaseButtonBehavior behavior = new BaseButtonBehavior(this) {
@Override
protected void execute(final MouseEvent e) {
Optional<Runnable> first = myAdditionalIcons.stream()
.filter(icon -> mouseOverIcon(icon))
.map(icon -> icon.getAction()).findFirst();
if (first.isPresent()) {
first.get().run();
return;
protected void execute(@NotNull MouseEvent e) {
for (AdditionalIcon icon : myAdditionalIcons) {
if (mouseOverIcon(icon)) {
icon.getAction().run();
return;
}
}
selectContent();
@@ -358,10 +352,10 @@ class ContentTabLabel extends BaseLabel {
@NotNull
private ContentManager getContentManager() {
return myUi.myWindow.getContentManager();
return myUi.getContentManager();
}
@Nullable
@NotNull
@Override
public Content getContent() {
return myContent;
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl.content;
import com.intellij.ide.dnd.DnDSupport;
@@ -39,10 +39,10 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
List<AnAction> myDoubleClickActions = new ArrayList<>();
TabContentLayout(ToolWindowContentUi ui) {
TabContentLayout(@NotNull ToolWindowContentUi ui) {
super(ui);
new BaseButtonBehavior(myUi) {
new BaseButtonBehavior(myUi.getTabComponent()) {
@Override
protected void execute(final MouseEvent e) {
if (!myUi.isCurrent(TabContentLayout.this)) return;
@@ -65,7 +65,7 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
}
};
ContentManager contentManager = myUi.contentManager;
ContentManager contentManager = myUi.getContentManager();
for (int i = 0; i < contentManager.getContentCount(); i++) {
contentAdded(new ContentManagerEvent(this, contentManager.getContent(i), i));
}
@@ -99,14 +99,14 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
List<? extends ContentTabLabel> tabs = ContainerUtil.filter(myTabs, myLastLayout.toDrop::contains);
final List<Content> contentsToShow = ContainerUtil.map(tabs, ContentTabLabel::getContent);
final SelectContentStep step = new SelectContentStep(contentsToShow);
RelativePoint point = new RelativePoint(myUi, new Point(rect.x, rect.y + rect.height));
RelativePoint point = new RelativePoint(myUi.getTabComponent(), new Point(rect.x, rect.y + rect.height));
JBPopupFactory.getInstance().createListPopup(step).show(point);
}
@Override
public void layout() {
Rectangle bounds = myUi.getBounds();
ContentManager manager = myUi.contentManager;
Rectangle bounds = myUi.getTabComponent().getBounds();
ContentManager manager = myUi.getContentManager();
LayoutData data = new LayoutData(myUi);
data.eachX = TAB_LAYOUT_START;
@@ -137,7 +137,6 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
}
}
if (data.fullLayout) {
for (ContentTabLabel eachTab : myTabs) {
final Dimension eachSize = eachTab.getPreferredSize();
@@ -200,8 +199,7 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
data.moreRect = null;
}
final Rectangle moreRect = data.moreRect == null ? null : new Rectangle(data.eachX, 0, /*getMoreToolbarWidth()*/16+MORE_ICON_BORDER, bounds.height);
Rectangle moreRect = data.moreRect == null ? null : new Rectangle(data.eachX, 0, /*getMoreToolbarWidth()*/16+MORE_ICON_BORDER, bounds.height);
myUi.isResizableArea = p -> moreRect == null || !moreRect.contains(p);
myLastLayout = data;
if (toolbarUpdateNeeded) {
@@ -220,7 +218,7 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
}
}
ContentManager contentManager = myUi.contentManager;
ContentManager contentManager = myUi.getContentManager();
Content selected = contentManager.getSelectedContent();
if (selected == null && contentManager.getContents().length > 0) {
selected = contentManager.getContents()[0];
@@ -237,14 +235,16 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
}
boolean isToDrawTabs() {
if(myTabs.size() > 1) return true;
if(myTabs.size() == 1) {
String title = myTabs.get(0).getContent().getToolwindowTitle();
return !StringUtil.isEmpty(title);
}
int size = myTabs.size();
if (size > 1) {
return true;
}
else if (size == 1) {
return !StringUtil.isEmpty(myTabs.get(0).getContent().getToolwindowTitle());
}
else {
return false;
}
}
static class LayoutData {
@@ -263,12 +263,12 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
public int contentCount;
LayoutData(ToolWindowContentUi ui) {
layoutSize = ui.getSize();
contentCount = ui.contentManager.getContentCount();
layoutSize = ui.getTabComponent().getSize();
contentCount = ui.getContentManager().getContentCount();
}
}
private JBTabPainter tabPainter = JBTabPainter.getTOOL_WINDOW();
private final JBTabPainter tabPainter = JBTabPainter.getTOOL_WINDOW();
@Override
public void paintComponent(Graphics g) {
@@ -292,11 +292,6 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
g2d.dispose();
}
@Override
public void paintChildren(Graphics g) {
if (!isToDrawTabs()) return;
}
@Override
public void update() {
for (ContentTabLabel each : myTabs) {
@@ -308,13 +303,13 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
@Override
public void rebuild() {
myUi.removeAll();
myUi.getTabComponent().removeAll();
myUi.add(myIdLabel);
myUi.getTabComponent().add(myIdLabel);
ToolWindowContentUi.initMouseListeners(myIdLabel, myUi, true);
for (ContentTabLabel each : myTabs) {
myUi.add(each);
myUi.getTabComponent().add(each);
ToolWindowContentUi.initMouseListeners(each, myUi, false);
}
}
@@ -359,7 +354,7 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
@Override
public void showContentPopup(ListPopup listPopup) {
Content selected = myUi.contentManager.getSelectedContent();
Content selected = myUi.getContentManager().getSelectedContent();
if (selected != null) {
ContentTabLabel tab = myContent2Tabs.get(selected);
listPopup.showUnderneathOf(tab);
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.openapi.wm.impl.content;
import com.intellij.ide.IdeEventQueue;
@@ -8,7 +8,6 @@ import com.intellij.reference.SoftReference;
import com.intellij.ui.content.TabbedContent;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.lang.ref.Reference;
@@ -18,8 +17,7 @@ import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class TabbedContentTabLabel extends ContentTabLabel {
public final class TabbedContentTabLabel extends ContentTabLabel {
private final TabbedContent myContent;
private Reference<JBPopup> myPopupReference = null;
@@ -80,7 +78,7 @@ public class TabbedContentTabLabel extends ContentTabLabel {
return hasMultipleTabs();
}
@Nullable
@NotNull
@Override
public Runnable getAction() {
return () -> selectContent();
@@ -99,7 +97,7 @@ public class TabbedContentTabLabel extends ContentTabLabel {
}
}
@Nullable
@NotNull
@Override
public TabbedContent getContent() {
return myContent;
@@ -13,22 +13,21 @@ import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.ui.ThreeComponentsSplitter;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.impl.ToolWindowImpl;
import com.intellij.openapi.wm.impl.ToolWindowManagerImpl;
import com.intellij.ui.ComponentUtil;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.content.*;
import com.intellij.ui.content.tabs.PinToolwindowTabAction;
import com.intellij.ui.content.tabs.TabbedContentAction;
import com.intellij.ui.layout.migLayout.MigLayoutBuilderKt;
import com.intellij.ui.layout.migLayout.patched.MigLayout;
import com.intellij.ui.tabs.impl.MorePopupAware;
import com.intellij.util.Alarm;
import com.intellij.util.ContentUtilEx;
import com.intellij.util.containers.JBIterable;
import com.intellij.util.containers.Predicate;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.LocationOnDragTracker;
@@ -44,62 +43,48 @@ import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public final class ToolWindowContentUi extends JPanel implements ContentUI, DataProvider, UISettingsListener {
public final class ToolWindowContentUi implements ContentUI, DataProvider {
// when client property is put in toolwindow component, hides toolwindow label
public static final String HIDE_ID_LABEL = "HideIdLabel";
private static final String TOOLWINDOW_UI_INSTALLED = "ToolWindowUiInstalled";
ContentManager contentManager;
private ContentManager contentManager;
final JPanel myContent = new JPanel(new BorderLayout());
ToolWindowImpl myWindow;
public ContentManager getContentManager() {
return contentManager;
}
TabbedContentAction.CloseAllAction myCloseAllAction;
TabbedContentAction.MyNextTabAction myNextTabAction;
TabbedContentAction.MyPreviousTabAction myPreviousTabAction;
private final JPanel myContent = new JPanel(new BorderLayout());
final ToolWindowImpl myWindow;
ShowContentAction myShowContent;
private TabbedContentAction.CloseAllAction myCloseAllAction;
private TabbedContentAction.MyNextTabAction myNextTabAction;
private TabbedContentAction.MyPreviousTabAction myPreviousTabAction;
TabContentLayout myTabsLayout = new TabContentLayout(this);
ContentLayout myComboLayout = new ComboContentLayout(this);
private ShowContentAction myShowContent;
private ToolWindowContentUiType myType = ToolWindowContentUiType.TABBED;
private final TabContentLayout myTabsLayout;
private ContentLayout myComboLayout;
private ToolWindowContentUiType myType;
public Predicate<Point> isResizableArea = p -> true;
public ToolWindowContentUi(@NotNull ToolWindowImpl window) {
private final JPanel tabComponent = new TabPanel();
@NotNull
public JPanel getTabComponent() {
return tabComponent;
}
public ToolWindowContentUi(@NotNull ToolWindowImpl window, @NotNull ToolWindowContentUiType contentUiType) {
myType = contentUiType;
myTabsLayout = new TabContentLayout(this);
myWindow = window;
myContent.setOpaque(false);
myContent.setFocusable(false);
setOpaque(false);
setBorder(JBUI.Borders.emptyRight(2));
// InternalDecorator adds myContent right after "this" (via ToolWindowHeader)
// also myContent is never removed (can be invisible due to DumbAwareHider)
ComponentUtil.putClientProperty(myContent, UIUtil.NOT_IN_HIERARCHY_COMPONENTS, new Iterable<JComponent>() {
@Override
public Iterator<JComponent> iterator() {
if (contentManager == null || contentManager.getContentCount() == 0) {
return Collections.emptyIterator();
}
return JBIterable.of(contentManager.getContents())
.map(content -> {
JComponent last = null;
for (Component c : UIUtil.uiParents(content.getComponent(), false)) {
if (c == contentManager.getComponent() || !(c instanceof JComponent)) return null;
last = (JComponent)c;
}
return last;
})
.filter(Conditions.notNull())
.iterator();
}
});
}
@NotNull
@@ -107,12 +92,6 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
return myWindow.getId();
}
@Override
public void uiSettingsChanged(@NotNull UISettings uiSettings) {
revalidate();
repaint();
}
private boolean isResizeable() {
if (myWindow.getType() == ToolWindowType.FLOATING || myWindow.getType() == ToolWindowType.WINDOWED) {
return false;
@@ -158,7 +137,15 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
@NotNull
private ContentLayout getCurrentLayout() {
return myType == ToolWindowContentUiType.TABBED ? myTabsLayout : myComboLayout;
if (myType == ToolWindowContentUiType.TABBED) {
return myTabsLayout;
}
else {
if (myComboLayout == null) {
myComboLayout = new ComboContentLayout(this);
}
return myComboLayout;
}
}
@Override
@@ -166,10 +153,6 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
return myContent;
}
public JComponent getTabComponent() {
return this;
}
@Override
public void setManager(@NotNull ContentManager manager) {
if (contentManager != null) {
@@ -214,7 +197,7 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
}
});
initMouseListeners(this, this, true);
initMouseListeners(tabComponent, this, true);
rebuild();
@@ -249,57 +232,19 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
getCurrentLayout().rebuild();
getCurrentLayout().update();
revalidate();
repaint();
tabComponent.revalidate();
tabComponent.repaint();
if (contentManager != null && contentManager.getContentCount() == 0 && myWindow.isToHideOnEmptyContent()) {
myWindow.hide(null);
}
}
@Override
public void doLayout() {
getCurrentLayout().layout();
}
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
getCurrentLayout().paintComponent(g);
}
@Override
protected void paintChildren(final Graphics g) {
super.paintChildren(g);
getCurrentLayout().paintChildren(g);
}
@Override
public Dimension getMinimumSize() {
Insets insets = getInsets();
return new Dimension(insets.left + insets.right + getCurrentLayout().getMinimumWidth(), super.getMinimumSize().height);
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension();
size.height = 0;
size.width = TabContentLayout.TAB_LAYOUT_START + getInsets().left + getInsets().right;
for (int i = 0; i < getComponentCount(); i++) {
final Component each = getComponent(i);
size.height = Math.max(each.getPreferredSize().height, size.height);
size.width += each.getPreferredSize().width;
}
size.width = Math.max(size.width, getMinimumSize().width);
return size;
}
private void update() {
getCurrentLayout().update();
revalidate();
repaint();
tabComponent.revalidate();
tabComponent.repaint();
}
@Override
@@ -363,7 +308,9 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
final Ref<LocationOnDragTracker> myDragTracker = Ref.create();
private Component getActualSplitter() {
if (!allowResize || !ui.isResizeable()) return null;
if (!allowResize || !ui.isResizeable()) {
return null;
}
Component component = c;
Component parent = component.getParent();
@@ -628,7 +575,8 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
}
else if (CloseAction.CloseTarget.KEY.is(dataId)) {
return computeCloseTarget();
} else if (MorePopupAware.KEY.is(dataId)) {
}
else if (MorePopupAware.KEY.is(dataId)) {
ContentLayout layout = getCurrentLayout();
return (layout instanceof TabContentLayout) ? layout : null;
}
@@ -685,4 +633,51 @@ public final class ToolWindowContentUi extends JPanel implements ContentUI, Data
new Alarm(Alarm.ThreadToUse.SWING_THREAD, popup).addRequest(() -> popup.handleSelect(false), 50);
}
}
private final class TabPanel extends JPanel implements UISettingsListener {
private TabPanel() {
super(new MigLayout(MigLayoutBuilderKt.createLayoutConstraints(0, 0).noVisualPadding().fillY()));
setOpaque(false);
setBorder(JBUI.Borders.emptyRight(2));
}
@Override
public void uiSettingsChanged(@NotNull UISettings uiSettings) {
revalidate();
repaint();
}
@Override
public void doLayout() {
getCurrentLayout().layout();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
getCurrentLayout().paintComponent(g);
}
@Override
public Dimension getMinimumSize() {
Insets insets = getInsets();
return new Dimension(insets.left + insets.right + getCurrentLayout().getMinimumWidth(), super.getMinimumSize().height);
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension();
size.height = 0;
size.width = TabContentLayout.TAB_LAYOUT_START + getInsets().left + getInsets().right;
for (int i = 0; i < getComponentCount(); i++) {
final Component each = getComponent(i);
size.height = Math.max(each.getPreferredSize().height, size.height);
size.width += each.getPreferredSize().width;
}
size.width = Math.max(size.width, getMinimumSize().width);
return size;
}
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.ui.content.impl;
import com.intellij.icons.AllIcons;
@@ -153,8 +153,7 @@ public class ContentImpl extends UserDataHolderBase implements Content {
@Override
public String getToolwindowTitle() {
if (myToolwindowTitle != null) return myToolwindowTitle;
return myDisplayName;
return myToolwindowTitle == null ? myDisplayName : myToolwindowTitle;
}
@Override
@@ -172,11 +171,6 @@ public class ContentImpl extends UserDataHolderBase implements Content {
myShouldDisposeContent = value;
}
@Override
public boolean shouldDisposeContent() {
return myShouldDisposeContent;
}
@Override
public String getDescription() {
return myDescription;
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package com.intellij.ui.content.impl;
import com.intellij.ide.DataManager;
@@ -169,7 +169,7 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene
@Override
public boolean removeContent(@NotNull Content content, boolean dispose) {
boolean wasFocused = content.getComponent() != null && UIUtil.isFocusAncestor(content.getComponent());
boolean wasFocused = UIUtil.isFocusAncestor(content.getComponent());
return removeContent(content, dispose, wasFocused, false).isDone();
}
@@ -1,4 +1,4 @@
// Copyright 2000-2019 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.
// 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.
package org.jetbrains.plugins.terminal;
import com.google.common.collect.Sets;
@@ -161,11 +161,9 @@ public class TerminalView {
}
@Nullable
private JBTerminalWidget createNewSession(@NotNull AbstractTerminalRunner terminalRunner, @Nullable TerminalTabState tabState, boolean requestFocus) {
private JBTerminalWidget createNewSession(@NotNull AbstractTerminalRunner<?> terminalRunner, @Nullable TerminalTabState tabState, boolean requestFocus) {
ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(TerminalToolWindowFactory.TOOL_WINDOW_ID);
if (window != null && window.isAvailable()) {
// ensure TerminalToolWindowFactory.createToolWindowContent gets called
((ToolWindowImpl)window).ensureContentInitialized();
Content content = createNewTab(null, terminalRunner, myToolWindow, tabState, requestFocus);
window.activate(null);
return Objects.requireNonNull(getWidgetByContent(content));
@@ -350,16 +348,16 @@ public class TerminalView {
public void openTerminalIn(@Nullable VirtualFile fileToOpen) {
ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(TerminalToolWindowFactory.TOOL_WINDOW_ID);
if (window != null && window.isAvailable()) {
// ensure TerminalToolWindowFactory.createToolWindowContent gets called
((ToolWindowImpl)window).ensureContentInitialized();
TerminalTabState state = new TerminalTabState();
if (fileToOpen != null) {
state.myWorkingDirectory = fileToOpen.getPath();
}
createNewSession(myTerminalRunner, state);
window.activate(null);
if (window == null || !window.isAvailable()) {
return;
}
TerminalTabState state = new TerminalTabState();
if (fileToOpen != null) {
state.myWorkingDirectory = fileToOpen.getPath();
}
createNewSession(myTerminalRunner, state);
window.activate(null);
}
@Nullable