/******************************************************************************* * Copyright (c) 2012 Pivotal Software, Inc. * 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: * Pivotal Software, Inc. - initial API and implementation *******************************************************************************/ package org.springsource.ide.eclipse.commons.frameworks.ui.internal.swt; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; /** * Part that adds a search text control where users can type a pattern that will * search for elements in a structured viewer based on the pattern. The viewer * will be filtered such that only elements that match the pattern are shown. * <p> * In order to properly initialise this part, the users must * <li>Create the part by specifying a parent where the text control should be * added</li> * <li>Connect to a structured viewer such that patterns entered in the text * control result in elements being shown in the viewer, and all other elements * filtered out</li> * </p> * Users must implement the matching conditions for each element in the viewer. * @author Nieraj Singh * @author Christian Dupuis */ public abstract class ViewerSearchPart { /** * User appropriate getter to access the viewer */ private StructuredViewer viewer; private Text searchText; private String pattern; /** * Parent must not be null. Text control will be added to the given parent * as a child when this part is created. * * @param parent * must not be null */ public ViewerSearchPart(Composite parent) { addPart(parent); } /** * Adds the text control to the given composite. Must not be null. * * @param parent * Cannot be null */ protected void addPart(Composite parent) { searchText = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL | SWT.ICON_SEARCH); searchText.setBackground(null); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) .grab(true, false).applyTo(searchText); searchText.addKeyListener(new KeyListener() { public void keyReleased(KeyEvent event) { handleSearch(searchText.getText()); } public void keyPressed(KeyEvent event) { // nothing } }); searchText.addSelectionListener(new SelectionAdapter() { public void widgetDefaultSelected(SelectionEvent e) { if (e.detail == SWT.CANCEL) { String searchString = searchText.getText(); handleSearch(searchString); } } }); searchText.setMessage("Type pattern to match"); } /** * Connects the viewer search part to the given structured viewer, and * creates the text search control such that search functionality is * integrated into the given viewer. Note that the viewer and the parent * Composite of this part need not be the same. The Text search control is * added to the parent composite specified when this part was first created, * but the specified viewer may not necessarily be in the same composite. * <p> * This decouples the area where the Text control is created with the area * where the structured viewer is present. * </p> * * @param viewer */ public void connectViewer(StructuredViewer viewer) { this.viewer = viewer; } protected StructuredViewer getViewer() { return viewer; } protected void handleSearch(String search) { refreshFilter(search); } abstract protected boolean matches(Object element, Object parentElement, String pattern); protected ViewerFilter getViewerFilter() { StructuredViewer viewer = getViewer(); if (viewer == null) { return null; } ViewerFilter[] filters = viewer.getFilters(); if (filters != null) { for (ViewerFilter filter : filters) { if (filter instanceof CommonSearchFilter) { return (CommonSearchFilter) filter; } } } return null; } protected void refreshFilter(String searchPattern) { StructuredViewer viewer = getViewer(); if (viewer == null) { return; } pattern = searchPattern; ViewerFilter patternFilter = getViewerFilter(); if (patternFilter != null) { if (pattern == null || isAllWhitespace(pattern)) { viewer.removeFilter(patternFilter); } else { viewer.refresh(false); } } else if (pattern != null && !isAllWhitespace(pattern)) { getViewer().addFilter(new CommonSearchFilter()); } } /** * Return active text control, or null if disposed or not created. * * @return active text control for the search part, or null if disposed or * not created. */ public Text getTextControl() { return searchText != null && !searchText.isDisposed() ? searchText : null; } /** * Filter used for text pattern filtering in the search area. * * @author nisingh * */ protected class CommonSearchFilter extends ViewerFilter { public boolean select(Viewer viewer, Object parentElement, Object element) { if (pattern == null || isAllWhitespace(pattern)) { return false; } return matches(element, parentElement, pattern); } } public static boolean isAllWhitespace(String pattern) { if (pattern == null) { return false; } for (int i = 0; i < pattern.length(); i++) { if (Character.isWhitespace(pattern.charAt(i))) { continue; } else { return false; } } return true; } }