From 5ccbcdae95281fdcdaa7375f1de23c9f9ef06318 Mon Sep 17 00:00:00 2001
From: Patrick Ziegler
+ * By default, this is set to
* Note: As of 4.13 not used anymore
* null
if there is no filter widget, or if the controls have not
+ * yet been created.
+ */
+ protected Text filterText;
+
+ /**
+ * The Composite on which the filter controls are created. This is used to set
+ * the background color of the filter controls to match the surrounding
+ * controls.
+ */
+ protected Composite filterComposite;
+
+ /**
+ * The text to initially show in the filter text control.
+ */
+ protected String initialText = ""; //$NON-NLS-1$
+
+ /**
+ * The job used to refresh the tree.
+ */
+ private Job refreshJob;
+
+ /**
+ * The parent composite of the filtered tree.
+ */
+ protected Composite parent;
+
+ /**
+ * Whether or not to show the filter controls (text and clear button). The
+ * default is to show these controls. This can be overridden by providing a
+ * setting in the product configuration file. The setting to add to not show
+ * these controls is:
+ *
+ * org.eclipse.ui/SHOW_FILTERED_TEXTS=false
+ */
+ protected boolean showFilterControls;
+
+ /**
+ * Tells whether this filtered tree is used to make quick selections. In this
+ * mode the first match in the tree is automatically selected while filtering
+ * and the 'Enter' key is not used to move the focus to the tree.
+ */
+ private boolean quickSelectionMode = false;
+
+ /**
+ * Time for refresh job delay in terms of expansion in long value
+ */
+ private final long refreshJobDelayInMillis;
+
+ protected AbstractFilteredViewer(Composite parent, int style, long refreshJobDelayInMillis) {
+ super(parent, style);
+ this.parent = parent;
+ this.refreshJobDelayInMillis = refreshJobDelayInMillis;
+ }
+
+ /**
+ * Create the viewer.
+ *
+ * @param style the style bits for the {@code viewer}.
+ */
+ protected final void init(int style) {
+ showFilterControls = PlatformUI.getPreferenceStore()
+ .getBoolean(IWorkbenchPreferenceConstants.SHOW_FILTERED_TEXTS);
+ createControl(parent, style);
+ createRefreshJob();
+ setInitialText(WorkbenchMessages.FilteredTree_FilterMessage);
+ setFont(parent.getFont());
+ getViewer().getControl().addDisposeListener(e -> refreshJob.cancel());
+ }
+
+ /**
+ * Create the filtered tree's controls. Subclasses should override.
+ *
+ * @param parent the parent
+ * @param treeStyle SWT style bits used to create the tree
+ */
+ protected void createControl(Composite parent, int treeStyle) {
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ setLayout(layout);
+
+ if (parent.getLayout() instanceof GridLayout) {
+ setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ }
+
+ if (showFilterControls) {
+ filterComposite = new Composite(this, SWT.NONE);
+ GridLayout filterLayout = new GridLayout();
+ filterLayout.marginHeight = 0;
+ filterLayout.marginWidth = 0;
+ filterComposite.setLayout(filterLayout);
+ filterComposite.setFont(parent.getFont());
+
+ createFilterControls(filterComposite);
+ filterComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+ }
+ }
+
+ /**
+ * Create the filter controls. By default, a text and corresponding tool bar
+ * button that clears the contents of the text is created. Subclasses may
+ * override.
+ *
+ * @param parent parent Composite
of the filter controls
+ * @return the Composite
that contains the filter controls
+ */
+ protected Composite createFilterControls(Composite parent) {
+ createFilterText(parent);
+ return parent;
+ }
+
+ /**
+ * Create the refresh job for the receiver.
+ */
+ private void createRefreshJob() {
+ refreshJob = doCreateRefreshJob();
+ refreshJob.setSystem(true);
+ }
+
+ /**
+ * Creates a workbench job that will refresh the tree based on the current
+ * filter text. Subclasses may override.
+ *
+ * @return a workbench job that can be scheduled to refresh the tree
+ */
+ protected abstract WorkbenchJob doCreateRefreshJob();
+
+ /**
+ * Creates the filter text and adds listeners. This method calls
+ * {@link #doCreateFilterText(Composite)} to create the text control. Subclasses
+ * should override {@link #doCreateFilterText(Composite)} instead of overriding
+ * this method.
+ *
+ * @param parent Composite
of the filter text
+ */
+ protected void createFilterText(Composite parent) {
+ filterText = doCreateFilterText(parent);
+
+ filterText.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ /*
+ * Running in an asyncExec because the selectAll() does not appear to work when
+ * using mouse to give focus to text.
+ */
+ Display display = filterText.getDisplay();
+ display.asyncExec(() -> {
+ if (!filterText.isDisposed()) {
+ if (getInitialText().equals(filterText.getText().trim())) {
+ filterText.selectAll();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (filterText.getText().equals(initialText)) {
+ setFilterText(""); //$NON-NLS-1$
+ textChanged();
+ }
+ }
+ });
+
+ filterText.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent e) {
+ if (filterText.getText().equals(initialText)) {
+ // XXX: We cannot call clearText() due to
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=260664
+ setFilterText(""); //$NON-NLS-1$
+ textChanged();
+ }
+ }
+ });
+
+ filterText.addModifyListener(e -> textChanged());
+
+ GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ filterText.setLayoutData(gridData);
+ }
+
+ /**
+ * Creates the text control for entering the filter text. Subclasses may
+ * override.
+ *
+ * @param parent the parent composite
+ * @return the text widget
+ */
+ protected Text doCreateFilterText(Composite parent) {
+ return new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
+ }
+
+ /**
+ * Update the receiver after the text has changed.
+ */
+ protected void textChanged() {
+ // cancel currently running job first, to prevent unnecessary redraw
+ refreshJob.cancel();
+ refreshJob.schedule(getRefreshJobDelay());
+ }
+
+ /**
+ * Return the time delay that should be used when scheduling the filter refresh
+ * job. Subclasses may override.
+ *
+ * @return a time delay in milliseconds before the job should run
+ */
+ protected long getRefreshJobDelay() {
+ return refreshJobDelayInMillis;
+ }
+
+ /**
+ * Clears the text in the filter text widget.
+ */
+ protected void clearText() {
+ setFilterText(""); //$NON-NLS-1$
+ textChanged();
+ }
+
+ /**
+ * Set the text in the filter control.
+ *
+ * @param filterText the text to set.
+ */
+ protected void setFilterText(String filterText) {
+ if (this.filterText != null) {
+ this.filterText.setText(filterText);
+ selectAll();
+ }
+ }
+
+ /**
+ * Get the column viewer of the receiver.
+ *
+ * @return the column viewer
+ */
+ public abstract ColumnViewer getViewer();
+
+ /**
+ * Get the filter text for the receiver, if it was created. Otherwise return
+ * null
.
+ *
+ * @return the filter Text, or null if it was not created
+ */
+ public Text getFilterControl() {
+ return filterText;
+ }
+
+ /**
+ * Convenience method to return the text of the filter control. If the text
+ * widget is not created, then null is returned.
+ *
+ * @return String in the text, or null if the text does not exist
+ */
+ protected String getFilterString() {
+ return filterText != null ? filterText.getText() : null;
+ }
+
+ /**
+ * Set the text that will be shown until the first focus. A default value is
+ * provided, so this method only need be called if overriding the default
+ * initial text is desired.
+ *
+ * @param text initial text to appear in text field
+ */
+ public void setInitialText(String text) {
+ initialText = text;
+ if (filterText != null) {
+ filterText.setMessage(text);
+ if (filterText.isFocusControl()) {
+ setFilterText(initialText);
+ textChanged();
+ } else {
+ getDisplay().asyncExec(() -> {
+ if (!filterText.isDisposed() && filterText.isFocusControl()) {
+ setFilterText(initialText);
+ textChanged();
+ }
+ });
+ }
+ } else {
+ setFilterText(initialText);
+ textChanged();
+ }
+ }
+
+ /**
+ * Sets whether this filtered tree is used to make quick selections. In this
+ * mode the first match in the tree is automatically selected while filtering
+ * and the 'Enter' key is not used to move the focus to the tree.
+ * false
.
+ * true
if this filtered tree is used to make quick
+ * selections, false
otherwise
+ */
+ public void setQuickSelectionMode(boolean enabled) {
+ this.quickSelectionMode = enabled;
+ }
+
+ /**
+ * Select all text in the filter text field.
+ */
+ protected void selectAll() {
+ if (filterText != null) {
+ filterText.selectAll();
+ }
+ }
+
+ /**
+ * Get the initial text for the receiver.
+ *
+ * @return String
+ */
+ protected String getInitialText() {
+ return initialText;
+ }
+
+ /**
+ * Get the quick selection mode.
+ *
+ * @return {@code true}, if enabled.
+ */
+ protected boolean isQuickSelectionMode() {
+ return quickSelectionMode;
+ }
+}
diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredTable.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredTable.java
new file mode 100644
index 00000000000..470ff207b35
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredTable.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Patrick Ziegler and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Patrick Ziegler - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.TextMatcher;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * A simple control that provides a text widget and a table viewer. The contents
+ * of the text widget are used to drive a TextMatcher that is on the viewer.
+ *
+ * @since 3.135
+ */
+public non-sealed class FilteredTable extends AbstractFilteredViewer {
+
+ /**
+ * Default time for refresh job delay in ms
+ */
+ private static final long DEFAULT_REFRESH_TIME = 200;
+
+ private TableViewer tableViewer;
+ private TextMatcher matcher;
+
+ public FilteredTable(Composite parent, int style) {
+ this(parent, style, DEFAULT_REFRESH_TIME);
+ }
+
+ public FilteredTable(Composite parent, int style, long refreshTime) {
+ super(parent, style, refreshTime);
+ init(style);
+ }
+
+ @Override
+ protected void createControl(Composite parent, int treeStyle) {
+ super.createControl(parent, treeStyle);
+
+ Composite tableComposite = new Composite(this, SWT.NONE);
+ GridLayout treeCompositeLayout = new GridLayout();
+ treeCompositeLayout.marginHeight = 0;
+ treeCompositeLayout.marginWidth = 0;
+ tableComposite.setLayout(treeCompositeLayout);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ tableComposite.setLayoutData(data);
+ createTableControl(tableComposite, treeStyle);
+ }
+
+ @Override
+ protected void createFilterText(Composite parent) {
+ super.createFilterText(parent);
+ filterText.getAccessible().addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(AccessibleEvent e) {
+ String filterTextString = filterText.getText();
+ if (filterTextString.isEmpty() || filterTextString.equals(initialText)) {
+ e.result = initialText;
+ } else {
+ e.result = NLS.bind(WorkbenchMessages.FilteredTree_AccessibleListenerFiltered,
+ new String[] { filterTextString, String.valueOf(getFilteredItemsCount()) });
+ }
+ }
+
+ private int getFilteredItemsCount() {
+ return getViewer().getTable().getItemCount();
+ }
+ });
+
+ filterText.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ // on a CR we want to transfer focus to the list
+ boolean hasItems = getViewer().getTable().getItemCount() > 0;
+ if (hasItems && e.keyCode == SWT.ARROW_DOWN) {
+ getViewer().getTable().setFocus();
+ return;
+ }
+ }
+ });
+
+ // enter key set focus to tree
+ filterText.addTraverseListener(e -> {
+ if (isQuickSelectionMode()) {
+ return;
+ }
+ if (e.detail == SWT.TRAVERSE_RETURN) {
+ e.doit = false;
+ updateTableSelection(true);
+ }
+ });
+ }
+
+ /**
+ * Updates the selection in the tree, based on the filter text.
+ *
+ * @param setFocus {@code true} if the focus should be set on the tree,
+ * {@code false} otherwise
+ */
+ private void updateTableSelection(boolean setFocus) {
+ Table table = tableViewer.getTable();
+ if (table.getItemCount() != 0) {
+ // if the initial filter text hasn't changed, do not try
+ // to match
+ boolean hasFocus = setFocus ? table.setFocus() : true;
+ boolean textChanged = !getInitialText().equals(filterText.getText().trim());
+ if (hasFocus && textChanged && filterText.getText().trim().length() > 0) {
+ TableItem item;
+ if (table.getSelectionCount() > 0) {
+ item = getFirstMatchingItem(table.getSelection());
+ } else {
+ item = getFirstMatchingItem(table.getItems());
+ }
+ if (item != null) {
+ table.setSelection(new TableItem[] { item });
+ tableViewer.setSelection(tableViewer.getSelection(), true);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the first item in the tree that matches the filter pattern.
+ *
+ * @return the first matching TreeItem
+ */
+ private TableItem getFirstMatchingItem(TableItem[] items) {
+ for (TableItem item : items) {
+ if (matcher == null) {
+ return item;
+ }
+
+ ILabelProvider labelProvider = (ILabelProvider) getViewer().getLabelProvider();
+ if (matcher.match(labelProvider.getText(item.getData()))) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates and set up the table and table viewer. This method calls
+ * {@link #doCreateTableViewer(Composite, int)} to create the table viewer.
+ * Subclasses should override {@link #doCreateTableViewer(Composite, int)}
+ * instead of overriding this method.
+ *
+ * @param parent parent Composite
+ * @param style SWT style bits used to create the table
+ * @return the table
+ */
+ protected Table createTableControl(Composite parent, int style) {
+ tableViewer = doCreateTableViewer(parent, style);
+ tableViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ tableViewer.addFilter(new ViewerFilter() {
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (matcher == null) {
+ return true;
+ }
+ ILabelProvider labelProvider = (ILabelProvider) tableViewer.getLabelProvider();
+ return matcher.match(labelProvider.getText(element));
+ }
+ });
+ return tableViewer.getTable();
+ }
+
+ /**
+ * Creates the table viewer. Subclasses may override.
+ *
+ * @param parent the parent composite
+ * @param style SWT style bits used to create the table viewer
+ * @return the table viewer
+ */
+ protected TableViewer doCreateTableViewer(Composite parent, int style) {
+ return new TableViewer(parent, style);
+ }
+
+ @Override
+ public TableViewer getViewer() {
+ return tableViewer;
+ }
+
+ @Override
+ protected WorkbenchJob doCreateRefreshJob() {
+ return new WorkbenchJob("Refresh Filter") {//$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ if (getViewer().getControl().isDisposed()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ String text = getFilterString();
+ if (text == null) {
+ return Status.OK_STATUS;
+ }
+
+ boolean initial = initialText != null && initialText.equals(text);
+ if (initial) {
+ matcher = null;
+ } else if (text != null) {
+ matcher = new TextMatcher(text + '*', true, false);
+ }
+
+ tableViewer.refresh(true);
+
+ if (isQuickSelectionMode()) {
+ updateTableSelection(false);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ }
+}
diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredTree.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredTree.java
index 24e2d884217..49d1601bd66 100644
--- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredTree.java
+++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredTree.java
@@ -19,7 +19,6 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.IContentProvider;
@@ -29,24 +28,16 @@
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
-import org.eclipse.ui.IWorkbenchPreferenceConstants;
-import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.progress.WorkbenchJob;
@@ -57,20 +48,16 @@
* @see org.eclipse.ui.dialogs.PatternFilter
* @since 3.2
*/
-public class FilteredTree extends Composite {
-
- /**
- * The filter text widget to be used by this tree. This value may be
- * null
if there is no filter widget, or if the controls have not
- * yet been created.
- */
- protected Text filterText;
+public non-sealed class FilteredTree extends AbstractFilteredViewer {
/**
*
null
.
*/
private PatternFilter patternFilter;
- /**
- * The text to initially show in the filter text control.
- */
- protected String initialText = ""; //$NON-NLS-1$
-
- /**
- * The job used to refresh the tree.
- */
- private Job refreshJob;
-
- /**
- * The parent composite of the filtered tree.
- *
- * @since 3.3
- */
- protected Composite parent;
-
- /**
- * Whether or not to show the filter controls (text and clear button). The
- * default is to show these controls. This can be overridden by providing a
- * setting in the product configuration file. The setting to add to not show
- * these controls is:
- *
- * org.eclipse.ui/SHOW_FILTERED_TEXTS=false
- */
- protected boolean showFilterControls;
-
/**
* @since 3.3
*/
protected Composite treeComposite;
- /**
- * Tells whether this filtered tree is used to make quick selections. In this
- * mode the first match in the tree is automatically selected while filtering
- * and the 'Enter' key is not used to move the focus to the tree.
- *
- * @since 3.105
- */
- private boolean quickSelectionMode = false;
-
/**
* Maximum time spent expanding the tree after the filter text has been updated
* (this is only used if we were able to at least expand the visible nodes)
*/
private static final long SOFT_MAX_EXPAND_TIME = 200;
- /**
- * Time for refresh job delay in terms of expansion in long value
- */
- private final long refreshJobDelayInMillis;
-
/**
* Default time for refresh job delay in ms
*/
@@ -179,9 +120,7 @@ public class FilteredTree extends Composite {
* @since 3.116
*/
public FilteredTree(Composite parent, boolean useNewLook, boolean useFastHashLookup) {
- super(parent, SWT.NONE);
- this.parent = parent;
- this.refreshJobDelayInMillis = DEFAULT_REFRESH_TIME;
+ super(parent, SWT.NONE, DEFAULT_REFRESH_TIME);
if (treeViewer != null) {
treeViewer.setUseHashlookup(useFastHashLookup);
}
@@ -225,9 +164,7 @@ public FilteredTree(Composite parent, int treeStyle, PatternFilter filter, boole
*/
public FilteredTree(Composite parent, int treeStyle, PatternFilter filter, boolean useNewLook,
boolean useFastHashLookup, long refreshJobDelayInMillis) {
- super(parent, SWT.NONE);
- this.parent = parent;
- this.refreshJobDelayInMillis = refreshJobDelayInMillis;
+ super(parent, SWT.NONE, refreshJobDelayInMillis);
init(treeStyle, filter);
if (treeViewer != null) {
treeViewer.setUseHashlookup(useFastHashLookup);
@@ -257,9 +194,7 @@ public FilteredTree(Composite parent, int treeStyle, PatternFilter filter, boole
*/
@Deprecated
protected FilteredTree(Composite parent) {
- super(parent, SWT.NONE);
- this.refreshJobDelayInMillis = DEFAULT_REFRESH_TIME;
- this.parent = parent;
+ super(parent, SWT.NONE, DEFAULT_REFRESH_TIME);
}
/**
@@ -347,43 +282,12 @@ public FilteredTree(Composite parent, int treeStyle, PatternFilter filter, boole
*/
protected void init(int treeStyle, PatternFilter filter) {
patternFilter = filter;
- showFilterControls = PlatformUI.getPreferenceStore()
- .getBoolean(IWorkbenchPreferenceConstants.SHOW_FILTERED_TEXTS);
- createControl(parent, treeStyle);
- createRefreshJob();
- setInitialText(WorkbenchMessages.FilteredTree_FilterMessage);
- setFont(parent.getFont());
-
+ init(treeStyle);
}
- /**
- * Create the filtered tree's controls. Subclasses should override.
- *
- * @param parent the parent
- * @param treeStyle SWT style bits used to create the tree
- */
+ @Override
protected void createControl(Composite parent, int treeStyle) {
- GridLayout layout = new GridLayout();
- layout.marginHeight = 0;
- layout.marginWidth = 0;
- setLayout(layout);
-
- if (parent.getLayout() instanceof GridLayout) {
- setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- }
-
- if (showFilterControls) {
- filterComposite = new Composite(this, SWT.NONE);
- GridLayout filterLayout = new GridLayout();
- filterLayout.marginHeight = 0;
- filterLayout.marginWidth = 0;
- filterComposite.setLayout(filterLayout);
- filterComposite.setFont(parent.getFont());
-
- createFilterControls(filterComposite);
- filterComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
- }
-
+ super.createControl(parent, treeStyle);
treeComposite = new Composite(this, SWT.NONE);
GridLayout treeCompositeLayout = new GridLayout();
treeCompositeLayout.marginHeight = 0;
@@ -394,19 +298,6 @@ protected void createControl(Composite parent, int treeStyle) {
createTreeControl(treeComposite, treeStyle);
}
- /**
- * Create the filter controls. By default, a text and corresponding tool bar
- * button that clears the contents of the text is created. Subclasses may
- * override.
- *
- * @param parent parent Composite
of the filter controls
- * @return the Composite
that contains the filter controls
- */
- protected Composite createFilterControls(Composite parent) {
- createFilterText(parent);
- return parent;
- }
-
/**
* Creates and set up the tree and tree viewer. This method calls
* {@link #doCreateTreeViewer(Composite, int)} to create the tree viewer.
@@ -421,7 +312,6 @@ protected Control createTreeControl(Composite parent, int style) {
treeViewer = doCreateTreeViewer(parent, style);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
treeViewer.getControl().setLayoutData(data);
- treeViewer.getControl().addDisposeListener(e -> refreshJob.cancel());
if (treeViewer instanceof NotifyingTreeViewer) {
patternFilter.setUseCache(true);
}
@@ -461,22 +351,7 @@ private TreeItem getFirstMatchingItem(TreeItem[] items) {
return null;
}
- /**
- * Create the refresh job for the receiver.
- */
- private void createRefreshJob() {
- refreshJob = doCreateRefreshJob();
- refreshJob.setSystem(true);
- }
-
- /**
- * Creates a workbench job that will refresh the tree based on the current
- * filter text. Subclasses may override.
- *
- * @return a workbench job that can be scheduled to refresh the tree
- *
- * @since 3.4
- */
+ @Override
protected WorkbenchJob doCreateRefreshJob() {
return new WorkbenchJob("Refresh Filter") {//$NON-NLS-1$
@Override
@@ -536,7 +411,7 @@ && recursiveExpand(items, monitor, stopTime, new int[] { numVisibleItems })) {
if (items.length > 0 && getViewer().getTree().getSelectionCount() == 0) {
treeViewer.getTree().setTopItem(items[0]);
}
- if (quickSelectionMode)
+ if (isQuickSelectionMode())
updateTreeSelection(false);
redrawFalseControl.setRedraw(true);
}
@@ -583,21 +458,16 @@ private boolean recursiveExpand(TreeItem[] items, IProgressMonitor monitor, long
* override.
*
* @param visible boolean
+ * @deprecated As of 4.13 not used anymore
*/
+ @Deprecated(forRemoval = true, since = "2025-03")
protected void updateToolbar(boolean visible) {
// nothing to do
}
- /**
- * Creates the filter text and adds listeners. This method calls
- * {@link #doCreateFilterText(Composite)} to create the text control. Subclasses
- * should override {@link #doCreateFilterText(Composite)} instead of overriding
- * this method.
- *
- * @param parent Composite
of the filter text
- */
+ @Override
protected void createFilterText(Composite parent) {
- filterText = doCreateFilterText(parent);
+ super.createFilterText(parent);
filterText.getAccessible().addAccessibleListener(new AccessibleAdapter() {
@Override
public void getName(AccessibleEvent e) {
@@ -641,44 +511,6 @@ private int itemCount(TreeItem treeItem) {
}
});
- filterText.addFocusListener(new FocusAdapter() {
- @Override
- public void focusGained(FocusEvent e) {
- /*
- * Running in an asyncExec because the selectAll() does not appear to work when
- * using mouse to give focus to text.
- */
- Display display = filterText.getDisplay();
- display.asyncExec(() -> {
- if (!filterText.isDisposed()) {
- if (getInitialText().equals(filterText.getText().trim())) {
- filterText.selectAll();
- }
- }
- });
- }
-
- @Override
- public void focusLost(FocusEvent e) {
- if (filterText.getText().equals(initialText)) {
- setFilterText(""); //$NON-NLS-1$
- textChanged();
- }
- }
- });
-
- filterText.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseDown(MouseEvent e) {
- if (filterText.getText().equals(initialText)) {
- // XXX: We cannot call clearText() due to
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=260664
- setFilterText(""); //$NON-NLS-1$
- textChanged();
- }
- }
- });
-
filterText.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
@@ -693,7 +525,7 @@ public void keyPressed(KeyEvent e) {
// enter key set focus to tree
filterText.addTraverseListener(e -> {
- if (quickSelectionMode) {
+ if (isQuickSelectionMode()) {
return;
}
if (e.detail == SWT.TRAVERSE_RETURN) {
@@ -701,11 +533,6 @@ public void keyPressed(KeyEvent e) {
updateTreeSelection(true);
}
});
-
- filterText.addModifyListener(e -> textChanged());
-
- GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
- filterText.setLayoutData(gridData);
}
/**
@@ -740,76 +567,17 @@ protected void updateTreeSelection(boolean setFocus) {
}
}
- /**
- * Creates the text control for entering the filter text. Subclasses may
- * override.
- *
- * @param parent the parent composite
- * @return the text widget
- *
- * @since 3.3
- */
- protected Text doCreateFilterText(Composite parent) {
- return new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
- }
-
private String previousFilterText;
private boolean narrowingDown;
- /**
- * Update the receiver after the text has changed.
- */
+ @Override
protected void textChanged() {
narrowingDown = previousFilterText == null
|| previousFilterText.equals(WorkbenchMessages.FilteredTree_FilterMessage)
|| getFilterString().startsWith(previousFilterText);
previousFilterText = getFilterString();
- // cancel currently running job first, to prevent unnecessary redraw
- refreshJob.cancel();
- refreshJob.schedule(getRefreshJobDelay());
- }
-
- /**
- * Return the time delay that should be used when scheduling the filter refresh
- * job. Subclasses may override.
- *
- * @return a time delay in milliseconds before the job should run
- *
- * @since 3.5
- */
- protected long getRefreshJobDelay() {
- return refreshJobDelayInMillis;
- }
-
- /**
- * Set the background for the widgets that support the filter text area.
- *
- * @param background background Color
to set
- */
- @Override
- public void setBackground(Color background) {
- super.setBackground(background);
- }
-
- /**
- * Clears the text in the filter text widget.
- */
- protected void clearText() {
- setFilterText(""); //$NON-NLS-1$
- textChanged();
- }
-
- /**
- * Set the text in the filter control.
- *
- * @param filterText the text to set.
- */
- protected void setFilterText(String filterText) {
- if (this.filterText != null) {
- this.filterText.setText(filterText);
- selectAll();
- }
+ super.textChanged();
}
/**
@@ -821,97 +589,11 @@ public final PatternFilter getPatternFilter() {
return patternFilter;
}
- /**
- * Get the tree viewer of the receiver.
- *
- * @return the tree viewer
- */
+ @Override
public TreeViewer getViewer() {
return treeViewer;
}
- /**
- * Get the filter text for the receiver, if it was created. Otherwise return
- * null
.
- *
- * @return the filter Text, or null if it was not created
- */
- public Text getFilterControl() {
- return filterText;
- }
-
- /**
- * Convenience method to return the text of the filter control. If the text
- * widget is not created, then null is returned.
- *
- * @return String in the text, or null if the text does not exist
- */
- protected String getFilterString() {
- return filterText != null ? filterText.getText() : null;
- }
-
- /**
- * Set the text that will be shown until the first focus. A default value is
- * provided, so this method only need be called if overriding the default
- * initial text is desired.
- *
- * @param text initial text to appear in text field
- */
- public void setInitialText(String text) {
- initialText = text;
- if (filterText != null) {
- filterText.setMessage(text);
- if (filterText.isFocusControl()) {
- setFilterText(initialText);
- textChanged();
- } else {
- getDisplay().asyncExec(() -> {
- if (!filterText.isDisposed() && filterText.isFocusControl()) {
- setFilterText(initialText);
- textChanged();
- }
- });
- }
- } else {
- setFilterText(initialText);
- textChanged();
- }
- }
-
- /**
- * Sets whether this filtered tree is used to make quick selections. In this
- * mode the first match in the tree is automatically selected while filtering
- * and the 'Enter' key is not used to move the focus to the tree.
- *
- * By default, this is set to false
.
- *
true
if this filtered tree is used to make quick
- * selections, false
otherwise
- * @since 3.105
- */
- public void setQuickSelectionMode(boolean enabled) {
- this.quickSelectionMode = enabled;
- }
-
- /**
- * Select all text in the filter text field.
- */
- protected void selectAll() {
- if (filterText != null) {
- filterText.selectAll();
- }
- }
-
- /**
- * Get the initial text for the receiver.
- *
- * @return String
- */
- protected String getInitialText() {
- return initialText;
- }
-
/**
* Return a bold font if the given element matches the given pattern. Clients
* can opt to call this method from a Viewer's label provider to get a bold font
diff --git a/examples/org.eclipse.ui.examples.filter/.classpath b/examples/org.eclipse.ui.examples.filter/.classpath
new file mode 100644
index 00000000000..c5932f42c7e
--- /dev/null
+++ b/examples/org.eclipse.ui.examples.filter/.classpath
@@ -0,0 +1,11 @@
+
+November 30, 2017
++ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +
+ ++ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +
+ + + \ No newline at end of file diff --git a/examples/org.eclipse.ui.examples.filter/build.properties b/examples/org.eclipse.ui.examples.filter/build.properties new file mode 100644 index 00000000000..adac29f50d5 --- /dev/null +++ b/examples/org.eclipse.ui.examples.filter/build.properties @@ -0,0 +1,8 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + plugin.properties,\ + plugin.xml,\ + about.html,\ + . +src.includes = about.html diff --git a/examples/org.eclipse.ui.examples.filter/plugin.properties b/examples/org.eclipse.ui.examples.filter/plugin.properties new file mode 100644 index 00000000000..9fa8ad8205c --- /dev/null +++ b/examples/org.eclipse.ui.examples.filter/plugin.properties @@ -0,0 +1,7 @@ +#Properties file for org.eclipse.ui.examples.filter +Bundle-Vendor = Eclipse.org +Bundle-Name = Eclipse Filtered Viewer + +view.tree.name = Filtered Tree View +view.table.name = Filtered Table View +view.table.virtual.name = Filtered (Virtual) Table View \ No newline at end of file diff --git a/examples/org.eclipse.ui.examples.filter/plugin.xml b/examples/org.eclipse.ui.examples.filter/plugin.xml new file mode 100644 index 00000000000..451dd217b11 --- /dev/null +++ b/examples/org.eclipse.ui.examples.filter/plugin.xml @@ -0,0 +1,26 @@ + + +