001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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: * Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
011: * font should be activated and used by other components.
012: *******************************************************************************/package org.eclipse.ui.dialogs;
013:
014: import org.eclipse.core.runtime.Assert;
015: import org.eclipse.core.runtime.IStatus;
016: import org.eclipse.core.runtime.Status;
017: import org.eclipse.jface.dialogs.IDialogConstants;
018: import org.eclipse.jface.viewers.ILabelProvider;
019: import org.eclipse.swt.SWT;
020: import org.eclipse.swt.custom.BusyIndicator;
021: import org.eclipse.swt.events.KeyEvent;
022: import org.eclipse.swt.events.KeyListener;
023: import org.eclipse.swt.events.SelectionEvent;
024: import org.eclipse.swt.events.SelectionListener;
025: import org.eclipse.swt.layout.GridData;
026: import org.eclipse.swt.widgets.Button;
027: import org.eclipse.swt.widgets.Composite;
028: import org.eclipse.swt.widgets.Event;
029: import org.eclipse.swt.widgets.Label;
030: import org.eclipse.swt.widgets.Listener;
031: import org.eclipse.swt.widgets.Shell;
032: import org.eclipse.swt.widgets.Text;
033: import org.eclipse.ui.PlatformUI;
034:
035: /**
036: * An abstract class to select elements out of a list of elements.
037: *
038: * @since 2.0
039: */
040: public abstract class AbstractElementListSelectionDialog extends
041: SelectionStatusDialog {
042:
043: private ILabelProvider fRenderer;
044:
045: private boolean fIgnoreCase = true;
046:
047: private boolean fIsMultipleSelection = false;
048:
049: private boolean fMatchEmptyString = true;
050:
051: private boolean fAllowDuplicates = true;
052:
053: private Label fMessage;
054:
055: protected FilteredList fFilteredList;
056:
057: private Text fFilterText;
058:
059: private ISelectionStatusValidator fValidator;
060:
061: private String fFilter = null;
062:
063: private String fEmptyListMessage = ""; //$NON-NLS-1$
064:
065: private String fEmptySelectionMessage = ""; //$NON-NLS-1$
066:
067: private int fWidth = 60;
068:
069: private int fHeight = 18;
070:
071: private Object[] fSelection = new Object[0];
072:
073: /**
074: * Constructs a list selection dialog.
075: * @param parent The parent for the list.
076: * @param renderer ILabelProvider for the list
077: */
078: protected AbstractElementListSelectionDialog(Shell parent,
079: ILabelProvider renderer) {
080: super (parent);
081: fRenderer = renderer;
082: }
083:
084: /**
085: * Handles default selection (double click).
086: * By default, the OK button is pressed.
087: */
088: protected void handleDefaultSelected() {
089: if (validateCurrentSelection()) {
090: buttonPressed(IDialogConstants.OK_ID);
091: }
092: }
093:
094: /**
095: * Specifies if sorting, filtering and folding is case sensitive.
096: * @param ignoreCase
097: */
098: public void setIgnoreCase(boolean ignoreCase) {
099: fIgnoreCase = ignoreCase;
100: }
101:
102: /**
103: * Returns if sorting, filtering and folding is case sensitive.
104: * @return boolean
105: */
106: public boolean isCaseIgnored() {
107: return fIgnoreCase;
108: }
109:
110: /**
111: * Specifies whether everything or nothing should be filtered on
112: * empty filter string.
113: * @param matchEmptyString boolean
114: */
115: public void setMatchEmptyString(boolean matchEmptyString) {
116: fMatchEmptyString = matchEmptyString;
117: }
118:
119: /**
120: * Specifies if multiple selection is allowed.
121: * @param multipleSelection
122: */
123: public void setMultipleSelection(boolean multipleSelection) {
124: fIsMultipleSelection = multipleSelection;
125: }
126:
127: /**
128: * Specifies whether duplicate entries are displayed or not.
129: * @param allowDuplicates
130: */
131: public void setAllowDuplicates(boolean allowDuplicates) {
132: fAllowDuplicates = allowDuplicates;
133: }
134:
135: /**
136: * Sets the list size in unit of characters.
137: * @param width the width of the list.
138: * @param height the height of the list.
139: */
140: public void setSize(int width, int height) {
141: fWidth = width;
142: fHeight = height;
143: }
144:
145: /**
146: * Sets the message to be displayed if the list is empty.
147: * @param message the message to be displayed.
148: */
149: public void setEmptyListMessage(String message) {
150: fEmptyListMessage = message;
151: }
152:
153: /**
154: * Sets the message to be displayed if the selection is empty.
155: * @param message the message to be displayed.
156: */
157: public void setEmptySelectionMessage(String message) {
158: fEmptySelectionMessage = message;
159: }
160:
161: /**
162: * Sets an optional validator to check if the selection is valid.
163: * The validator is invoked whenever the selection changes.
164: * @param validator the validator to validate the selection.
165: */
166: public void setValidator(ISelectionStatusValidator validator) {
167: fValidator = validator;
168: }
169:
170: /**
171: * Sets the elements of the list (widget).
172: * To be called within open().
173: * @param elements the elements of the list.
174: */
175: protected void setListElements(Object[] elements) {
176: Assert.isNotNull(fFilteredList);
177: fFilteredList.setElements(elements);
178: }
179:
180: /**
181: * Sets the filter pattern.
182: * @param filter the filter pattern.
183: */
184: public void setFilter(String filter) {
185: if (fFilterText == null) {
186: fFilter = filter;
187: } else {
188: fFilterText.setText(filter);
189: }
190: }
191:
192: /**
193: * Returns the current filter pattern.
194: * @return returns the current filter pattern or <code>null<code> if filter was not set.
195: */
196: public String getFilter() {
197: if (fFilteredList == null) {
198: return fFilter;
199: } else {
200: return fFilteredList.getFilter();
201: }
202: }
203:
204: /**
205: * Returns the indices referring the current selection.
206: * To be called within open().
207: * @return returns the indices of the current selection.
208: */
209: protected int[] getSelectionIndices() {
210: Assert.isNotNull(fFilteredList);
211: return fFilteredList.getSelectionIndices();
212: }
213:
214: /**
215: * Returns an index referring the first current selection.
216: * To be called within open().
217: * @return returns the indices of the current selection.
218: */
219: protected int getSelectionIndex() {
220: Assert.isNotNull(fFilteredList);
221: return fFilteredList.getSelectionIndex();
222: }
223:
224: /**
225: * Sets the selection referenced by an array of elements.
226: * Empty or null array removes selection.
227: * To be called within open().
228: * @param selection the indices of the selection.
229: */
230: protected void setSelection(Object[] selection) {
231: Assert.isNotNull(fFilteredList);
232: fFilteredList.setSelection(selection);
233: }
234:
235: /**
236: * Returns an array of the currently selected elements.
237: * To be called within or after open().
238: * @return returns an array of the currently selected elements.
239: */
240: protected Object[] getSelectedElements() {
241: Assert.isNotNull(fFilteredList);
242: return fFilteredList.getSelection();
243: }
244:
245: /**
246: * Returns all elements which are folded together to one entry in the list.
247: * @param index the index selecting the entry in the list.
248: * @return returns an array of elements folded together.
249: */
250: public Object[] getFoldedElements(int index) {
251: Assert.isNotNull(fFilteredList);
252: return fFilteredList.getFoldedElements(index);
253: }
254:
255: /**
256: * Creates the message text widget and sets layout data.
257: * @param composite the parent composite of the message area.
258: */
259: protected Label createMessageArea(Composite composite) {
260: Label label = super .createMessageArea(composite);
261:
262: GridData data = new GridData();
263: data.grabExcessVerticalSpace = false;
264: data.grabExcessHorizontalSpace = true;
265: data.horizontalAlignment = GridData.FILL;
266: data.verticalAlignment = GridData.BEGINNING;
267: label.setLayoutData(data);
268:
269: fMessage = label;
270:
271: return label;
272: }
273:
274: /**
275: * Handles a selection changed event.
276: * By default, the current selection is validated.
277: */
278: protected void handleSelectionChanged() {
279: validateCurrentSelection();
280: }
281:
282: /**
283: * Validates the current selection and updates the status line
284: * accordingly.
285: * @return boolean <code>true</code> if the current selection is
286: * valid.
287: */
288: protected boolean validateCurrentSelection() {
289: Assert.isNotNull(fFilteredList);
290:
291: IStatus status;
292: Object[] elements = getSelectedElements();
293:
294: if (elements.length > 0) {
295: if (fValidator != null) {
296: status = fValidator.validate(elements);
297: } else {
298: status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
299: IStatus.OK, "", //$NON-NLS-1$
300: null);
301: }
302: } else {
303: if (fFilteredList.isEmpty()) {
304: status = new Status(IStatus.ERROR,
305: PlatformUI.PLUGIN_ID, IStatus.ERROR,
306: fEmptyListMessage, null);
307: } else {
308: status = new Status(IStatus.ERROR,
309: PlatformUI.PLUGIN_ID, IStatus.ERROR,
310: fEmptySelectionMessage, null);
311: }
312: }
313:
314: updateStatus(status);
315:
316: return status.isOK();
317: }
318:
319: /*
320: * @see Dialog#cancelPressed
321: */
322: protected void cancelPressed() {
323: setResult(null);
324: super .cancelPressed();
325: }
326:
327: /**
328: * Creates a filtered list.
329: * @param parent the parent composite.
330: * @return returns the filtered list widget.
331: */
332: protected FilteredList createFilteredList(Composite parent) {
333: int flags = SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
334: | (fIsMultipleSelection ? SWT.MULTI : SWT.SINGLE);
335:
336: FilteredList list = new FilteredList(parent, flags, fRenderer,
337: fIgnoreCase, fAllowDuplicates, fMatchEmptyString);
338:
339: GridData data = new GridData();
340: data.widthHint = convertWidthInCharsToPixels(fWidth);
341: data.heightHint = convertHeightInCharsToPixels(fHeight);
342: data.grabExcessVerticalSpace = true;
343: data.grabExcessHorizontalSpace = true;
344: data.horizontalAlignment = GridData.FILL;
345: data.verticalAlignment = GridData.FILL;
346: list.setLayoutData(data);
347: list.setFont(parent.getFont());
348: list.setFilter((fFilter == null ? "" : fFilter)); //$NON-NLS-1$
349:
350: list.addSelectionListener(new SelectionListener() {
351: public void widgetDefaultSelected(SelectionEvent e) {
352: handleDefaultSelected();
353: }
354:
355: public void widgetSelected(SelectionEvent e) {
356: handleWidgetSelected();
357: }
358: });
359:
360: fFilteredList = list;
361:
362: return list;
363: }
364:
365: // 3515
366: private void handleWidgetSelected() {
367: Object[] newSelection = fFilteredList.getSelection();
368:
369: if (newSelection.length != fSelection.length) {
370: fSelection = newSelection;
371: handleSelectionChanged();
372: } else {
373: for (int i = 0; i != newSelection.length; i++) {
374: if (!newSelection[i].equals(fSelection[i])) {
375: fSelection = newSelection;
376: handleSelectionChanged();
377: break;
378: }
379: }
380: }
381: }
382:
383: protected Text createFilterText(Composite parent) {
384: Text text = new Text(parent, SWT.BORDER);
385:
386: GridData data = new GridData();
387: data.grabExcessVerticalSpace = false;
388: data.grabExcessHorizontalSpace = true;
389: data.horizontalAlignment = GridData.FILL;
390: data.verticalAlignment = GridData.BEGINNING;
391: text.setLayoutData(data);
392: text.setFont(parent.getFont());
393:
394: text.setText((fFilter == null ? "" : fFilter)); //$NON-NLS-1$
395:
396: Listener listener = new Listener() {
397: public void handleEvent(Event e) {
398: fFilteredList.setFilter(fFilterText.getText());
399: }
400: };
401: text.addListener(SWT.Modify, listener);
402:
403: text.addKeyListener(new KeyListener() {
404: public void keyPressed(KeyEvent e) {
405: if (e.keyCode == SWT.ARROW_DOWN) {
406: fFilteredList.setFocus();
407: }
408: }
409:
410: public void keyReleased(KeyEvent e) {
411: }
412: });
413:
414: fFilterText = text;
415:
416: return text;
417: }
418:
419: /*
420: * (non-Javadoc)
421: * @see org.eclipse.jface.window.Window#open()
422: */
423: public int open() {
424: super .open();
425: return getReturnCode();
426: }
427:
428: private void access$super Create() {
429: super .create();
430: }
431:
432: /*
433: * (non-Javadoc)
434: * @see org.eclipse.jface.window.Window#create()
435: */
436: public void create() {
437:
438: BusyIndicator.showWhile(null, new Runnable() {
439: public void run() {
440: access$super Create();
441:
442: Assert.isNotNull(fFilteredList);
443:
444: if (fFilteredList.isEmpty()) {
445: handleEmptyList();
446: } else {
447: validateCurrentSelection();
448: fFilterText.selectAll();
449: fFilterText.setFocus();
450: }
451: }
452: });
453:
454: }
455:
456: /**
457: * Handles empty list by disabling widgets.
458: */
459: protected void handleEmptyList() {
460: fMessage.setEnabled(false);
461: fFilterText.setEnabled(false);
462: fFilteredList.setEnabled(false);
463: updateOkState();
464: }
465:
466: /**
467: * Update the enablement of the OK button based on whether or not there
468: * is a selection.
469: *
470: */
471: protected void updateOkState() {
472: Button okButton = getOkButton();
473: if (okButton != null) {
474: okButton.setEnabled(getSelectedElements().length != 0);
475: }
476: }
477: }
|