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