Commit | Line | Data |
---|---|---|
40b7b614 GP |
1 | /******************************************************************************* |
2 | * Copyright (c) 2014 Inria | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * Generoso Pagano, Inria - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
2bdf0193 | 13 | package org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs; |
40b7b614 GP |
14 | |
15 | import java.util.HashSet; | |
16 | import java.util.Set; | |
17 | ||
18 | import org.eclipse.core.runtime.jobs.IJobChangeEvent; | |
19 | import org.eclipse.core.runtime.jobs.JobChangeAdapter; | |
20 | import org.eclipse.jface.viewers.CheckStateChangedEvent; | |
21 | import org.eclipse.jface.viewers.CheckboxTreeViewer; | |
22 | import org.eclipse.jface.viewers.ICheckStateListener; | |
23 | import org.eclipse.jface.viewers.ICheckable; | |
24 | import org.eclipse.jface.viewers.ITreeContentProvider; | |
25 | import org.eclipse.jface.viewers.TreeViewer; | |
26 | import org.eclipse.swt.widgets.Composite; | |
27 | import org.eclipse.ui.dialogs.FilteredTree; | |
28 | import org.eclipse.ui.dialogs.PatternFilter; | |
29 | import org.eclipse.ui.progress.WorkbenchJob; | |
30 | ||
31 | /** | |
32 | * A <code>FilteredTree</code> wrapping a <code>CheckboxTreeViewer</code>. | |
33 | * | |
34 | * This tree keeps the check state of the nodes in sync, regardless of the fact | |
35 | * that a node is filtered or not. This way, even if an node is filtered (not | |
36 | * visible), the caller can get and set the check state. | |
37 | * | |
38 | * Note that all the "uncheck" operations act only on what is not filtered and | |
39 | * what is child of something not filtered (even if such a child is filtered). | |
40 | * On the contrary, all the "check" operations act only on what is not filtered. | |
41 | * | |
42 | * @author "Generoso Pagano <generoso.pagano@inria.fr>" | |
40b7b614 GP |
43 | */ |
44 | public class FilteredCheckboxTree extends FilteredTree implements ICheckable { | |
45 | ||
46 | /** | |
47 | * Set containing only the tree items that are checked | |
48 | */ | |
49 | private Set<Object> fObjects = new HashSet<>(); | |
50 | ||
51 | /** | |
52 | * Handle to the tree viewer | |
53 | */ | |
54 | private CheckboxTreeViewer fCheckboxTreeViewer; | |
55 | ||
56 | /** | |
57 | * Create a new instance of the receiver. | |
58 | * | |
59 | * @param parent | |
60 | * the parent <code>Composite</code> | |
61 | * @param treeStyle | |
62 | * the style bits for the <code>Tree</code> | |
63 | * @param filter | |
64 | * the filter to be used | |
65 | * @param useNewLook | |
66 | * <code>true</code> if the new <code>FilteredTree</code> look | |
67 | * should be used | |
68 | */ | |
69 | public FilteredCheckboxTree(Composite parent, int treeStyle, PatternFilter filter, | |
70 | boolean useNewLook) { | |
71 | super(parent, treeStyle, filter, useNewLook); | |
72 | } | |
73 | ||
74 | @Override | |
75 | protected TreeViewer doCreateTreeViewer(Composite parentComposite, int style) { | |
76 | fCheckboxTreeViewer = new CheckboxTreeViewer(parentComposite, style); | |
ded8b718 | 77 | fCheckboxTreeViewer.setUseHashlookup(true); |
40b7b614 GP |
78 | fCheckboxTreeViewer.addCheckStateListener(new ICheckStateListener() { |
79 | @Override | |
80 | public void checkStateChanged(CheckStateChangedEvent event) { | |
81 | if (event.getChecked()) { | |
82 | fObjects.add(event.getElement()); | |
83 | } else { | |
84 | fObjects.remove(event.getElement()); | |
85 | } | |
86 | } | |
87 | }); | |
88 | return fCheckboxTreeViewer; | |
89 | } | |
90 | ||
91 | @Override | |
92 | protected WorkbenchJob doCreateRefreshJob() { | |
93 | WorkbenchJob job = super.doCreateRefreshJob(); | |
94 | job.addJobChangeListener(new JobChangeAdapter() { | |
95 | @Override | |
96 | public void done(IJobChangeEvent event) { | |
97 | fCheckboxTreeViewer.expandAll(); | |
98 | fCheckboxTreeViewer.setCheckedElements(getCheckedElements()); | |
99 | } | |
100 | }); | |
101 | return job; | |
102 | } | |
103 | ||
104 | @Override | |
105 | public boolean getChecked(Object element) { | |
106 | return fObjects.contains(element); | |
107 | } | |
108 | ||
109 | @Override | |
110 | public boolean setChecked(Object element, boolean state) { | |
111 | boolean checkable = fCheckboxTreeViewer.setChecked(element, state); | |
112 | if (!state) { | |
113 | fObjects.remove(element); | |
114 | } else if (checkable) { | |
115 | fObjects.add(element); | |
116 | } | |
117 | return checkable; | |
118 | } | |
119 | ||
120 | @Override | |
121 | public void addCheckStateListener(ICheckStateListener listener) { | |
122 | fCheckboxTreeViewer.addCheckStateListener(listener); | |
123 | } | |
124 | ||
125 | @Override | |
126 | public void removeCheckStateListener(ICheckStateListener listener) { | |
127 | fCheckboxTreeViewer.addCheckStateListener(listener); | |
128 | } | |
129 | ||
130 | /** | |
131 | * Returns all the checked elements of this tree, either visible or not. | |
132 | * | |
133 | * @return an array containing all the checked elements | |
134 | */ | |
135 | public Object[] getCheckedElements() { | |
136 | return fObjects.toArray(); | |
137 | } | |
138 | ||
139 | /** | |
140 | * Checks all the passed elements and unchecks all the other. | |
141 | * | |
142 | * @param elements | |
143 | * the elements to check | |
144 | */ | |
145 | public void setCheckedElements(Object[] elements) { | |
146 | fObjects = new HashSet<>(); | |
147 | for (Object element : elements) { | |
148 | fObjects.add(element); | |
149 | } | |
150 | fCheckboxTreeViewer.setCheckedElements(elements); | |
151 | } | |
152 | ||
153 | /** | |
154 | * Sets the check state for the given element and its children in this | |
155 | * viewer. The unchecked state is always set, while the checked state is set | |
156 | * only on visible elements. | |
157 | * | |
158 | * @param element | |
159 | * the element | |
160 | * @param state | |
161 | * the check state to set | |
162 | * @return <code>true</code> if the check state could be set, and | |
163 | * <code>false</code> otherwise | |
164 | */ | |
165 | public boolean setSubtreeChecked(Object element, boolean state) { | |
166 | checkSubtree(element, state); | |
167 | return fCheckboxTreeViewer.setSubtreeChecked(element, state); | |
168 | } | |
169 | ||
170 | /** | |
171 | * Recursively sets the check state on an element and its children, using | |
172 | * the politic specified in {@link #setSubtreeChecked(Object, boolean)} | |
173 | * documentation. | |
174 | * | |
175 | * @param element | |
176 | * the element | |
177 | * @param state | |
178 | * the check state to set | |
179 | */ | |
180 | private void checkSubtree(Object element, boolean state) { | |
181 | if (!state || (fCheckboxTreeViewer.testFindItem(element) != null)) { | |
182 | if (state) { | |
183 | fObjects.add(element); | |
184 | } else { | |
185 | fObjects.remove(element); | |
186 | } | |
187 | for (Object o : ((ITreeContentProvider) fCheckboxTreeViewer.getContentProvider()).getChildren(element)) { | |
188 | checkSubtree(o, state); | |
189 | } | |
190 | } | |
191 | } | |
192 | ||
193 | } |