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
;
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() {
61 protected boolean isShowListForEmptyPattern(){
65 protected boolean isCloseByFocusLost(){
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
) {
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
);
122 StatisticsManager
.getInstance().incUseCount(new StatisticsInfo(statisticsContext(), text
));
129 if (!chosenElements
.isEmpty()){
130 final String enteredText
= myTextField
.getText();
131 if (enteredText
.indexOf('*') >= 0) {
132 FeatureUsageTracker
.getInstance().triggerFeatureUsed("navigation.popup.wildcards");
135 for (Object element
: chosenElements
) {
136 final String name
= myModel
.getElementName(element
);
138 if (!StringUtil
.startsWithIgnoreCase(name
, enteredText
)) {
139 FeatureUsageTracker
.getInstance().triggerFeatureUsed("navigation.popup.camelprefix");
151 myDisposedFlag
= true;
152 myAlarm
.cancelAllRequests();
153 myProject
.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY
, null);
155 //LaterInvocator.leaveModal(myTextFieldPanel);
158 myActionListener
.onClose ();
161 private void cleanupUI() {
162 JLayeredPane layeredPane
= null;
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.
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
);
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
);
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;
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
) {}
247 public int getColumnPosition() {
248 return getLineOrColumn(false);