diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionManager.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionManager.java index a815babdf848..6d763dcf74e9 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionManager.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionManager.java @@ -159,6 +159,10 @@ public abstract class ActionManager implements ApplicationComponent { public abstract void removeTimerListener(TimerListener listener); + public abstract void addTransparrentTimerListener(int delay, TimerListener listener); + + public abstract void removeTransparrentTimerListener(TimerListener listener); + public abstract ActionCallback tryToExecute(@NotNull AnAction action, @NotNull InputEvent inputEvent, @Nullable Component contextComponent, @Nullable String place, boolean now); diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java index ef267b111d14..c45a1d6f4c0f 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java @@ -70,7 +70,9 @@ public abstract class AnAction { private static final ShortcutSet ourEmptyShortcutSet = new CustomShortcutSet(new Shortcut[0]); private boolean myIsDefaultIcon = true; private boolean myWorksInInjected; - + + + private boolean myTransparentUpdate = false; /** * Creates a new action with its text, description and icon set to null. */ @@ -288,4 +290,12 @@ public abstract class AnAction { public boolean isInInjectedContext() { return myWorksInInjected; } + + public boolean isTransparentUpdate() { + return myTransparentUpdate; + } + + public void setTransparentUpdate(boolean transparentUpdate) { + myTransparentUpdate = transparentUpdate; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/ActionManagerEx.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/ActionManagerEx.java index e479e503649b..a6c648a6153a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/ActionManagerEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/ActionManagerEx.java @@ -144,5 +144,6 @@ public abstract class ActionManagerEx extends ActionManager{ public abstract boolean isActionPopupStackEmpty(); + public abstract boolean isTransparrentOnlyActionsUpdateNow(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java index 1bdcb48f543d..b82d57e5ab64 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java @@ -120,6 +120,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat private final Map myQueuedNotificationsEvents = new LinkedHashMap(); private Runnable myPreloadActionsRunnable; + private boolean myTransparrentOnlyUpdate; ActionManagerImpl(KeymapManager keymapManager, DataManager dataManager) { myId2Action = new THashMap(); @@ -145,20 +146,39 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat } public void addTimerListener(int delay, final TimerListener listener) { + _addTimerListener(delay, listener, false); + } + + public void removeTimerListener(TimerListener listener) { + _removeTimerListener(listener, false); + } + + @Override + public void addTransparrentTimerListener(int delay, TimerListener listener) { + _addTimerListener(delay, listener, true); + } + + @Override + public void removeTransparrentTimerListener(TimerListener listener) { + _removeTimerListener(listener, true); + } + + + private void _addTimerListener(int delay, final TimerListener listener, boolean transparrent) { if (ApplicationManager.getApplication().isUnitTestMode()) return; if (myTimer == null) { myTimer = new MyTimer(); myTimer.start(); } - myTimer.addTimerListener(listener); + myTimer.addTimerListener(listener, transparrent); } - public void removeTimerListener(TimerListener listener) { + private void _removeTimerListener(TimerListener listener, boolean transparrent) { if (ApplicationManager.getApplication().isUnitTestMode()) return; LOG.assertTrue(myTimer != null); - myTimer.removeTimerListener(listener); + myTimer.removeTimerListener(listener, transparrent); } public ActionPopupMenu createActionPopupMenu(String place, @NotNull ActionGroup group, @Nullable PresentationFactory presentationFactory) { @@ -975,6 +995,11 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat return myPopups.isEmpty(); } + @Override + public boolean isTransparrentOnlyActionsUpdateNow() { + return myTransparrentOnlyUpdate; + } + private void flushActionPerformed() { final Set actions = myQueuedNotifications.keySet(); for (final AnAction eachAction : actions) { @@ -1147,6 +1172,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat private class MyTimer extends Timer implements ActionListener { private final List myTimerListeners = Collections.synchronizedList(new ArrayList()); + private final List myTransparrentTimerListeners = Collections.synchronizedList(new ArrayList()); private int myLastTimePerformed; MyTimer() { @@ -1155,12 +1181,20 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat setRepeats(true); } - public void addTimerListener(TimerListener listener){ - myTimerListeners.add(listener); + public void addTimerListener(TimerListener listener, boolean transparent){ + if (transparent) { + myTransparrentTimerListeners.add(listener); + } else { + myTimerListeners.add(listener); + } } - public void removeTimerListener(TimerListener listener){ - myTimerListeners.remove(listener); + public void removeTimerListener(TimerListener listener, boolean transparent){ + if (transparent) { + myTransparrentTimerListeners.remove(listener); + } else { + myTimerListeners.remove(listener); + } } public void actionPerformed(ActionEvent e) { @@ -1171,16 +1205,34 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat final int lastEventCount = myLastTimePerformed; myLastTimePerformed = ActivityTracker.getInstance().getCount(); - if (myLastTimePerformed == lastEventCount) { - return; - } + boolean transparentOnly = myLastTimePerformed == lastEventCount; - final TimerListener[] listeners = myTimerListeners.toArray(new TimerListener[myTimerListeners.size()]); + try { + HashSet notified = new HashSet(); + myTransparrentOnlyUpdate = transparentOnly; + notifyListeners(myTransparrentTimerListeners, notified); + + if (transparentOnly) { + return; + } + + notifyListeners(myTimerListeners, notified); + } + finally { + myTransparrentOnlyUpdate = false; + } + } + + private void notifyListeners(final List timerListeners, final Set notified) { + final TimerListener[] listeners = timerListeners.toArray(new TimerListener[timerListeners.size()]); IdeFocusManager.getInstance(null).doWhenFocusSettlesDown(new Runnable() { public void run() { for (TimerListener listener : listeners) { - if (myTimerListeners.contains(listener)) { - runListenerAction(listener); + if (timerListeners.contains(listener)) { + if (!notified.contains(listener)) { + notified.add(listener); + runListenerAction(listener); + } } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java index 1ffca22860ac..3047c9753bc2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java @@ -73,7 +73,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private final ActionGroup myActionGroup; private final String myPlace; @SuppressWarnings({"FieldCanBeLocal"}) private final MyKeymapManagerListener myKeymapManagerListener; - @SuppressWarnings({"FieldCanBeLocal"}) private final MyTimerListener myTimerListener; private ArrayList myNewVisibleActions; protected ArrayList myVisibleActions; private final PresentationFactory myPresentationFactory; @@ -100,6 +99,8 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { private JComponent myTargetComponent; private boolean myReservePlaceAutoPopupIcon = true; + private WeakTimerListener myWeakTimerListener; + private ActionToolbarImpl.MyTimerListener myTimerListener; public ActionToolbarImpl(final String place, final ActionGroup actionGroup, @@ -127,7 +128,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { myActionGroup = actionGroup; myPresentationFactory = new PresentationFactory(); myKeymapManagerListener = new MyKeymapManagerListener(); - myTimerListener = new MyTimerListener(); myVisibleActions = new ArrayList(); myNewVisibleActions = new ArrayList(); myDataManager = dataManager; @@ -138,15 +138,30 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { mySecondaryActions.getTemplatePresentation().setIcon(mySecondaryGroupIcon); mySecondaryActions.setPopup(true); - updateActions(updateActionsNow); + updateActions(updateActionsNow, false); // keymapManager.addKeymapManagerListener(new WeakKeymapManagerListener(keymapManager, myKeymapManagerListener)); - actionManager.addTimerListener(500, new WeakTimerListener(actionManager, myTimerListener)); + myTimerListener = new MyTimerListener(); + myWeakTimerListener = new WeakTimerListener(actionManager, myTimerListener); // If the panel doesn't handle mouse event then it will be passed to its parent. // It means that if the panel is in slidindg mode then the focus goes to the editor // and panel will be automatically hidden. - enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); + enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.COMPONENT_EVENT_MASK | AWTEvent.CONTAINER_EVENT_MASK); + } + + @Override + public void addNotify() { + super.addNotify(); + myActionManager.addTimerListener(500, myWeakTimerListener); + myActionManager.addTransparrentTimerListener(500, myWeakTimerListener); + } + + @Override + public void removeNotify() { + super.removeNotify(); + myActionManager.removeTimerListener(myWeakTimerListener); + myActionManager.removeTransparrentTimerListener(myWeakTimerListener); } public JComponent getComponent() { @@ -656,6 +671,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } private final class MyTimerListener implements TimerListener { + public ModalityState getModalityState() { return ModalityState.stateForComponent(ActionToolbarImpl.this); } @@ -682,7 +698,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } } - updateActions(false); + updateActions(false, myActionManager.isTransparrentOnlyActionsUpdateNow()); } } @@ -715,16 +731,16 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public void updateActionsImmediately() { ApplicationManager.getApplication().assertIsDispatchThread(); - updateActions(true); + updateActions(true, false); } - private void updateActions(boolean now) { + private void updateActions(boolean now, final boolean transparrentOnly) { final Runnable updateRunnable = new Runnable() { public void run() { myNewVisibleActions.clear(); final DataContext dataContext = getDataContext(); - Utils.expandActionGroup(myActionGroup, myNewVisibleActions, myPresentationFactory, dataContext, myPlace, myActionManager); + Utils.expandActionGroup(myActionGroup, myNewVisibleActions, myPresentationFactory, dataContext, myPlace, myActionManager, transparrentOnly); if (!myNewVisibleActions.equals(myVisibleActions)) { // should rebuild UI @@ -781,7 +797,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { if (myTargetComponent != null && myTargetComponent.isVisible()) { ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() { public void run() { - updateActions(false); + updateActions(false, false); } }, ModalityState.stateForComponent(myTargetComponent)); } @@ -927,7 +943,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { Disposer.dispose(myPopup); myPopup = null; - updateActions(false); + updateActions(false, false); } abstract static class PopupToolbar extends ActionToolbarImpl implements AnActionListener, Disposable { diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java index 6dd22e93b87c..ae711f12b18c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java @@ -80,6 +80,17 @@ public class Utils{ PresentationFactory presentationFactory, DataContext context, String place, ActionManager actionManager){ + expandActionGroup(group, list, presentationFactory, context, place, actionManager, false); + } + /** + * @param actionManager manager + * @param list this list contains expanded actions. + */ + public static void expandActionGroup(@NotNull ActionGroup group, + ArrayList list, + PresentationFactory presentationFactory, + DataContext context, + String place, ActionManager actionManager, boolean transparrentOnly){ Presentation presentation = presentationFactory.getPresentation(group); AnActionEvent e = new AnActionEvent( null, @@ -106,7 +117,11 @@ public class Utils{ presentation = presentationFactory.getPresentation(child); AnActionEvent e1 = new AnActionEvent(null, context, place, presentation, actionManager, 0); e1.setInjectedContext(child.isInInjectedContext()); - if (!doUpdate(child, e1, presentation)) continue; + + if ((transparrentOnly && child.isTransparentUpdate()) || !transparrentOnly) { + if (!doUpdate(child, e1, presentation)) continue; + } + if (!presentation.isVisible()) { // don't create invisible items in the menu continue; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java index 67f45ae98d54..c97bbd79f26f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/XDebuggerActionBase.java @@ -29,6 +29,7 @@ public abstract class XDebuggerActionBase extends AnAction { protected XDebuggerActionBase() { this(false); + setTransparentUpdate(true); } protected XDebuggerActionBase(final boolean hideDisabledInPopup) {