IDEA-167805 Keyboard navigation in debug tool window

GitOrigin-RevId: 1b07992e854cfa45714154c4cf8cca109d7c36d7
This commit is contained in:
Viktor Shatrov
2019-09-04 09:32:01 +00:00
committed by intellij-monorepo-bot
parent 6f5dde8f50
commit 1437c1dcd3
7 changed files with 144 additions and 17 deletions
@@ -323,7 +323,7 @@ public class JavaDebugProcess extends XDebugProcess {
final ThreadsPanel panel = new ThreadsPanel(myJavaSession.getProject(), getDebuggerStateManager());
final Content threadsContent = ui.createContent(
DebuggerContentInfo.THREADS_CONTENT, panel, XDebuggerBundle.message("debugger.session.tab.threads.title"),
null, null);
null, panel.getDefaultFocusedComponent());
threadsContent.setCloseable(false);
ui.addContent(threadsContent, 0, PlaceInGrid.left, true);
ui.addListener(new ContentManagerAdapter() {
@@ -355,7 +355,7 @@ public class JavaDebugProcess extends XDebugProcess {
final Content memoryViewContent =
ui.createContent(MemoryViewManager.MEMORY_VIEW_CONTENT, classesFilteredView, "Memory",
null, null);
null, classesFilteredView.getDefaultFocusedComponent());
memoryViewContent.setCloseable(false);
memoryViewContent.setShouldDisposeContent(true);
@@ -387,7 +387,7 @@ public class JavaDebugProcess extends XDebugProcess {
DebugProcessImpl process = myJavaSession.getProcess();
OverheadView monitor = new OverheadView(process);
Content overheadContent = ui.createContent("OverheadMonitor", monitor, "Overhead", null, null);
Content overheadContent = ui.createContent("OverheadMonitor", monitor, "Overhead", null, monitor.getDefaultFocusedComponent());
monitor.setBouncer(() -> ui.setBouncing(overheadContent, true));
@@ -23,6 +23,7 @@ import com.intellij.util.Alarm;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
@@ -125,6 +126,10 @@ public class ThreadsPanel extends DebuggerTreePanel{
super.dispose();
}
public JComponent getDefaultFocusedComponent() {
return getThreadsTree();
}
private static void updateNodeLabels(DebuggerTreeNodeImpl from) {
Enumeration children = from.children();
try {
@@ -121,6 +121,11 @@ public class OverheadView extends BorderLayoutPanel implements Disposable, DataP
.map(XBreakpoint::getNavigatable).nonNull();
}
public JComponent getDefaultFocusedComponent() {
return myTable;
}
@Nullable
@Override
public Object getData(@NotNull String dataId) {
@@ -2,6 +2,8 @@
package com.intellij.execution.ui.layout.impl;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunContentManager;
import com.intellij.execution.ui.RunnerLayoutUi;
import com.intellij.execution.ui.layout.*;
import com.intellij.execution.ui.layout.actions.CloseViewAction;
@@ -10,11 +12,17 @@ import com.intellij.execution.ui.layout.actions.RestoreViewAction;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.actions.CloseAction;
import com.intellij.ide.actions.ShowContentAction;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.AbstractPainter;
import com.intellij.openapi.ui.ShadowAction;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.ActiveRunnable;
import com.intellij.openapi.util.Disposer;
@@ -25,6 +33,7 @@ import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.IdeGlassPaneUtil;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.impl.ToolWindowsPane;
import com.intellij.openapi.wm.impl.content.SelectContentStep;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
@@ -41,6 +50,7 @@ import com.intellij.ui.tabs.JBTabs;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsListener;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.NotNullFunction;
import com.intellij.util.containers.ContainerUtil;
@@ -67,6 +77,8 @@ import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;
import static com.intellij.ui.tabs.JBTabsEx.NAVIGATION_ACTIONS_KEY;
public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Facade, ViewContextEx, PropertyChangeListener,
QuickActionProvider, DockContainer.Dialog {
public static final DataKey<RunnerContentUi> KEY = DataKey.create("DebuggerContentUI");
@@ -77,6 +89,8 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
@NonNls private static final String VIEW_POPUP = "Runner.View.Popup";
@NonNls static final String VIEW_TOOLBAR = "Runner.View.Toolbar";
private ShowDebugContentAction myShowDebugContentAction = null;
private ContentManager myManager;
private final RunnerLayout myLayoutSettings;
@@ -320,6 +334,11 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
DefaultActionGroup group = new DefaultActionGroup(VIEW_POPUP, original.isPopup());
if (myShowDebugContentAction == null) {
myShowDebugContentAction = new ShowDebugContentAction(this, myTabs.getComponent(), this);
}
group.add(myShowDebugContentAction);
final AnActionEvent event = new AnActionEvent(null, DataManager.getInstance().getDataContext(), place, new Presentation(),
ActionManager.getInstance(), 0);
final AnAction[] originalActions = original.getChildren(event);
@@ -585,6 +604,45 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
return myCurrentOverImg;
}
public void toggleContentPopup(JBTabs tabs) {
if (myOriginal != null) {
myOriginal.toggleContentPopup(tabs);
return;
}
List<Content> contents = getPopupContents();
final Content selectedContent = myManager.getSelectedContent();
final SelectContentStep step = new SelectContentStep(contents);
if (selectedContent != null) {
step.setDefaultOptionIndex(myManager.getIndexOfContent(selectedContent));
}
final ListPopup popup = JBPopupFactory.getInstance().createListPopup(step);
popup.showUnderneathOf(tabs.getTabLabel(tabs.getSelectedInfo()));
if (selectedContent instanceof TabbedContent) {
new Alarm(Alarm.ThreadToUse.SWING_THREAD, popup).addRequest(() -> popup.handleSelect(false), 50);
}
}
public List<Content> getPopupContents() {
if (myOriginal != null) return myOriginal.getPopupContents();
List<Content> contents = new ArrayList<>(Arrays.asList(myManager.getContents()));
myChildren.stream()
.flatMap(child -> Arrays.stream(child.myManager.getContents()))
.forEachOrdered(contents::add);
RunContentManager contentManager = RunContentManager.getInstance(myProject);
RunContentDescriptor selectedDescriptor = contentManager.getSelectedContent();
contentManager.getAllDescriptors().stream()
.filter(descriptor -> descriptor != selectedDescriptor)
.map(descriptor -> descriptor.getAttachedContent())
.forEachOrdered(contents::add);
return contents;
}
@NotNull
private static PlaceInGrid calcPlaceInGrid(Point point, Dimension size) {
// 1/3 (left) | (center/bottom) | 1/3 (right)
@@ -1889,6 +1947,34 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
}
public class ShowDebugContentAction extends AnAction implements DumbAware {
public static final String ACTION_ID = "ShowDebugContent";
private RunnerContentUi myContentUi;
@SuppressWarnings({"UnusedDeclaration"})
public ShowDebugContentAction() {
}
public ShowDebugContentAction(RunnerContentUi runner, JComponent component, @NotNull Disposable parentDisposable) {
myContentUi = runner;
AnAction original = ActionManager.getInstance().getAction(ShowContentAction.ACTION_ID);
new ShadowAction(this, original, component, parentDisposable);
ActionUtil.copyFrom(this, ShowContentAction.ACTION_ID);
}
@Override
public void update(@NotNull AnActionEvent e) {
e.getPresentation().setEnabledAndVisible(myContentUi != null && myContentUi.getPopupContents().size() > 1);
e.getPresentation().setText("Show List of Tabs");
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
myContentUi.toggleContentPopup(e.getData(NAVIGATION_ACTIONS_KEY));
}
}
private void fireContentOpened(@NotNull Content content) {
for (Listener each : myDockingListeners) {
each.contentAdded(content);
@@ -79,14 +79,17 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
@SuppressWarnings("Duplicates")
public Component getComponentAfter(Container aContainer, Component aComponent) {
Component comp;
if (aComponent == myFirstComponent) {
comp = findChildToFocus(myInnerComponent);
if (SwingUtilities.isDescendingFrom(aComponent, myFirstComponent)) {
Component next = nextVisible(myFirstComponent);
comp = (next != null) ? findChildToFocus(next) : aComponent;
}
else if (aComponent == myInnerComponent) {
comp = findChildToFocus(myLastComponent);
else if (SwingUtilities.isDescendingFrom(aComponent, myInnerComponent)) {
Component next = nextVisible(myInnerComponent);
comp = (next != null) ? findChildToFocus(next) : aComponent;
}
else {
comp = findChildToFocus(myFirstComponent);
Component next = nextVisible(myLastComponent);
comp = (next != null) ? findChildToFocus(next) : aComponent;
}
if (comp == aComponent) {
// if focus is stuck on the component let it go further
@@ -99,14 +102,17 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
@SuppressWarnings("Duplicates")
public Component getComponentBefore(Container aContainer, Component aComponent) {
Component comp;
if (aComponent == myInnerComponent) {
comp = findChildToFocus(myFirstComponent);
if (SwingUtilities.isDescendingFrom(aComponent, myInnerComponent)) {
Component prev = prevVisible(myInnerComponent);
comp = (prev != null) ? findChildToFocus(prev) : aComponent;
}
else if (aComponent == myLastComponent) {
comp = findChildToFocus(myInnerComponent);
else if (SwingUtilities.isDescendingFrom(aComponent, myLastComponent)) {
Component prev = prevVisible(myLastComponent);
comp = (prev != null) ? findChildToFocus(prev) : aComponent;
}
else {
comp = findChildToFocus(myFirstComponent);
Component prev = prevVisible(myFirstComponent);
comp = (prev != null) ? findChildToFocus(prev) : aComponent;
}
if (comp == aComponent) {
// if focus is stuck on the component let it go further
@@ -115,14 +121,33 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
return comp;
}
private Component nextVisible(Component comp) {
if (comp == myFirstComponent) return innerVisible() ? myInnerComponent : lastVisible() ? myLastComponent : null;
if (comp == myInnerComponent) return lastVisible() ? myLastComponent : firstVisible() ? myFirstComponent : null;
if (comp == myLastComponent) return firstVisible() ? myFirstComponent : innerVisible() ? myInnerComponent : null;
return null;
}
private Component prevVisible(Component comp) {
if (comp == myFirstComponent) return lastVisible() ? myLastComponent : innerVisible() ? myInnerComponent : null;
if (comp == myInnerComponent) return firstVisible() ? myFirstComponent : lastVisible() ? myLastComponent : null;
if (comp == myLastComponent) return innerVisible() ? myInnerComponent : firstVisible() ? myFirstComponent : null;
return null;
}
@Override
public Component getFirstComponent(Container aContainer) {
return findChildToFocus(myFirstComponent);
if (firstVisible()) return findChildToFocus(myFirstComponent);
Component next = nextVisible(myFirstComponent);
return next != null ? findChildToFocus(next) : null;
}
@Override
public Component getLastComponent(Container aContainer) {
return findChildToFocus(myLastComponent);
if (lastVisible()) return findChildToFocus(myLastComponent);
Component prev = prevVisible(myLastComponent);
return prev != null ? findChildToFocus(prev) : null;
}
private boolean myReentrantLock = false;
@@ -131,7 +156,9 @@ public class ThreeComponentsSplitter extends JPanel implements Disposable {
if (myReentrantLock) return null;
try {
myReentrantLock = true;
return findChildToFocus(myInnerComponent);
if (innerVisible()) return findChildToFocus(myInnerComponent);
Component next = nextVisible(myLastComponent);
return next != null ? findChildToFocus(next) : null;
} finally {
myReentrantLock = false;
}
@@ -433,7 +433,7 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene
mySelectionHistory.remove(content);
mySelectionHistory.add(0, content);
if (isSelected(content) && requestFocus) {
return requestFocus(content, forcedFocus);
return getFocusManager().requestFocus(getComponent(), true).doWhenProcessed(() -> requestFocus(content, forcedFocus));
}
if (!checkSelectionChangeShouldBeProcessed(content, implicit)) {
@@ -170,6 +170,10 @@ public abstract class ClassesFilteredViewBase extends BorderLayoutPanel implemen
addToCenter(scroll);
}
public JComponent getDefaultFocusedComponent() {
return myFilterTextField;
}
@NotNull
protected ClassesTable createClassesTable(MemoryViewManagerState memoryViewManagerState) {
return new ClassesTable(myProject,this, memoryViewManagerState.isShowWithDiffOnly,