Revert "forbid calling ensureContentInitialized explicitly, reduce usages of isActive"

This reverts commit 360a585b

GitOrigin-RevId: 9ecee36b3ffa3169c7643bfc341f0c0a1c81fa3f
This commit is contained in:
Vladimir Krivosheev
2019-12-23 17:33:43 +00:00
committed by intellij-monorepo-bot
parent 02b75e2017
commit a4bf9b0405
25 changed files with 390 additions and 361 deletions
@@ -14,6 +14,7 @@ import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.impl.ToolWindowHeadlessManagerImpl;
import com.intellij.openapi.wm.impl.ToolWindowImpl;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -30,7 +31,8 @@ import java.util.Set;
*
* @author Denis Zhdanov
*/
public final class ExternalToolWindowManager {
public class ExternalToolWindowManager {
@SuppressWarnings("unchecked")
public static void handle(@NotNull Project project) {
for (final ExternalSystemManager<?, ?, ?, ?, ?> manager : ExternalSystemApiUtil.getAllManagers()) {
@@ -80,7 +82,14 @@ public final class ExternalToolWindowManager {
@Nullable
public static ToolWindow getToolWindow(@NotNull Project project, @NotNull ProjectSystemId externalSystemId) {
ToolWindow result = ToolWindowManager.getInstance(project).getToolWindow(externalSystemId.getReadableName());
final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
if (toolWindowManager == null) {
return null;
}
ToolWindow result = toolWindowManager.getToolWindow(externalSystemId.getReadableName());
if (result instanceof ToolWindowImpl) {
((ToolWindowImpl)result).ensureContentInitialized();
}
if (result == null && ApplicationManager.getApplication().isUnitTestMode()) {
result = new ToolWindowHeadlessManagerImpl.MockToolWindow(project);
}
@@ -86,6 +86,7 @@ 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;
@@ -106,7 +107,10 @@ import java.util.function.Supplier;
import static com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings.SyncType.*;
import static com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.doWriteAction;
public final class ExternalSystemUtil {
/**
* @author Denis Zhdanov
*/
public class ExternalSystemUtil {
private static final Logger LOG = Logger.getInstance(ExternalSystemUtil.class);
@NotNull private static final Map<String, String> RUNNER_IDS = new HashMap<>();
@@ -181,7 +185,16 @@ public final class ExternalSystemUtil {
@Nullable
public static ToolWindow ensureToolWindowContentInitialized(@NotNull Project project, @NotNull ProjectSystemId externalSystemId) {
return ToolWindowManager.getInstance(project).getToolWindow(externalSystemId.getReadableName());
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;
}
/**
@@ -269,9 +282,9 @@ public final class ExternalSystemUtil {
}
}
@NotNull
@Nullable
private static String extractDetails(@NotNull Throwable e) {
Throwable unwrapped = RemoteUtil.unwrap(e);
final Throwable unwrapped = RemoteUtil.unwrap(e);
if (unwrapped instanceof ExternalSystemException) {
return ((ExternalSystemException)unwrapped).getOriginalReason();
}
@@ -35,7 +35,7 @@ import java.util.function.IntPredicate;
*
* @author lesya
*/
public final class MnemonicHelper extends ComponentTreeWatcher {
public class MnemonicHelper extends ComponentTreeWatcher {
private static final Logger LOG = Logger.getInstance(MnemonicHelper.class);
public static final Key<IntPredicate> MNEMONIC_CHECKER = Key.create("MNEMONIC_CHECKER");
@@ -190,16 +190,11 @@ public final class MnemonicHelper extends ComponentTreeWatcher {
private static final MnemonicFixer ourMnemonicFixer = new MnemonicFixer();
private static final class MnemonicFixer implements ContainerListener {
private static class MnemonicFixer implements ContainerListener {
void addTo(Component component) {
for (Component c : UIUtil.uiTraverser(component)) {
if (c instanceof Container) {
((Container)c).addContainerListener(this);
}
if (c instanceof ActionButtonComponent) {
assert c instanceof JComponent;
fixMacMnemonicKeyStroke((JComponent)c, null);
}
if (c instanceof Container) ((Container)c).addContainerListener(this);
if (c instanceof ActionButtonComponent) fixMacMnemonicKeyStroke((JComponent)c, null);
MnemonicWrapper.getWrapper(c);
}
}
@@ -1,4 +1,19 @@
// 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-2017 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.project;
import com.intellij.ui.components.JBPanelWithEmptyText;
@@ -10,7 +25,8 @@ import java.awt.*;
/**
* @author peter
*/
public final class DumbUnawareHider extends JBPanelWithEmptyText {
public class DumbUnawareHider extends JBPanelWithEmptyText {
private final JComponent myDumbUnawareContent;
public DumbUnawareHider(@NotNull JComponent dumbUnawareContent) {
@@ -20,7 +36,6 @@ public final class DumbUnawareHider extends JBPanelWithEmptyText {
add(dumbUnawareContent, BorderLayout.CENTER);
}
@NotNull
public JComponent getContent() {
return myDumbUnawareContent;
}
@@ -474,15 +474,18 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
*
*/
public void setFirstComponent(@Nullable JComponent component) {
if (myFirstComponent == component) {
return;
}
if (myFirstComponent != component) {
if (myFirstComponent != null) {
remove(myFirstComponent);
}
myFirstComponent = component;
updateComponentTreeUI(myFirstComponent);
if (myFirstComponent != null) {
remove(myFirstComponent);
if (myFirstComponent != null) {
add(myFirstComponent);
myFirstComponent.invalidate();
}
}
myFirstComponent = component;
doAddComponent(component);
}
@Nullable
@@ -490,20 +493,25 @@ 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) {
return;
}
if (myLastComponent != component) {
if (myLastComponent != null) {
remove(myLastComponent);
}
myLastComponent = component;
updateComponentTreeUI(myLastComponent);
if (myLastComponent != null) {
remove(myLastComponent);
if (myLastComponent != null) {
add(myLastComponent);
myLastComponent.invalidate();
}
}
myLastComponent = component;
doAddComponent(component);
}
@Nullable
@@ -511,12 +519,10 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
return myInnerComponent;
}
private static void updateComponentTreeUI(@Nullable JComponent rootComponent) {
for (Component component : UIUtil.uiTraverser(rootComponent).postOrderDfsTraversal()) {
if (component instanceof JComponent) {
((JComponent)component).updateUI();
}
}
private static void updateComponentTreeUI(@Nullable JComponent component) {
UIUtil.uiTraverser(component).postOrderDfsTraversal().
filter(c -> c instanceof JComponent).
forEach(c -> ((JComponent)c).updateUI());
}
/**
@@ -531,15 +537,13 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
if (myInnerComponent != null) {
remove(myInnerComponent);
}
myInnerComponent = component;
doAddComponent(component);
}
private void doAddComponent(@Nullable JComponent component) {
if (component != null) {
updateComponentTreeUI(component);
add(component);
component.invalidate();
myInnerComponent = component;
updateComponentTreeUI(myInnerComponent);
if (myInnerComponent != null) {
add(myInnerComponent);
myInnerComponent.invalidate();
}
}
@@ -633,6 +637,11 @@ 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();
@@ -641,6 +650,11 @@ 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();
@@ -650,7 +664,7 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
private final MouseAdapter myListener = new MyMouseAdapter();
private MouseEvent getTargetEvent(@NotNull MouseEvent e) {
private MouseEvent getTargetEvent(MouseEvent e) {
return SwingUtilities.convertMouseEvent(e.getComponent(), e, this);
}
@@ -50,9 +50,8 @@ public interface Content extends UserDataHolder, ComponentContainer {
void setTabName(String tabName);
String getTabName();
String getToolwindowTitle();
void setToolwindowTitle(String toolwindowTitle);
String getToolwindowTitle();
Disposable getDisposer();
@@ -60,6 +59,8 @@ public interface Content extends UserDataHolder, ComponentContainer {
void setShouldDisposeContent(boolean value);
boolean shouldDisposeContent();
String getDescription();
void setDescription(String description);
@@ -7,7 +7,7 @@ import java.awt.Color
import java.awt.Graphics2D
import java.awt.Rectangle
internal class ToolWindowTabPainter: JBDefaultTabPainter(ToolWindowTabTheme()) {
class ToolWindowTabPainter: JBDefaultTabPainter(ToolWindowTabTheme()) {
override fun paintTab(position: JBTabsPosition,
g: Graphics2D,
rect: Rectangle,
@@ -18,8 +18,8 @@ internal class ToolWindowTabPainter: JBDefaultTabPainter(ToolWindowTabTheme())
rect.y += borderThickness
rect.height -= borderThickness
if (position == JBTabsPosition.top) {
rect.height -= borderThickness
when (position) {
JBTabsPosition.top -> rect.height -= borderThickness
}
super.paintTab(position, g, rect, borderThickness, tabColor, active, hovered)
@@ -78,7 +78,7 @@ class EditorTabTheme : TabTheme {
get() = JBUI.CurrentTheme.EditorTabs.inactiveColoredFileBackground()
}
internal class ToolWindowTabTheme : DefaultTabTheme() {
class ToolWindowTabTheme : DefaultTabTheme() {
override val background: Color?
get() = null
override val borderColor: Color
@@ -104,7 +104,7 @@ internal class ToolWindowTabTheme : DefaultTabTheme() {
get() = JBUI.CurrentTheme.ToolWindow.underlinedTabInactiveForeground()
}
internal class DebuggerTabTheme : DefaultTabTheme() {
class DebuggerTabTheme : DefaultTabTheme() {
override val underlineHeight: Int
get() = JBUI.CurrentTheme.DebuggerTabs.underlineHeight()
override val underlinedTabBackground: Color?
@@ -313,7 +313,7 @@ public final class StripeButton extends AnchoredButton implements DataProvider {
}
void apply(@NotNull WindowInfo info) {
setSelected(info.isVisible());
setSelected(info.isVisible() || info.isActive());
updateState(toolWindow);
}
@@ -13,14 +13,12 @@ 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.layout.migLayout.MigLayoutBuilderKt;
import com.intellij.ui.layout.migLayout.patched.MigLayout;
import com.intellij.ui.components.panels.NonOpaquePanel;
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.layout.CC;
import net.miginfocom.layout.ConstraintParser;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -37,7 +35,6 @@ 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
@@ -53,19 +50,20 @@ public abstract class ToolWindowHeader extends JPanel implements UISettingsListe
private ActionToolbar myToolbarWest;
private final JPanel myWestPanel;
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;
ToolWindowHeader(@NotNull ToolWindowImpl toolWindow, @NotNull Supplier<? extends ActionGroup> gearProducer) {
myGearProducer = gearProducer;
AccessibleContextUtil.setName(this, "Tool Window Header");
myToolWindow = toolWindow;
myWestPanel = contentUi.getTabComponent();
add(myWestPanel, new CC().grow());
ToolWindowContentUi.initMouseListeners(myWestPanel, contentUi, true);
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);
ActionManager actionManager = ActionManager.getInstance();
AnAction tabListAction = actionManager.getAction("TabList");
@@ -85,7 +83,8 @@ 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) {
contentUi.showContextMenu(comp, x, y, toolWindow.getPopupGroup(), contentUi.getContentManager().getSelectedContent());
toolWindow.getContentUI()
.showContextMenu(comp, x, y, toolWindow.getPopupGroup(), toolWindow.getContentManager().getSelectedContent());
}
});
myWestPanel.addMouseListener(new MouseAdapter() {
@@ -140,7 +139,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 contentUi.getData(dataId);
return ((ToolWindowImpl)myToolWindow).getContentUI().getData(dataId);
}
return null;
}
@@ -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,22 +22,18 @@ 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
@@ -49,7 +45,7 @@ private val LOG = logger<ToolWindowImpl>()
class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManagerImpl,
val id: String,
private val canCloseContent: Boolean,
private val dumbAware: Boolean,
private val canWorkInDumbMode: Boolean,
component: JComponent?,
private val parentDisposable: Disposable,
windowInfo: WindowInfo,
@@ -60,14 +56,16 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
var windowInfo: WindowInfo = windowInfo
private set
private var contentUi: ToolWindowContentUi? = null
private val contentUi by lazy {
ToolWindowContentUi(this)
}
private var decorator: InternalDecorator? = null
private var hideOnEmptyContent = false
var isPlaceholderMode = false
private var pendingContentManagerListeners: MutableList<ContentManagerListener>? = null
private val pendingContentManagerListeners: List<ContentManagerListener>? = null
private val showing = object : BusyObject.Impl() {
override fun isReady(): Boolean {
@@ -84,7 +82,36 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
internal var icon: ToolWindowIcon? = null
private val contentManager = lazy {
createContentManager()
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
}
init {
@@ -96,92 +123,13 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
}
internal fun getOrCreateDecoratorComponent(): JComponent {
ensureContentManagerInitialized()
return decorator!!
}
private fun createContentManager(): ContentManagerImpl {
val contentUi = ToolWindowContentUi(this, windowInfo.contentUiType)
val contentManager = ContentManagerImpl(contentUi, canCloseContent, toolWindowManager.project, parentDisposable)
UIUtil.putClientProperty(contentUi.component, UIUtil.NOT_IN_HIERARCHY_COMPONENTS, object : Iterable<JComponent> {
override fun iterator(): Iterator<JComponent> {
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()
}
})
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)
if (windowInfo.isVisible) {
createContentIfNeeded()
}
// 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
val decorator = decorator
contentUi?.setType(info.contentUiType)
if (decorator != null) {
decorator.applyWindowInfo(info)
decorator.validate()
decorator.repaint()
}
decorator?.applyWindowInfo(info)
}
val decoratorComponent: JComponent?
@@ -194,7 +142,6 @@ 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
@@ -217,7 +164,19 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
override fun isActive(): Boolean {
ApplicationManager.getApplication().assertIsDispatchThread()
return windowInfo.isVisible && decorator != null && toolWindowManager.activeToolWindowId == id
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))
}
}
override fun getReady(requestor: Any): ActionCallback {
@@ -303,22 +262,27 @@ 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) {
createContentIfNeeded()
contentManager.value
decorator!!.setTitleActions(actions)
}
override fun setTabActions(vararg actions: AnAction) {
createContentIfNeeded()
contentManager.value
decorator!!.setTabActions(actions)
}
fun setTabDoubleClickActions(vararg actions: AnAction) {
contentUi?.setTabDoubleClickActions(*actions)
contentUi.setTabDoubleClickActions(*actions)
}
override fun setAvailable(available: Boolean, runnable: Runnable?) {
@@ -357,7 +321,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
override fun getContentManager(): ContentManager {
createContentIfNeeded()
ensureContentInitialized()
return contentManager.value
}
@@ -365,12 +329,6 @@ 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
@@ -456,35 +414,17 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
override fun isDisposed() = contentManager.isInitialized() && contentManager.value.isDisposed
private fun ensureContentManagerInitialized() {
contentManager.value
}
// if content manager due to some incorrect call was already initialized, content will be not created
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)
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)
}
else {
ensureContentManagerInitialized()
}
currentContentFactory.createToolWindowContent(toolWindowManager.project, this)
}
override fun getHelpId() = helpId
@@ -494,8 +434,9 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
override fun showContentPopup(inputEvent: InputEvent) {
// called only when tool window is already opened, so, content should be already created
ToolWindowContentUi.toggleContentPopup(contentUi!!, contentManager.value)
// create before access contentUi
val contentManager = contentManager.value
ToolWindowContentUi.toggleContentPopup(contentUi, contentManager)
}
@JvmOverloads
@@ -583,7 +524,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
createContentIfNeeded()
contentManager.value
val component = decorator
val toolWindow = this@ToolWindowImpl
arrayOf(
@@ -617,7 +558,7 @@ class ToolWindowImpl internal constructor(val toolWindowManager: ToolWindowManag
}
override fun update(e: AnActionEvent) {
hadSeveralContents = hadSeveralContents || (contentManager.isInitialized() && contentManager.value.contentCount > 1)
hadSeveralContents = hadSeveralContents || getContentManager().contentCount > 1
super.update(e)
e.presentation.isVisible = hadSeveralContents
}
@@ -50,6 +50,7 @@ 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
@@ -622,6 +623,9 @@ 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
}
@@ -772,7 +776,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.isActive
val wasActive = entry.toolWindow.isFocused
if (!wasActive && !info.isVisible) {
return false
@@ -853,6 +857,8 @@ 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)
}
@@ -895,14 +901,12 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
}
}
toolWindowPane!!.addDecorator(entry.toolWindow.getOrCreateDecoratorComponent(), info, dirtyMode, this)
toolWindowPane!!.addDecorator(entry.toolWindow.decoratorComponent!!, info, dirtyMode, this)
// remove tool window from the SideStack
if (isStackEnabled) {
sideStack.remove(entry.id)
}
}
entry.toolWindow.scheduleContentInitializationIfNeeded()
}
override fun registerToolWindow(task: RegisterToolWindowTask): ToolWindowImpl {
@@ -1379,7 +1383,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.isActive
val wasFocused = entry.toolWindow.isFocused
if (wasVisible) {
doHide(entry, info, dirtyMode = true, moveFocus = false)
}
@@ -187,6 +187,9 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi
}
/**
* Creates command which shows tool window with specified set of parameters.
* Command uses cloned copy of passed {@code info} object.
*
* @param dirtyMode if {@code true} then JRootPane will not be validated and repainted after adding
* the decorator. Moreover in this (dirty) mode animation doesn't work.
*/
@@ -288,7 +291,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi
}
}
private void setComponent(@Nullable JComponent component, @NotNull ToolWindowAnchor anchor, float weight) {
private void setComponent(@Nullable JComponent component, @NotNull ToolWindowAnchor anchor, final float weight) {
if (ToolWindowAnchor.TOP == anchor) {
verticalSplitter.setFirstComponent(component);
verticalSplitter.setFirstSize((int)(layeredPane.getHeight() * weight));
@@ -12,7 +12,6 @@ import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.WatermarkIcon;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.accessibility.AccessibleContext;
@@ -28,7 +27,7 @@ public class BaseLabel extends JLabel {
private Color myPassiveFg;
private boolean myBold;
public BaseLabel(@NotNull ToolWindowContentUi ui, boolean bold) {
public BaseLabel(ToolWindowContentUi ui, boolean bold) {
myUi = ui;
setOpaque(false);
myBold = bold;
@@ -34,7 +34,7 @@ final class ComboContentLayout extends ContentLayout {
@Override
public void layout() {
Rectangle bounds = myUi.getTabComponent().getBounds();
Rectangle bounds = myUi.getBounds();
Dimension idSize = isIdVisible() ? myIdLabel.getPreferredSize() : JBUI.emptySize();
int eachX = 0;
@@ -70,6 +70,9 @@ 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);
@@ -78,17 +81,17 @@ final class ComboContentLayout extends ContentLayout {
@Override
public void rebuild() {
myUi.getTabComponent().removeAll();
myUi.removeAll();
myUi.getTabComponent().add(myIdLabel);
myUi.add(myIdLabel);
ToolWindowContentUi.initMouseListeners(myIdLabel, myUi, true);
myUi.getTabComponent().add(myComboLabel);
myUi.add(myComboLabel);
ToolWindowContentUi.initMouseListeners(myComboLabel, myUi, false);
}
boolean isToDrawCombo() {
ContentManager manager = myUi.getContentManager();
ContentManager manager = myUi.contentManager;
return manager != null && manager.getContentCount() > 1;
}
@@ -3,7 +3,6 @@ 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;
@@ -45,7 +44,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.getContentManager());
ToolWindowContentUi.toggleContentPopup(myUi, myUi.contentManager);
}
super.keyPressed(e);
}
@@ -58,7 +57,7 @@ final class ContentComboLabel extends BaseLabel {
super.processMouseEvent(e);
if (UIUtil.isActionClick(e)) {
ToolWindowContentUi.toggleContentPopup(myUi, myUi.getContentManager());
ToolWindowContentUi.toggleContentPopup(myUi, myUi.contentManager);
}
}
@@ -110,8 +109,7 @@ final class ContentComboLabel extends BaseLabel {
@Nullable
@Override
public Content getContent() {
ContentManager contentManager = myUi.getContentManager();
return contentManager == null ? null : contentManager.getSelectedContent();
return myUi.contentManager == null ? null : myUi.contentManager.getSelectedContent();
}
@Override
@@ -147,7 +145,7 @@ final class ContentComboLabel extends BaseLabel {
@Override
public boolean doAccessibleAction(int index) {
if (index == 0) {
ToolWindowContentUi.toggleContentPopup(myUi, myUi.getContentManager());
ToolWindowContentUi.toggleContentPopup(myUi, myUi.contentManager);
return true;
}
else {
@@ -13,6 +13,8 @@ import javax.swing.*;
import java.awt.*;
abstract class ContentLayout {
static final int TAB_ARC = 2;
ToolWindowContentUi myUi;
BaseLabel myIdLabel;
@@ -28,6 +30,8 @@ abstract class ContentLayout {
public abstract void paintComponent(Graphics g);
public abstract void paintChildren(Graphics g);
public abstract void update();
public abstract void rebuild();
@@ -50,7 +54,7 @@ abstract class ContentLayout {
}
private String getTitleSuffix() {
ContentManager manager = myUi.getContentManager();
ContentManager manager = myUi.contentManager;
switch (manager == null ? 0 : manager.getContentCount()) {
case 0:
return null;
@@ -23,6 +23,7 @@ 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;
@@ -104,6 +105,7 @@ 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);
@@ -116,6 +118,7 @@ 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() {
@@ -127,12 +130,15 @@ class ContentTabLabel extends BaseLabel {
private final BaseButtonBehavior behavior = new BaseButtonBehavior(this) {
@Override
protected void execute(@NotNull MouseEvent e) {
for (AdditionalIcon icon : myAdditionalIcons) {
if (mouseOverIcon(icon)) {
icon.getAction().run();
return;
}
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;
}
selectContent();
@@ -352,10 +358,10 @@ class ContentTabLabel extends BaseLabel {
@NotNull
private ContentManager getContentManager() {
return myUi.getContentManager();
return myUi.myWindow.getContentManager();
}
@NotNull
@Nullable
@Override
public Content getContent() {
return myContent;
@@ -39,10 +39,10 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
List<AnAction> myDoubleClickActions = new ArrayList<>();
TabContentLayout(@NotNull ToolWindowContentUi ui) {
TabContentLayout(ToolWindowContentUi ui) {
super(ui);
new BaseButtonBehavior(myUi.getTabComponent()) {
new BaseButtonBehavior(myUi) {
@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.getContentManager();
ContentManager contentManager = myUi.contentManager;
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.getTabComponent(), new Point(rect.x, rect.y + rect.height));
RelativePoint point = new RelativePoint(myUi, new Point(rect.x, rect.y + rect.height));
JBPopupFactory.getInstance().createListPopup(step).show(point);
}
@Override
public void layout() {
Rectangle bounds = myUi.getTabComponent().getBounds();
ContentManager manager = myUi.getContentManager();
Rectangle bounds = myUi.getBounds();
ContentManager manager = myUi.contentManager;
LayoutData data = new LayoutData(myUi);
data.eachX = TAB_LAYOUT_START;
@@ -137,6 +137,7 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
}
}
if (data.fullLayout) {
for (ContentTabLabel eachTab : myTabs) {
final Dimension eachSize = eachTab.getPreferredSize();
@@ -199,7 +200,8 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
data.moreRect = null;
}
Rectangle moreRect = data.moreRect == null ? null : new Rectangle(data.eachX, 0, /*getMoreToolbarWidth()*/16+MORE_ICON_BORDER, bounds.height);
final 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) {
@@ -218,7 +220,7 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
}
}
ContentManager contentManager = myUi.getContentManager();
ContentManager contentManager = myUi.contentManager;
Content selected = contentManager.getSelectedContent();
if (selected == null && contentManager.getContents().length > 0) {
selected = contentManager.getContents()[0];
@@ -235,16 +237,14 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
}
boolean isToDrawTabs() {
int size = myTabs.size();
if (size > 1) {
return true;
}
else if (size == 1) {
return !StringUtil.isEmpty(myTabs.get(0).getContent().getToolwindowTitle());
}
else {
if(myTabs.size() > 1) return true;
if(myTabs.size() == 1) {
String title = myTabs.get(0).getContent().getToolwindowTitle();
return !StringUtil.isEmpty(title);
}
return false;
}
}
static class LayoutData {
@@ -263,12 +263,12 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
public int contentCount;
LayoutData(ToolWindowContentUi ui) {
layoutSize = ui.getTabComponent().getSize();
contentCount = ui.getContentManager().getContentCount();
layoutSize = ui.getSize();
contentCount = ui.contentManager.getContentCount();
}
}
private final JBTabPainter tabPainter = JBTabPainter.getTOOL_WINDOW();
private JBTabPainter tabPainter = JBTabPainter.getTOOL_WINDOW();
@Override
public void paintComponent(Graphics g) {
@@ -292,6 +292,11 @@ 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) {
@@ -303,13 +308,13 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
@Override
public void rebuild() {
myUi.getTabComponent().removeAll();
myUi.removeAll();
myUi.getTabComponent().add(myIdLabel);
myUi.add(myIdLabel);
ToolWindowContentUi.initMouseListeners(myIdLabel, myUi, true);
for (ContentTabLabel each : myTabs) {
myUi.getTabComponent().add(each);
myUi.add(each);
ToolWindowContentUi.initMouseListeners(each, myUi, false);
}
}
@@ -354,7 +359,7 @@ final class TabContentLayout extends ContentLayout implements MorePopupAware {
@Override
public void showContentPopup(ListPopup listPopup) {
Content selected = myUi.getContentManager().getSelectedContent();
Content selected = myUi.contentManager.getSelectedContent();
if (selected != null) {
ContentTabLabel tab = myContent2Tabs.get(selected);
listPopup.showUnderneathOf(tab);
@@ -8,6 +8,7 @@ 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;
@@ -17,7 +18,8 @@ import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public final class TabbedContentTabLabel extends ContentTabLabel {
public class TabbedContentTabLabel extends ContentTabLabel {
private final TabbedContent myContent;
private Reference<JBPopup> myPopupReference = null;
@@ -78,7 +80,7 @@ public final class TabbedContentTabLabel extends ContentTabLabel {
return hasMultipleTabs();
}
@NotNull
@Nullable
@Override
public Runnable getAction() {
return () -> selectContent();
@@ -97,7 +99,7 @@ public final class TabbedContentTabLabel extends ContentTabLabel {
}
}
@NotNull
@Nullable
@Override
public TabbedContent getContent() {
return myContent;
@@ -13,6 +13,7 @@ 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;
@@ -23,11 +24,10 @@ 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;
@@ -43,48 +43,73 @@ 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 implements ContentUI, DataProvider {
public final class ToolWindowContentUi extends JPanel implements ContentUI, DataProvider, UISettingsListener {
// 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";
private ContentManager contentManager;
ContentManager contentManager;
public ContentManager getContentManager() {
return contentManager;
}
final JPanel myContent = new JPanel(new BorderLayout());
ToolWindowImpl myWindow;
private final JPanel myContent = new JPanel(new BorderLayout());
final ToolWindowImpl myWindow;
TabbedContentAction.CloseAllAction myCloseAllAction;
TabbedContentAction.MyNextTabAction myNextTabAction;
TabbedContentAction.MyPreviousTabAction myPreviousTabAction;
private TabbedContentAction.CloseAllAction myCloseAllAction;
private TabbedContentAction.MyNextTabAction myNextTabAction;
private TabbedContentAction.MyPreviousTabAction myPreviousTabAction;
ShowContentAction myShowContent;
private ShowContentAction myShowContent;
TabContentLayout myTabsLayout = new TabContentLayout(this);
ContentLayout myComboLayout = new ComboContentLayout(this);
private final TabContentLayout myTabsLayout;
private ContentLayout myComboLayout;
private ToolWindowContentUiType myType;
private ToolWindowContentUiType myType = ToolWindowContentUiType.TABBED;
public Predicate<Point> isResizableArea = p -> true;
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);
public ToolWindowContentUi(@NotNull ToolWindowImpl window) {
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)
UIUtil.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
public String getToolWindowId() {
return myWindow.getId();
}
@Override
public void uiSettingsChanged(@NotNull UISettings uiSettings) {
revalidate();
repaint();
}
private boolean isResizeable() {
@@ -132,15 +157,7 @@ public final class ToolWindowContentUi implements ContentUI, DataProvider {
@NotNull
private ContentLayout getCurrentLayout() {
if (myType == ToolWindowContentUiType.TABBED) {
return myTabsLayout;
}
else {
if (myComboLayout == null) {
myComboLayout = new ComboContentLayout(this);
}
return myComboLayout;
}
return myType == ToolWindowContentUiType.TABBED ? myTabsLayout : myComboLayout;
}
@Override
@@ -148,6 +165,10 @@ public final class ToolWindowContentUi implements ContentUI, DataProvider {
return myContent;
}
public JComponent getTabComponent() {
return this;
}
@Override
public void setManager(@NotNull ContentManager manager) {
if (contentManager != null) {
@@ -192,7 +213,7 @@ public final class ToolWindowContentUi implements ContentUI, DataProvider {
}
});
initMouseListeners(tabComponent, this, true);
initMouseListeners(this, this, true);
rebuild();
@@ -227,19 +248,57 @@ public final class ToolWindowContentUi implements ContentUI, DataProvider {
getCurrentLayout().rebuild();
getCurrentLayout().update();
tabComponent.revalidate();
tabComponent.repaint();
revalidate();
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();
tabComponent.revalidate();
tabComponent.repaint();
revalidate();
repaint();
}
@Override
@@ -303,9 +362,7 @@ public final class ToolWindowContentUi implements ContentUI, DataProvider {
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();
@@ -570,8 +627,7 @@ public final class ToolWindowContentUi implements ContentUI, DataProvider {
}
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;
}
@@ -628,51 +684,4 @@ public final class ToolWindowContentUi implements ContentUI, DataProvider {
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;
}
}
}
@@ -153,7 +153,8 @@ public class ContentImpl extends UserDataHolderBase implements Content {
@Override
public String getToolwindowTitle() {
return myToolwindowTitle == null ? myDisplayName : myToolwindowTitle;
if (myToolwindowTitle != null) return myToolwindowTitle;
return myDisplayName;
}
@Override
@@ -171,6 +172,11 @@ public class ContentImpl extends UserDataHolderBase implements Content {
myShouldDisposeContent = value;
}
@Override
public boolean shouldDisposeContent() {
return myShouldDisposeContent;
}
@Override
public String getDescription() {
return myDescription;
@@ -168,7 +168,7 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene
@Override
public boolean removeContent(@NotNull Content content, boolean dispose) {
boolean wasFocused = UIUtil.isFocusAncestor(content.getComponent());
boolean wasFocused = content.getComponent() != null && UIUtil.isFocusAncestor(content.getComponent());
return removeContent(content, dispose, wasFocused, false).isDone();
}
@@ -2642,6 +2642,7 @@ public final class UIUtil {
return result;
});
public static void scrollListToVisibleIfNeeded(@NotNull final JList<?> list) {
SwingUtilities.invokeLater(() -> {
final int selectedIndex = list.getSelectedIndex();
@@ -161,9 +161,11 @@ 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));
@@ -348,16 +350,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()) {
return;
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);
}
TerminalTabState state = new TerminalTabState();
if (fileToOpen != null) {
state.myWorkingDirectory = fileToOpen.getPath();
}
createNewSession(myTerminalRunner, state);
window.activate(null);
}
@Nullable