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