visual switcher - auto init session
authorKirill Kalishev <kirill.kalishev@jetbrains.com>
Fri, 23 Apr 2010 09:32:45 +0000 (13:32 +0400)
committerKirill Kalishev <kirill.kalishev@jetbrains.com>
Fri, 23 Apr 2010 09:32:45 +0000 (13:32 +0400)
platform/platform-api/src/com/intellij/ui/switcher/SwitchAction.java
platform/platform-api/src/com/intellij/ui/switcher/SwitchManager.java
platform/platform-api/src/com/intellij/ui/switcher/SwitchingSession.java

index 6e7588e6f022128d2c9c2bd35b483e2481b2f3ba..ad8ea02a340dca907d0107d7c3fc95151dae92cc 100644 (file)
@@ -21,6 +21,8 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys;
 import com.intellij.openapi.project.DumbAware;
 import com.intellij.openapi.project.Project;
 
+import java.awt.event.KeyEvent;
+
 public abstract class SwitchAction extends AnAction implements DumbAware {
 
   @Override
@@ -34,7 +36,7 @@ public abstract class SwitchAction extends AnAction implements DumbAware {
     SwitchingSession session = getSession(e);
     if (session == null || session.isFinished()) {
       SwitchProvider provider = getProvider(e);
-      session = new SwitchingSession(provider, e);
+      session = new SwitchingSession(provider, (KeyEvent)e.getInputEvent());
       initSession(e, session);
     }
 
index 80aa490e0d1175174b9c3a7a94979cd61b1f5293..3b2c3c0197f366d0b99a72b4d9bd390305b160cc 100644 (file)
  */
 package com.intellij.ui.switcher;
 
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.KeyboardShortcut;
+import com.intellij.openapi.actionSystem.Shortcut;
 import com.intellij.openapi.components.ProjectComponent;
+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.Disposer;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.util.Alarm;
+import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 
-public class SwitchManager implements ProjectComponent {
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import java.util.HashSet;
+import java.util.Set;
+
+public class SwitchManager implements ProjectComponent, KeyEventDispatcher, KeymapManagerListener, Keymap.Listener  {
+
+  private Project myProject;
 
   private SwitchingSession mySession;
 
-  public void projectOpened() {
+  private Set<Integer> myModifierCodes;
+
+  private Keymap myKeymap;
+  @NonNls private static final String SWITCH_UP = "SwitchUp";
+
+  private boolean myWaitingForAutoInitSession;
+  private Alarm myInitSessionAlarm = new Alarm();
+  private KeyEvent myAutoInitSessionEvent;
+
+  public SwitchManager(Project project) {
+    myProject = project;
   }
 
-  public void projectClosed() {
+  public boolean dispatchKeyEvent(KeyEvent e) {
+    if (mySession != null && !mySession.isFinished()) return false;
+    if (e.getID() != KeyEvent.KEY_PRESSED) {
+      if (myWaitingForAutoInitSession) {
+        cancelWaitingForAutoInit();
+      }
+      return false;
+    }
+
+    if (myModifierCodes.contains(e.getKeyCode())) {
+      if (areAllModifiersPressed(e.getModifiers())) {
+        myWaitingForAutoInitSession = true;
+        myAutoInitSessionEvent = e;
+        myInitSessionAlarm.addRequest(new Runnable() {
+          public void run() {
+            IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(new Runnable() {
+              public void run() {
+                if (myWaitingForAutoInitSession) {
+                  autoInitSession();
+                }
+              }
+            });
+          }
+        }, 200);
+      }
+    } else {
+      if (myWaitingForAutoInitSession) {
+        cancelWaitingForAutoInit();
+      }
+    }
+
+    return false;
   }
 
-  @NotNull
-  public String getComponentName() {
-    return "ViewSwitchManager";
+  private void autoInitSession() {
+    Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
+    SwitchProvider provider = SwitchProvider.KEY.getData(DataManager.getInstance().getDataContext(owner));
+    if (provider != null) {
+      initSession(new SwitchingSession(provider, myAutoInitSessionEvent));
+    }
+  }
+
+  private void cancelWaitingForAutoInit() {
+    myWaitingForAutoInitSession = false;
+    myAutoInitSessionEvent = null;
+    myInitSessionAlarm.cancelAllRequests();
+  }
+
+  public void activeKeymapChanged(Keymap keymap) {
+    KeymapManager mgr = KeymapManager.getInstance();
+
+    if (myKeymap != null) {
+      myKeymap.removeShortcutChangeListener(this);
+    }
+
+    myKeymap = mgr.getActiveKeymap();
+    myKeymap.addShortcutChangeListener(this);
+
+    onShortcutChanged(SWITCH_UP);
+  }
+
+  public void onShortcutChanged(String actionId) {
+    if (!SWITCH_UP.equals(actionId)) return;
+
+    Shortcut[] shortcuts = myKeymap.getShortcuts(SWITCH_UP);
+    myModifierCodes = null;
+
+    if (shortcuts.length > 0) {
+      for (Shortcut each : shortcuts) {
+        if (each instanceof KeyboardShortcut) {
+          KeyboardShortcut kbs = (KeyboardShortcut)each;
+          KeyStroke stroke = kbs.getFirstKeyStroke();
+          myModifierCodes = getModifiersCodes(stroke.getModifiers());
+          break;
+        }
+      }
+    }
+  }
+
+  private boolean areAllModifiersPressed(int modifiers) {
+    int mask = 0;
+    for (Integer each : myModifierCodes) {
+      if (each == KeyEvent.VK_SHIFT) {
+        mask |= KeyEvent.SHIFT_MASK;
+      }
+
+      if (each == KeyEvent.VK_CONTROL) {
+        mask |= KeyEvent.CTRL_MASK;
+      }
+
+      if (each == KeyEvent.VK_META) {
+        mask |= KeyEvent.META_MASK;
+      }
+
+      if (each == KeyEvent.VK_ALT) {
+        mask |= KeyEvent.ALT_MASK;
+      }
+    }
+
+    return (modifiers ^ mask) == 0;
+  }
+
+  private Set<Integer> getModifiersCodes(int modifiers) {
+    Set<Integer> codes = new HashSet<Integer>();
+    if ((modifiers & KeyEvent.SHIFT_MASK) > 0) {
+      codes.add(KeyEvent.VK_SHIFT);
+    }
+    if ((modifiers & KeyEvent.CTRL_MASK) > 0) {
+      codes.add(KeyEvent.VK_CONTROL);
+    }
+
+    if ((modifiers & KeyEvent.META_MASK) > 0) {
+      codes.add(KeyEvent.VK_META);
+    }
+
+    if ((modifiers & KeyEvent.ALT_MASK) > 0) {
+      codes.add(KeyEvent.VK_ALT);
+    }
+
+    return codes;
   }
 
   public void initComponent() {
+    KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
+    KeymapManager kmMgr = KeymapManager.getInstance();
+    kmMgr.addKeymapManagerListener(this);
+
+    activeKeymapChanged(kmMgr.getActiveKeymap());
   }
 
   public void disposeComponent() {
+    KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
+    KeymapManager.getInstance().removeKeymapManagerListener(this);
+
+    if (myKeymap != null) {
+      myKeymap.removeShortcutChangeListener(this);
+      myKeymap = null;
+    }
   }
 
   public static SwitchManager getInstance(Project project) {
@@ -60,4 +213,16 @@ public class SwitchManager implements ProjectComponent {
       mySession = null;
     }
   }
+
+  public void projectOpened() {
+  }
+
+  public void projectClosed() {
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return "ViewSwitchManager";
+  }
+
 }
index 3f19f80600ac32def5f4d57184086560dab0d125..7c211436bcdf8b95d0a87ffc4ec48e4c475c0415 100644 (file)
@@ -37,7 +37,7 @@ import static java.lang.Math.sqrt;
 public class SwitchingSession implements KeyEventDispatcher, Disposable {
 
   private SwitchProvider myProvider;
-  private AnActionEvent myInitialEvent;
+  private KeyEvent myInitialEvent;
   private boolean myFinished;
   private java.util.List<SwitchTarget> myTargets;
   private IdeGlassPane myGlassPane;
@@ -46,7 +46,7 @@ public class SwitchingSession implements KeyEventDispatcher, Disposable {
   private JComponent myRootComponent;
   private SwitchTarget mySelection;
 
-  public SwitchingSession(SwitchProvider provider, AnActionEvent e) {
+  public SwitchingSession(SwitchProvider provider, KeyEvent e) {
     myProvider = provider;
     myInitialEvent = e;
 
@@ -92,7 +92,7 @@ public class SwitchingSession implements KeyEventDispatcher, Disposable {
   }
 
   public boolean dispatchKeyEvent(KeyEvent e) {
-    KeyEvent event = (KeyEvent)myInitialEvent.getInputEvent();
+    KeyEvent event = myInitialEvent;
     if ((e.getModifiers() & event.getModifiers()) == 0) {
       finish();
       return false;