Skip to content

Commit 12ec3ef

Browse files
committed
Wrap viewer in CheckboxTablePart within a FilteredTable
By using the FilteredTable, we get a quick-filter for all extending parts for free. This includes: - The Cross-platform page of the "Deployable features" export wizard. - The Update Java Classpath page of the "Update classpath..." action - The Selection page of the "Import Plug-ins and Fragments" wizard - The Update Java Classpath page of the "Plug-in from Existing JAR Archives" wizard. - The Template Selection page of the "Plug-in Project" page. Together with the quick-filter comes a caching of the checked table items. Those elements remain checked, even if currently hidden by the filter and will be restored once they become visible again. Furthermore, the PluginListPage has been adapted to use a CheckboxTablePart rather than a CheckboxTreePart (effectively reverting 4c1edad), to match the list of plugins that it displays. Contributes to #1497
1 parent c7d99fd commit 12ec3ef

12 files changed

+391
-68
lines changed

ui/org.eclipse.pde.ui/.settings/.api_filters

+8
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@
120120
</message_arguments>
121121
</filter>
122122
</resource>
123+
<resource path="src/org/eclipse/pde/internal/ui/shared/CachedCheckboxTableViewer.java" type="org.eclipse.pde.internal.ui.shared.CachedCheckboxTableViewer">
124+
<filter comment="Extends CheckboxTableViewer to match CachedCheckboxTreeviewer" id="571473929">
125+
<message_arguments>
126+
<message_argument value="CheckboxTableViewer"/>
127+
<message_argument value="CachedCheckboxTableViewer"/>
128+
</message_arguments>
129+
</filter>
130+
</resource>
123131
<resource path="src/org/eclipse/pde/internal/ui/shared/target/EditTargetContainerPage.java" type="org.eclipse.pde.internal.ui.shared.target.EditTargetContainerPage">
124132
<filter id="640712815">
125133
<message_arguments>

ui/org.eclipse.pde.ui/META-INF/MANIFEST.MF

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Require-Bundle:
7777
org.eclipse.pde.core;bundle-version="[3.17.200,4.0.0)";visibility:=reexport,
7878
org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)",
7979
org.eclipse.e4.core.services;bundle-version="[2.4.200,3.0.0)",
80+
org.eclipse.e4.ui.dialogs;bundle-version="[1.6.0,2.0.0)",
8081
org.eclipse.ui.ide;bundle-version="[3.21.200,4.0.0)",
8182
org.eclipse.ui.views;bundle-version="[3.12.100,4.0.0)",
8283
org.eclipse.jface.text;bundle-version="[3.24.200,4.0.0)",

ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/parts/CheckboxTablePart.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2018 IBM Corporation and others.
2+
* Copyright (c) 2000, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -13,15 +13,18 @@
1313
*******************************************************************************/
1414
package org.eclipse.pde.internal.ui.parts;
1515

16-
import org.eclipse.jface.viewers.CheckboxTableViewer;
1716
import org.eclipse.jface.viewers.IStructuredSelection;
1817
import org.eclipse.jface.viewers.StructuredViewer;
18+
import org.eclipse.pde.internal.ui.shared.CachedCheckboxTableViewer;
19+
import org.eclipse.pde.internal.ui.shared.FilteredCheckboxTable;
1920
import org.eclipse.swt.SWT;
2021
import org.eclipse.swt.widgets.Button;
2122
import org.eclipse.swt.widgets.Composite;
2223
import org.eclipse.ui.forms.widgets.FormToolkit;
2324

2425
public class CheckboxTablePart extends StructuredViewerPart {
26+
private FilteredCheckboxTable filteredTable;
27+
2528
public CheckboxTablePart(String[] buttonLabels) {
2629
super(buttonLabels);
2730
}
@@ -34,15 +37,16 @@ protected StructuredViewer createStructuredViewer(Composite parent, int style, F
3437
} else {
3538
style |= toolkit.getBorderStyle();
3639
}
37-
CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, style);
40+
filteredTable = new FilteredCheckboxTable(parent, toolkit, style);
41+
CachedCheckboxTableViewer tableViewer = filteredTable.getViewer();
3842
tableViewer
3943
.addSelectionChangedListener(e -> CheckboxTablePart.this.selectionChanged(e.getStructuredSelection()));
4044
tableViewer.addCheckStateListener(event -> elementChecked(event.getElement(), event.getChecked()));
4145
return tableViewer;
4246
}
4347

44-
public CheckboxTableViewer getTableViewer() {
45-
return (CheckboxTableViewer) getViewer();
48+
public CachedCheckboxTableViewer getTableViewer() {
49+
return (CachedCheckboxTableViewer) getViewer();
4650
}
4751

4852
@Override

ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/parts/WizardCheckboxTablePart.java

+24-27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2015 IBM Corporation and others.
2+
* Copyright (c) 2000, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -14,9 +14,11 @@
1414
package org.eclipse.pde.internal.ui.parts;
1515

1616
import org.eclipse.jface.viewers.CheckboxTableViewer;
17+
import org.eclipse.jface.viewers.IStructuredContentProvider;
1718
import org.eclipse.jface.viewers.StructuredViewer;
1819
import org.eclipse.osgi.util.NLS;
1920
import org.eclipse.pde.internal.ui.PDEUIMessages;
21+
import org.eclipse.pde.internal.ui.shared.CachedCheckboxTableViewer;
2022
import org.eclipse.pde.internal.ui.util.SWTUtil;
2123
import org.eclipse.pde.internal.ui.wizards.ListUtil;
2224
import org.eclipse.swt.SWT;
@@ -33,7 +35,6 @@ public class WizardCheckboxTablePart extends CheckboxTablePart {
3335
private int selectIndex = -1;
3436
private int deselectIndex = -1;
3537
private final String tableName;
36-
private int counter;
3738
private Label counterLabel;
3839

3940
/**
@@ -92,7 +93,7 @@ public Object[] getSelection() {
9293
public void setSelection(Object[] selected) {
9394
CheckboxTableViewer viewer = getTableViewer();
9495
viewer.setCheckedElements(selected);
95-
updateCounter(viewer.getCheckedElements().length);
96+
updateCounterLabel();
9697
}
9798

9899
public void createControl(Composite parent) {
@@ -105,7 +106,7 @@ public void createControl(Composite parent, int span) {
105106
GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_FILL);
106107
gd.horizontalSpan = span;
107108
counterLabel.setLayoutData(gd);
108-
updateCounter(0);
109+
updateCounterLabel();
109110
}
110111

111112
public void createControl(Composite parent, int span, boolean multiselect) {
@@ -118,7 +119,7 @@ public void createControl(Composite parent, int span, boolean multiselect) {
118119
GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_FILL);
119120
gd.horizontalSpan = span;
120121
counterLabel.setLayoutData(gd);
121-
updateCounter(0);
122+
updateCounterLabel();
122123
}
123124

124125
@Override
@@ -146,24 +147,19 @@ protected void createMainLabel(Composite parent, int span, FormToolkit toolkit)
146147
label.setLayoutData(gd);
147148
}
148149

149-
protected void updateCounter(int amount) {
150-
counter = amount;
151-
updateCounterLabel();
152-
}
153-
154-
public void updateCount(int amount) {
155-
updateCounter(amount);
156-
}
157-
158-
protected void updateCounterLabel() {
150+
public void updateCounterLabel() {
159151
String number = "" + getSelectionCount(); //$NON-NLS-1$
160152
String totalNumber = "" + getTotalCount(); //$NON-NLS-1$
161153
String message = NLS.bind(PDEUIMessages.WizardCheckboxTablePart_counter, (new String[] {number, totalNumber}));
162154
counterLabel.setText(message);
163155
}
164156

165157
public int getSelectionCount() {
166-
return counter;
158+
CachedCheckboxTableViewer viewer = getTableViewer();
159+
if (viewer == null) {
160+
return 0;
161+
}
162+
return viewer.getAllCheckedCount();
167163
}
168164

169165
public void selectAll(boolean select) {
@@ -172,19 +168,21 @@ public void selectAll(boolean select) {
172168

173169
private int getTotalCount() {
174170
CheckboxTableViewer viewer = getTableViewer();
175-
return viewer.getTable().getItemCount();
171+
if (viewer == null) {
172+
return 0;
173+
}
174+
175+
IStructuredContentProvider contentProvider = (IStructuredContentProvider) viewer.getContentProvider();
176+
if (contentProvider == null) {
177+
return 0;
178+
}
179+
return contentProvider.getElements(viewer.getInput()).length;
176180
}
177181

178182
protected void handleSelectAll(boolean select) {
179183
CheckboxTableViewer viewer = getTableViewer();
180184
viewer.setAllChecked(select);
181-
int selected;
182-
if (!select) {
183-
selected = 0;
184-
} else {
185-
selected = getTotalCount();
186-
}
187-
updateCounter(selected);
185+
updateCounterLabel();
188186
}
189187

190188
protected void handleSelect(boolean select) {
@@ -194,14 +192,13 @@ protected void handleSelect(boolean select) {
194192
for (TableItem selectedItem : selected) {
195193
selectedItem.setChecked(select);
196194
}
197-
updateCounter(viewer.getCheckedElements().length);
195+
updateCounterLabel();
198196
}
199197
}
200198

201199
@Override
202200
protected void elementChecked(Object element, boolean checked) {
203-
int count = getSelectionCount();
204-
updateCounter(checked ? count + 1 : count - 1);
201+
updateCounterLabel();
205202
}
206203

207204
public Label getCounterLabel() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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

Comments
 (0)