Add multi-column tree selection dialog
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / dialogs / TimeGraphFilterDialog.java
CommitLineData
8f91a789
AM
1/*******************************************************************************
2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be
11 * activated and used by other components.
12 * Lubomir Marinov <lubomir.marinov@gmail.com> - Fix for bug 182122 -[Dialogs]
13 * CheckedTreeSelectionDialog#createSelectionButtons(Composite) fails to
14 * align the selection buttons to the right
15 * François Rajotte - Support for multiple columns + selection control
16 *******************************************************************************/
17
18package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs;
19
20import java.util.ArrayList;
21import java.util.Arrays;
22import java.util.List;
23
24import org.eclipse.core.runtime.IStatus;
25import org.eclipse.core.runtime.Status;
26import org.eclipse.jface.dialogs.IDialogConstants;
27import org.eclipse.jface.viewers.CheckStateChangedEvent;
28import org.eclipse.jface.viewers.CheckboxTreeViewer;
29import org.eclipse.jface.viewers.IBaseLabelProvider;
30import org.eclipse.jface.viewers.ICheckStateListener;
31import org.eclipse.jface.viewers.ITreeContentProvider;
32import org.eclipse.jface.viewers.ViewerComparator;
33import org.eclipse.jface.viewers.ViewerFilter;
34import org.eclipse.linuxtools.internal.tmf.ui.Messages;
35import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
36import org.eclipse.swt.SWT;
37import org.eclipse.swt.custom.BusyIndicator;
38import org.eclipse.swt.events.SelectionAdapter;
39import org.eclipse.swt.events.SelectionEvent;
40import org.eclipse.swt.events.SelectionListener;
41import org.eclipse.swt.layout.GridData;
42import org.eclipse.swt.layout.GridLayout;
43import org.eclipse.swt.widgets.Button;
44import org.eclipse.swt.widgets.Composite;
45import org.eclipse.swt.widgets.Control;
46import org.eclipse.swt.widgets.Label;
47import org.eclipse.swt.widgets.Shell;
48import org.eclipse.swt.widgets.Tree;
49import org.eclipse.swt.widgets.TreeColumn;
50import org.eclipse.ui.PlatformUI;
51import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
52import org.eclipse.ui.dialogs.ISelectionStatusValidator;
53import org.eclipse.ui.dialogs.SelectionStatusDialog;
54
55/**
56 * Filter dialog for the time graphs
57 * This class is derived from the CheckedTreeSelectionDialog
58 * It was necessary to develop this similar dialog to allow multiple columns
59 *
60 * @version 1.0
61 * @since 2.0
62 * @author François Rajotte
63 */
64public class TimeGraphFilterDialog extends SelectionStatusDialog {
65
66 private CheckboxTreeViewer fViewer;
67
68 private IBaseLabelProvider fLabelProvider;
69
70 private ITreeContentProvider fContentProvider;
71
72 private String[] fColumnNames;
73
74 private ISelectionStatusValidator fValidator = null;
75
76 private ViewerComparator fComparator;
77
78 private String fEmptyListMessage = ""; //$NON-NLS-1$
79
80 private IStatus fCurrStatus = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
81 0, "", null); //$NON-NLS-1$
82
83 private List<ViewerFilter> fFilters;
84
85 private Object fInput;
86
87 private boolean fIsEmpty;
88
89 private int fWidth = 60;
90
91 private int fHeight = 18;
92
93 private boolean fContainerMode;
94
95 private Object[] fExpandedElements;
96
97 /**
98 * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
99 *
100 * @param parent
101 * The shell to parent from.
102 */
103 public TimeGraphFilterDialog(Shell parent) {
104 super(parent);
105 setResult(new ArrayList<Object>(0));
106 setStatusLineAboveButtons(true);
107 setHelpAvailable(false);
108 fContainerMode = false;
109 fExpandedElements = null;
110 }
111
112 /**
113 * If set, the checked /gray state of containers (inner nodes) is derived
114 * from the checked state of its leaf nodes.
115 *
116 * @param containerMode
117 * The containerMode to set
118 */
119 public void setContainerMode(boolean containerMode) {
120 fContainerMode = containerMode;
121 }
122
123 /**
124 * Sets the initial selection. Convenience method.
125 *
126 * @param selection
127 * the initial selection.
128 */
129 public void setInitialSelection(Object selection) {
130 setInitialSelections(new Object[] { selection });
131 }
132
133 /**
134 * Sets the message to be displayed if the list is empty.
135 *
136 * @param message
137 * the message to be displayed.
138 */
139 public void setEmptyListMessage(String message) {
140 fEmptyListMessage = message;
141 }
142
143 /**
144 * Sets the comparator used by the tree viewer.
145 *
146 * @param comparator
147 * The comparator
148 */
149 public void setComparator(ViewerComparator comparator) {
150 fComparator = comparator;
151 }
152
153 /**
154 * Adds a filter to the tree viewer.
155 *
156 * @param filter
157 * a filter.
158 */
159 public void addFilter(ViewerFilter filter) {
160 if (fFilters == null) {
161 fFilters = new ArrayList<ViewerFilter>(4);
162 }
163 fFilters.add(filter);
164 }
165
166 /**
167 * Sets an optional validator to check if the selection is valid. The
168 * validator is invoked whenever the selection changes.
169 *
170 * @param validator
171 * the validator to validate the selection.
172 */
173 public void setValidator(ISelectionStatusValidator validator) {
174 fValidator = validator;
175 }
176
177 /**
178 * Sets the tree input.
179 *
180 * @param input
181 * the tree input.
182 */
183 public void setInput(Object input) {
184 fInput = input;
185 }
186
187 /**
188 * Expands elements in the tree.
189 *
190 * @param elements
191 * The elements that will be expanded.
192 */
193 public void setExpandedElements(Object[] elements) {
194 fExpandedElements = elements;
195 }
196
197 /**
198 * Sets the size of the tree in unit of characters.
199 *
200 * @param width
201 * the width of the tree.
202 * @param height
203 * the height of the tree.
204 */
205 public void setSize(int width, int height) {
206 fWidth = width;
207 fHeight = height;
208 }
209
210 /**
211 * @param contentProvider The content provider for the table
212 */
213 public void setContentProvider(ITreeContentProvider contentProvider) {
214 fContentProvider = contentProvider;
215 }
216
217 /**
218 * @param labelProvider The label provider for the table
219 */
220 public void setLabelProvider(IBaseLabelProvider labelProvider) {
221 fLabelProvider = labelProvider;
222 }
223
224 /**
225 * @param columnNames An array of column names to display
226 */
227 public void setColumnNames(String[] columnNames) {
228 fColumnNames = columnNames;
229 }
230
231 /**
232 * Validate the receiver and update the status with the result.
233 *
234 */
235 protected void updateOKStatus() {
236 if (!fIsEmpty) {
237 if (fValidator != null) {
238 fCurrStatus = fValidator.validate(fViewer.getCheckedElements());
239 updateStatus(fCurrStatus);
240 } else if (!fCurrStatus.isOK()) {
241 fCurrStatus = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
242 IStatus.OK, "", //$NON-NLS-1$
243 null);
244 }
245 } else {
246 fCurrStatus = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
247 IStatus.OK, fEmptyListMessage, null);
248 }
249 updateStatus(fCurrStatus);
250 }
251
252 @Override
253 public int open() {
254 fIsEmpty = evaluateIfTreeEmpty(fInput);
255 super.open();
256 return getReturnCode();
257 }
258
259 private void access$superCreate() {
260 super.create();
261 }
262
263 @Override
264 protected void cancelPressed() {
265 setResult(null);
266 super.cancelPressed();
267 }
268
269 @Override
270 protected void computeResult() {
271 setResult(Arrays.asList(fViewer.getCheckedElements()));
272 }
273
274 @Override
275 public void create() {
276 BusyIndicator.showWhile(null, new Runnable() {
277 @Override
278 public void run() {
279 access$superCreate();
280 fViewer.setCheckedElements(getInitialElementSelections()
281 .toArray());
282 if (fExpandedElements != null) {
283 fViewer.setExpandedElements(fExpandedElements);
284 }
285 updateOKStatus();
286 }
287 });
288 }
289
290 @Override
291 protected Control createDialogArea(Composite parent) {
292 Composite composite = (Composite) super.createDialogArea(parent);
293 Label messageLabel = createMessageArea(composite);
294 CheckboxTreeViewer treeViewer = createTreeViewer(composite);
295 Control buttonComposite = createSelectionButtons(composite);
296 GridData data = new GridData(GridData.FILL_BOTH);
297 data.widthHint = convertWidthInCharsToPixels(fWidth);
298 data.heightHint = convertHeightInCharsToPixels(fHeight);
299 Tree treeWidget = treeViewer.getTree();
300 treeWidget.setLayoutData(data);
301 treeWidget.setFont(parent.getFont());
302 if (fIsEmpty) {
303 messageLabel.setEnabled(false);
304 treeWidget.setEnabled(false);
305 buttonComposite.setEnabled(false);
306 }
307 return composite;
308 }
309
310 /**
311 * Creates the tree viewer.
312 *
313 * @param parent
314 * the parent composite
315 * @return the tree viewer
316 */
317 protected CheckboxTreeViewer createTreeViewer(Composite parent) {
318 if (fContainerMode) {
319 fViewer = new ContainerCheckedTreeViewer(parent, SWT.BORDER);
320 } else {
321 fViewer = new CheckboxTreeViewer(parent, SWT.BORDER);
322 }
323
324 Tree tree = fViewer.getTree();
325 tree.setHeaderVisible(true);
326 for (String columnName : fColumnNames) {
327 TreeColumn column = new TreeColumn(tree, SWT.LEFT);
328 column.setText(columnName);
329 column.pack();
330 }
331
332 fViewer.setContentProvider(fContentProvider);
333 fViewer.setLabelProvider(fLabelProvider);
334 fViewer.addCheckStateListener(new CheckStateListener());
335 fViewer.addCheckStateListener(new ICheckStateListener() {
336 @Override
337 public void checkStateChanged(CheckStateChangedEvent event) {
338 updateOKStatus();
339 }
340 });
341 fViewer.setComparator(fComparator);
342 if (fFilters != null) {
343 for (int i = 0; i != fFilters.size(); i++) {
344 fViewer.addFilter(fFilters.get(i));
345 }
346 }
347 fViewer.setInput(fInput);
348
349 //pack the columns again for a nice view...
350 for (TreeColumn column : tree.getColumns()) {
351 column.pack();
352 }
353 return fViewer;
354 }
355
356 /**
357 * Returns the tree viewer.
358 *
359 * @return the tree viewer
360 */
361 protected CheckboxTreeViewer getTreeViewer() {
362 return fViewer;
363 }
364
365 /**
366 * Adds the selection and deselection buttons to the dialog.
367 *
368 * @param composite
369 * the parent composite
370 * @return Composite the composite the buttons were created in.
371 */
372 protected Composite createSelectionButtons(Composite composite) {
373 Composite buttonComposite = new Composite(composite, SWT.RIGHT);
374 GridLayout layout = new GridLayout();
375 layout.numColumns = 0;
376 layout.marginWidth = 0;
377 layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
378 buttonComposite.setLayout(layout);
379 buttonComposite.setFont(composite.getFont());
380 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END
381 | GridData.GRAB_HORIZONTAL);
382 data.grabExcessHorizontalSpace = true;
383 buttonComposite.setLayoutData(data);
384 Button selectButton = createButton(buttonComposite,
385 IDialogConstants.SELECT_ALL_ID, Messages.TmfTimeFilterDialog_SELECT_ALL,
386 false);
387 SelectionListener listener = new SelectionAdapter() {
388 @Override
389 public void widgetSelected(SelectionEvent e) {
390 Object[] viewerElements = fContentProvider.getElements(fInput);
391 if (fContainerMode) {
392 fViewer.setCheckedElements(viewerElements);
393 } else {
394 for (int i = 0; i < viewerElements.length; i++) {
395 fViewer.setSubtreeChecked(viewerElements[i], true);
396 }
397 }
398 updateOKStatus();
399 }
400 };
401 selectButton.addSelectionListener(listener);
402 Button deselectButton = createButton(buttonComposite,
403 IDialogConstants.DESELECT_ALL_ID, Messages.TmfTimeFilterDialog_DESELECT_ALL,
404 false);
405 listener = new SelectionAdapter() {
406 @Override
407 public void widgetSelected(SelectionEvent e) {
408 fViewer.setCheckedElements(new Object[0]);
409 updateOKStatus();
410 }
411 };
412 deselectButton.addSelectionListener(listener);
413 return buttonComposite;
414 }
415
416 private boolean evaluateIfTreeEmpty(Object input) {
417 Object[] elements = fContentProvider.getElements(input);
418 if (elements.length > 0) {
419 if (fFilters != null) {
420 for (int i = 0; i < fFilters.size(); i++) {
421 ViewerFilter curr = fFilters.get(i);
422 elements = curr.filter(fViewer, input, elements);
423 }
424 }
425 }
426 return elements.length == 0;
427 }
428
429 /**
430 * Private classes
431 */
432
433 private class CheckStateListener implements ICheckStateListener {
434
435 CheckStateListener() {
436 }
437 @Override
438 public void checkStateChanged(CheckStateChangedEvent event) {
439 try {
440 ITimeGraphEntry entry = (ITimeGraphEntry) event.getElement();
441 boolean checked = event.getChecked();
442 if (!checked) {
443 uncheckChildren(entry);
444 }
445 else
446 {
447 checkParent(entry);
448 }
449 } catch (ClassCastException e) {
450 return;
451 }
452 }
453
454 private void uncheckChildren(ITimeGraphEntry entry) {
455
456 for (ITimeGraphEntry child : entry.getChildren()) {
457 getTreeViewer().setChecked(child, false);
458 uncheckChildren(child);
459 }
460 }
461
462 private void checkParent(ITimeGraphEntry entry) {
463
464 if (entry.getParent() != null) {
465 getTreeViewer().setChecked(entry.getParent(), true);
466 checkParent(entry.getParent());
467 }
468 }
469 }
470}
This page took 0.055897 seconds and 5 git commands to generate.