switcher combined with show quick actions
authorKirill Kalishev <kirill.kalishev@jetbrains.com>
Tue, 27 Apr 2010 09:26:44 +0000 (13:26 +0400)
committerKirill Kalishev <kirill.kalishev@jetbrains.com>
Tue, 27 Apr 2010 09:26:44 +0000 (13:26 +0400)
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerLayoutUiImpl.java
platform/platform-api/src/com/intellij/ui/switcher/ApplySwitchAction.java
platform/platform-api/src/com/intellij/ui/switcher/QuickAccessProvider.java [new file with mode: 0644]
platform/platform-api/src/com/intellij/ui/switcher/QuickActionManager.java [new file with mode: 0644]
platform/platform-api/src/com/intellij/ui/switcher/QuickActionProvider.java [new file with mode: 0644]
platform/platform-api/src/com/intellij/ui/switcher/SwitchManager.java
platform/platform-api/src/com/intellij/ui/switcher/SwitchProvider.java
platform/platform-api/src/com/intellij/ui/switcher/SwitchingSession.java
platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java
platform/platform-resources/src/componentSets/UICore.xml

index d94b6c4bfd27a9c808fa248d437f0ceefb8d0fce..e2558f361fd4831af643d38fadaff22d1c4e0e07 100644 (file)
@@ -32,6 +32,7 @@ import com.intellij.openapi.wm.ToolWindow;
 import com.intellij.ui.components.panels.NonOpaquePanel;
 import com.intellij.ui.components.panels.Wrapper;
 import com.intellij.ui.content.*;
+import com.intellij.ui.switcher.QuickActionProvider;
 import com.intellij.ui.switcher.SwitchProvider;
 import com.intellij.ui.switcher.SwitchTarget;
 import com.intellij.ui.tabs.JBTabs;
@@ -52,7 +53,8 @@ import java.beans.PropertyChangeListener;
 import java.util.*;
 import java.util.List;
 
-public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Facade, ViewContextEx, PropertyChangeListener, SwitchProvider {
+public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Facade, ViewContextEx, PropertyChangeListener, SwitchProvider,
+                                        QuickActionProvider {
 
   @NonNls public static final String LAYOUT = "Runner.Layout";
   @NonNls public static final String VIEW_POPUP = "Runner.View.Popup";
@@ -103,6 +105,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
   private boolean myToDisposeRemovedContent = true;
 
   private int myAttractionCount;
+  private ActionGroup myLeftToolbarActions;
 
   public RunnerContentUi(Project project,
                          RunnerLayoutUi ui,
@@ -135,6 +138,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     final ActionToolbar tb = myActionManager.createActionToolbar(place, group, false);
     tb.setTargetComponent(myComponent);
     myToolbar.setContent(tb.getComponent());
+    myLeftToolbarActions = group;
 
     myComponent.revalidate();
     myComponent.repaint();
@@ -729,7 +733,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     return myToDisposeRemovedContent;
   }
 
-  private class MyComponent extends Wrapper.FocusHolder implements DataProvider {
+  private class MyComponent extends Wrapper.FocusHolder implements DataProvider, QuickActionProvider {
 
     private boolean myWasEverAdded;
 
@@ -749,6 +753,23 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
       }
     }
 
+    @Override
+    public String getName() {
+      return RunnerContentUi.this.getName();
+    }
+
+    public List<AnAction> getActions(boolean originalProvider) {
+      return RunnerContentUi.this.getActions(originalProvider);
+    }
+
+    public JComponent getComponent() {
+      return RunnerContentUi.this.getComponent();
+    }
+
+    public boolean isCycleRoot() {
+      return RunnerContentUi.this.isCycleRoot();
+    }
+
     public void addNotify() {
       super.addNotify();
 
@@ -1109,6 +1130,21 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     return myRunnerUi;
   }
 
+  public String getName() {
+    return mySessionName;
+  }
+
+  public List<AnAction> getActions(boolean originalProvider) {
+    ArrayList<AnAction> result = new ArrayList<AnAction>();
+    if (myLeftToolbarActions != null) {
+      AnAction[] kids = myLeftToolbarActions.getChildren(null);
+      for (AnAction each : kids) {
+        result.add(each);
+      }
+    }
+    return result;
+  }
+
   public SwitchTarget getCurrentTarget() {
     Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
     if (owner == null) return myTabs.getCurrentTarget();
index 505022faa0532060ba706ba8c79b3e9f42fd533b..ce8120d2a9e3bfc6b0ca8466d9446957ecbf363e 100644 (file)
@@ -36,6 +36,8 @@ import com.intellij.ui.content.Content;
 import com.intellij.ui.content.ContentFactory;
 import com.intellij.ui.content.ContentManager;
 import com.intellij.ui.content.ContentManagerListener;
+import com.intellij.ui.switcher.QuickAccessProvider;
+import com.intellij.ui.switcher.QuickActionProvider;
 import com.intellij.ui.switcher.SwitchProvider;
 import com.intellij.ui.switcher.SwitchTarget;
 import org.jetbrains.annotations.NonNls;
@@ -313,6 +315,10 @@ public class RunnerLayoutUiImpl implements Disposable, RunnerLayoutUi, LayoutSta
         return myContentUI;
       }
 
+      if (QuickActionProvider.KEY.getName().equals(dataId)) {
+        return myContentUI;
+      }
+
       return null;
     }
   }
index 1d32e3e5e0b0041de692ea4eef2057273255e505..b76995b61ea44834614be224c7962226c9ee793c 100644 (file)
@@ -18,22 +18,42 @@ package com.intellij.ui.switcher;
 import com.intellij.openapi.actionSystem.AnAction;
 import com.intellij.openapi.actionSystem.AnActionEvent;
 import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
 
 public class ApplySwitchAction extends AnAction {
 
   @Override
   public void update(AnActionEvent e) {
-    SwitchManager mgr = getManager(e);
-    e.getPresentation().setEnabled(mgr != null && mgr.isSessionActive());
+    Project project = getProject(e);
+    if (project == null) {
+      e.getPresentation().setEnabled(false);
+      return;
+    }
 
+    SwitchManager mgr = SwitchManager.getInstance(project);
+
+    boolean switchActionActive = mgr != null && mgr.isSessionActive();
+    e.getPresentation().setEnabled(switchActionActive);
+    if (!switchActionActive) {
+      QuickActionProvider quickActionProvider = QuickActionProvider.KEY.getData(e.getDataContext());
+      e.getPresentation().setEnabled(quickActionProvider != null);
+    }
   }
 
-  private SwitchManager getManager(AnActionEvent e) {
-    return SwitchManager.getInstance(PlatformDataKeys.PROJECT.getData(e.getDataContext()));
+  private Project getProject(AnActionEvent e) {
+    return PlatformDataKeys.PROJECT.getData(e.getDataContext());
   }
 
   @Override
   public void actionPerformed(AnActionEvent e) {
-    getManager(e).applySwitch();
+    Project project = getProject(e);
+
+    SwitchManager switchManager = SwitchManager.getInstance(project);
+    if (switchManager.canApplySwitch()) {
+      switchManager.applySwitch();
+    } else {
+      QuickActionManager.getInstance(project).showQuickActions();
+    }
+    
   }
 }
diff --git a/platform/platform-api/src/com/intellij/ui/switcher/QuickAccessProvider.java b/platform/platform-api/src/com/intellij/ui/switcher/QuickAccessProvider.java
new file mode 100644 (file)
index 0000000..be4bbca
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2010 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.ui.switcher;
+
+import javax.swing.*;
+
+public interface QuickAccessProvider {
+
+  JComponent getComponent();
+  boolean isCycleRoot();
+
+}
diff --git a/platform/platform-api/src/com/intellij/ui/switcher/QuickActionManager.java b/platform/platform-api/src/com/intellij/ui/switcher/QuickActionManager.java
new file mode 100644 (file)
index 0000000..a792fa7
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2000-2010 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.ui.switcher;
+
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.AsyncResult;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+public class QuickActionManager implements ProjectComponent {
+
+  private SwitchProvider myActiveProvider;
+
+  public void projectOpened() {
+  }
+
+  public void projectClosed() {
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return "QuickActionsManager";
+  }
+
+  public void initComponent() {
+  }
+
+  public void disposeComponent() {
+  }
+
+  public static QuickActionManager getInstance(Project project) {
+    return project != null ? project.getComponent(QuickActionManager.class) : null;
+  }
+
+  public void showQuickActions() {
+    if (isActive()) return;
+
+    showActionsPopup();
+  }
+
+  private void showActionsPopup() {
+    DataManager.getInstance().getDataContextFromFocus().doWhenDone(new AsyncResult.Handler<DataContext>() {
+      public void run(DataContext context) {
+        QuickActionProvider provider = QuickActionProvider.KEY.getData(context);
+        if (provider == null) return;
+
+        List<AnAction> actions = provider.getActions(true);
+        DefaultActionGroup group = new DefaultActionGroup();
+        for (AnAction each : actions) {
+          group.add(each);
+        }
+
+        boolean firstParent = true;
+        Component eachParent = provider.getComponent().getParent();
+        while (eachParent != null) {
+          if (eachParent instanceof QuickActionProvider) {
+            QuickActionProvider eachProvider = (QuickActionProvider)eachParent;
+            if (firstParent) {
+              group.addSeparator();
+              firstParent = false;
+            }
+            List<AnAction> eachActionList = eachProvider.getActions(false);
+            if (eachActionList.size() > 0) {
+              group.add(new Group(eachActionList, eachProvider.getName()));
+            }
+            if (eachProvider.isCycleRoot()) break;
+
+          }
+          eachParent = eachParent.getParent();
+        }
+
+        JBPopupFactory.getInstance()
+          .createActionGroupPopup(null, group, context, JBPopupFactory.ActionSelectionAid.ALPHA_NUMBERING, true, new Runnable() {
+            public void run() {
+              myActiveProvider = null;
+            }
+          }, -1).showInFocusCenter();
+
+      }
+    });
+
+  }
+
+  private class Group extends DefaultActionGroup {
+    private String myTitle;
+
+    private Group(List<AnAction> actions, String title) {
+      setPopup(true);
+      for (AnAction each : actions) {
+        add(each);
+      }
+      myTitle = title;
+    }
+
+    @Override
+    public void update(AnActionEvent e) {
+      e.getPresentation().setText(myTitle);
+    }
+  }
+
+  public boolean isActive() {
+    return myActiveProvider != null;
+  }
+}
diff --git a/platform/platform-api/src/com/intellij/ui/switcher/QuickActionProvider.java b/platform/platform-api/src/com/intellij/ui/switcher/QuickActionProvider.java
new file mode 100644 (file)
index 0000000..d6f157f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2010 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.ui.switcher;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DataKey;
+
+import javax.swing.*;
+import java.util.List;
+
+public interface QuickActionProvider extends QuickAccessProvider {
+
+  DataKey<QuickActionProvider> KEY = DataKey.create("QuickActionProvider");
+
+  String getName();
+  List<AnAction> getActions(boolean originalProvider);
+
+}
index 8e914e150e639929a4aaa51f99037304830a5ce9..f327baa94bdbd1b5368fc799d2ce19e1ffe60f0f 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.openapi.keymap.Keymap;
 import com.intellij.openapi.keymap.KeymapManager;
 import com.intellij.openapi.keymap.KeymapManagerListener;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.ActionCallback;
 import com.intellij.openapi.util.AsyncResult;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.wm.IdeFocusManager;
@@ -99,14 +100,16 @@ public class SwitchManager implements ProjectComponent, KeyEventDispatcher, Keym
     return false;
   }
 
-  private void tryToInitSessionFromFocus(@Nullable SwitchTarget preselected) {
-    if (mySession != null && !mySession.isFinished()) return;
+  private ActionCallback tryToInitSessionFromFocus(@Nullable SwitchTarget preselected) {
+    if (mySession != null && !mySession.isFinished()) return new ActionCallback.Rejected();
 
     Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
     SwitchProvider provider = SwitchProvider.KEY.getData(DataManager.getInstance().getDataContext(owner));
     if (provider != null) {
-      initSession(new SwitchingSession(provider, myAutoInitSessionEvent, preselected));
+      return initSession(new SwitchingSession(provider, myAutoInitSessionEvent, preselected));
     }
+
+    return new ActionCallback.Rejected();
   }
 
   private void cancelWaitingForAutoInit() {
@@ -215,9 +218,10 @@ public class SwitchManager implements ProjectComponent, KeyEventDispatcher, Keym
     return mySession;
   }
 
-  public void initSession(SwitchingSession session) {
+  public ActionCallback initSession(SwitchingSession session) {
     disposeSession(mySession);
     mySession = session;
+    return new ActionCallback.Done();
   }
 
   private void disposeSession(SwitchingSession session) {
@@ -242,18 +246,31 @@ public class SwitchManager implements ProjectComponent, KeyEventDispatcher, Keym
     return mySession != null && !mySession.isFinished();
   }
 
-  public void applySwitch() {
+  public ActionCallback applySwitch() {
+    final ActionCallback result = new ActionCallback();
     if (isSessionActive()) {
       mySession.finish().doWhenDone(new AsyncResult.Handler<SwitchTarget>() {
         public void run(final SwitchTarget switchTarget) {
           mySession = null;
           IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(new Runnable() {
             public void run() {
-              tryToInitSessionFromFocus(switchTarget);
+              tryToInitSessionFromFocus(switchTarget).doWhenProcessed(new Runnable() {
+                public void run() {
+                  result.setDone();
+                }
+              });
             }
           });
         }
       });
+    } else {
+      result.setDone();
     }
+
+    return result;
+  }
+
+  public boolean canApplySwitch() {
+    return isSessionActive() && mySession.isSelectionWasMoved();
   }
 }
index 8b97f695227c7266dd37d52dbc21efa115577df7..484083849149cc17f28d1e12a5539f60320401f2 100644 (file)
@@ -20,15 +20,12 @@ import com.intellij.openapi.actionSystem.DataKey;
 import javax.swing.*;
 import java.util.List;
 
-public interface SwitchProvider {
+public interface SwitchProvider extends QuickAccessProvider {
 
   DataKey<SwitchProvider> KEY = DataKey.create("SwitchProvider");
 
   List<SwitchTarget> getTargets(boolean onlyVisible, boolean originalProvider);
   SwitchTarget getCurrentTarget();
 
-  JComponent getComponent();
-
-  boolean isCycleRoot();
 
 }
index 3f54199ad382a3881b57cd2c28702fba3dcf5afa..dc9186a5c4db4d606998d1205b21a0bfda831838 100644 (file)
@@ -45,7 +45,11 @@ public class SwitchingSession implements KeyEventDispatcher, Disposable {
 
   private Map<SwitchTarget, TargetPainer> myPainters = new Hashtable<SwitchTarget, TargetPainer>();
   private JComponent myRootComponent;
+
   private SwitchTarget mySelection;
+  private SwitchTarget myStartSelection;
+
+  private boolean mySelectionWasMoved;
 
   public SwitchingSession(SwitchProvider provider, KeyEvent e, @Nullable SwitchTarget preselected) {
     myProvider = provider;
@@ -83,6 +87,8 @@ public class SwitchingSession implements KeyEventDispatcher, Disposable {
       mySelection = preselected;
     }
 
+    myStartSelection = mySelection;
+
     myGlassPane = IdeGlassPaneUtil.find(myProvider.getComponent());
     for (SwitchTarget each : myTargets) {
       TargetPainer eachPainter = new TargetPainer(each);
@@ -109,6 +115,10 @@ public class SwitchingSession implements KeyEventDispatcher, Disposable {
     return mySelection;
   }
 
+  public boolean isSelectionWasMoved() {
+    return mySelectionWasMoved;
+  }
+
   private class TargetPainer extends AbstractPainter implements Disposable {
 
     private SwitchTarget myTarget;
@@ -185,6 +195,8 @@ public class SwitchingSession implements KeyEventDispatcher, Disposable {
   private void setSelection(SwitchTarget target) {
     mySelection = target;
 
+    mySelectionWasMoved = !mySelection.equals(myStartSelection);
+
     for (TargetPainer each : myPainters.values()) {
       each.setNeedsRepaint(true);
     }
index 7a436021127a1e4122ce948f26e59f6d8b969b65..093801d183d3df10f55879214b16f4e04882da54 100644 (file)
@@ -30,6 +30,7 @@ import com.intellij.openapi.wm.IdeGlassPaneUtil;
 import com.intellij.openapi.wm.impl.content.GraphicsConfig;
 import com.intellij.ui.CaptionPanel;
 import com.intellij.ui.awt.RelativeRectangle;
+import com.intellij.ui.switcher.QuickActionProvider;
 import com.intellij.ui.switcher.SwitchProvider;
 import com.intellij.ui.switcher.SwitchTarget;
 import com.intellij.ui.tabs.*;
@@ -60,7 +61,7 @@ import java.util.*;
 import java.util.List;
 
 public class JBTabsImpl extends JComponent
-  implements JBTabs, PropertyChangeListener, TimerListener, DataProvider, PopupMenuListener, Disposable, JBTabsPresentation, Queryable {
+  implements JBTabs, PropertyChangeListener, TimerListener, DataProvider, PopupMenuListener, Disposable, JBTabsPresentation, Queryable, QuickActionProvider {
 
   static DataKey<JBTabsImpl> NAVIGATION_ACTIONS_KEY = DataKey.create("JBTabs");
 
@@ -2602,9 +2603,29 @@ public class JBTabsImpl extends JComponent
       return this;
     }
 
+    if (QuickActionProvider.KEY.getName().equals(dataId)) {
+      return this;
+    }
+
     return NAVIGATION_ACTIONS_KEY.is(dataId) ? this : null;
   }
 
+  public List<AnAction> getActions(boolean originalProvider) {
+    ArrayList<AnAction> result = new ArrayList<AnAction>();
+
+    TabInfo selection = getSelectedInfo();
+    if (selection != null) {
+      ActionGroup group = selection.getGroup();
+      if (group != null) {
+        AnAction[] children = group.getChildren(null);
+        for (int i = 0; i < children.length; i++) {
+          result.add(children[i]);
+        }
+      }
+    }
+
+    return result;
+  }
 
   public DataProvider getDataProvider() {
     return myDataProvider;
index 7c334143fbc03bb4a2550533f3f1335f51969a5d..41c7143f9b91cfa3c311d390dfdc5050d5d79699 100644 (file)
@@ -61,5 +61,8 @@
     <component>
       <implementation-class>com.intellij.ui.switcher.SwitchManager</implementation-class>
     </component>
+    <component>
+      <implementation-class>com.intellij.ui.switcher.QuickActionManager</implementation-class>
+    </component>
   </project-components>
 </components>