mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-229505 Focus is not returned to Editor from Tool window in Float or Window view mode by Esc button
GitOrigin-RevId: d5aee42851410aee608387cd43edb129d1e3b2e8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
53c9d5b93f
commit
8a2dc52e4b
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 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-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.
|
||||
|
||||
/*
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -23,12 +23,13 @@ import com.intellij.xdebugger.impl.actions.XDebuggerActions;
|
||||
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
|
||||
import com.sun.jdi.VMDisconnectedException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public abstract class DebuggerTreePanel extends UpdatableDebuggerView implements DataProvider, Disposable {
|
||||
public static final DataKey<DebuggerTreePanel> DATA_KEY = DataKey.create("DebuggerPanel");
|
||||
|
||||
|
||||
private final SingleAlarm myRebuildAlarm = new SingleAlarm(() -> {
|
||||
try {
|
||||
final DebuggerContextImpl context = getContext();
|
||||
@@ -59,6 +60,12 @@ public abstract class DebuggerTreePanel extends UpdatableDebuggerView implements
|
||||
myTree.addMouseListener(popupHandler);
|
||||
|
||||
setFocusTraversalPolicy(new IdeFocusTraversalPolicy() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDefaultComponent(Container focusCycleRoot) {
|
||||
return myTree;
|
||||
|
||||
@@ -1009,6 +1009,12 @@ public abstract class DiffRequestProcessor implements Disposable {
|
||||
if (component == null) return null;
|
||||
return IdeFocusTraversalPolicy.getPreferredFocusedComponent(component, this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyDiffContext extends DiffContextEx {
|
||||
|
||||
@@ -546,6 +546,12 @@ public abstract class MergeRequestProcessor implements Disposable {
|
||||
if (component == null) return null;
|
||||
return IdeFocusTraversalPolicy.getPreferredFocusedComponent(component, this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyDiffContext extends MergeContextEx {
|
||||
|
||||
@@ -10,7 +10,7 @@ import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.ExpirableRunnable;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.ui.ComponentUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -166,18 +166,15 @@ public abstract class IdeFocusManager implements FocusRequestor {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static IdeFocusManager findInstanceByComponent(@NotNull Component c) {
|
||||
final IdeFocusManager instance = findByComponent(c);
|
||||
return instance != null ? instance : findInstanceByContext(null);
|
||||
public static IdeFocusManager findInstanceByComponent(@NotNull Component component) {
|
||||
IdeFocusManager instance = findByComponent(component);
|
||||
return instance == null ? findInstanceByContext(null) : instance;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static IdeFocusManager findByComponent(Component c) {
|
||||
final Component parent = UIUtil.findUltimateParent(c);
|
||||
if (parent instanceof IdeFrame) {
|
||||
return getInstanceSafe(((IdeFrame)parent).getProject());
|
||||
}
|
||||
return null;
|
||||
private static IdeFocusManager findByComponent(@NotNull Component component) {
|
||||
Component parent = ComponentUtil.findUltimateParent(component);
|
||||
return parent instanceof IdeFrame ? getInstanceSafe(((IdeFrame)parent).getProject()) : null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,19 +18,6 @@ abstract class ToolWindowManager {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): ToolWindowManager = project.getService(ToolWindowManager::class.java)
|
||||
|
||||
@JvmStatic
|
||||
fun getActiveToolWindow(): ToolWindow? {
|
||||
val frame = IdeFocusManager.getGlobalInstance().lastFocusedFrame
|
||||
val project = frame?.project
|
||||
if (project == null || project.isDisposed || project.isDefault) {
|
||||
return null
|
||||
}
|
||||
|
||||
val toolWindowManager = getInstance(project)
|
||||
val activeId = toolWindowManager.activeToolWindowId
|
||||
return activeId?.let { toolWindowManager.getToolWindow(it) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getActiveId(): String? {
|
||||
val project = IdeFocusManager.getGlobalInstance().lastFocusedFrame?.project ?: return null
|
||||
@@ -112,8 +99,6 @@ abstract class ToolWindowManager {
|
||||
@Deprecated("Use ToolWindowFactory and toolWindow extension point")
|
||||
abstract fun unregisterToolWindow(id: String)
|
||||
|
||||
/**
|
||||
*/
|
||||
abstract fun activateEditorComponent()
|
||||
|
||||
/**
|
||||
|
||||
+21
-11
@@ -557,6 +557,12 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
|
||||
}
|
||||
return IdeFocusTraversalPolicy.getPreferredFocusedComponent(EditorsSplitters.this, this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return myManager.getProject();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -964,16 +970,17 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static EditorsSplitters getSplittersToFocus() {
|
||||
private static EditorsSplitters getSplittersToFocus(@Nullable Project project) {
|
||||
Window activeWindow = WindowManagerEx.getInstanceEx().getMostRecentFocusedWindow();
|
||||
|
||||
if (activeWindow instanceof FloatingDecorator) {
|
||||
IdeFocusManager ideFocusManager = IdeFocusManager.findInstanceByComponent(activeWindow);
|
||||
IdeFrame lastFocusedFrame = ideFocusManager.getLastFocusedFrame();
|
||||
IdeFrame lastFocusedFrame = IdeFocusManager.findInstanceByComponent(activeWindow).getLastFocusedFrame();
|
||||
JComponent frameComponent = lastFocusedFrame != null ? lastFocusedFrame.getComponent() : null;
|
||||
Window lastFocusedWindow = frameComponent != null ? SwingUtilities.getWindowAncestor(frameComponent) : null;
|
||||
Window lastFocusedWindow = frameComponent == null ? null : SwingUtilities.getWindowAncestor(frameComponent);
|
||||
activeWindow = ObjectUtils.notNull(lastFocusedWindow, activeWindow);
|
||||
Project project = lastFocusedFrame == null ? null : lastFocusedFrame.getProject();
|
||||
if (project == null) {
|
||||
project = lastFocusedFrame == null ? null : lastFocusedFrame.getProject();
|
||||
}
|
||||
FileEditorManagerEx fileEditorManager = project == null || project.isDisposed() ? null : FileEditorManagerEx.getInstanceEx(project);
|
||||
if (fileEditorManager == null) {
|
||||
return null;
|
||||
@@ -983,7 +990,9 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
|
||||
}
|
||||
|
||||
if (activeWindow instanceof IdeFrame.Child) {
|
||||
Project project = ((IdeFrame.Child)activeWindow).getProject();
|
||||
if (project == null) {
|
||||
project = ((IdeFrame.Child)activeWindow).getProject();
|
||||
}
|
||||
return getSplittersForProject(WindowManager.getInstance().getFrame(project), project);
|
||||
}
|
||||
|
||||
@@ -1006,8 +1015,8 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JComponent findDefaultComponentInSplitters() {
|
||||
EditorsSplitters splittersToFocus = getSplittersToFocus();
|
||||
public static JComponent findDefaultComponentInSplitters(@Nullable Project project) {
|
||||
EditorsSplitters splittersToFocus = getSplittersToFocus(project);
|
||||
if (splittersToFocus == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -1023,10 +1032,11 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean focusDefaultComponentInSplittersIfPresent() {
|
||||
JComponent defaultFocusedComponentInEditor = findDefaultComponentInSplitters();
|
||||
public static boolean focusDefaultComponentInSplittersIfPresent(@NotNull Project project) {
|
||||
JComponent defaultFocusedComponentInEditor = findDefaultComponentInSplitters(project);
|
||||
if (defaultFocusedComponentInEditor != null) {
|
||||
defaultFocusedComponentInEditor.requestFocusInWindow();
|
||||
// not requestFocus because if floating or windowed tool window is deactivated (or, ESC pressed to focus editor), then we should focus our window
|
||||
defaultFocusedComponentInEditor.requestFocus();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
+19
-21
@@ -54,7 +54,6 @@ import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileMoveEvent;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.openapi.wm.ex.StatusBarEx;
|
||||
import com.intellij.reference.SoftReference;
|
||||
@@ -902,7 +901,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis
|
||||
Window windowAncestor = SwingUtilities.getWindowAncestor(window.myPanel);
|
||||
if (windowAncestor != null &&
|
||||
windowAncestor.equals(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow())) {
|
||||
ToolWindowManager.getInstance(myProject).activateEditorComponent();
|
||||
EditorsSplitters.focusDefaultComponentInSplittersIfPresent(myProject);
|
||||
IdeFocusManager.getInstance(myProject).toFront(window.getOwner());
|
||||
}
|
||||
}
|
||||
@@ -1458,23 +1457,21 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis
|
||||
return;
|
||||
}
|
||||
|
||||
ToolWindowManager.getInstance(myProject).invokeLater(() -> {
|
||||
if (!myProject.isDisposed()) {
|
||||
CommandProcessor.getInstance().executeCommand(myProject, () -> {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
long currentTime = System.nanoTime();
|
||||
Long startTime = myProject.getUserData(ProjectImpl.CREATION_TIME);
|
||||
if (startTime != null) {
|
||||
long time = (currentTime - startTime.longValue()) / 1000000;
|
||||
LifecycleUsageTriggerCollector.onProjectOpenFinished(myProject, time);
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
CommandProcessor.getInstance().executeCommand(myProject, () -> {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
long currentTime = System.nanoTime();
|
||||
Long startTime = myProject.getUserData(ProjectImpl.CREATION_TIME);
|
||||
if (startTime != null) {
|
||||
long time = (currentTime - startTime.longValue()) / 1000000;
|
||||
LifecycleUsageTriggerCollector.onProjectOpenFinished(myProject, time);
|
||||
|
||||
LOG.info("Project opening took " + time + " ms");
|
||||
}
|
||||
}, myProject.getDisposed());
|
||||
// group 1
|
||||
}, "", null);
|
||||
}
|
||||
});
|
||||
LOG.info("Project opening took " + time + " ms");
|
||||
}
|
||||
}, myProject.getDisposed());
|
||||
// group 1
|
||||
}, "", null);
|
||||
}, myProject.getDisposed());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1602,9 +1599,10 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis
|
||||
|
||||
final FileEditor selectedEditor = editor.getSelectedEditor();
|
||||
for (int i = editors.length - 1; i >= 0; i--) {
|
||||
final FileEditor editor1 = editors[i];
|
||||
final FileEditorProvider provider = providers[i];
|
||||
if (!editor.equals(selectedEditor)) { // we already notified the myEditor (when fire event)
|
||||
FileEditor editor1 = editors[i];
|
||||
FileEditorProvider provider = providers[i];
|
||||
if (!editor.equals(selectedEditor)) {
|
||||
// we already notified the myEditor (when fire event)
|
||||
if (selectedEditor.equals(editor1)) {
|
||||
editor1.deselectNotify();
|
||||
}
|
||||
|
||||
+17
-13
@@ -4,6 +4,7 @@ package com.intellij.openapi.wm.ex;
|
||||
import com.intellij.openapi.editor.impl.EditorComponentImpl;
|
||||
import com.intellij.openapi.fileEditor.impl.EditorWindowHolder;
|
||||
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -30,30 +31,34 @@ public class IdeFocusTraversalPolicy extends LayoutFocusTraversalPolicy {
|
||||
@Override
|
||||
public Component getComponentAfter(Container aContainer, Component aComponent) {
|
||||
Component after = super.getComponentAfter(aContainer, aComponent);
|
||||
Component defaultFocusableComponent = findDefaultFocusedComponentIfSplitters(after);
|
||||
if (defaultFocusableComponent != null) return defaultFocusableComponent;
|
||||
if (after != null) return after.isFocusable() ? after : findFocusableComponentIn((JComponent)after, null);
|
||||
return findFocusableComponentIn(aContainer, aComponent);
|
||||
return doFind(aContainer, aComponent, after);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponentBefore(Container aContainer, Component aComponent) {
|
||||
Component before = super.getComponentBefore(aContainer, aComponent);
|
||||
Component defaultFocusableComponent = findDefaultFocusedComponentIfSplitters(before);
|
||||
if (defaultFocusableComponent != null) return defaultFocusableComponent;
|
||||
if (before != null) return before.isFocusable() ? before : findFocusableComponentIn((JComponent)before, null);
|
||||
return findFocusableComponentIn(aContainer, aComponent);
|
||||
return doFind(aContainer, aComponent, before);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Component findDefaultFocusedComponentIfSplitters(Component componentToSearchInto) {
|
||||
if (componentToSearchInto instanceof EditorsSplitters) {
|
||||
JComponent defaultFocusableComponent = EditorsSplitters.findDefaultComponentInSplitters();
|
||||
protected Project getProject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Component doFind(Container aContainer, Component aComponent, @Nullable Component siblingComponent) {
|
||||
if (siblingComponent == null) {
|
||||
return findFocusableComponentIn(aContainer, aComponent);
|
||||
}
|
||||
|
||||
if (siblingComponent instanceof EditorsSplitters) {
|
||||
Component defaultFocusableComponent = EditorsSplitters.findDefaultComponentInSplitters(getProject());
|
||||
if (defaultFocusableComponent != null) {
|
||||
return defaultFocusableComponent;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
return siblingComponent.isFocusable() ? siblingComponent : findFocusableComponentIn((JComponent)siblingComponent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +146,6 @@ public class IdeFocusTraversalPolicy extends LayoutFocusTraversalPolicy {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO[anton,vova] implement Policy in Editor component instead */
|
||||
if (component instanceof EditorComponentImpl || component instanceof EditorWindowHolder) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ import java.beans.PropertyChangeListener
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.function.Predicate
|
||||
import javax.swing.*
|
||||
import javax.swing.event.HyperlinkEvent
|
||||
import javax.swing.event.HyperlinkListener
|
||||
@@ -167,18 +166,14 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
|
||||
}
|
||||
})
|
||||
|
||||
Windows.ToolWindowProvider(Windows.Signal(Predicate { event ->
|
||||
event.id == FocusEvent.FOCUS_LOST || event.id == FocusEvent.FOCUS_GAINED || event.id == MouseEvent.MOUSE_PRESSED || event.id == KeyEvent.KEY_PRESSED
|
||||
}))
|
||||
.withEscAction()
|
||||
.handleFocusLostOnPinned { toolWindowId ->
|
||||
addFocusLostListener(pinnedWindowFocusLostHandler = { toolWindowId ->
|
||||
process { manager ->
|
||||
val entry = manager.idToEntry.get(toolWindowId) ?: return@process
|
||||
val info = manager.layout.getInfo(toolWindowId) ?: return@process
|
||||
manager.doDeactivateToolWindow(info, entry)
|
||||
}
|
||||
}
|
||||
.bind(ApplicationManager.getApplication())
|
||||
)
|
||||
|
||||
connection.subscribe(KeymapManagerListener.TOPIC, object : KeymapManagerListener {
|
||||
override fun activeKeymapChanged(keymap: Keymap?) {
|
||||
@@ -500,8 +495,9 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
|
||||
}
|
||||
|
||||
override fun activateEditorComponent() {
|
||||
if (!EditorsSplitters.focusDefaultComponentInSplittersIfPresent()) {
|
||||
frame?.rootPane?.requestFocusInWindow()
|
||||
if (!EditorsSplitters.focusDefaultComponentInSplittersIfPresent(project)) {
|
||||
// see note about requestFocus in focusDefaultComponentInSplittersIfPresent
|
||||
frame?.rootPane?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1907,4 +1903,52 @@ private const val LAYOUT_TO_RESTORE = "layout-to-restore"
|
||||
|
||||
internal enum class ToolWindowProperty {
|
||||
TITLE, ICON, AVAILABLE, STRIPE_TITLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun addFocusLostListener(pinnedWindowFocusLostHandler: (String) -> Unit) {
|
||||
val listener = AWTEventListener { event ->
|
||||
val eventId = event.id
|
||||
if (event !is FocusEvent || !(eventId == FocusEvent.FOCUS_LOST || eventId == FocusEvent.FOCUS_LOST || eventId == FocusEvent.FOCUS_GAINED)) {
|
||||
return@AWTEventListener
|
||||
}
|
||||
|
||||
val id = ToolWindowManager.getActiveId() ?: return@AWTEventListener
|
||||
|
||||
// let's check that it is a toolwindow who loses the focus
|
||||
if (event.oppositeComponent != null && isInActiveToolWindow(event.source) && !isInActiveToolWindow(event.oppositeComponent)) {
|
||||
// a toolwindow lost focus
|
||||
val activeToolWindow = getActiveToolWindow()
|
||||
val focusGoesToPopup = JBPopupFactory.getInstance().getParentBalloonFor(event.oppositeComponent) != null
|
||||
if (!event.isTemporary &&
|
||||
!focusGoesToPopup && activeToolWindow != null &&
|
||||
(activeToolWindow.isAutoHide || activeToolWindow.type == ToolWindowType.SLIDING)) {
|
||||
pinnedWindowFocusLostHandler(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
Toolkit.getDefaultToolkit().addAWTEventListener(listener, AWTEvent.FOCUS_EVENT_MASK)
|
||||
}
|
||||
|
||||
private fun isInActiveToolWindow(component: Any?): Boolean {
|
||||
val activeToolWindow = getActiveToolWindow() ?: return false
|
||||
var source = if (component is JComponent) component else null
|
||||
val activeToolWindowComponent = activeToolWindow.getComponentIfInitialized()
|
||||
if (activeToolWindowComponent != null) {
|
||||
while (source != null && source !== activeToolWindowComponent) {
|
||||
source = if (source.parent != null && source.parent is JComponent) source.parent as JComponent else null
|
||||
}
|
||||
}
|
||||
return source != null
|
||||
}
|
||||
|
||||
private fun getActiveToolWindow(): ToolWindowImpl? {
|
||||
val frame = IdeFocusManager.getGlobalInstance().lastFocusedFrame
|
||||
val project = frame?.project
|
||||
if (project == null || project.isDisposed || project.isDefault) {
|
||||
return null
|
||||
}
|
||||
|
||||
val toolWindowManager = ToolWindowManager.getInstance(project)
|
||||
val activeId = toolWindowManager.activeToolWindowId
|
||||
return activeId?.let { toolWindowManager.getToolWindow(it) as ToolWindowImpl }
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
// 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.
|
||||
package com.intellij.openapi.wm.impl;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.openapi.wm.ToolWindowType;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.AWTEventListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class Windows {
|
||||
public final static class ToolWindowProvider {
|
||||
private final Signal mySignal;
|
||||
|
||||
private Consumer<? super String> pinnedWindowFocusLostHandler;
|
||||
|
||||
public ToolWindowProvider(@NotNull Signal signal) {
|
||||
mySignal = signal;
|
||||
}
|
||||
|
||||
public ToolWindowProvider handleFocusLostOnPinned(@NotNull Consumer<? super String> value) {
|
||||
pinnedWindowFocusLostHandler = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolWindowProvider withEscAction() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public static boolean isInActiveToolWindow(@Nullable Object component) {
|
||||
ToolWindowImpl activeToolWindow = (ToolWindowImpl)ToolWindowManager.getActiveToolWindow();
|
||||
if (activeToolWindow == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JComponent source = component instanceof JComponent ? (JComponent)component : null;
|
||||
JComponent activeToolWindowComponent = activeToolWindow.getComponentIfInitialized();
|
||||
if (activeToolWindowComponent != null) {
|
||||
while (source != null && source != activeToolWindowComponent) {
|
||||
source = ((source.getParent() != null) && (source.getParent() instanceof JComponent)) ? ((JComponent)source.getParent()) : null;
|
||||
}
|
||||
}
|
||||
return source != null;
|
||||
}
|
||||
|
||||
public void bind(@NotNull Disposable parentDisposable) {
|
||||
AWTEventListener listener = new AWTEventListener() {
|
||||
@Override
|
||||
public void eventDispatched(AWTEvent event) {
|
||||
if (!mySignal.isAppropriatePredicate.test(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find toolwindows from the event
|
||||
// pass the toolwindow to the appropriate consumers
|
||||
|
||||
// FocusEvent
|
||||
// for now we are interested in focus lost events
|
||||
String id = ToolWindowManager.getActiveId();
|
||||
if (event.getID() != FocusEvent.FOCUS_LOST) {
|
||||
return;
|
||||
}
|
||||
// let's check that it is a toolwindow who loses the focus
|
||||
|
||||
FocusEvent focusEvent = (FocusEvent)event;
|
||||
|
||||
if (isInActiveToolWindow(focusEvent.getSource())
|
||||
&& !isInActiveToolWindow(focusEvent.getOppositeComponent())
|
||||
&& focusEvent.getOppositeComponent() != null) {
|
||||
//System.err.println("Tool window is loosing focus: " + ToolWindowManager.getActiveToolWindow().getStripeTitle());
|
||||
|
||||
// A toolwindow lost focus
|
||||
ToolWindow activeToolWindow = ToolWindowManager.getActiveToolWindow();
|
||||
boolean focusGoesToPopup = JBPopupFactory.getInstance().getParentBalloonFor(focusEvent.getOppositeComponent()) != null;
|
||||
if (!focusEvent.isTemporary() &&
|
||||
!focusGoesToPopup &&
|
||||
activeToolWindow != null &&
|
||||
(activeToolWindow.isAutoHide() || activeToolWindow.getType() == ToolWindowType.SLIDING)) {
|
||||
pinnedWindowFocusLostHandler.accept(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Toolkit.getDefaultToolkit().addAWTEventListener(listener, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK);
|
||||
Disposer.register(parentDisposable, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
Toolkit.getDefaultToolkit().removeAWTEventListener(listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static final class Signal {
|
||||
private final Predicate<? super AWTEvent> isAppropriatePredicate;
|
||||
|
||||
Signal(Predicate<? super AWTEvent> isAppropriatePredicate) {
|
||||
this.isAppropriatePredicate = isAppropriatePredicate;
|
||||
}
|
||||
|
||||
public boolean appropriate(AWTEvent event) {
|
||||
return isAppropriatePredicate.test(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package com.intellij.ui;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
|
||||
Reference in New Issue
Block a user