1
+ /*******************************************************************************
2
+ * Copyright (c) 2025 Patrick Ziegler and others.
3
+ *
4
+ * This program and the accompanying materials
5
+ * are made available under the terms of the Eclipse Public License 2.0
6
+ * which accompanies this distribution, and is available at
7
+ * https://www.eclipse.org/legal/epl-2.0/
8
+ *
9
+ * SPDX-License-Identifier: EPL-2.0
10
+ *
11
+ * Contributors:
12
+ * Patrick Ziegler - initial API and implementation
13
+ *******************************************************************************/
14
+ package org .eclipse .pde .internal .ui .shared ;
15
+
16
+ import java .util .Collections ;
17
+ import java .util .HashSet ;
18
+ import java .util .Set ;
19
+
20
+ import org .eclipse .jface .viewers .CheckboxTableViewer ;
21
+ import org .eclipse .jface .viewers .CheckboxTreeViewer ;
22
+ import org .eclipse .swt .widgets .Table ;
23
+ import org .eclipse .swt .widgets .Tree ;
24
+
25
+ /**
26
+ * Counterpart of the {@link CachedCheckboxTreeViewer} which is specialized for
27
+ * use with {@link FilteredCheckboxTable}. This viewer caches the check state of
28
+ * the table items. When a filter is applied the cache stores which nodes are
29
+ * checked. When a filter is removed the viewer can be told to restore check
30
+ * state from the cache.
31
+ * <p>
32
+ * Note: If duplicate items are added to the table the cache will treat them as
33
+ * a single entry.
34
+ * </p>
35
+ */
36
+ public class CachedCheckboxTableViewer extends CheckboxTableViewer {
37
+
38
+ private Set <Object > checkState = new HashSet <>();
39
+ private static final Object [] NO_ELEMENTS = new Object [0 ];
40
+
41
+ /**
42
+ * Constructor for ContainerCheckedTreeViewer.
43
+ * @see CheckboxTreeViewer#CheckboxTreeViewer(Tree)
44
+ */
45
+ protected CachedCheckboxTableViewer (Table table ) {
46
+ super (table );
47
+ addCheckStateListener (event -> updateCheckState (event .getElement (), event .getChecked ()));
48
+ setUseHashlookup (true );
49
+ }
50
+
51
+ protected void updateCheckState (Object element , boolean state ) {
52
+ if (state ) {
53
+ checkState .add (element );
54
+ } else {
55
+ checkState .remove (element );
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Restores the checked state of items based on the cached check state.No
61
+ * events will be fired.
62
+ */
63
+ public void restoreCachedState () {
64
+ getTable ().setRedraw (false );
65
+ // Call the super class so we don't mess up the cache
66
+ super .setCheckedElements (NO_ELEMENTS );
67
+ setGrayedElements (NO_ELEMENTS );
68
+ // Now we are only going to set the check state of the leaf nodes
69
+ // and rely on our container checked code to update the parents properly.
70
+ super .setCheckedElements (checkState .toArray ());
71
+ getTable ().setRedraw (true );
72
+ }
73
+
74
+ @ Override
75
+ protected void preservingSelection (Runnable updateCode ) {
76
+ super .preservingSelection (updateCode );
77
+ // The super class implementation will preserve a root element's check
78
+ // mark but that can cause newly unfiltered children to become check
79
+ // marked.
80
+ // See https://github.com/eclipse-pde/eclipse.pde/issues/62
81
+ restoreCachedState ();
82
+ }
83
+
84
+ /**
85
+ * Returns the contents of the cached check state. The contents will be all
86
+ * checked leaf nodes ignoring any filters.
87
+ *
88
+ * @return checked leaf elements
89
+ */
90
+ public Object [] getAllCheckedElements () {
91
+ return checkState .toArray (new Object [checkState .size ()]);
92
+ }
93
+
94
+ /**
95
+ * Returns the number of checked nodes. This method uses its internal check
96
+ * state cache to determine what has been checked, not what is visible in
97
+ * the viewer. The cache does not count duplicate items in the table.
98
+ *
99
+ * @return number of elements checked according to the cached check state
100
+ */
101
+ public int getAllCheckedCount () {
102
+ return checkState .size ();
103
+ }
104
+
105
+ /**
106
+ * Returns whether {@code element} is checked. This method uses its internal
107
+ * check state cache to determine what has been checked, not what is visible
108
+ * in the viewer.
109
+ */
110
+ public boolean isCheckedElement (Object element ) {
111
+ return checkState .contains (element );
112
+ }
113
+
114
+ @ Override
115
+ public boolean setChecked (Object element , boolean state ) {
116
+ updateCheckState (element , state );
117
+ return super .setChecked (element , state );
118
+ }
119
+
120
+ @ Override
121
+ public void setCheckedElements (Object [] elements ) {
122
+ checkState .clear ();
123
+ for (Object element : elements ) {
124
+ checkState .add (element );
125
+ }
126
+ super .setCheckedElements (elements );
127
+ }
128
+
129
+ @ Override
130
+ public void setAllChecked (boolean state ) {
131
+ super .setAllChecked (state );
132
+ if (state ) {
133
+ // Find all visible children and check them
134
+ Object [] visible = getFilteredChildren (getRoot ());
135
+ Collections .addAll (checkState , visible );
136
+ } else {
137
+ // Remove any item in the check state that is visible (passes the filters)
138
+ Object [] visible = filter (checkState .toArray ());
139
+ for (Object visibleObject : visible ) {
140
+ checkState .remove (visibleObject );
141
+ }
142
+ }
143
+ }
144
+
145
+ @ Override
146
+ public void remove (Object [] elements ) {
147
+ for (Object element : elements ) {
148
+ updateCheckState (element , false );
149
+ }
150
+ super .remove (elements );
151
+ }
152
+
153
+ @ Override
154
+ public void remove (Object element ) {
155
+ updateCheckState (element , false );
156
+ super .remove (element );
157
+ }
158
+ }
0 commit comments