update menu items on app activation fix
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / actionSystem / impl / Utils.java
blob0f444fb37a8bd501412dd12d6809ee1f9ca7f5fa
1 /*
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.ide.DataManager;
19 import com.intellij.openapi.actionSystem.*;
20 import com.intellij.openapi.actionSystem.ex.ActionUtil;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.progress.ProcessCanceledException;
24 import com.intellij.openapi.project.DumbAware;
25 import com.intellij.openapi.project.DumbService;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.util.ActionCallback;
28 import com.intellij.openapi.util.SystemInfo;
29 import com.intellij.openapi.util.registry.Registry;
30 import com.intellij.openapi.wm.IdeFocusManager;
31 import org.jetbrains.annotations.NonNls;
32 import org.jetbrains.annotations.NotNull;
34 import javax.swing.*;
35 import java.awt.*;
36 import java.util.ArrayList;
38 /**
39 * @author Anton Katilin
40 * @author Vladimir Kondratyev
42 public class Utils{
43 private static final Logger LOG=Logger.getInstance("#com.intellij.openapi.actionSystem.impl.Utils");
44 @NonNls public static final String NOTHING_HERE = "Nothing here";
45 public static final AnAction EMPTY_MENU_FILLER = new AnAction(NOTHING_HERE) {
48 getTemplatePresentation().setEnabled(false);
51 @Override
52 public void actionPerformed(AnActionEvent e) {
55 @Override
56 public void update(AnActionEvent e) {
57 e.getPresentation().setEnabled(false);
58 super.update(e);
62 private Utils() {}
64 private static void handleUpdateException(AnAction action, Presentation presentation, Throwable exc) {
65 String id = ActionManager.getInstance().getId(action);
66 if (id != null) {
67 LOG.error("update failed for AnAction with ID=" + id, exc);
69 else {
70 LOG.error("update failed for ActionGroup: " + action + "[" + presentation.getText() + "]", exc);
74 /**
75 * @param actionManager manager
76 * @param list this list contains expanded actions.
78 public static void expandActionGroup(@NotNull ActionGroup group,
79 ArrayList<AnAction> list,
80 PresentationFactory presentationFactory,
81 DataContext context,
82 String place, ActionManager actionManager){
83 Presentation presentation = presentationFactory.getPresentation(group);
84 AnActionEvent e = new AnActionEvent(
85 null,
86 context,
87 place,
88 presentation,
89 actionManager,
92 if (!doUpdate(group, e, presentation)) return;
94 if(!presentation.isVisible()){ // don't process invisible groups
95 return;
97 AnAction[] children=group.getChildren(e);
98 for (int i = 0; i < children.length; i++) {
99 AnAction child = children[i];
100 if (child == null) {
101 String groupId = ActionManager.getInstance().getId(group);
102 LOG.assertTrue(false, "action is null: i=" + i + " group=" + group + " group id=" + groupId);
103 continue;
106 presentation = presentationFactory.getPresentation(child);
107 AnActionEvent e1 = new AnActionEvent(null, context, place, presentation, actionManager, 0);
108 e1.setInjectedContext(child.isInInjectedContext());
109 if (!doUpdate(child, e1, presentation)) continue;
110 if (!presentation.isVisible()) { // don't create invisible items in the menu
111 continue;
113 if (child instanceof ActionGroup) {
114 ActionGroup actionGroup = (ActionGroup)child;
115 if (actionGroup.isPopup()) { // popup menu has its own presentation
116 // disable group if it contains no visible actions
117 final boolean enabled = hasVisibleChildren(actionGroup, presentationFactory, context, place);
118 presentation.setEnabled(enabled);
119 list.add(child);
121 else {
122 expandActionGroup((ActionGroup)child, list, presentationFactory, context, place, actionManager);
125 else if (child instanceof Separator) {
126 if (!list.isEmpty() && !(list.get(list.size() - 1) instanceof Separator)) {
127 list.add(child);
130 else {
131 list.add(child);
136 // returns false if exception was thrown and handled
137 private static boolean doUpdate(final AnAction action, final AnActionEvent e, final Presentation presentation) throws ProcessCanceledException {
138 if (ApplicationManager.getApplication().isDisposed()) return false;
140 long startTime = System.currentTimeMillis();
141 final boolean result;
142 try {
143 result = !ActionUtil.performDumbAwareUpdate(action, e, false);
145 catch (ProcessCanceledException ex) {
146 throw ex;
148 catch (Throwable exc) {
149 handleUpdateException(action, presentation, exc);
150 return false;
152 long endTime = System.currentTimeMillis();
153 if (endTime - startTime > 10 && LOG.isDebugEnabled()) {
154 LOG.debug("Action " + action + ": updated in " + (endTime-startTime) + " ms");
156 return result;
159 private static boolean hasVisibleChildren(ActionGroup group, PresentationFactory factory, DataContext context, String place) {
160 AnActionEvent event = new AnActionEvent(null, context, place, factory.getPresentation(group), ActionManager.getInstance(), 0);
161 event.setInjectedContext(group.isInInjectedContext());
162 AnAction[] children = group.getChildren(event);
163 for (AnAction anAction : children) {
164 if (anAction instanceof Separator) {
165 continue;
167 final Project project = PlatformDataKeys.PROJECT.getData(context);
168 if (project != null && DumbService.getInstance(project).isDumb() && !(anAction instanceof DumbAware) && !(anAction instanceof ActionGroup)) {
169 continue;
172 LOG.assertTrue(anAction != null, "Null action found in group " + group);
174 final Presentation presentation = factory.getPresentation(anAction);
175 updateGroupChild(context, place, anAction, presentation);
176 if (anAction instanceof ActionGroup) {
177 ActionGroup childGroup = (ActionGroup)anAction;
179 // popup menu must be visible itself
180 if (childGroup.isPopup()) {
181 if (!presentation.isVisible()) {
182 continue;
186 if (hasVisibleChildren(childGroup, factory, context, place)) {
187 return true;
190 else if (presentation.isVisible()) {
191 return true;
195 return false;
198 public static void updateGroupChild(DataContext context, String place, AnAction anAction, final Presentation presentation) {
199 AnActionEvent event1 = new AnActionEvent(null, context, place, presentation, ActionManager.getInstance(), 0);
200 event1.setInjectedContext(anAction.isInInjectedContext());
201 doUpdate(anAction, event1, presentation);
205 public static void fillMenu(@NotNull final ActionGroup group,
206 final JComponent component, boolean enableMnemonics, final PresentationFactory presentationFactory, DataContext context, final String place, boolean isWindowMenu){
207 final ActionCallback menuBuilt = new ActionCallback();
209 ArrayList<AnAction> list = new ArrayList<AnAction>();
210 expandActionGroup(group, list, presentationFactory, context, place, ActionManager.getInstance());
212 final boolean fixMacScreenMenu = SystemInfo.isMacSystemMenu && isWindowMenu && Registry.is("actionSystem.mac.screenMenuNotUpdatedFix");
214 final ArrayList<Component> children = new ArrayList<Component>();
216 for (int i = 0; i < list.size(); i++) {
217 AnAction action = list.get(i);
218 if (action instanceof Separator) {
219 if (i > 0 && i < list.size() - 1) {
220 component.add(new JPopupMenu.Separator());
223 else if (action instanceof ActionGroup) {
224 ActionMenu menu = new ActionMenu(context, place, (ActionGroup)action, presentationFactory, enableMnemonics);
225 component.add(menu);
226 children.add(menu);
228 else {
229 final ActionMenuItem each =
230 new ActionMenuItem(action, presentationFactory.getPresentation(action), place, context, enableMnemonics, !fixMacScreenMenu);
231 component.add(each);
232 children.add(each);
236 if (list.isEmpty()) {
237 final ActionMenuItem each =
238 new ActionMenuItem(EMPTY_MENU_FILLER, presentationFactory.getPresentation(EMPTY_MENU_FILLER), place, context, enableMnemonics,
239 !fixMacScreenMenu);
240 component.add(each);
241 children.add(each);
244 if (fixMacScreenMenu) {
245 SwingUtilities.invokeLater(new Runnable() {
246 public void run() {
247 for (Component each : children) {
248 if (each.getParent() != null && each instanceof ActionMenuItem) {
249 ((ActionMenuItem)each).prepare();
252 menuBuilt.setDone();
255 } else {
256 menuBuilt.setDone();
260 menuBuilt.doWhenDone(new Runnable() {
261 public void run() {
262 if (IdeFocusManager.getInstance(null).isFocusBeingTransferred()) {
263 IdeFocusManager.getInstance(null).doWhenFocusSettlesDown(new Runnable() {
264 public void run() {
265 if (!component.isShowing()) return;
267 DataContext context = DataManager.getInstance().getDataContext();
268 expandActionGroup(group, new ArrayList<AnAction>(), presentationFactory, context, place, ActionManager.getInstance());
270 for (Component each : children) {
271 if (each instanceof ActionMenuItem) {
272 ((ActionMenuItem)each).updateContext(context);
273 } else if (each instanceof ActionMenu) {
274 ((ActionMenu)each).updateContext(context);