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
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 *******************************************************************************/
19 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.dialogs
;
21 import java
.util
.ArrayList
;
22 import java
.util
.Arrays
;
23 import java
.util
.List
;
25 import org
.eclipse
.core
.runtime
.IStatus
;
26 import org
.eclipse
.core
.runtime
.Status
;
27 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
28 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
29 import org
.eclipse
.jface
.viewers
.CheckboxTreeViewer
;
30 import org
.eclipse
.jface
.viewers
.IBaseLabelProvider
;
31 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
32 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
33 import org
.eclipse
.jface
.viewers
.TreeSelection
;
34 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
35 import org
.eclipse
.jface
.viewers
.ViewerFilter
;
36 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Messages
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
38 import org
.eclipse
.swt
.SWT
;
39 import org
.eclipse
.swt
.custom
.BusyIndicator
;
40 import org
.eclipse
.swt
.events
.SelectionAdapter
;
41 import org
.eclipse
.swt
.events
.SelectionEvent
;
42 import org
.eclipse
.swt
.layout
.GridData
;
43 import org
.eclipse
.swt
.layout
.GridLayout
;
44 import org
.eclipse
.swt
.widgets
.Button
;
45 import org
.eclipse
.swt
.widgets
.Composite
;
46 import org
.eclipse
.swt
.widgets
.Control
;
47 import org
.eclipse
.swt
.widgets
.Label
;
48 import org
.eclipse
.swt
.widgets
.Shell
;
49 import org
.eclipse
.swt
.widgets
.Tree
;
50 import org
.eclipse
.swt
.widgets
.TreeColumn
;
51 import org
.eclipse
.ui
.PlatformUI
;
52 import org
.eclipse
.ui
.dialogs
.ISelectionStatusValidator
;
53 import org
.eclipse
.ui
.dialogs
.SelectionStatusDialog
;
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
62 * @author François Rajotte
64 public class TimeGraphFilterDialog
extends SelectionStatusDialog
{
65 private static final int BUTTON_CHECK_SELECTED_ID
= IDialogConstants
.CLIENT_ID
;
66 private static final int BUTTON_UNCHECK_SELECTED_ID
= IDialogConstants
.CLIENT_ID
+ 1;
67 private static final int BUTTON_CHECK_SUBTREE_ID
= IDialogConstants
.CLIENT_ID
+ 2;
68 private static final int BUTTON_UNCHECK_SUBTREE_ID
= IDialogConstants
.CLIENT_ID
+ 3;
70 private static final int DEFAULT_WIDTH
= 60;
71 private static final int DEFAULT_HEIGHT
= 18;
73 private CheckboxTreeViewer fViewer
;
75 private IBaseLabelProvider fLabelProvider
;
77 private ITreeContentProvider fContentProvider
;
79 private String
[] fColumnNames
;
81 private ISelectionStatusValidator fValidator
= null;
83 private ViewerComparator fComparator
;
85 private String fEmptyListMessage
= ""; //$NON-NLS-1$
87 private IStatus fCurrStatus
= new Status(IStatus
.OK
, PlatformUI
.PLUGIN_ID
,
88 0, "", null); //$NON-NLS-1$
90 private List
<ViewerFilter
> fFilters
;
92 private Object fInput
;
94 private boolean fIsEmpty
;
96 private int fWidth
= DEFAULT_WIDTH
;
98 private int fHeight
= DEFAULT_HEIGHT
;
100 private Object
[] fExpandedElements
;
103 * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
106 * The shell to parent from.
108 public TimeGraphFilterDialog(Shell parent
) {
110 setResult(new ArrayList
<>(0));
111 setStatusLineAboveButtons(true);
112 setHelpAvailable(false);
113 fExpandedElements
= null;
117 * Sets the initial selection. Convenience method.
120 * the initial selection.
122 public void setInitialSelection(Object selection
) {
123 setInitialSelections(new Object
[] { selection
});
127 * Sets the message to be displayed if the list is empty.
130 * the message to be displayed.
132 public void setEmptyListMessage(String message
) {
133 fEmptyListMessage
= message
;
137 * Sets the comparator used by the tree viewer.
142 public void setComparator(ViewerComparator comparator
) {
143 fComparator
= comparator
;
147 * Adds a filter to the tree viewer.
152 public void addFilter(ViewerFilter filter
) {
153 if (fFilters
== null) {
154 fFilters
= new ArrayList
<>();
156 fFilters
.add(filter
);
160 * Sets an optional validator to check if the selection is valid. The
161 * validator is invoked whenever the selection changes.
164 * the validator to validate the selection.
166 public void setValidator(ISelectionStatusValidator validator
) {
167 fValidator
= validator
;
171 * Sets the tree input.
176 public void setInput(Object input
) {
181 * Expands elements in the tree.
184 * The elements that will be expanded.
186 public void setExpandedElements(Object
[] elements
) {
187 if (elements
!= null) {
188 fExpandedElements
= Arrays
.copyOf(elements
, elements
.length
);
190 fExpandedElements
= null;
195 * Sets the size of the tree in unit of characters.
198 * the width of the tree.
200 * the height of the tree.
202 public void setSize(int width
, int height
) {
208 * @param contentProvider The content provider for the table
210 public void setContentProvider(ITreeContentProvider contentProvider
) {
211 fContentProvider
= contentProvider
;
215 * @param labelProvider The label provider for the table
217 public void setLabelProvider(IBaseLabelProvider labelProvider
) {
218 fLabelProvider
= labelProvider
;
222 * @param columnNames An array of column names to display
224 public void setColumnNames(String
[] columnNames
) {
225 if (columnNames
!= null) {
226 fColumnNames
= Arrays
.copyOf(columnNames
, columnNames
.length
);
233 * Validate the receiver and update the status with the result.
236 protected void updateOKStatus() {
238 if (fValidator
!= null) {
239 fCurrStatus
= fValidator
.validate(fViewer
.getCheckedElements());
240 updateStatus(fCurrStatus
);
241 } else if (!fCurrStatus
.isOK()) {
242 fCurrStatus
= new Status(IStatus
.OK
, PlatformUI
.PLUGIN_ID
,
243 IStatus
.OK
, "", //$NON-NLS-1$
247 fCurrStatus
= new Status(IStatus
.ERROR
, PlatformUI
.PLUGIN_ID
,
248 IStatus
.OK
, fEmptyListMessage
, null);
250 updateStatus(fCurrStatus
);
255 fIsEmpty
= evaluateIfTreeEmpty(fInput
);
257 return getReturnCode();
261 protected void cancelPressed() {
263 super.cancelPressed();
267 protected void computeResult() {
268 setResult(Arrays
.asList(fViewer
.getCheckedElements()));
272 public void create() {
273 BusyIndicator
.showWhile(null, new Runnable() {
276 TimeGraphFilterDialog
.super.create();
277 fViewer
.setCheckedElements(getInitialElementSelections()
279 if (fExpandedElements
!= null) {
280 fViewer
.setExpandedElements(fExpandedElements
);
288 protected Control
createDialogArea(Composite parent
) {
289 Composite composite
= (Composite
) super.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());
300 messageLabel
.setEnabled(false);
301 treeWidget
.setEnabled(false);
302 buttonComposite
.setEnabled(false);
308 * Creates the tree viewer.
311 * the parent composite
312 * @return the tree viewer
314 protected CheckboxTreeViewer
createTreeViewer(Composite parent
) {
315 fViewer
= new CheckboxTreeViewer(parent
, SWT
.BORDER
| SWT
.MULTI
);
317 Tree tree
= fViewer
.getTree();
318 tree
.setHeaderVisible(true);
319 for (String columnName
: fColumnNames
) {
320 TreeColumn column
= new TreeColumn(tree
, SWT
.LEFT
);
321 column
.setText(columnName
);
325 fViewer
.setContentProvider(fContentProvider
);
326 fViewer
.setLabelProvider(fLabelProvider
);
327 fViewer
.addCheckStateListener(new CheckStateListener());
328 fViewer
.addCheckStateListener(new ICheckStateListener() {
330 public void checkStateChanged(CheckStateChangedEvent event
) {
334 fViewer
.setComparator(fComparator
);
335 if (fFilters
!= null) {
336 for (int i
= 0; i
!= fFilters
.size(); i
++) {
337 fViewer
.addFilter(fFilters
.get(i
));
340 fViewer
.setInput(fInput
);
342 //pack the columns again for a nice view...
343 for (TreeColumn column
: tree
.getColumns()) {
350 * Returns the tree viewer.
352 * @return the tree viewer
354 protected CheckboxTreeViewer
getTreeViewer() {
359 * Adds the selection and deselection buttons to the dialog.
362 * the parent composite
363 * @return Composite the composite the buttons were created in.
365 protected Composite
createSelectionButtons(Composite composite
) {
366 Composite buttonComposite
= new Composite(composite
, SWT
.RIGHT
);
367 GridLayout layout
= new GridLayout();
368 layout
.marginWidth
= 0;
369 layout
.horizontalSpacing
= convertHorizontalDLUsToPixels(IDialogConstants
.HORIZONTAL_SPACING
);
370 buttonComposite
.setLayout(layout
);
371 buttonComposite
.setFont(composite
.getFont());
372 GridData data
= new GridData(GridData
.HORIZONTAL_ALIGN_END
373 | GridData
.GRAB_HORIZONTAL
);
374 data
.grabExcessHorizontalSpace
= true;
375 buttonComposite
.setLayoutData(data
);
377 /* Create the buttons in the good order to place them as we want */
378 Button checkSelectedButton
= createButton(buttonComposite
,
379 BUTTON_CHECK_SELECTED_ID
, Messages
.TmfTimeFilterDialog_CHECK_SELECTED
,
381 Button checkSubtreeButton
= createButton(buttonComposite
,
382 BUTTON_CHECK_SUBTREE_ID
, Messages
.TmfTimeFilterDialog_CHECK_SUBTREE
,
384 Button checkAllButton
= createButton(buttonComposite
,
385 IDialogConstants
.SELECT_ALL_ID
, Messages
.TmfTimeFilterDialog_CHECK_ALL
,
388 Button uncheckSelectedButton
= createButton(buttonComposite
,
389 BUTTON_UNCHECK_SELECTED_ID
, Messages
.TmfTimeFilterDialog_UNCHECK_SELECTED
,
391 Button uncheckSubtreeButton
= createButton(buttonComposite
,
392 BUTTON_UNCHECK_SUBTREE_ID
, Messages
.TmfTimeFilterDialog_UNCHECK_SUBTREE
,
394 Button uncheckAllButton
= createButton(buttonComposite
,
395 IDialogConstants
.DESELECT_ALL_ID
, Messages
.TmfTimeFilterDialog_UNCHECK_ALL
,
400 * Apply the layout again after creating the buttons to override
401 * createButton messing with the columns
403 layout
.numColumns
= 3;
404 buttonComposite
.setLayout(layout
);
406 /* Add a listener to each button */
407 checkSelectedButton
.addSelectionListener(new SelectionAdapter() {
409 public void widgetSelected(SelectionEvent e
) {
410 TreeSelection selection
= (TreeSelection
) fViewer
.getSelection();
412 for (Object element
: selection
.toArray()) {
413 checkElement(element
);
420 checkSubtreeButton
.addSelectionListener(new SelectionAdapter() {
422 public void widgetSelected(SelectionEvent e
) {
423 TreeSelection selection
= (TreeSelection
) fViewer
.getSelection();
425 for (Object element
: selection
.toArray()) {
426 checkElementAndSubtree(element
);
431 checkAllButton
.addSelectionListener(new SelectionAdapter() {
433 public void widgetSelected(SelectionEvent e
) {
434 Object
[] viewerElements
= fContentProvider
.getElements(fInput
);
436 for (int i
= 0; i
< viewerElements
.length
; i
++) {
437 fViewer
.setSubtreeChecked(viewerElements
[i
], true);
444 uncheckSelectedButton
.addSelectionListener(new SelectionAdapter() {
446 public void widgetSelected(SelectionEvent e
) {
447 TreeSelection selection
= (TreeSelection
) fViewer
.getSelection();
449 for (Object element
: selection
.toArray()) {
450 uncheckElement(element
);
457 uncheckSubtreeButton
.addSelectionListener(new SelectionAdapter() {
459 public void widgetSelected(SelectionEvent e
) {
460 TreeSelection selection
= (TreeSelection
) fViewer
.getSelection();
462 for (Object element
: selection
.toArray()) {
463 uncheckElement(element
);
470 uncheckAllButton
.addSelectionListener(new SelectionAdapter() {
472 public void widgetSelected(SelectionEvent e
) {
473 fViewer
.setCheckedElements(new Object
[0]);
478 return buttonComposite
;
482 * Check an element and all its parents.
485 * The element to check.
487 private void checkElement(Object element
) {
488 fViewer
.setChecked(element
, true);
490 Object parent
= fContentProvider
.getParent(element
);
492 if (parent
!= null) {
493 checkElement(parent
);
498 * Check an element, all its parents and all its children.
501 * The element to check.
503 private void checkElementAndSubtree(Object element
) {
504 checkElement(element
);
506 for (Object child
: fContentProvider
.getChildren(element
)) {
507 checkElementAndSubtree(child
);
512 * Uncheck an element and all its children.
515 * The element to uncheck.
517 private void uncheckElement(Object element
) {
518 fViewer
.setChecked(element
, false);
520 for (Object child
: fContentProvider
.getChildren(element
)) {
521 uncheckElement(child
);
525 private boolean evaluateIfTreeEmpty(Object input
) {
526 Object
[] elements
= fContentProvider
.getElements(input
);
527 if (elements
.length
> 0 && fFilters
!= null) {
528 for (int i
= 0; i
< fFilters
.size(); i
++) {
529 ViewerFilter curr
= fFilters
.get(i
);
530 elements
= curr
.filter(fViewer
, input
, elements
);
533 return elements
.length
== 0;
540 private class CheckStateListener
implements ICheckStateListener
{
542 CheckStateListener() {
546 public void checkStateChanged(CheckStateChangedEvent event
) {
548 ITimeGraphEntry entry
= (ITimeGraphEntry
) event
.getElement();
549 boolean checked
= event
.getChecked();
553 uncheckElement(entry
);
555 } catch (ClassCastException e
) {