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: * Carsten Pfeiffer <carsten.pfeiffer@gebit.de> - Fix for bug 182354 -
013: * [Dialogs] API - make ElementTreeSelectionDialog usable with a
014: * FilteredTree
015: *******************************************************************************/package org.eclipse.ui.dialogs;
016:
017: import java.util.ArrayList;
018: import java.util.List;
019:
020: import org.eclipse.core.runtime.IStatus;
021: import org.eclipse.core.runtime.Status;
022: import org.eclipse.jface.dialogs.IDialogConstants;
023: import org.eclipse.jface.viewers.DoubleClickEvent;
024: import org.eclipse.jface.viewers.IDoubleClickListener;
025: import org.eclipse.jface.viewers.ILabelProvider;
026: import org.eclipse.jface.viewers.ISelection;
027: import org.eclipse.jface.viewers.ISelectionChangedListener;
028: import org.eclipse.jface.viewers.IStructuredSelection;
029: import org.eclipse.jface.viewers.ITreeContentProvider;
030: import org.eclipse.jface.viewers.SelectionChangedEvent;
031: import org.eclipse.jface.viewers.StructuredSelection;
032: import org.eclipse.jface.viewers.TreeViewer;
033: import org.eclipse.jface.viewers.ViewerComparator;
034: import org.eclipse.jface.viewers.ViewerFilter;
035: import org.eclipse.jface.viewers.ViewerSorter;
036: import org.eclipse.swt.SWT;
037: import org.eclipse.swt.custom.BusyIndicator;
038: import org.eclipse.swt.events.SelectionAdapter;
039: import org.eclipse.swt.events.SelectionEvent;
040: import org.eclipse.swt.layout.GridData;
041: import org.eclipse.swt.widgets.Composite;
042: import org.eclipse.swt.widgets.Control;
043: import org.eclipse.swt.widgets.Label;
044: import org.eclipse.swt.widgets.Shell;
045: import org.eclipse.swt.widgets.Tree;
046: import org.eclipse.ui.PlatformUI;
047: import org.eclipse.ui.internal.WorkbenchMessages;
048:
049: /**
050: * A class to select elements out of a tree structure.
051: *
052: * @since 2.0
053: */
054: public class ElementTreeSelectionDialog extends SelectionStatusDialog {
055:
056: private TreeViewer fViewer;
057:
058: private ILabelProvider fLabelProvider;
059:
060: private ITreeContentProvider fContentProvider;
061:
062: private ISelectionStatusValidator fValidator = null;
063:
064: private ViewerComparator fComparator;
065:
066: private boolean fAllowMultiple = true;
067:
068: private boolean fDoubleClickSelects = true;
069:
070: private String fEmptyListMessage = WorkbenchMessages.ElementTreeSelectionDialog_nothing_available;
071:
072: private IStatus fCurrStatus = new Status(IStatus.OK,
073: PlatformUI.PLUGIN_ID, IStatus.OK, "", null); //$NON-NLS-1$
074:
075: private List fFilters;
076:
077: private Object fInput;
078:
079: private boolean fIsEmpty;
080:
081: private int fWidth = 60;
082:
083: private int fHeight = 18;
084:
085: /**
086: * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
087: * @param parent The parent shell for the dialog
088: * @param labelProvider the label provider to render the entries
089: * @param contentProvider the content provider to evaluate the tree structure
090: */
091: public ElementTreeSelectionDialog(Shell parent,
092: ILabelProvider labelProvider,
093: ITreeContentProvider contentProvider) {
094: super (parent);
095:
096: fLabelProvider = labelProvider;
097: fContentProvider = contentProvider;
098:
099: setResult(new ArrayList(0));
100: setStatusLineAboveButtons(true);
101: }
102:
103: /**
104: * Sets the initial selection.
105: * Convenience method.
106: * @param selection the initial selection.
107: */
108: public void setInitialSelection(Object selection) {
109: setInitialSelections(new Object[] { selection });
110: }
111:
112: /**
113: * Sets the message to be displayed if the list is empty.
114: * @param message the message to be displayed.
115: */
116: public void setEmptyListMessage(String message) {
117: fEmptyListMessage = message;
118: }
119:
120: /**
121: * Specifies if multiple selection is allowed.
122: * @param allowMultiple
123: */
124: public void setAllowMultiple(boolean allowMultiple) {
125: fAllowMultiple = allowMultiple;
126: }
127:
128: /**
129: * Specifies if default selected events (double click) are created.
130: * @param doubleClickSelects
131: */
132: public void setDoubleClickSelects(boolean doubleClickSelects) {
133: fDoubleClickSelects = doubleClickSelects;
134: }
135:
136: /**
137: * Sets the sorter used by the tree viewer.
138: * @param sorter
139: * @deprecated as of 3.3, use {@link ElementTreeSelectionDialog#setComparator(ViewerComparator)} instead
140: */
141: public void setSorter(ViewerSorter sorter) {
142: fComparator = sorter;
143: }
144:
145: /**
146: * Sets the comparator used by the tree viewer.
147: * @param comparator
148: * @since 3.3
149: */
150: public void setComparator(ViewerComparator comparator) {
151: fComparator = comparator;
152: }
153:
154: /**
155: * Adds a filter to the tree viewer.
156: * @param filter a filter.
157: */
158: public void addFilter(ViewerFilter filter) {
159: if (fFilters == null) {
160: fFilters = new ArrayList(4);
161: }
162:
163: fFilters.add(filter);
164: }
165:
166: /**
167: * Sets an optional validator to check if the selection is valid.
168: * The validator is invoked whenever the selection changes.
169: * @param validator the validator to validate the selection.
170: */
171: public void setValidator(ISelectionStatusValidator validator) {
172: fValidator = validator;
173: }
174:
175: /**
176: * Sets the tree input.
177: * @param input the tree input.
178: */
179: public void setInput(Object input) {
180: fInput = input;
181: }
182:
183: /**
184: * Sets the size of the tree in unit of characters.
185: * @param width the width of the tree.
186: * @param height the height of the tree.
187: */
188: public void setSize(int width, int height) {
189: fWidth = width;
190: fHeight = height;
191: }
192:
193: /**
194: * Validate the receiver and update the ok status.
195: *
196: */
197: protected void updateOKStatus() {
198: if (!fIsEmpty) {
199: if (fValidator != null) {
200: fCurrStatus = fValidator.validate(getResult());
201: updateStatus(fCurrStatus);
202: } else {
203: fCurrStatus = new Status(IStatus.OK,
204: PlatformUI.PLUGIN_ID, IStatus.OK, "", //$NON-NLS-1$
205: null);
206: }
207: } else {
208: fCurrStatus = new Status(IStatus.ERROR,
209: PlatformUI.PLUGIN_ID, IStatus.ERROR,
210: fEmptyListMessage, null);
211: }
212: updateStatus(fCurrStatus);
213: }
214:
215: /*
216: * (non-Javadoc)
217: * @see org.eclipse.jface.window.Window#open()
218: */
219: public int open() {
220: fIsEmpty = evaluateIfTreeEmpty(fInput);
221: super .open();
222: return getReturnCode();
223: }
224:
225: private void access$super Create() {
226: super .create();
227: }
228:
229: /**
230: * Handles cancel button pressed event.
231: */
232: protected void cancelPressed() {
233: setResult(null);
234: super .cancelPressed();
235: }
236:
237: /*
238: * @see SelectionStatusDialog#computeResult()
239: */
240: protected void computeResult() {
241: setResult(((IStructuredSelection) fViewer.getSelection())
242: .toList());
243: }
244:
245: /*
246: * (non-Javadoc)
247: * @see org.eclipse.jface.window.Window#create()
248: */
249: public void create() {
250: BusyIndicator.showWhile(null, new Runnable() {
251: public void run() {
252: access$super Create();
253: fViewer.setSelection(new StructuredSelection(
254: getInitialElementSelections()), true);
255: updateOKStatus();
256: }
257: });
258: }
259:
260: /*
261: * @see Dialog#createDialogArea(Composite)
262: */
263: protected Control createDialogArea(Composite parent) {
264: Composite composite = (Composite) super
265: .createDialogArea(parent);
266:
267: Label messageLabel = createMessageArea(composite);
268: TreeViewer treeViewer = createTreeViewer(composite);
269:
270: GridData data = new GridData(GridData.FILL_BOTH);
271: data.widthHint = convertWidthInCharsToPixels(fWidth);
272: data.heightHint = convertHeightInCharsToPixels(fHeight);
273:
274: Tree treeWidget = treeViewer.getTree();
275: treeWidget.setLayoutData(data);
276: treeWidget.setFont(parent.getFont());
277:
278: if (fIsEmpty) {
279: messageLabel.setEnabled(false);
280: treeWidget.setEnabled(false);
281: }
282:
283: return composite;
284: }
285:
286: /**
287: * Creates and initializes the tree viewer.
288: *
289: * @param parent the parent composite
290: * @return the tree viewer
291: * @see #doCreateTreeViewer(Composite, int)
292: */
293: protected TreeViewer createTreeViewer(Composite parent) {
294: int style = SWT.BORDER
295: | (fAllowMultiple ? SWT.MULTI : SWT.SINGLE);
296:
297: fViewer = doCreateTreeViewer(parent, style);
298: fViewer.setContentProvider(fContentProvider);
299: fViewer.setLabelProvider(fLabelProvider);
300: fViewer
301: .addSelectionChangedListener(new ISelectionChangedListener() {
302: public void selectionChanged(
303: SelectionChangedEvent event) {
304: access$setResult(((IStructuredSelection) event
305: .getSelection()).toList());
306: updateOKStatus();
307: }
308: });
309:
310: fViewer.setComparator(fComparator);
311: if (fFilters != null) {
312: for (int i = 0; i != fFilters.size(); i++) {
313: fViewer.addFilter((ViewerFilter) fFilters.get(i));
314: }
315: }
316:
317: if (fDoubleClickSelects) {
318: Tree tree = fViewer.getTree();
319: tree.addSelectionListener(new SelectionAdapter() {
320: public void widgetDefaultSelected(SelectionEvent e) {
321: updateOKStatus();
322: if (fCurrStatus.isOK()) {
323: access$super ButtonPressed(IDialogConstants.OK_ID);
324: }
325: }
326: });
327: }
328: fViewer.addDoubleClickListener(new IDoubleClickListener() {
329: public void doubleClick(DoubleClickEvent event) {
330: updateOKStatus();
331:
332: //If it is not OK or if double click does not
333: //select then expand
334: if (!(fDoubleClickSelects && fCurrStatus.isOK())) {
335: ISelection selection = event.getSelection();
336: if (selection instanceof IStructuredSelection) {
337: Object item = ((IStructuredSelection) selection)
338: .getFirstElement();
339: if (fViewer.getExpandedState(item)) {
340: fViewer.collapseToLevel(item, 1);
341: } else {
342: fViewer.expandToLevel(item, 1);
343: }
344: }
345: }
346: }
347: });
348:
349: fViewer.setInput(fInput);
350:
351: return fViewer;
352: }
353:
354: /**
355: * Creates the tree viewer.
356: *
357: * @param parent the parent composite
358: * @param style the {@link SWT} style bits
359: * @return the tree viewer
360: * @since 3.4
361: */
362: protected TreeViewer doCreateTreeViewer(Composite parent, int style) {
363: return new TreeViewer(new Tree(parent, style));
364: }
365:
366: /**
367: * Returns the tree viewer.
368: *
369: * @return the tree viewer
370: */
371: protected TreeViewer getTreeViewer() {
372: return fViewer;
373: }
374:
375: private boolean evaluateIfTreeEmpty(Object input) {
376: Object[] elements = fContentProvider.getElements(input);
377: if (elements.length > 0) {
378: if (fFilters != null) {
379: for (int i = 0; i < fFilters.size(); i++) {
380: ViewerFilter curr = (ViewerFilter) fFilters.get(i);
381: elements = curr.filter(fViewer, input, elements);
382: }
383: }
384: }
385: return elements.length == 0;
386: }
387:
388: /**
389: * Set the result using the super class implementation of
390: * buttonPressed.
391: * @param id
392: * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
393: */
394: protected void access$super ButtonPressed(int id) {
395: super .buttonPressed(id);
396: }
397:
398: /**
399: * Set the result using the super class implementation of
400: * setResult.
401: * @param result
402: * @see SelectionStatusDialog#setResult(int, Object)
403: */
404: protected void access$setResult(List result) {
405: super .setResult(result);
406: }
407:
408: /**
409: * @see org.eclipse.jface.window.Window#handleShellCloseEvent()
410: */
411: protected void handleShellCloseEvent() {
412: super .handleShellCloseEvent();
413:
414: //Handle the closing of the shell by selecting the close icon
415: if (getReturnCode() == CANCEL) {
416: setResult(null);
417: }
418: }
419:
420: }
|