API for custom matchers in ChooseByName popup
[fedora-idea.git] / lang-impl / src / com / intellij / ide / util / gotoByName / GotoActionModel.java
blob90513e0d9d977021f88ccd938fa9d59dfac5e871
1 package com.intellij.ide.util.gotoByName;
3 import com.intellij.ide.DataManager;
4 import com.intellij.ide.IdeBundle;
5 import com.intellij.ide.util.PropertiesComponent;
6 import com.intellij.openapi.actionSystem.*;
7 import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
8 import com.intellij.openapi.keymap.KeymapManager;
9 import com.intellij.openapi.keymap.KeymapUtil;
10 import com.intellij.openapi.project.Project;
11 import com.intellij.openapi.util.Comparing;
12 import com.intellij.ui.LayeredIcon;
13 import com.intellij.util.ui.EmptyIcon;
14 import com.intellij.util.ui.UIUtil;
15 import com.intellij.util.ArrayUtil;
16 import org.apache.oro.text.regex.*;
17 import org.jetbrains.annotations.NonNls;
18 import org.jetbrains.annotations.NotNull;
19 import org.jetbrains.annotations.Nullable;
21 import javax.swing.*;
22 import java.awt.*;
23 import java.util.*;
25 public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel {
26 private final Project myProject;
27 private final Component myContextComponent;
29 private final ActionManager myActionManager = ActionManager.getInstance();
31 private static final EmptyIcon EMPTY_ICON = new EmptyIcon(18, 18);
33 private String myPattern;
35 private Pattern myCompiledPattern;
36 private final PatternMatcher myMatcher = new Perl5Matcher();
39 public GotoActionModel(Project project, final Component component) {
40 myProject = project;
41 myContextComponent = component;
44 public String getPromptText() {
45 return IdeBundle.message("prompt.gotoaction.enter.action");
48 public String getCheckBoxName() {
49 return IdeBundle.message("checkbox.other.included");
52 public char getCheckBoxMnemonic() {
53 return 'd';
56 public String getNotInMessage() {
57 return IdeBundle.message("label.no.menu.actions.found");
60 public String getNotFoundMessage() {
61 return IdeBundle.message("label.no.actions.found");
64 public boolean loadInitialCheckBoxState() {
65 PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(myProject);
66 return propertiesComponent.isTrueValue("GoToAction.allIncluded");
69 public void saveInitialCheckBoxState(boolean state) {
70 PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(myProject);
71 propertiesComponent.setValue("GoToAction.allIncluded", Boolean.toString(state));
74 public ListCellRenderer getListCellRenderer() {
75 return new DefaultListCellRenderer() {
77 public Component getListCellRendererComponent(final JList list,
78 final Object value,
79 final int index, final boolean isSelected, final boolean cellHasFocus) {
80 final JPanel panel = new JPanel(new BorderLayout());
81 panel.setOpaque(true);
82 final Color bg = isSelected ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground();
83 panel.setBackground(bg);
86 if (value instanceof Map.Entry) {
88 final Map.Entry actionWithParentGroup = (Map.Entry)value;
90 final AnAction anAction = (AnAction)actionWithParentGroup.getKey();
91 final Presentation templatePresentation = anAction.getTemplatePresentation();
92 final Icon icon = templatePresentation.getIcon();
93 final LayeredIcon layeredIcon = new LayeredIcon(2);
94 layeredIcon.setIcon(EMPTY_ICON, 0);
95 if (icon != null && icon.getIconWidth() <= EMPTY_ICON.getIconWidth() && icon.getIconHeight() <= EMPTY_ICON.getIconHeight()) {
96 layeredIcon.setIcon(icon, 1, (- icon.getIconWidth() + EMPTY_ICON.getIconWidth())/2, (EMPTY_ICON.getIconHeight() - icon.getIconHeight())/2);
99 final Presentation presentation = new Presentation();
101 final AnActionEvent event = new AnActionEvent(null, DataManager.getInstance().getDataContext(myContextComponent),
102 ActionPlaces.UNKNOWN, presentation, ActionManager.getInstance(),
104 anAction.beforeActionPerformedUpdate(event);
105 anAction.update(event);
107 final Color fg = isSelected ? UIUtil.getListSelectionForeground() :
108 presentation.isEnabled() && presentation.isVisible() ? UIUtil.getListForeground() : UIUtil.getInactiveTextColor();
110 final Shortcut[] shortcutSet = KeymapManager.getInstance().getActiveKeymap().getShortcuts(myActionManager.getId(anAction));
111 final String actionPresentation = templatePresentation.getText() + (shortcutSet != null && shortcutSet.length > 0
112 ? " (" + KeymapUtil.getShortcutText(shortcutSet[0]) + ")"
113 : "");
114 final JLabel actionLabel = new JLabel(actionPresentation, layeredIcon, SwingConstants.LEFT);
115 actionLabel.setBackground(bg);
116 actionLabel.setForeground(fg);
118 panel.add(actionLabel, BorderLayout.WEST);
120 final String groupName = (String)actionWithParentGroup.getValue();
121 if (groupName != null) {
122 final JLabel groupLabel = new JLabel(groupName);
123 groupLabel.setBackground(bg);
124 groupLabel.setForeground(fg);
125 panel.add(groupLabel, BorderLayout.EAST);
128 return panel;
133 public String[] getNames(boolean checkBoxState) {
134 final ArrayList<String> result = new ArrayList<String>();
135 collectActionIds(result, (ActionGroup)myActionManager.getActionOrStub(IdeActions.GROUP_MAIN_MENU));
136 if (checkBoxState) {
137 final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
138 for (String id : ids) {
139 final AnAction anAction = myActionManager.getAction(id);
140 if (!(anAction instanceof ActionGroup)) {
141 result.add(id);
145 return ArrayUtil.toStringArray(result);
148 private void collectActionIds(Collection<String> result, ActionGroup group){
149 final AnAction[] actions = group.getChildren(null);
150 for (AnAction action : actions) {
151 if (action instanceof ActionGroup) {
152 collectActionIds(result, (ActionGroup)action);
153 } else {
154 result.add(myActionManager.getId(action));
159 public Object[] getElementsByName(final String id, final boolean checkBoxState, final String pattern) {
160 final HashMap<AnAction, String> map = new HashMap<AnAction, String>();
161 final ActionGroup mainMenu = (ActionGroup)myActionManager.getActionOrStub(IdeActions.GROUP_MAIN_MENU);
162 collectActions(id, map, mainMenu, mainMenu.getTemplatePresentation().getText());
163 if (checkBoxState) {
164 final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
165 for (AnAction action : map.keySet()) { //do not add already included actions
166 ids.remove(myActionManager.getId(action));
168 if (ids.contains(id)) {
169 final AnAction anAction = myActionManager.getAction(id);
170 if (!(anAction instanceof ActionGroup)) {
171 map.put(anAction, null);
175 return map.entrySet().toArray(new Map.Entry[map.size()]);
178 private void collectActions(String id, Map<AnAction, String> result, ActionGroup group, final String containingGroupName){
179 final AnAction[] actions = group.getChildren(null);
180 for (AnAction action : actions) {
181 if (action instanceof ActionGroup) {
182 final ActionGroup actionGroup = (ActionGroup)action;
183 final String groupName = actionGroup.getTemplatePresentation().getText();
184 collectActions(id, result, actionGroup, groupName != null ? groupName : containingGroupName);
185 } else if (myActionManager.getId(action) == id) {
186 final String groupName = group.getTemplatePresentation().getText();
187 result.put(action, groupName != null && groupName.length() > 0 ? groupName : containingGroupName);
192 @Nullable
193 public String getFullName(final Object element) {
194 return getElementName(element);
197 @NotNull
198 public String[] getSeparators() {
199 return ArrayUtil.EMPTY_STRING_ARRAY;
202 public String getElementName(final Object element) {
203 if (!(element instanceof Map.Entry)) return null;
204 return ((AnAction)((Map.Entry)element).getKey()).getTemplatePresentation().getText();
207 public boolean matches(@NotNull final String name, @NotNull final String pattern) {
208 final AnAction anAction = myActionManager.getAction(name);
209 if (!(anAction instanceof ActionGroup)) {
210 final Presentation presentation = anAction.getTemplatePresentation();
211 final String text = presentation.getText();
212 final String description = presentation.getDescription();
213 final Pattern compiledPattern = getPattern(pattern);
214 if ((text != null && myMatcher.matches(text, compiledPattern)) ||
215 (description != null && myMatcher.matches(description, compiledPattern))) {
216 return true;
219 return false;
222 @NotNull
223 private Pattern getPattern(String pattern) {
224 if (!Comparing.strEqual(pattern, myPattern)) {
225 myCompiledPattern = null;
226 myPattern = pattern;
228 if (myCompiledPattern == null) {
229 boolean allowToLower = true;
230 final int eol = pattern.indexOf('\n');
231 if (eol != -1) {
232 pattern = pattern.substring(0, eol);
234 if (pattern.length() >= 80) {
235 pattern = pattern.substring(0, 80);
238 final @NonNls StringBuffer buffer = new StringBuffer();
240 if (containsOnlyUppercaseLetters(pattern)) {
241 allowToLower = false;
244 if (allowToLower) {
245 buffer.append(".*");
248 boolean firstIdentifierLetter = true;
249 for (int i = 0; i < pattern.length(); i++) {
250 final char c = pattern.charAt(i);
251 if (Character.isLetterOrDigit(c)) {
252 // This logic allows to use uppercase letters only to catch the name like PDM for PsiDocumentManager
253 if (Character.isUpperCase(c) || Character.isDigit(c)) {
255 if (!firstIdentifierLetter) {
256 buffer.append("[^A-Z]*");
259 buffer.append("[");
260 buffer.append(c);
261 if (allowToLower || i == 0) {
262 buffer.append('|');
263 buffer.append(Character.toLowerCase(c));
265 buffer.append("]");
267 else if (Character.isLowerCase(c)) {
268 buffer.append('[');
269 buffer.append(c);
270 buffer.append('|');
271 buffer.append(Character.toUpperCase(c));
272 buffer.append(']');
274 else {
275 buffer.append(c);
278 firstIdentifierLetter = false;
280 else if (c == '*') {
281 buffer.append(".*");
282 firstIdentifierLetter = true;
284 else if (c == '.') {
285 buffer.append("\\.");
286 firstIdentifierLetter = true;
288 else if (c == ' ') {
289 buffer.append("[^A-Z]*\\ ");
290 firstIdentifierLetter = true;
292 else {
293 firstIdentifierLetter = true;
294 // for standard RegExp engine
295 // buffer.append("\\u");
296 // buffer.append(Integer.toHexString(c + 0x20000).substring(1));
298 // for OROMATCHER RegExp engine
299 buffer.append("\\x");
300 buffer.append(Integer.toHexString(c + 0x20000).substring(3));
304 buffer.append(".*");
307 try {
308 myCompiledPattern = new Perl5Compiler().compile(buffer.toString());
310 catch (MalformedPatternException e) {
311 //do nothing
315 return myCompiledPattern;
318 private static boolean containsOnlyUppercaseLetters(String s) {
319 for (int i = 0; i < s.length(); i++) {
320 char c = s.charAt(i);
321 if (c != '*' && c != ' ' && !Character.isUpperCase(c)) return false;
323 return true;