02dd80ef1a34a675446bdd6b6721a283bc6b223d
[fedora-idea.git] / platform / lang-impl / src / com / intellij / ide / util / gotoByName / ChooseByNamePopup.java
blob02dd80ef1a34a675446bdd6b6721a283bc6b223d
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;
29 import javax.swing.*;
30 import java.awt.*;
31 import java.util.List;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
35 public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent{
36 private static final Key<ChooseByNamePopup> CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY = new Key<ChooseByNamePopup>("ChooseByNamePopup");
37 private Component myOldFocusOwner = null;
38 private ChooseByNamePopup(final Project project, final ChooseByNameModel model, final ChooseByNamePopup oldPopup, final PsiElement context) {
39 super(project, model, oldPopup != null ? oldPopup.myTextField.getText() : null, context);
40 if (oldPopup != null) { //inherit old focus owner
41 myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent;
45 protected void initUI(final Callback callback, final ModalityState modalityState, boolean allowMultipleSelection) {
46 super.initUI(callback, modalityState, allowMultipleSelection);
47 //LaterInvocator.enterModal(myTextFieldPanel);
48 if (myInitialText != null) {
49 rebuildList(0, 0, null, ModalityState.current());
51 if (myOldFocusOwner != null){
52 myPreviouslyFocusedComponent = myOldFocusOwner;
53 myOldFocusOwner = null;
57 protected boolean isCheckboxVisible() {
58 return true;
61 protected boolean isShowListForEmptyPattern(){
62 return false;
65 protected boolean isCloseByFocusLost(){
66 return true;
69 protected void showList() {
70 final JLayeredPane layeredPane = myTextField.getRootPane().getLayeredPane();
71 final Rectangle bounds = myTextFieldPanel.getBounds();
72 bounds.y += myTextFieldPanel.getHeight();
73 final Dimension preferredScrollPaneSize = myListScrollPane.getPreferredSize();
74 preferredScrollPaneSize.width = Math.max(myTextFieldPanel.getWidth(), preferredScrollPaneSize.width);
75 if (bounds.y + preferredScrollPaneSize.height > layeredPane.getHeight()){ // clip scroll pane
76 preferredScrollPaneSize.height = layeredPane.getHeight() - bounds.y;
79 if (preferredScrollPaneSize.width > layeredPane.getWidth() - bounds.x) {
80 bounds.x = layeredPane.getX() + Math.max(1, layeredPane.getWidth() - preferredScrollPaneSize.width);
81 if (preferredScrollPaneSize.width > layeredPane.getWidth() - bounds.x) {
82 preferredScrollPaneSize.width = layeredPane.getWidth() - bounds.x;
83 final JScrollBar horizontalScrollBar = myListScrollPane.getHorizontalScrollBar();
84 if (horizontalScrollBar != null){
85 preferredScrollPaneSize.height += horizontalScrollBar.getPreferredSize().getHeight();
90 Rectangle prefferedBounds = new Rectangle(bounds.x, bounds.y, preferredScrollPaneSize.width, preferredScrollPaneSize.height);
92 if (myListScrollPane.isVisible()) {
93 myListScrollPane.setBounds(prefferedBounds);
96 layeredPane.add(myListScrollPane, Integer.valueOf(600));
97 layeredPane.moveToFront(myListScrollPane);
98 myListScrollPane.validate();
99 myListScrollPane.setVisible(true);
102 protected void hideList() {
103 if (myListScrollPane.isVisible()){
104 myListScrollPane.setVisible(false);
108 protected void close(final boolean isOk) {
109 if (myDisposedFlag){
110 return;
113 if (isOk){
114 myModel.saveInitialCheckBoxState(myCheckBox.isSelected());
116 final List<Object> chosenElements = getChosenElements();
117 if (chosenElements != null) {
118 for (Object element : chosenElements) {
119 myActionListener.elementChosen(element);
120 String text = myModel.getFullName(element);
121 if (text != null) {
122 StatisticsManager.getInstance().incUseCount(new StatisticsInfo(statisticsContext(), text));
125 } else {
126 return;
129 if (!chosenElements.isEmpty()){
130 final String enteredText = myTextField.getText();
131 if (enteredText.indexOf('*') >= 0) {
132 FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.wildcards");
134 else {
135 for (Object element : chosenElements) {
136 final String name = myModel.getElementName(element);
137 if (name != null) {
138 if (!StringUtil.startsWithIgnoreCase(name, enteredText)) {
139 FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.camelprefix");
140 break;
146 else{
147 return;
151 myDisposedFlag = true;
152 myAlarm.cancelAllRequests();
153 myProject.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, null);
155 //LaterInvocator.leaveModal(myTextFieldPanel);
157 cleanupUI();
158 myActionListener.onClose ();
161 private void cleanupUI() {
162 JLayeredPane layeredPane = null;
163 try {
164 // check if the currently focused component was changed already, so we could leave focus intact
165 final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
166 if (owner != null && SwingUtilities.isDescendingFrom(owner, myTextField)) {
167 // Return focus back to the previous focused component if we need to do it and
168 // previous focused component is showing.
169 if (
170 myPreviouslyFocusedComponent instanceof JComponent &&
171 myPreviouslyFocusedComponent.isShowing()
173 final JComponent _component = (JComponent)myPreviouslyFocusedComponent;
174 LayoutFocusTraversalPolicyExt.setOverridenDefaultComponent(_component);
176 if (myPreviouslyFocusedComponent != null) {
177 myPreviouslyFocusedComponent.requestFocus();
181 final JRootPane rootPane = myTextFieldPanel.getRootPane();
182 if (rootPane != null) {
183 layeredPane = rootPane.getLayeredPane();
184 layeredPane.remove(myListScrollPane);
185 layeredPane.remove(myTextFieldPanel);
188 finally {
189 LayoutFocusTraversalPolicyExt.setOverridenDefaultComponent(null);
192 if (layeredPane != null) {
193 layeredPane.validate();
194 layeredPane.repaint();
198 public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context) {
199 final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
200 if (oldPopup != null) {
201 oldPopup.close(false);
203 ChooseByNamePopup newPopup = new ChooseByNamePopup(project, model, oldPopup, context);
205 project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup);
206 return newPopup;
209 private static final Pattern patternToDetectLinesAndColumns = Pattern.compile("(.*?)(?:\\:|@|,|#)(\\d+)?(?:(?:\\D)(\\d+)?)?");
211 public String getNamePattern(String pattern) {
212 if (pattern.indexOf(':') != -1 ||
213 pattern.indexOf(',') != -1 ||
214 pattern.indexOf(';') != -1 ||
215 pattern.indexOf('#') != -1 ||
216 pattern.indexOf('@') != -1) { // quick test if reg exp should be used
217 final Matcher matcher = patternToDetectLinesAndColumns.matcher(pattern);
218 if (matcher.matches()) {
219 pattern = matcher.group(1);
223 return super.getNamePattern(pattern);
226 public int getLinePosition() {
227 return getLineOrColumn(true);
230 private int getLineOrColumn(final boolean line) {
231 final Matcher matcher = patternToDetectLinesAndColumns.matcher(myTextField.getText());
232 if (matcher.matches()) {
233 final int groupNumber = line ? 2:3;
234 try {
235 if(groupNumber <= matcher.groupCount()) {
236 final String group = matcher.group(groupNumber);
237 if (group != null) return Integer.parseInt(group) - 1;
239 if (!line && getLineOrColumn(true) != -1) return 0;
241 catch (NumberFormatException ignored) {}
244 return -1;
247 public int getColumnPosition() {
248 return getLineOrColumn(false);