fixed [RUBY-5133] Keep last rake search
[fedora-idea.git] / platform / lang-impl / src / com / intellij / ide / util / gotoByName / ChooseByNamePopup.java
blob7549872216e8939ea4e3ed6052d99c5fa93063cd
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.
17 package com.intellij.ide.util.gotoByName;
19 import com.intellij.featureStatistics.FeatureUsageTracker;
20 import com.intellij.openapi.application.ModalityState;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.util.Key;
23 import com.intellij.openapi.util.text.StringUtil;
24 import com.intellij.openapi.wm.ex.LayoutFocusTraversalPolicyExt;
25 import com.intellij.psi.PsiElement;
26 import com.intellij.psi.statistics.StatisticsInfo;
27 import com.intellij.psi.statistics.StatisticsManager;
28 import org.jetbrains.annotations.Nullable;
30 import javax.swing.*;
31 import java.awt.*;
32 import java.util.List;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
36 public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent{
37 private static final Key<ChooseByNamePopup> CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY = new Key<ChooseByNamePopup>("ChooseByNamePopup");
38 private Component myOldFocusOwner = null;
40 private ChooseByNamePopup(final Project project, final ChooseByNameModel model, final ChooseByNamePopup oldPopup,
41 final PsiElement context, @Nullable final String predefinedText) {
42 super(project, model, oldPopup != null ? oldPopup.getEnteredText() : predefinedText, context);
43 if (oldPopup != null) { //inherit old focus owner
44 myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent;
48 public String getEnteredText() {
49 return myTextField.getText();
52 protected void initUI(final Callback callback, final ModalityState modalityState, boolean allowMultipleSelection) {
53 super.initUI(callback, modalityState, allowMultipleSelection);
54 //LaterInvocator.enterModal(myTextFieldPanel);
55 if (myInitialText != null) {
56 rebuildList(0, 0, null, ModalityState.current());
58 if (myOldFocusOwner != null){
59 myPreviouslyFocusedComponent = myOldFocusOwner;
60 myOldFocusOwner = null;
64 protected boolean isCheckboxVisible() {
65 return true;
68 protected boolean isShowListForEmptyPattern(){
69 return false;
72 protected boolean isCloseByFocusLost(){
73 return true;
76 protected void showList() {
77 final JLayeredPane layeredPane = myTextField.getRootPane().getLayeredPane();
78 final Rectangle bounds = myTextFieldPanel.getBounds();
79 bounds.y += myTextFieldPanel.getHeight();
80 final Dimension preferredScrollPaneSize = myListScrollPane.getPreferredSize();
81 preferredScrollPaneSize.width = Math.max(myTextFieldPanel.getWidth(), preferredScrollPaneSize.width);
82 if (bounds.y + preferredScrollPaneSize.height > layeredPane.getHeight()){ // clip scroll pane
83 preferredScrollPaneSize.height = layeredPane.getHeight() - bounds.y;
86 if (preferredScrollPaneSize.width > layeredPane.getWidth() - bounds.x) {
87 bounds.x = layeredPane.getX() + Math.max(1, layeredPane.getWidth() - preferredScrollPaneSize.width);
88 if (preferredScrollPaneSize.width > layeredPane.getWidth() - bounds.x) {
89 preferredScrollPaneSize.width = layeredPane.getWidth() - bounds.x;
90 final JScrollBar horizontalScrollBar = myListScrollPane.getHorizontalScrollBar();
91 if (horizontalScrollBar != null){
92 preferredScrollPaneSize.height += horizontalScrollBar.getPreferredSize().getHeight();
97 Rectangle prefferedBounds = new Rectangle(bounds.x, bounds.y, preferredScrollPaneSize.width, preferredScrollPaneSize.height);
99 if (myListScrollPane.isVisible()) {
100 myListScrollPane.setBounds(prefferedBounds);
103 layeredPane.add(myListScrollPane, Integer.valueOf(600));
104 layeredPane.moveToFront(myListScrollPane);
105 myListScrollPane.validate();
106 myListScrollPane.setVisible(true);
109 protected void hideList() {
110 if (myListScrollPane.isVisible()){
111 myListScrollPane.setVisible(false);
115 protected void close(final boolean isOk) {
116 if (myDisposedFlag){
117 return;
120 if (isOk){
121 myModel.saveInitialCheckBoxState(myCheckBox.isSelected());
123 final List<Object> chosenElements = getChosenElements();
124 if (chosenElements != null) {
125 for (Object element : chosenElements) {
126 myActionListener.elementChosen(element);
127 String text = myModel.getFullName(element);
128 if (text != null) {
129 StatisticsManager.getInstance().incUseCount(new StatisticsInfo(statisticsContext(), text));
132 } else {
133 return;
136 if (!chosenElements.isEmpty()){
137 final String enteredText = getEnteredText();
138 if (enteredText.indexOf('*') >= 0) {
139 FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.wildcards");
141 else {
142 for (Object element : chosenElements) {
143 final String name = myModel.getElementName(element);
144 if (name != null) {
145 if (!StringUtil.startsWithIgnoreCase(name, enteredText)) {
146 FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.camelprefix");
147 break;
153 else{
154 return;
158 myDisposedFlag = true;
159 myAlarm.cancelAllRequests();
160 myProject.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, null);
162 //LaterInvocator.leaveModal(myTextFieldPanel);
164 cleanupUI();
165 myActionListener.onClose ();
168 private void cleanupUI() {
169 JLayeredPane layeredPane = null;
170 try {
171 // check if the currently focused component was changed already, so we could leave focus intact
172 final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
173 if (owner != null && SwingUtilities.isDescendingFrom(owner, myTextField)) {
174 // Return focus back to the previous focused component if we need to do it and
175 // previous focused component is showing.
176 if (
177 myPreviouslyFocusedComponent instanceof JComponent &&
178 myPreviouslyFocusedComponent.isShowing()
180 final JComponent _component = (JComponent)myPreviouslyFocusedComponent;
181 LayoutFocusTraversalPolicyExt.setOverridenDefaultComponent(_component);
183 if (myPreviouslyFocusedComponent != null) {
184 myPreviouslyFocusedComponent.requestFocus();
188 final JRootPane rootPane = myTextFieldPanel.getRootPane();
189 if (rootPane != null) {
190 layeredPane = rootPane.getLayeredPane();
191 layeredPane.remove(myListScrollPane);
192 layeredPane.remove(myTextFieldPanel);
195 finally {
196 LayoutFocusTraversalPolicyExt.setOverridenDefaultComponent(null);
199 if (layeredPane != null) {
200 layeredPane.validate();
201 layeredPane.repaint();
205 public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context) {
206 return createPopup(project, model, context, null);
208 public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context,
209 @Nullable final String predefinedText) {
210 final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
211 if (oldPopup != null) {
212 oldPopup.close(false);
214 ChooseByNamePopup newPopup = new ChooseByNamePopup(project, model, oldPopup, context, predefinedText);
216 project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup);
217 return newPopup;
220 private static final Pattern patternToDetectLinesAndColumns = Pattern.compile("(.*?)(?:\\:|@|,|#)(\\d+)?(?:(?:\\D)(\\d+)?)?");
222 public String getNamePattern(String pattern) {
223 if (pattern.indexOf(':') != -1 ||
224 pattern.indexOf(',') != -1 ||
225 pattern.indexOf(';') != -1 ||
226 pattern.indexOf('#') != -1 ||
227 pattern.indexOf('@') != -1) { // quick test if reg exp should be used
228 final Matcher matcher = patternToDetectLinesAndColumns.matcher(pattern);
229 if (matcher.matches()) {
230 pattern = matcher.group(1);
234 return super.getNamePattern(pattern);
237 public int getLinePosition() {
238 return getLineOrColumn(true);
241 private int getLineOrColumn(final boolean line) {
242 final Matcher matcher = patternToDetectLinesAndColumns.matcher(getEnteredText());
243 if (matcher.matches()) {
244 final int groupNumber = line ? 2:3;
245 try {
246 if(groupNumber <= matcher.groupCount()) {
247 final String group = matcher.group(groupNumber);
248 if (group != null) return Integer.parseInt(group) - 1;
250 if (!line && getLineOrColumn(true) != -1) return 0;
252 catch (NumberFormatException ignored) {}
255 return -1;
258 public int getColumnPosition() {
259 return getLineOrColumn(false);