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