/*******************************************************************************
* Copyright (c) 2013 GoPivotal, 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:
* GoPivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.wizard.gettingstarted.guides;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.internal.misc.StringMatcher;
import org.eclipse.ui.internal.misc.StringMatcher.Position;
import org.springframework.ide.eclipse.wizard.gettingstarted.content.Describable;
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
import org.springsource.ide.eclipse.commons.livexp.ui.IPageWithSections;
/**
* Wizard section to choose one element from list of elements. Uses a table viewer to allow selecting
* an element.
* <p>
* This class is very similar in functionality (from client's point of view) to {@link ChooseOneSectionCombo}.
* It should be possible to use either one of these classes as functional replacements for one another.
*/
@SuppressWarnings("restriction")
public class ChooseOneSectionTable<T> extends ChooseOneSection {
private class ChoicesFilter extends ViewerFilter {
private StringMatcher matcher = null;
public ChoicesFilter() {
if (searchBox!=null) {
setSearchTerm(searchBox.getText());
}
}
public void setSearchTerm(String text) {
matcher = new StringMatcher(text, true, false);
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (matcher==null) {
return true;
} else {
String label = labelProvider.getText(element);
if (match(label)) {
return true;
} else if (element instanceof Describable) {
String description = ((Describable) element).getDescription();
return match(description);
}
return false;
}
}
private boolean match(String text) {
if (matcher==null) {
return true; // Search term not set... anything is acceptable.
} else {
Position x = matcher.find(text, 0, text.length());
return x!=null;
}
}
}
private SelectionModel<T> selection;
private String label; //Descriptive Label for this section
private T[] options; //The elements to choose from
private Text searchBox;
private ChoicesFilter filter;
public ChooseOneSectionTable(IPageWithSections owner, String label, SelectionModel<T> selection, T[] options) {
super(owner);
this.label = label;
this.selection = selection;
this.options = options;
}
@Override
public LiveExpression<ValidationResult> getValidator() {
return selection.validator;
}
@Override
public void createContents(Composite page) {
Composite field = new Composite(page, SWT.NONE);
int cols = label==null ? 1 : 2;
GridLayout layout = GridLayoutFactory.fillDefaults().numColumns(cols).create();
field.setLayout(layout);
searchBox = new Text(field, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
GridDataFactory.fillDefaults().grab(true, false).applyTo(searchBox);
Label fieldNameLabel = null;
if (label!=null) {
fieldNameLabel = new Label(field, SWT.NONE);
fieldNameLabel.setText(label);
}
final TableViewer tv = new TableViewer(field, SWT.SINGLE|SWT.BORDER|SWT.V_SCROLL);
tv.addFilter(filter = new ChoicesFilter());
tv.setLabelProvider(labelProvider);
tv.setContentProvider(ArrayContentProvider.getInstance());
tv.setInput(options);
if (fieldNameLabel!=null) {
GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.BEGINNING).applyTo(fieldNameLabel);
}
GridDataFactory grab = GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, 150);
grab.applyTo(field);
grab.applyTo(tv.getTable());
whenVisible(tv.getControl(), new Runnable() {
public void run() {
T preSelect = selection.selection.getValue();
if (preSelect!=null) {
tv.setSelection(new StructuredSelection(preSelect), true);
} else {
tv.setSelection(StructuredSelection.EMPTY, true);
}
}
});
tv.addSelectionChangedListener(new ISelectionChangedListener() {
@SuppressWarnings("unchecked")
public void selectionChanged(SelectionChangedEvent event) {
ISelection sel = tv.getSelection();
if (sel.isEmpty()) {
selection.selection.setValue(null);
} else if (sel instanceof IStructuredSelection){
IStructuredSelection ss = (IStructuredSelection) sel;
selection.selection.setValue((T)ss.getFirstElement());
}
}
});
searchBox.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
filter.setSearchTerm(searchBox.getText());
tv.refresh();
}
});
}
private void whenVisible(final Control control, final Runnable runnable) {
PaintListener l = new PaintListener() {
public void paintControl(PaintEvent e) {
runnable.run();
control.removePaintListener(this);
}
};
control.addPaintListener(l);
}
// private String[] getLabels() {
// String[] labels = new String[options.length];
// for (int i = 0; i < labels.length; i++) {
// labels[i] = labelProvider.getText(options[i]);
// }
// return labels;
// }
}