2 * Copyright 2000-2007 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
.openapi
.ui
.popup
;
19 import com
.intellij
.openapi
.actionSystem
.DataConstants
;
20 import com
.intellij
.openapi
.actionSystem
.DataProvider
;
21 import com
.intellij
.openapi
.util
.Computable
;
22 import com
.intellij
.ui
.ListScrollingUtil
;
23 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
24 import com
.intellij
.util
.ui
.treetable
.TreeTable
;
25 import org
.jetbrains
.annotations
.Nls
;
26 import org
.jetbrains
.annotations
.NonNls
;
27 import org
.jetbrains
.annotations
.NotNull
;
28 import org
.jetbrains
.annotations
.Nullable
;
31 import javax
.swing
.border
.Border
;
33 import java
.awt
.event
.*;
34 import java
.util
.ArrayList
;
39 public class PopupChooserBuilder
{
40 private JComponent myChooserComponent
;
41 private String myTitle
;
42 private ArrayList
<KeyStroke
> myAdditionalKeystrokes
= new ArrayList
<KeyStroke
>();
43 private Runnable myItemChoosenRunnable
;
44 private JComponent mySouthComponent
;
46 private JBPopup myPopup
;
48 private boolean myRequestFocus
= true;
49 private boolean myForceResizable
= false;
50 private boolean myForceMovable
= false;
51 private String myDimensionServiceKey
= null;
52 private Computable
<Boolean
> myCancelCallback
;
53 private boolean myAutoselect
= true;
54 private float myAlpha
;
55 private Component
[] myFocusOwners
= new Component
[0];
56 private boolean myCancelKeyEnabled
= true;
58 ArrayList
<JBPopupListener
> myListeners
= new ArrayList
<JBPopupListener
>();
60 private Dimension myMinSize
;
63 public PopupChooserBuilder(@NotNull JList list
) {
64 myChooserComponent
= new MyListWrapper(list
);
67 public PopupChooserBuilder(@NotNull JTable table
) {
68 myChooserComponent
= table
;
71 public PopupChooserBuilder(@NotNull JTree tree
) {
72 myChooserComponent
= tree
;
76 public PopupChooserBuilder
setTitle(@NotNull @Nls String title
) {
82 public PopupChooserBuilder
addAdditionalChooseKeystroke(@Nullable KeyStroke keyStroke
) {
83 if (keyStroke
!= null) {
84 myAdditionalKeystrokes
.add(keyStroke
);
90 public PopupChooserBuilder
setItemChoosenCallback(@NotNull Runnable runnable
) {
91 myItemChoosenRunnable
= runnable
;
96 public PopupChooserBuilder
setSouthComponent(@NotNull JComponent cmp
) {
97 mySouthComponent
= cmp
;
102 public PopupChooserBuilder
setRequestFocus(final boolean requestFocus
) {
103 myRequestFocus
= requestFocus
;
107 public PopupChooserBuilder
setResizable(final boolean forceResizable
) {
108 myForceResizable
= forceResizable
;
113 public PopupChooserBuilder
setMovable(final boolean forceMovable
) {
114 myForceMovable
= forceMovable
;
118 public PopupChooserBuilder
setDimensionServiceKey(@NonNls String key
){
119 myDimensionServiceKey
= key
;
123 public PopupChooserBuilder
setCancelCalllback(Computable
<Boolean
> callback
) {
124 myCancelCallback
= callback
;
128 public PopupChooserBuilder
setAlpha(final float alpha
) {
134 public JBPopup
createPopup() {
135 JPanel contentPane
= new JPanel(new BorderLayout());
136 if (!myForceMovable
&& myTitle
!= null) {
137 JLabel label
= new JLabel(myTitle
);
138 label
.setBorder(BorderFactory
.createEmptyBorder(2, 5, 2, 5));
139 label
.setHorizontalAlignment(SwingConstants
.CENTER
);
140 contentPane
.add(label
, BorderLayout
.NORTH
);
143 if (myChooserComponent
instanceof MyListWrapper
) {
144 JList list
= ((MyListWrapper
)myChooserComponent
).myList
;
145 if (list
.getSelectedIndex() == -1 && myAutoselect
) {
146 list
.setSelectedIndex(0);
150 myChooserComponent
.setBorder(BorderFactory
.createEmptyBorder(5, 5, 5, 5));
152 myChooserComponent
.addMouseListener(new MouseAdapter() {
153 public void mouseClicked(MouseEvent e
) {
154 if (!isSelectionButtonDown(e
) && !e
.isConsumed()) {
160 regsiterClosePopupKeyboardAction(KeyStroke
.getKeyStroke(KeyEvent
.VK_ESCAPE
, 0), false);
161 regsiterClosePopupKeyboardAction(KeyStroke
.getKeyStroke(KeyEvent
.VK_ENTER
, 0), true);
162 for (KeyStroke keystroke
: myAdditionalKeystrokes
) {
163 regsiterClosePopupKeyboardAction(keystroke
, true);
166 final JScrollPane scrollPane
;
167 if (myChooserComponent
instanceof MyListWrapper
) {
168 scrollPane
= (MyListWrapper
)myChooserComponent
;
170 else if (myChooserComponent
instanceof JTable
) {
171 scrollPane
= createScrollPane((JTable
)myChooserComponent
);
173 else if (myChooserComponent
instanceof JTree
) {
174 scrollPane
= createScrollPane((JTree
)myChooserComponent
);
177 throw new IllegalStateException("PopupChooserBuilder is intended to be constructed with one of JTable, JTree, JList components");
180 scrollPane
.getViewport().setCursor(Cursor
.getPredefinedCursor(Cursor
.HAND_CURSOR
));
181 contentPane
.add(scrollPane
, BorderLayout
.CENTER
);
183 if (mySouthComponent
!= null) {
184 contentPane
.add(mySouthComponent
, BorderLayout
.SOUTH
);
187 ComponentPopupBuilder builder
= JBPopupFactory
.getInstance()
188 .createComponentPopupBuilder(contentPane
, myChooserComponent
);
189 for (JBPopupListener each
: myListeners
) {
190 builder
.addListener(each
);
193 builder
.setDimensionServiceKey(null, myDimensionServiceKey
, false)
194 .setRequestFocus(myRequestFocus
)
195 .setResizable(myForceResizable
)
196 .setMovable(myForceMovable
)
197 .setTitle(myForceMovable ? myTitle
: null)
198 .setCancelCallback(myCancelCallback
)
200 .setFocusOwners(myFocusOwners
)
201 .setCancelKeyEnabled(myCancelKeyEnabled
)
204 if (myMinSize
!= null) {
205 builder
.setMinSize(myMinSize
);
208 myPopup
= builder
.createPopup();
212 public PopupChooserBuilder
setMinSize(final Dimension dimension
) {
213 myMinSize
= dimension
;
217 private void regsiterClosePopupKeyboardAction(final KeyStroke keyStroke
, final boolean shouldPerformAction
) {
218 myChooserComponent
.registerKeyboardAction(new AbstractAction() {
219 public void actionPerformed(ActionEvent e
) {
220 closePopup(shouldPerformAction
);
222 }, keyStroke
, JComponent
.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
);
225 private void closePopup(boolean shouldPerformAction
) {
228 if (shouldPerformAction
) {
229 if (myItemChoosenRunnable
!= null) {
230 myItemChoosenRunnable
.run();
236 public static JScrollPane
createScrollPane(final JTable table
) {
237 if (table
instanceof TreeTable
) {
238 TreeUtil
.expandAll(((TreeTable
)table
).getTree());
241 JScrollPane scrollPane
= new JScrollPane(table
);
243 scrollPane
.setBorder(BorderFactory
.createEmptyBorder(0, 0, 0, 0));
245 if (table
.getSelectedRow() == -1) {
246 table
.getSelectionModel().setSelectionInterval(0, 0);
249 if (table
.getRowCount() >= 20) {
250 scrollPane
.getViewport().setPreferredSize(new Dimension(table
.getPreferredScrollableViewportSize().width
, 300));
253 scrollPane
.getViewport().setPreferredSize(table
.getPreferredSize());
256 table
.addMouseMotionListener(new MouseMotionAdapter() {
257 boolean myIsEngaged
= false;
258 public void mouseMoved(MouseEvent e
) {
260 int index
= table
.rowAtPoint(e
.getPoint());
261 table
.getSelectionModel().setSelectionInterval(index
, index
);
273 public static JScrollPane
createScrollPane(final JTree tree
) {
274 TreeUtil
.expandAll(tree
);
276 JScrollPane scrollPane
= new JScrollPane(tree
);
278 scrollPane
.setBorder(BorderFactory
.createEmptyBorder(0, 0, 0, 0));
280 if (tree
.getSelectionCount() == 0) {
281 tree
.setSelectionRow(0);
284 if (tree
.getRowCount() >= 20) {
285 scrollPane
.getViewport().setPreferredSize(new Dimension(tree
.getPreferredScrollableViewportSize().width
, 300));
288 scrollPane
.getViewport().setPreferredSize(tree
.getPreferredSize());
291 tree
.addMouseMotionListener(new MouseMotionAdapter() {
292 boolean myIsEngaged
= false;
293 public void mouseMoved(MouseEvent e
) {
295 final Point p
= e
.getPoint();
296 int index
= tree
.getRowForLocation(p
.x
, p
.y
);
297 tree
.setSelectionRow(index
);
308 public PopupChooserBuilder
setAutoSelectIfEmpty(final boolean autoselect
) {
309 myAutoselect
= autoselect
;
313 public PopupChooserBuilder
setCancelKeyEnabled(final boolean enabled
) {
314 myCancelKeyEnabled
= enabled
;
318 public PopupChooserBuilder
addListener(final JBPopupListener listener
) {
319 myListeners
.add(listener
);
323 private static boolean isSelectionButtonDown(MouseEvent e
) {
324 return e
.isShiftDown() || e
.isControlDown() || e
.isMetaDown();
327 private class MyListWrapper
extends JScrollPane
implements DataProvider
{
328 @SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"})
329 private JList myList
;
331 public MyListWrapper(final JList list
) {
333 list
.addMouseMotionListener(new MouseMotionAdapter() {
334 boolean myIsEngaged
= false;
335 public void mouseMoved(MouseEvent e
) {
336 if (myIsEngaged
&& !isSelectionButtonDown(e
)) {
337 Point point
= e
.getPoint();
338 int index
= list
.locationToIndex(point
);
339 list
.setSelectedIndex(index
);
347 ListScrollingUtil
.installActions(list
);
349 int modelSize
= list
.getModel().getSize();
350 setBorder(BorderFactory
.createEmptyBorder(0, 0, 0, 0));
351 if (modelSize
> 0 && modelSize
<= 20) {
352 list
.setVisibleRowCount(0);
353 getViewport().setPreferredSize(list
.getPreferredSize());
356 list
.setVisibleRowCount(20);
363 public Object
getData(@NonNls String dataId
) {
364 if (dataId
.equals(DataConstants
.SELECTED_ITEM
)){
365 return myList
.getSelectedValue();
370 public void setBorder(Border border
) {
372 myList
.setBorder(border
);
376 public void requestFocus() {
377 myList
.requestFocus();
380 public synchronized void addMouseListener(MouseListener l
) {
381 myList
.addMouseListener(l
);
386 public PopupChooserBuilder
setFocusOwners(@NotNull Component
[] focusOwners
) {
387 myFocusOwners
= focusOwners
;
392 public PopupChooserBuilder
setAdText(String ad
) {