IDEA-121775 XDebugger: merge Watches and Variables in one view - allow to switch... clion/146.687
authorEgor.Ushakov <egor.ushakov@jetbrains.com>
Fri, 18 Mar 2016 08:54:32 +0000 (11:54 +0300)
committerEgor.Ushakov <egor.ushakov@jetbrains.com>
Fri, 18 Mar 2016 09:00:09 +0000 (12:00 +0300)
platform/platform-resources-en/src/messages/XDebuggerBundle.properties
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java

index ed9eb2f0535a447628f48a600e9c6ded9db7b759..19e568e7a77ff4686ecf1cdc586aa92ecc9f2830 100644 (file)
@@ -109,6 +109,7 @@ stack.frame.loading.text=Loading\u2026
 invalid.frame=<invalid frame>
 xdebugger.drag.text.0.elements={0} elements
 xdebugger.drop.text.add.to.watches=Add to watches
+debugger.session.tab.show.watches.in.variables=Show watches in variables tab
 
 debugger.frames.not.available=Frames are not available
 debugger.threads.not.available=Threads are not available
index 8ce2f6ad15a65e9f830b5d6838f0cb4466d10a5d..3768cbe7fa92b39d2a2f4cbf28d8d305043be8a8 100644 (file)
@@ -17,6 +17,7 @@ package com.intellij.xdebugger.impl.frame;
 
 import com.intellij.debugger.ui.DebuggerContentInfo;
 import com.intellij.execution.ui.layout.impl.RunnerContentUi;
+import com.intellij.icons.AllIcons;
 import com.intellij.ide.DataManager;
 import com.intellij.ide.dnd.DnDEvent;
 import com.intellij.ide.dnd.DnDManager;
@@ -29,7 +30,6 @@ import com.intellij.openapi.ide.CopyPasteManager;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.util.EmptyRunnable;
 import com.intellij.openapi.util.SystemInfo;
-import com.intellij.openapi.util.registry.Registry;
 import com.intellij.ui.*;
 import com.intellij.ui.border.CustomLineBorder;
 import com.intellij.util.Alarm;
@@ -72,9 +72,11 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
 
   private final CompositeDisposable myDisposables = new CompositeDisposable();
   private boolean myRebuildNeeded;
+  private final boolean myWatchesInVariables;
 
-  public XWatchesViewImpl(@NotNull XDebugSessionImpl session) {
+  public XWatchesViewImpl(@NotNull XDebugSessionImpl session, boolean watchesInVariables) {
     super(session);
+    myWatchesInVariables = watchesInVariables;
 
     ActionManager actionManager = ActionManager.getInstance();
 
@@ -123,6 +125,22 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
       return e.getPresentation().isEnabled();
     });
     decorator.addExtraAction(AnActionButton.fromAction(copyAction));
+    decorator.addExtraAction(
+      new ToggleActionButton(XDebuggerBundle.message("debugger.session.tab.show.watches.in.variables"), AllIcons.Debugger.Watches) {
+        @Override
+        public boolean isSelected(AnActionEvent e) {
+          XDebugSessionTab tab = session.getSessionTab();
+          return tab == null || tab.isWatchesInVariables();
+        }
+
+        @Override
+        public void setSelected(AnActionEvent e, boolean state) {
+          XDebugSessionTab tab = session.getSessionTab();
+          if (tab != null) {
+            tab.setWatchesInVariables(!tab.isWatchesInVariables());
+          }
+        }
+      });
     decorator.setMoveUpAction(button -> {
       List<? extends WatchNode> nodes = XWatchesTreeActionBase.getSelectedNodes(getTree(), WatchNode.class);
       assert nodes.size() == 1;
@@ -151,7 +169,7 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
     decorator.setToolbarBorder(border);
     decorator.setPanelBorder(BorderFactory.createEmptyBorder());
     getPanel().removeAll();
-    if (Registry.is("debugger.watches.in.variables")) {
+    if (myWatchesInVariables) {
       decorator.setToolbarPosition(ActionToolbarPosition.LEFT);
     }
     else {
@@ -244,6 +262,7 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
   public void dispose() {
     Disposer.dispose(myDisposables);
     DnDManager.getInstance().unregisterTarget(this, getTree());
+    super.dispose();
   }
 
   private static boolean isAboveSelectedItem(MouseEvent event, XDebuggerTree watchTree) {
@@ -298,7 +317,7 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
 
   @Override
   public void processSessionEvent(@NotNull final SessionEvent event) {
-    if (Registry.is("debugger.watches.in.variables") ||
+    if (myWatchesInVariables ||
         getPanel().isShowing() ||
         ApplicationManager.getApplication().isUnitTestMode()) {
       myRebuildNeeded = false;
@@ -312,7 +331,7 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
 
   @Override
   protected XValueContainerNode createNewRootNode(@Nullable XStackFrame stackFrame) {
-    WatchesRootNode node = new WatchesRootNode(getTree(), this, getExpressions(), stackFrame);
+    WatchesRootNode node = new WatchesRootNode(getTree(), this, getExpressions(), stackFrame, myWatchesInVariables);
     myRootNode = node;
     getTree().setRoot(node, false);
     return node;
@@ -320,7 +339,7 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
 
   @Override
   protected void addEmptyMessage(XValueContainerNode root) {
-    if (Registry.is("debugger.watches.in.variables")) {
+    if (myWatchesInVariables) {
       super.addEmptyMessage(root);
     }
   }
index 7cd529a767b159f4ea2d995e813ca667629d741f..33c34fb0bf7f707ab8a91215636d58c91833f02e 100644 (file)
@@ -41,6 +41,7 @@ import com.intellij.ui.content.ContentManagerEvent;
 import com.intellij.ui.content.tabs.PinToolwindowTabAction;
 import com.intellij.util.SystemProperties;
 import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.hash.LinkedHashMap;
 import com.intellij.xdebugger.XDebugSession;
 import com.intellij.xdebugger.XDebuggerBundle;
 import com.intellij.xdebugger.impl.XDebugSessionImpl;
@@ -59,7 +60,8 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
   public static final DataKey<XDebugSessionTab> TAB_KEY = DataKey.create("XDebugSessionTab");
 
   private XWatchesViewImpl myWatchesView;
-  private final List<XDebugView> myViews = ContainerUtil.newArrayList();
+  private boolean myWatchesInVariables = Registry.is("debugger.watches.in.variables");
+  private final LinkedHashMap<String, XDebugView> myViews = new LinkedHashMap<>();
 
   @Nullable
   private XDebugSessionImpl mySession;
@@ -106,14 +108,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
     setSession(session, environment, icon);
 
     myUi.addContent(createFramesContent(), 0, PlaceInGrid.left, false);
-    myUi.addContent(createVariablesContent(session), 0, PlaceInGrid.center, false);
-    if (!Registry.is("debugger.watches.in.variables")) {
-      myUi.addContent(createWatchesContent(session), 0, PlaceInGrid.right, false);
-    }
-
-    for (XDebugView view : myViews) {
-      Disposer.register(myRunContentDescriptor, view);
-    }
+    addVariablesAndWatches(session);
 
     attachToSession(session);
 
@@ -135,6 +130,13 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
     rebuildViews();
   }
 
+  private void addVariablesAndWatches(@NotNull XDebugSessionImpl session) {
+    myUi.addContent(createVariablesContent(session), 0, PlaceInGrid.center, false);
+    if (!myWatchesInVariables) {
+      myUi.addContent(createWatchesContent(session), 0, PlaceInGrid.right, false);
+    }
+  }
+
   private void setSession(@NotNull XDebugSessionImpl session, @Nullable ExecutionEnvironment environment, @Nullable Icon icon) {
     myEnvironment = environment;
     mySession = session;
@@ -183,13 +185,13 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
 
   private Content createVariablesContent(@NotNull XDebugSessionImpl session) {
     XVariablesView variablesView;
-    if (Registry.is("debugger.watches.in.variables")) {
-      variablesView = myWatchesView = new XWatchesViewImpl(session);
+    if (myWatchesInVariables) {
+      variablesView = myWatchesView = new XWatchesViewImpl(session, myWatchesInVariables);
     }
     else {
       variablesView = new XVariablesView(session);
     }
-    myViews.add(variablesView);
+    registerView(DebuggerContentInfo.VARIABLES_CONTENT, variablesView);
     Content result = myUi.createContent(DebuggerContentInfo.VARIABLES_CONTENT, variablesView.getPanel(),
                                         XDebuggerBundle.message("debugger.session.tab.variables.title"),
                                         AllIcons.Debugger.Value, null);
@@ -201,8 +203,8 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
   }
 
   private Content createWatchesContent(@NotNull XDebugSessionImpl session) {
-    myWatchesView = new XWatchesViewImpl(session);
-    myViews.add(myWatchesView);
+    myWatchesView = new XWatchesViewImpl(session, myWatchesInVariables);
+    registerView(DebuggerContentInfo.WATCHES_CONTENT, myWatchesView);
     Content watchesContent = myUi.createContent(DebuggerContentInfo.WATCHES_CONTENT, myWatchesView.getPanel(),
                                                 XDebuggerBundle.message("debugger.session.tab.watches.title"), AllIcons.Debugger.Watches, null);
     watchesContent.setCloseable(false);
@@ -212,7 +214,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
   @NotNull
   private Content createFramesContent() {
     XFramesView framesView = new XFramesView(myProject);
-    myViews.add(framesView);
+    registerView(DebuggerContentInfo.FRAME_CONTENT, framesView);
     Content framesContent = myUi.createContent(DebuggerContentInfo.FRAME_CONTENT, framesView.getMainPanel(),
                                                XDebuggerBundle.message("debugger.session.tab.frames.title"), AllIcons.Debugger.Frame, null);
     framesContent.setCloseable(false);
@@ -221,7 +223,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
 
   public void rebuildViews() {
     AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> {
-      for (XDebugView view : myViews) {
+      for (XDebugView view : myViews.values()) {
         view.processSessionEvent(XDebugView.SessionEvent.SETTINGS_CHANGED);
       }
     });
@@ -232,8 +234,8 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
   }
 
   private void attachToSession(@NotNull XDebugSessionImpl session) {
-    for (XDebugView view : myViews) {
-      session.addSessionListener(new XDebugViewSessionListener(view), myRunContentDescriptor);
+    for (XDebugView view : myViews.values()) {
+      attachViewToSession(session, view);
     }
 
     XDebugTabLayouter layouter = session.getDebugProcess().createTabLayouter();
@@ -293,6 +295,12 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
     }
   }
 
+  private static void attachViewToSession(@NotNull XDebugSessionImpl session, @Nullable XDebugView view) {
+    if (view != null) {
+      session.addSessionListener(new XDebugViewSessionListener(view), view);
+    }
+  }
+
   public void detachFromSession() {
     assert mySession != null;
     mySession = null;
@@ -303,6 +311,48 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
     return myRunContentDescriptor;
   }
 
+  public boolean isWatchesInVariables() {
+    return myWatchesInVariables;
+  }
+
+  public void setWatchesInVariables(boolean watchesInVariables) {
+    if (myWatchesInVariables != watchesInVariables) {
+      myWatchesInVariables = watchesInVariables;
+      Registry.get("debugger.watches.in.variables").setValue(watchesInVariables);
+      if (mySession != null) {
+        removeContent(DebuggerContentInfo.VARIABLES_CONTENT);
+        removeContent(DebuggerContentInfo.WATCHES_CONTENT);
+        addVariablesAndWatches(mySession);
+        XDebugView variablesView = myViews.get(DebuggerContentInfo.VARIABLES_CONTENT);
+        if (variablesView != null) {
+          Disposer.register(myRunContentDescriptor, variablesView);
+        }
+        attachViewToSession(mySession, variablesView);
+        if (!myWatchesInVariables) {
+          XDebugView watchesView = myViews.get(DebuggerContentInfo.WATCHES_CONTENT);
+          if (watchesView != null) {
+            Disposer.register(myRunContentDescriptor, watchesView);
+          }
+          attachViewToSession(mySession, watchesView);
+        }
+        rebuildViews();
+      }
+    }
+  }
+
+  private void registerView(String contentId, @NotNull XDebugView view) {
+    myViews.put(contentId, view);
+    Disposer.register(myRunContentDescriptor, view);
+  }
+
+  private void removeContent(String contentId) {
+    myUi.removeContent(myUi.findContent(contentId), true);
+    XDebugView view = myViews.remove(contentId);
+    if (view != null) {
+      Disposer.dispose(view);
+    }
+  }
+
   private static class ToggleSortValuesAction extends SortValuesToggleAction {
     private final boolean myShowIcon;
 
index b4d536eb1b9e98d793578f99ea6f0de29b569076..f67a2c09f6fa8a08b49a21de33ea0ac90a1fe26a 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.intellij.xdebugger.impl.ui.tree.nodes;
 
-import com.intellij.openapi.util.registry.Registry;
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.ui.tree.TreeUtil;
@@ -49,17 +48,18 @@ public class WatchesRootNode extends XValueContainerNode<XValueContainer> {
   public WatchesRootNode(@NotNull XDebuggerTree tree,
                          @NotNull XWatchesView watchesView,
                          @NotNull XExpression[] expressions) {
-    this(tree, watchesView, expressions, null);
+    this(tree, watchesView, expressions, null, false);
   }
 
   public WatchesRootNode(@NotNull XDebuggerTree tree,
                          @NotNull XWatchesView watchesView,
                          @NotNull XExpression[] expressions,
-                         @Nullable XStackFrame stackFrame) {
+                         @Nullable XStackFrame stackFrame,
+                         boolean watchesInVariables) {
     super(tree, null, new XValueContainer() {
       @Override
       public void computeChildren(@NotNull XCompositeNode node) {
-        if (stackFrame != null && Registry.is("debugger.watches.in.variables")) {
+        if (stackFrame != null && watchesInVariables) {
           stackFrame.computeChildren(node);
         }
         else {