2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.actionSystem
.impl
;
18 import com
.intellij
.openapi
.actionSystem
.*;
19 import com
.intellij
.openapi
.actionSystem
.ex
.ActionUtil
;
20 import com
.intellij
.openapi
.application
.ApplicationManager
;
21 import com
.intellij
.openapi
.diagnostic
.Logger
;
22 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
23 import com
.intellij
.openapi
.project
.DumbAware
;
24 import com
.intellij
.openapi
.project
.DumbService
;
25 import com
.intellij
.openapi
.project
.Project
;
26 import com
.intellij
.openapi
.util
.SystemInfo
;
27 import com
.intellij
.openapi
.util
.registry
.Registry
;
28 import org
.jetbrains
.annotations
.NonNls
;
29 import org
.jetbrains
.annotations
.NotNull
;
32 import java
.util
.ArrayList
;
35 * @author Anton Katilin
36 * @author Vladimir Kondratyev
39 private static final Logger LOG
=Logger
.getInstance("#com.intellij.openapi.actionSystem.impl.Utils");
40 @NonNls public static final String NOTHING_HERE
= "Nothing here";
41 public static final AnAction EMPTY_MENU_FILLER
= new AnAction(NOTHING_HERE
) {
44 getTemplatePresentation().setEnabled(false);
48 public void actionPerformed(AnActionEvent e
) {
52 public void update(AnActionEvent e
) {
53 e
.getPresentation().setEnabled(false);
60 private static void handleUpdateException(AnAction action
, Presentation presentation
, Throwable exc
) {
61 String id
= ActionManager
.getInstance().getId(action
);
63 LOG
.error("update failed for AnAction with ID=" + id
, exc
);
66 LOG
.error("update failed for ActionGroup: " + action
+ "[" + presentation
.getText() + "]", exc
);
71 * @param actionManager manager
72 * @param list this list contains expanded actions.
74 public static void expandActionGroup(@NotNull ActionGroup group
,
75 ArrayList
<AnAction
> list
,
76 PresentationFactory presentationFactory
,
78 String place
, ActionManager actionManager
){
79 Presentation presentation
= presentationFactory
.getPresentation(group
);
80 AnActionEvent e
= new AnActionEvent(
88 if (!doUpdate(group
, e
, presentation
)) return;
90 if(!presentation
.isVisible()){ // don't process invisible groups
93 AnAction
[] children
=group
.getChildren(e
);
94 for (int i
= 0; i
< children
.length
; i
++) {
95 AnAction child
= children
[i
];
97 String groupId
= ActionManager
.getInstance().getId(group
);
98 LOG
.assertTrue(false, "action is null: i=" + i
+ " group=" + group
+ " group id=" + groupId
);
102 presentation
= presentationFactory
.getPresentation(child
);
103 AnActionEvent e1
= new AnActionEvent(null, context
, place
, presentation
, actionManager
, 0);
104 e1
.setInjectedContext(child
.isInInjectedContext());
105 if (!doUpdate(child
, e1
, presentation
)) continue;
106 if (!presentation
.isVisible()) { // don't create invisible items in the menu
109 if (child
instanceof ActionGroup
) {
110 ActionGroup actionGroup
= (ActionGroup
)child
;
111 if (actionGroup
.isPopup()) { // popup menu has its own presentation
112 // disable group if it contains no visible actions
113 final boolean enabled
= hasVisibleChildren(actionGroup
, presentationFactory
, context
, place
);
114 presentation
.setEnabled(enabled
);
118 expandActionGroup((ActionGroup
)child
, list
, presentationFactory
, context
, place
, actionManager
);
121 else if (child
instanceof Separator
) {
122 if (!list
.isEmpty() && !(list
.get(list
.size() - 1) instanceof Separator
)) {
132 // returns false if exception was thrown and handled
133 private static boolean doUpdate(final AnAction action
, final AnActionEvent e
, final Presentation presentation
) throws ProcessCanceledException
{
134 if (ApplicationManager
.getApplication().isDisposed()) return false;
136 long startTime
= System
.currentTimeMillis();
137 final boolean result
;
139 result
= !ActionUtil
.performDumbAwareUpdate(action
, e
, false);
141 catch (ProcessCanceledException ex
) {
144 catch (Throwable exc
) {
145 handleUpdateException(action
, presentation
, exc
);
148 long endTime
= System
.currentTimeMillis();
149 if (endTime
- startTime
> 10 && LOG
.isDebugEnabled()) {
150 LOG
.debug("Action " + action
+ ": updated in " + (endTime
-startTime
) + " ms");
155 private static boolean hasVisibleChildren(ActionGroup group
, PresentationFactory factory
, DataContext context
, String place
) {
156 AnActionEvent event
= new AnActionEvent(null, context
, place
, factory
.getPresentation(group
), ActionManager
.getInstance(), 0);
157 event
.setInjectedContext(group
.isInInjectedContext());
158 AnAction
[] children
= group
.getChildren(event
);
159 for (AnAction anAction
: children
) {
160 if (anAction
instanceof Separator
) {
163 final Project project
= PlatformDataKeys
.PROJECT
.getData(context
);
164 if (project
!= null && DumbService
.getInstance(project
).isDumb() && !(anAction
instanceof DumbAware
) && !(anAction
instanceof ActionGroup
)) {
168 LOG
.assertTrue(anAction
!= null, "Null action found in group " + group
);
170 final Presentation presentation
= factory
.getPresentation(anAction
);
171 updateGroupChild(context
, place
, anAction
, presentation
);
172 if (anAction
instanceof ActionGroup
) {
173 ActionGroup childGroup
= (ActionGroup
)anAction
;
175 // popup menu must be visible itself
176 if (childGroup
.isPopup()) {
177 if (!presentation
.isVisible()) {
182 if (hasVisibleChildren(childGroup
, factory
, context
, place
)) {
186 else if (presentation
.isVisible()) {
194 public static void updateGroupChild(DataContext context
, String place
, AnAction anAction
, final Presentation presentation
) {
195 AnActionEvent event1
= new AnActionEvent(null, context
, place
, presentation
, ActionManager
.getInstance(), 0);
196 event1
.setInjectedContext(anAction
.isInInjectedContext());
197 doUpdate(anAction
, event1
, presentation
);
201 public static void fillMenu(@NotNull ActionGroup group
,JComponent component
, boolean enableMnemonics
, PresentationFactory presentationFactory
, DataContext context
, String place
, boolean isWindowMenu
){
202 ArrayList
<AnAction
> list
= new ArrayList
<AnAction
>();
203 expandActionGroup(group
, list
, presentationFactory
, context
, place
, ActionManager
.getInstance());
205 final boolean fixMacScreenMenu
= SystemInfo
.isMacSystemMenu
&& isWindowMenu
&& Registry
.is("actionSystem.mac.screenMenuNotUpdatedFix");
207 final ArrayList
<ActionMenuItem
> menuItems
= new ArrayList
<ActionMenuItem
>();
209 for (int i
= 0; i
< list
.size(); i
++) {
210 AnAction action
= list
.get(i
);
211 if (action
instanceof Separator
) {
212 if (i
> 0 && i
< list
.size() - 1) {
213 component
.add(new JPopupMenu
.Separator());
216 else if (action
instanceof ActionGroup
) {
217 component
.add(new ActionMenu(context
, place
, (ActionGroup
)action
, presentationFactory
, enableMnemonics
));
220 final ActionMenuItem each
=
221 new ActionMenuItem(action
, presentationFactory
.getPresentation(action
), place
, context
, enableMnemonics
, !fixMacScreenMenu
);
227 if (list
.isEmpty()) {
228 final ActionMenuItem each
=
229 new ActionMenuItem(EMPTY_MENU_FILLER
, presentationFactory
.getPresentation(EMPTY_MENU_FILLER
), place
, context
, enableMnemonics
,
235 if (fixMacScreenMenu
) {
236 SwingUtilities
.invokeLater(new Runnable() {
238 for (ActionMenuItem each
: menuItems
) {
239 if (each
.getParent() != null) {