6f19f34de5f2aba8eacaa805aba756e639954edb
[fedora-idea.git] / platform / lang-impl / src / com / intellij / ide / util / gotoByName / ChooseByNamePopup.java
blob6f19f34de5f2aba8eacaa805aba756e639954edb
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.myTextField.getText() : predefinedText, context);
43 if (oldPopup != null) { //inherit old focus owner
44 myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent;
48 protected void initUI(final Callback callback, final ModalityState modalityState, boolean allowMultipleSelection) {
49 super.initUI(callback, modalityState, allowMultipleSelection);
50 //LaterInvocator.enterModal(myTextFieldPanel);
51 if (myInitialText != null) {
52 rebuildList(0, 0, null, ModalityState.current());
54 if (myOldFocusOwner != null){
55 myPreviouslyFocusedComponent = myOldFocusOwner;
56 myOldFocusOwner = null;
60 protected boolean isCheckboxVisible() {
61 return true;
64 protected boolean isShowListForEmptyPattern(){
65 return false;
68 protected boolean isCloseByFocusLost(){
69 return true;
72 protected void showList() {
73 final JLayeredPane layeredPane = myTextField.getRootPane().getLayeredPane();
74 final Rectangle bounds = myTextFieldPanel.getBounds();
75 bounds.y += myTextFieldPanel.getHeight();
76 final Dimension preferredScrollPaneSize = myListScrollPane.getPreferredSize();
77 preferredScrollPaneSize.width = Math.max(myTextFieldPanel.getWidth(), preferredScrollPaneSize.width);
78 if (bounds.y + preferredScrollPaneSize.height > layeredPane.getHeight()){ // clip scroll pane
79 preferredScrollPaneSize.height = layeredPane.getHeight() - bounds.y;
82 if (preferredScrollPaneSize.width > layeredPane.getWidth() - bounds.x) {
83 bounds.x = layeredPane.getX() + Math.max(1, layeredPane.getWidth() - preferredScrollPaneSize.width);
84 if (preferredScrollPaneSize.width > layeredPane.getWidth() - bounds.x) {
85 preferredScrollPaneSize.width = layeredPane.getWidth() - bounds.x;
86 final JScrollBar horizontalScrollBar = myListScrollPane.getHorizontalScrollBar();
87 if (horizontalScrollBar != null){
88 preferredScrollPaneSize.height += horizontalScrollBar.getPreferredSize().getHeight();
93 Rectangle prefferedBounds = new Rectangle(bounds.x, bounds.y, preferredScrollPaneSize.width, preferredScrollPaneSize.height);
95 if (myListScrollPane.isVisible()) {
96 myListScrollPane.setBounds(prefferedBounds);
99 layeredPane.add(myListScrollPane, Integer.valueOf(600));
100 layeredPane.moveToFront(myListScrollPane);
101 myListScrollPane.validate();
102 myListScrollPane.setVisible(true);
105 protected void hideList() {
106 if (myListScrollPane.isVisible()){
107 myListScrollPane.setVisible(false);
111 protected void close(final boolean isOk) {
112 if (myDisposedFlag){
113 return;
116 if (isOk){
117 myModel.saveInitialCheckBoxState(myCheckBox.isSelected());
119 final List<Object> chosenElements = getChosenElements();
120 if (chosenElements != null) {
121 for (Object element : chosenElements) {
122 myActionListener.elementChosen(element);
123 String text = myModel.getFullName(element);
124 if (text != null) {
125 StatisticsManager.getInstance().incUseCount(new StatisticsInfo(statisticsContext(), text));
128 } else {
129 return;
132 if (!chosenElements.isEmpty()){
133 final String enteredText = myTextField.getText();
134 if (enteredText.indexOf('*') >= 0) {
135 FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.wildcards");
137 else {
138 for (Object element : chosenElements) {
139 final String name = myModel.getElementName(element);
140 if (name != null) {
141 if (!StringUtil.startsWithIgnoreCase(name, enteredText)) {
142 FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.camelprefix");
143 break;
149 else{
150 return;
154 myDisposedFlag = true;
155 myAlarm.cancelAllRequests();
156 myProject.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, null);
158 //LaterInvocator.leaveModal(myTextFieldPanel);
160 cleanupUI();
161 myActionListener.onClose ();
164 private void cleanupUI() {
165 JLayeredPane layeredPane = null;
166 try {
167 // check if the currently focused component was changed already, so we could leave focus intact
168 final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
169 if (owner != null && SwingUtilities.isDescendingFrom(owner, myTextField)) {
170 // Return focus back to the previous focused component if we need to do it and
171 // previous focused component is showing.
172 if (
173 myPreviouslyFocusedComponent instanceof JComponent &&
174 myPreviouslyFocusedComponent.isShowing()
176 final JComponent _component = (JComponent)myPreviouslyFocusedComponent;
177 LayoutFocusTraversalPolicyExt.setOverridenDefaultComponent(_component);
179 if (myPreviouslyFocusedComponent != null) {
180 myPreviouslyFocusedComponent.requestFocus();
184 final JRootPane rootPane = myTextFieldPanel.getRootPane();
185 if (rootPane != null) {
186 layeredPane = rootPane.getLayeredPane();
187 layeredPane.remove(myListScrollPane);
188 layeredPane.remove(myTextFieldPanel);
191 finally {
192 LayoutFocusTraversalPolicyExt.setOverridenDefaultComponent(null);
195 if (layeredPane != null) {
196 layeredPane.validate();
197 layeredPane.repaint();
201 public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context) {
202 return createPopup(project, model, context, null);
204 public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context,
205 @Nullable final String predefinedText) {
206 final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
207 if (oldPopup != null) {
208 oldPopup.close(false);
210 ChooseByNamePopup newPopup = new ChooseByNamePopup(project, model, oldPopup, context, predefinedText);
212 project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup);
213 return newPopup;
216 private static final Pattern patternToDetectLinesAndColumns = Pattern.compile("(.*?)(?:\\:|@|,|#)(\\d+)?(?:(?:\\D)(\\d+)?)?");
218 public String getNamePattern(String pattern) {
219 if (pattern.indexOf(':') != -1 ||
220 pattern.indexOf(',') != -1 ||
221 pattern.indexOf(';') != -1 ||
222 pattern.indexOf('#') != -1 ||
223 pattern.indexOf('@') != -1) { // quick test if reg exp should be used
224 final Matcher matcher = patternToDetectLinesAndColumns.matcher(pattern);
225 if (matcher.matches()) {
226 pattern = matcher.group(1);
230 return super.getNamePattern(pattern);
233 public int getLinePosition() {
234 return getLineOrColumn(true);
237 private int getLineOrColumn(final boolean line) {
238 final Matcher matcher = patternToDetectLinesAndColumns.matcher(myTextField.getText());
239 if (matcher.matches()) {
240 final int groupNumber = line ? 2:3;
241 try {
242 if(groupNumber <= matcher.groupCount()) {
243 final String group = matcher.group(groupNumber);
244 if (group != null) return Integer.parseInt(group) - 1;
246 if (!line && getLineOrColumn(true) != -1) return 0;
248 catch (NumberFormatException ignored) {}
251 return -1;
254 public int getColumnPosition() {
255 return getLineOrColumn(false);