blob: e3ecb9f4d4c8972907a1cc3241479f2a40bfa658 [file] [log] [blame]
/*
* 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.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
public class SwitchManager implements ProjectComponent, KeyEventDispatcher, AnActionListener {
private final Project myProject;
private QuickAccessSettings myQa;
private SwitchingSession mySession;
private boolean myWaitingForAutoInitSession;
private final Alarm myInitSessionAlarm = new Alarm();
private KeyEvent myAutoInitSessionEvent;
private final Set<AnAction> mySwitchActions = new HashSet<AnAction>();
private final Set<SwitchingSession> myFadingAway = new HashSet<SwitchingSession>();
public SwitchManager(Project project, QuickAccessSettings quickAccess, ActionManager actionManager) {
myProject = project;
myQa = quickAccess;
actionManager.addAnActionListener(this, project);
mySwitchActions.add(actionManager.getAction(QuickAccessSettings.SWITCH_UP));
mySwitchActions.add(actionManager.getAction(QuickAccessSettings.SWITCH_DOWN));
mySwitchActions.add(actionManager.getAction(QuickAccessSettings.SWITCH_LEFT));
mySwitchActions.add(actionManager.getAction(QuickAccessSettings.SWITCH_RIGHT));
mySwitchActions.add(actionManager.getAction(QuickAccessSettings.SWITCH_APPLY));
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
Disposer.register(project, new Disposable() {
@Override
public void dispose() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(SwitchManager.this);
}
});
}
public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
if (!mySwitchActions.contains(action)) {
disposeCurrentSession(false);
}
}
public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
}
public void beforeEditorTyping(char c, DataContext dataContext) {
}
public boolean dispatchKeyEvent(KeyEvent e) {
if (!myQa.isEnabled()) return false;
if (mySession != null && !mySession.isFinished()) return false;
Component c = e.getComponent();
Component frame = UIUtil.findUltimateParent(c);
if (frame instanceof IdeFrame) {
if (((IdeFrame)frame).getProject() != myProject) return false;
}
if (e.getID() != KeyEvent.KEY_PRESSED) {
if (myWaitingForAutoInitSession) {
cancelWaitingForAutoInit();
}
return false;
}
if (myQa.getModiferCodes().contains(e.getKeyCode())) {
if (areAllModifiersPressed(e.getModifiers(), myQa.getModiferCodes())) {
myWaitingForAutoInitSession = true;
myAutoInitSessionEvent = e;
Runnable initRunnable = new Runnable() {
public void run() {
IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(new Runnable() {
public void run() {
if (myWaitingForAutoInitSession) {
tryToInitSessionFromFocus(null, false);
}
}
});
}
};
if (myFadingAway.isEmpty()) {
myInitSessionAlarm.addRequest(initRunnable, Registry.intValue("actionSystem.keyGestureHoldTime"));
}
else {
initRunnable.run();
}
}
}
else {
if (myWaitingForAutoInitSession) {
cancelWaitingForAutoInit();
}
}
return false;
}
private ActionCallback tryToInitSessionFromFocus(@Nullable SwitchTarget preselected, boolean showSpots) {
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) {
return initSession(new SwitchingSession(this, provider, myAutoInitSessionEvent, preselected, showSpots));
}
return new ActionCallback.Rejected();
}
private void cancelWaitingForAutoInit() {
myWaitingForAutoInitSession = false;
myInitSessionAlarm.cancelAllRequests();
}
public static boolean areAllModifiersPressed(@JdkConstants.InputEventMask int modifiers, Set<Integer> modifierCodes) {
int mask = 0;
for (Integer each : modifierCodes) {
if (each == KeyEvent.VK_SHIFT) {
mask |= InputEvent.SHIFT_MASK;
}
if (each == KeyEvent.VK_CONTROL) {
mask |= InputEvent.CTRL_MASK;
}
if (each == KeyEvent.VK_META) {
mask |= InputEvent.META_MASK;
}
if (each == KeyEvent.VK_ALT) {
mask |= InputEvent.ALT_MASK;
}
}
return (modifiers ^ mask) == 0;
}
public void initComponent() {
}
public void disposeComponent() {
myQa = null;
}
public static SwitchManager getInstance(Project project) {
return project != null ? project.getComponent(SwitchManager.class) : null;
}
public SwitchingSession getSession() {
return mySession;
}
public ActionCallback initSession(SwitchingSession session) {
cancelWaitingForAutoInit();
disposeCurrentSession(false);
mySession = session;
return new ActionCallback.Done();
}
public void disposeCurrentSession(boolean fadeAway) {
if (mySession != null) {
mySession.setFadeaway(fadeAway);
Disposer.dispose(mySession);
mySession = null;
}
}
public void projectOpened() {
}
public void projectClosed() {
}
@NotNull
public String getComponentName() {
return "ViewSwitchManager";
}
public boolean isSessionActive() {
return mySession != null && !mySession.isFinished();
}
public ActionCallback applySwitch() {
final ActionCallback result = new ActionCallback();
if (isSessionActive()) {
final boolean showSpots = mySession.isShowspots();
mySession.finish(false).doWhenDone(new Consumer<SwitchTarget>() {
@Override
public void consume(final SwitchTarget switchTarget) {
mySession = null;
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(new Runnable() {
public void run() {
tryToInitSessionFromFocus(switchTarget, showSpots).doWhenProcessed(result.createSetDoneRunnable());
}
});
}
});
}
else {
result.setDone();
}
return result;
}
public boolean canApplySwitch() {
return isSessionActive() && mySession.isSelectionWasMoved();
}
public boolean isSelectionWasMoved() {
return isSessionActive() && mySession.isSelectionWasMoved();
}
public void addFadingAway(SwitchingSession session) {
myFadingAway.add(session);
}
public void removeFadingAway(SwitchingSession session) {
myFadingAway.remove(session);
}
}