001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.custom;
011:
012: import org.eclipse.swt.*;
013: import org.eclipse.swt.events.*;
014: import org.eclipse.swt.graphics.*;
015: import org.eclipse.swt.widgets.*;
016:
017: /**
018: * A PopupList is a list of selectable items that appears in its own shell positioned above
019: * its parent shell. It is used for selecting items when editing a Table cell (similar to the
020: * list that appears when you open a Combo box).
021: *
022: * The list will be positioned so that it does not run off the screen and the largest number of items
023: * are visible. It may appear above the current cursor location or below it depending how close you
024: * are to the edge of the screen.
025: */
026: public class PopupList {
027: Shell shell;
028: List list;
029: int minimumWidth;
030:
031: /**
032: * Creates a PopupList above the specified shell.
033: *
034: * @param parent a Shell control which will be the parent of the new instance (cannot be null)
035: */
036: public PopupList(Shell parent) {
037: this (parent, 0);
038: }
039:
040: /**
041: * Creates a PopupList above the specified shell.
042: *
043: * @param parent a widget which will be the parent of the new instance (cannot be null)
044: * @param style the style of widget to construct
045: *
046: * @since 3.0
047: */
048: public PopupList(Shell parent, int style) {
049: shell = new Shell(parent, checkStyle(style));
050:
051: list = new List(shell, SWT.SINGLE | SWT.V_SCROLL);
052:
053: // close dialog if user selects outside of the shell
054: shell.addListener(SWT.Deactivate, new Listener() {
055: public void handleEvent(Event e) {
056: shell.setVisible(false);
057: }
058: });
059:
060: // resize shell when list resizes
061: shell.addControlListener(new ControlListener() {
062: public void controlMoved(ControlEvent e) {
063: }
064:
065: public void controlResized(ControlEvent e) {
066: Rectangle shellSize = shell.getClientArea();
067: list.setSize(shellSize.width, shellSize.height);
068: }
069: });
070:
071: // return list selection on Mouse Up or Carriage Return
072: list.addMouseListener(new MouseListener() {
073: public void mouseDoubleClick(MouseEvent e) {
074: }
075:
076: public void mouseDown(MouseEvent e) {
077: }
078:
079: public void mouseUp(MouseEvent e) {
080: shell.setVisible(false);
081: }
082: });
083: list.addKeyListener(new KeyListener() {
084: public void keyReleased(KeyEvent e) {
085: }
086:
087: public void keyPressed(KeyEvent e) {
088: if (e.character == '\r') {
089: shell.setVisible(false);
090: }
091: }
092: });
093:
094: }
095:
096: private static int checkStyle(int style) {
097: int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
098: return style & mask;
099: }
100:
101: /**
102: * Gets the widget font.
103: * <p>
104: * @return the widget font
105: *
106: * @exception SWTException <ul>
107: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
108: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
109: * </ul>
110: */
111: public Font getFont() {
112: return list.getFont();
113: }
114:
115: /**
116: * Gets the items.
117: * <p>
118: * This operation will fail if the items cannot
119: * be queried from the OS.
120: *
121: * @return the items in the widget
122: *
123: * @exception SWTException <ul>
124: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
125: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
126: * </ul>
127: */
128: public String[] getItems() {
129: return list.getItems();
130: }
131:
132: /**
133: * Gets the minimum width of the list.
134: *
135: * @return the minimum width of the list
136: */
137: public int getMinimumWidth() {
138: return minimumWidth;
139: }
140:
141: /**
142: * Launches the Popup List, waits for an item to be selected and then closes the PopupList.
143: *
144: * @param rect the initial size and location of the PopupList; the dialog will be
145: * positioned so that it does not run off the screen and the largest number of items are visible
146: *
147: * @return the text of the selected item or null if no item is selected
148: */
149: public String open(Rectangle rect) {
150:
151: Point listSize = list.computeSize(rect.width, SWT.DEFAULT,
152: false);
153: Rectangle screenSize = shell.getDisplay().getBounds();
154:
155: // Position the dialog so that it does not run off the screen and the largest number of items are visible
156: int spaceBelow = screenSize.height - (rect.y + rect.height)
157: - 30;
158: int spaceAbove = rect.y - 30;
159:
160: int y = 0;
161: if (spaceAbove > spaceBelow && listSize.y > spaceBelow) {
162: // place popup list above table cell
163: if (listSize.y > spaceAbove) {
164: listSize.y = spaceAbove;
165: } else {
166: listSize.y += 2;
167: }
168: y = rect.y - listSize.y;
169:
170: } else {
171: // place popup list below table cell
172: if (listSize.y > spaceBelow) {
173: listSize.y = spaceBelow;
174: } else {
175: listSize.y += 2;
176: }
177: y = rect.y + rect.height;
178: }
179:
180: // Make dialog as wide as the cell
181: listSize.x = rect.width;
182: // dialog width should not be less than minimumWidth
183: if (listSize.x < minimumWidth)
184: listSize.x = minimumWidth;
185:
186: // Align right side of dialog with right side of cell
187: int x = rect.x + rect.width - listSize.x;
188:
189: shell.setBounds(x, y, listSize.x, listSize.y);
190:
191: shell.open();
192: list.setFocus();
193:
194: Display display = shell.getDisplay();
195: while (!shell.isDisposed() && shell.isVisible()) {
196: if (!display.readAndDispatch())
197: display.sleep();
198: }
199:
200: String result = null;
201: if (!shell.isDisposed()) {
202: String[] strings = list.getSelection();
203: shell.dispose();
204: if (strings.length != 0)
205: result = strings[0];
206: }
207: return result;
208: }
209:
210: /**
211: * Selects an item with text that starts with specified String.
212: * <p>
213: * If the item is not currently selected, it is selected.
214: * If the item at an index is selected, it remains selected.
215: * If the string is not matched, it is ignored.
216: *
217: * @param string the text of the item
218: *
219: * @exception SWTException <ul>
220: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
221: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
222: * </ul>
223: */
224: public void select(String string) {
225: String[] items = list.getItems();
226:
227: // find the first entry in the list that starts with the
228: // specified string
229: if (string != null) {
230: for (int i = 0; i < items.length; i++) {
231: if (items[i].startsWith(string)) {
232: int index = list.indexOf(items[i]);
233: list.select(index);
234: break;
235: }
236: }
237: }
238: }
239:
240: /**
241: * Sets the widget font.
242: * <p>
243: * When new font is null, the font reverts
244: * to the default system font for the widget.
245: *
246: * @param font the new font (or null)
247: *
248: * @exception SWTException <ul>
249: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
250: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
251: * </ul>
252: */
253: public void setFont(Font font) {
254: list.setFont(font);
255: }
256:
257: /**
258: * Sets all items.
259: * <p>
260: * The previous selection is cleared.
261: * The previous items are deleted.
262: * The new items are added.
263: * The top index is set to 0.
264: *
265: * @param strings the array of items
266: *
267: * This operation will fail when an item is null
268: * or could not be added in the OS.
269: *
270: * @exception IllegalArgumentException <ul>
271: * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
272: * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
273: * </ul>
274: * @exception SWTException <ul>
275: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
276: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
277: * </ul>
278: */
279: public void setItems(String[] strings) {
280: list.setItems(strings);
281: }
282:
283: /**
284: * Sets the minimum width of the list.
285: *
286: * @param width the minimum width of the list
287: */
288: public void setMinimumWidth(int width) {
289: if (width < 0)
290: SWT.error(SWT.ERROR_INVALID_ARGUMENT);
291:
292: minimumWidth = width;
293: }
294: }
|