a9fe2bfea964a16a9991359403bfe69166c5926c
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / actionSystem / impl / Utils.java
bloba9fe2bfea964a16a9991359403bfe69166c5926c
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.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;
31 import javax.swing.*;
32 import java.util.ArrayList;
34 /**
35 * @author Anton Katilin
36 * @author Vladimir Kondratyev
38 public class Utils{
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);
47 @Override
48 public void actionPerformed(AnActionEvent e) {
51 @Override
52 public void update(AnActionEvent e) {
53 e.getPresentation().setEnabled(false);
54 super.update(e);
58 private Utils() {}
60 private static void handleUpdateException(AnAction action, Presentation presentation, Throwable exc) {
61 String id = ActionManager.getInstance().getId(action);
62 if (id != null) {
63 LOG.error("update failed for AnAction with ID=" + id, exc);
65 else {
66 LOG.error("update failed for ActionGroup: " + action + "[" + presentation.getText() + "]", exc);
70 /**
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,
77 DataContext context,
78 String place, ActionManager actionManager){
79 Presentation presentation = presentationFactory.getPresentation(group);
80 AnActionEvent e = new AnActionEvent(
81 null,
82 context,
83 place,
84 presentation,
85 actionManager,
88 if (!doUpdate(group, e, presentation)) return;
90 if(!presentation.isVisible()){ // don't process invisible groups
91 return;
93 AnAction[] children=group.getChildren(e);
94 for (int i = 0; i < children.length; i++) {
95 AnAction child = children[i];
96 if (child == null) {
97 String groupId = ActionManager.getInstance().getId(group);
98 LOG.assertTrue(false, "action is null: i=" + i + " group=" + group + " group id=" + groupId);
99 continue;
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
107 continue;
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);
115 list.add(child);
117 else {
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)) {
123 list.add(child);
126 else {
127 list.add(child);
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;
138 try {
139 result = !ActionUtil.performDumbAwareUpdate(action, e, false);
141 catch (ProcessCanceledException ex) {
142 throw ex;
144 catch (Throwable exc) {
145 handleUpdateException(action, presentation, exc);
146 return false;
148 long endTime = System.currentTimeMillis();
149 if (endTime - startTime > 10 && LOG.isDebugEnabled()) {
150 LOG.debug("Action " + action + ": updated in " + (endTime-startTime) + " ms");
152 return result;
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) {
161 continue;
163 final Project project = PlatformDataKeys.PROJECT.getData(context);
164 if (project != null && DumbService.getInstance(project).isDumb() && !(anAction instanceof DumbAware) && !(anAction instanceof ActionGroup)) {
165 continue;
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()) {
178 continue;
182 if (hasVisibleChildren(childGroup, factory, context, place)) {
183 return true;
186 else if (presentation.isVisible()) {
187 return true;
191 return false;
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));
219 else {
220 final ActionMenuItem each =
221 new ActionMenuItem(action, presentationFactory.getPresentation(action), place, context, enableMnemonics, !fixMacScreenMenu);
222 component.add(each);
223 menuItems.add(each);
227 if (list.isEmpty()) {
228 final ActionMenuItem each =
229 new ActionMenuItem(EMPTY_MENU_FILLER, presentationFactory.getPresentation(EMPTY_MENU_FILLER), place, context, enableMnemonics,
230 !fixMacScreenMenu);
231 component.add(each);
232 menuItems.add(each);
235 if (fixMacScreenMenu) {
236 SwingUtilities.invokeLater(new Runnable() {
237 public void run() {
238 for (ActionMenuItem each : menuItems) {
239 if (each.getParent() != null) {
240 each.prepare();