blob: 790ffa9f075ebc57468735a99563653bdb27677c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jacek Pospychala - bug 187762
* Mohamed Tarief - tarief@eg.ibm.com - IBM - Bug 174481
* Tasktop Technologies - generalized filter code for structured viewers
* Benjamin Muskalla, Tasktop Technologies - bug 342164
*******************************************************************************/
package org.eclipse.equinox.internal.p2.ui.discovery.util;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.ui.discovery.wizards.Messages;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.progress.WorkbenchJob;
/**
* Based on {@link org.eclipse.ui.dialogs.FilteredTree}.
*
* @author Steffen Pingel
*/
public abstract class FilteredViewer {
private boolean automaticFind;
private Label clearFilterTextControl;
private Composite container;
TextSearchControl filterText;
private int minimumHeight;
String previousFilterText = ""; //$NON-NLS-1$
WorkbenchJob refreshJob;
private long refreshJobDelay = 200L;
private PatternFilter searchFilter;
protected StructuredViewer viewer;
private Composite header;
public FilteredViewer() {
setAutomaticFind(true);
}
void clearFilterText() {
filterText.getTextControl().setText(""); //$NON-NLS-1$
filterTextChanged();
}
public void createControl(Composite parent) {
container = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().margins(0, 0).applyTo(container);
container.addDisposeListener(e -> {
if (refreshJob != null) {
refreshJob.cancel();
}
});
doCreateHeader();
viewer = doCreateViewer(container);
searchFilter = doCreateFilter();
viewer.addFilter(searchFilter);
GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, minimumHeight).applyTo(viewer.getControl());
}
protected PatternFilter doCreateFilter() {
return new PatternFilter() {
@Override
protected boolean isParentMatch(Viewer viewer, Object element) {
return false;
}
};
}
private void doCreateFindControl(Composite parent) {
Label label = new Label(parent, SWT.NONE);
label.setText(Messages.ConnectorDiscoveryWizardMainPage_filterLabel);
GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.CENTER).applyTo(label);
filterText = new TextSearchControl(parent, automaticFind);
if (automaticFind) {
filterText.addModifyListener(e -> filterTextChanged());
} else {
filterText.getTextControl().addTraverseListener(e -> {
if (e.detail == SWT.TRAVERSE_RETURN) {
e.doit = false;
filterTextChanged();
}
});
}
filterText.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
if (e.detail == SWT.ICON_CANCEL) {
clearFilterText();
} else {
// search icon and enter
filterTextChanged();
}
}
});
GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(filterText);
}
private void doCreateHeader() {
header = new Composite(container, SWT.NONE);
GridLayoutFactory.fillDefaults().applyTo(header);
GridDataFactory.fillDefaults().grab(true, false).applyTo(header);
doCreateFindControl(header);
doCreateHeaderControls(header);
// arrange all header controls horizontally
GridLayoutFactory.fillDefaults().numColumns(header.getChildren().length).applyTo(header);
}
protected void doCreateHeaderControls(Composite parent) {
// ignore
}
public void setHeaderVisible(boolean visible) {
if (header != null && visible != header.getVisible()) {
header.setVisible(visible);
GridData headerLayout = (GridData) header.getLayoutData();
headerLayout.exclude = !visible;
container.layout(true, true);
}
}
public boolean isHeaderVisible() {
return header != null && header.getVisible();
}
protected WorkbenchJob doCreateRefreshJob() {
return new WorkbenchJob("filter") { //$NON-NLS-1$
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (filterText.isDisposed()) {
return Status.CANCEL_STATUS;
}
String text = filterText.getTextControl().getText();
text = text.trim();
if (!previousFilterText.equals(text)) {
previousFilterText = text;
doFind(text);
}
return Status.OK_STATUS;
}
};
}
protected abstract StructuredViewer doCreateViewer(Composite parent);
protected void doFind(String text) {
searchFilter.setPattern(text);
if (clearFilterTextControl != null) {
clearFilterTextControl.setVisible(text != null && text.length() != 0);
}
viewer.refresh(true);
}
/**
* Invoked whenever the filter text is changed or the user otherwise causes the filter text to change.
*/
protected void filterTextChanged() {
if (refreshJob == null) {
refreshJob = doCreateRefreshJob();
} else {
refreshJob.cancel();
}
refreshJob.schedule(refreshJobDelay);
}
/**
* Provides the text string of the search widget.
*/
protected String getFilterText() {
return filterText == null ? null : filterText.getTextControl().getText();
}
protected void setFilterText(String newFilter) {
if (filterText == null) {
throw new IllegalStateException("Needs be invoked after controls are created"); //$NON-NLS-1$
}
filterText.getTextControl().setText(newFilter);
}
public Control getControl() {
return container;
}
public int getMinimumHeight() {
return minimumHeight;
}
protected long getRefreshJobDelay() {
return refreshJobDelay;
}
public StructuredViewer getViewer() {
return viewer;
}
public void setMinimumHeight(int minimumHeight) {
this.minimumHeight = minimumHeight;
if (viewer != null) {
GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, minimumHeight).applyTo(viewer.getControl());
}
}
protected void setRefreshJobDelay(long refreshJobDelay) {
this.refreshJobDelay = refreshJobDelay;
}
public final void setAutomaticFind(boolean automaticFind) {
if (filterText != null) {
throw new IllegalStateException("setAutomaticFind() needs be invoked before controls are created"); //$NON-NLS-1$
}
this.automaticFind = automaticFind;
}
public final boolean isAutomaticFind() {
return automaticFind;
}
}