4 package com
.intellij
.ui
;
6 import com
.intellij
.ide
.ui
.LafManager
;
7 import com
.intellij
.openapi
.actionSystem
.ActionManager
;
8 import com
.intellij
.openapi
.actionSystem
.AnAction
;
9 import com
.intellij
.openapi
.actionSystem
.CommonShortcuts
;
10 import com
.intellij
.openapi
.actionSystem
.IdeActions
;
11 import com
.intellij
.openapi
.ui
.popup
.JBPopup
;
12 import com
.intellij
.openapi
.ui
.popup
.JBPopupFactory
;
13 import com
.intellij
.openapi
.util
.IconLoader
;
14 import com
.intellij
.openapi
.util
.SystemInfo
;
15 import com
.intellij
.util
.ui
.UIUtil
;
18 import javax
.swing
.border
.Border
;
19 import javax
.swing
.border
.CompoundBorder
;
20 import javax
.swing
.event
.DocumentListener
;
22 import java
.awt
.event
.*;
23 import java
.util
.ArrayList
;
25 public class SearchTextField
extends JPanel
{
26 private int myHistorySize
= 5;
27 private final MyModel myModel
;
28 private final TextFieldWithProcessing myTextField
;
30 private JBPopup myPopup
;
31 private JLabel myClearFieldLabel
;
32 private JLabel myToggleHistoryLabel
;
33 private JPopupMenu myNativeSearchPopup
;
35 private KeyListener myListener
= null;
36 private JMenuItem myNoItems
;
38 public SearchTextField() {
42 public SearchTextField(boolean historyEnabled
) {
43 super(new BorderLayout());
45 myModel
= new MyModel();
47 myTextField
= new TextFieldWithProcessing() {
49 public void processKeyEvent(final KeyEvent e
) {
50 if (preprocessEventForTextField(e
)) return;
51 super.processKeyEvent(e
);
55 public void setBackground(final Color bg
) {
56 super.setBackground(bg
);
57 if (myClearFieldLabel
!= null) {
58 myClearFieldLabel
.setBackground(bg
);
61 if (myToggleHistoryLabel
!= null) {
62 myToggleHistoryLabel
.setBackground(bg
);
66 myTextField
.setColumns(15);
67 add(myTextField
, BorderLayout
.CENTER
);
69 if (hasNativeLeopardSearchControl()) {
70 myTextField
.putClientProperty("JTextField.variant", "search");
71 myNativeSearchPopup
= new JPopupMenu();
72 myNoItems
= new JMenuItem("No recent searches");
73 myNoItems
.setEnabled(false);
77 myTextField
.putClientProperty("JTextField.Search.FindPopup", myNativeSearchPopup
);
81 myToggleHistoryLabel
= new JLabel(IconLoader
.findIcon("/actions/search.png"));
82 myToggleHistoryLabel
.setOpaque(true);
83 myToggleHistoryLabel
.setBackground(myTextField
.getBackground());
84 myToggleHistoryLabel
.addMouseListener(new MouseAdapter() {
85 public void mousePressed(MouseEvent e
) {
90 add(myToggleHistoryLabel
, BorderLayout
.WEST
);
93 myClearFieldLabel
= new JLabel(IconLoader
.findIcon("/actions/cleanLight.png"));
94 myClearFieldLabel
.setOpaque(true);
95 myClearFieldLabel
.setBackground(myTextField
.getBackground());
96 add(myClearFieldLabel
, BorderLayout
.EAST
);
97 myClearFieldLabel
.addMouseListener(new MouseAdapter() {
98 public void mousePressed(MouseEvent e
) {
99 myTextField
.setText("");
103 final Border originalBorder
;
104 if (SystemInfo
.isMac
) {
105 originalBorder
= BorderFactory
.createLoweredBevelBorder();
108 originalBorder
= myTextField
.getBorder();
111 setBorder(new CompoundBorder(IdeBorderFactory
.createEmptyBorder(4, 0, 4, 0), originalBorder
));
113 myTextField
.setOpaque(true);
114 myTextField
.setBorder(IdeBorderFactory
.createEmptyBorder(0, 5, 0, 5));
117 final ActionManager actionManager
= ActionManager
.getInstance();
118 if (actionManager
!= null) {
119 final AnAction clearTextAction
= actionManager
.getAction(IdeActions
.ACTION_CLEAR_TEXT
);
120 if (clearTextAction
.getShortcutSet().getShortcuts().length
== 0) {
121 clearTextAction
.registerCustomShortcutSet(CommonShortcuts
.ESCAPE
, this);
126 private void updateMenu() {
127 if (myNativeSearchPopup
!= null) {
128 myNativeSearchPopup
.removeAll();
129 final int itemsCount
= myModel
.getSize();
130 if (itemsCount
== 0) {
131 myNativeSearchPopup
.add(myNoItems
);
134 for (int i
= 0; i
< itemsCount
; i
++) {
135 String item
= (String
)myModel
.getElementAt(i
);
142 private static boolean hasNativeLeopardSearchControl() {
143 return SystemInfo
.isMacOSLeopard
&& LafManager
.getInstance().isUnderAquaLookAndFeel();
146 public void addDocumentListener(DocumentListener listener
) {
147 getTextEditor().getDocument().addDocumentListener(listener
);
150 public void removeDocumentListener(DocumentListener listener
) {
151 getTextEditor().getDocument().removeDocumentListener(listener
);
154 public void addKeyboardListener(final KeyListener listener
) {
155 getTextEditor().addKeyListener(listener
);
158 public void setEnabled(boolean enabled
) {
159 super.setEnabled(enabled
);
160 if (myToggleHistoryLabel
!= null) {
161 final Color bg
= enabled ? UIUtil
.getTextFieldBackground() : UIUtil
.getPanelBackground();
162 myToggleHistoryLabel
.setBackground(bg
);
163 myClearFieldLabel
.setBackground(bg
);
167 public void setHistorySize(int aHistorySize
) {
168 myHistorySize
= aHistorySize
;
171 public void setHistory(java
.util
.List
<String
> aHistory
) {
172 myModel
.setItems(aHistory
);
175 public java
.util
.List
<String
> getHistory() {
176 final int itemsCount
= myModel
.getSize();
177 java
.util
.List
<String
> history
= new ArrayList
<String
>(itemsCount
);
178 for (int i
= 0; i
< itemsCount
; i
++) {
179 history
.add((String
)myModel
.getElementAt(i
));
184 public void setText(String aText
) {
185 getTextEditor().setText(aText
);
188 public String
getText() {
189 return getTextEditor().getText();
192 public void removeNotify() {
193 super.removeNotify();
197 public void addCurrentTextToHistory() {
198 final String item
= getText();
199 myModel
.addElement(item
);
202 private void addMenuItem(final String item
) {
203 if (myNativeSearchPopup
!= null) {
204 myNativeSearchPopup
.remove(myNoItems
);
205 final JMenuItem menuItem
= new JMenuItem(item
);
206 myNativeSearchPopup
.add(menuItem
);
207 menuItem
.addActionListener(new ActionListener() {
208 public void actionPerformed(final ActionEvent e
) {
209 myTextField
.setText(item
);
215 public void selectText() {
216 getTextEditor().selectAll();
219 public JTextField
getTextEditor() {
223 public boolean requestFocusInWindow() {
224 return myTextField
.requestFocusInWindow();
227 public void requestFocus() {
228 getTextEditor().requestFocus();
231 public class MyModel
extends AbstractListModel
{
232 private java
.util
.List
<String
> myFullList
= new ArrayList
<String
>();
234 private Object mySelectedItem
;
236 public Object
getElementAt(int index
) {
237 return myFullList
.get(index
);
240 public int getSize() {
241 return Math
.min(myHistorySize
, myFullList
.size());
244 public void addElement(Object obj
) {
245 String newItem
= ((String
)obj
).trim();
247 if (0 == newItem
.length()) {
251 if (!contains(newItem
)) {
252 insertElementAt(newItem
, 0);
256 public void insertElementAt(Object obj
, int index
) {
257 myFullList
.add(index
, (String
)obj
);
258 fireContentsChanged();
261 public Object
getSelectedItem() {
262 return mySelectedItem
;
265 public void setSelectedItem(Object anItem
) {
266 mySelectedItem
= anItem
;
269 public void fireContentsChanged() {
270 fireContentsChanged(this, -1, -1);
274 public boolean contains(String aNewValue
) {
275 return myFullList
.contains(aNewValue
);
278 public void setItems(java
.util
.List
<String
> aList
) {
279 myFullList
= new ArrayList
<String
>(aList
);
280 fireContentsChanged();
284 private void hidePopup() {
285 if (myPopup
!= null) {
291 private void showPopup() {
292 if (myPopup
== null) {
293 final JList list
= new JList(myModel
);
294 if (myListener
!= null) {
295 removeKeyListener(myListener
);
297 final Runnable chooseRunnable
= new Runnable() {
299 final String value
= (String
)list
.getSelectedValue();
300 getTextEditor().setText(value
!= null ? value
: "");
301 if (myPopup
!= null) {
307 myListener
= new KeyAdapter() {
308 public void keyPressed(KeyEvent e
) {
309 if (e
.getKeyCode() == KeyEvent
.VK_DOWN
) {
310 if (list
.getSelectedIndex() < list
.getModel().getSize() - 1) {
311 list
.setSelectedIndex(list
.getSelectedIndex() + 1);
314 else if (e
.getKeyCode() == KeyEvent
.VK_UP
) {
315 if (list
.getSelectedIndex() > 0) {
316 list
.setSelectedIndex(list
.getSelectedIndex() - 1);
319 else if (e
.getKeyCode() == KeyEvent
.VK_ENTER
) {
320 if (list
.getSelectedIndex() > -1) {
321 chooseRunnable
.run();
326 addKeyboardListener(myListener
);
327 myPopup
= JBPopupFactory
.getInstance().createListPopupBuilder(list
)
329 .setRequestFocus(false)
330 .setItemChoosenCallback(chooseRunnable
).createPopup();
332 if (isShowing()) myPopup
.showUnderneathOf(this);
336 private void togglePopup() {
337 if (myPopup
== null) {
345 public void setSelectedItem(final String s
) {
346 getTextEditor().setText(s
);
349 public int getSelectedIndex() {
350 return myModel
.myFullList
.indexOf(getText());
353 protected static class TextFieldWithProcessing
extends JTextField
{
354 public void processKeyEvent(KeyEvent e
) {
355 super.processKeyEvent(e
);
359 public final void keyEventToTextField(KeyEvent e
) {
360 myTextField
.processKeyEvent(e
);
363 protected boolean preprocessEventForTextField(KeyEvent e
) {