blob: 20efc8eb3d434a88ba8268a0cb5f2919801edbdb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 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
*******************************************************************************/
package org.eclipse.jface.examples.databinding.contentprovider.test;
import java.util.Iterator;
import java.util.Random;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.set.MappedSet;
import org.eclipse.core.databinding.observable.set.WritableSet;
import org.eclipse.core.databinding.observable.value.ComputedValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ObservableSetContentProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.internal.databinding.provisional.swt.ControlUpdater;
import org.eclipse.jface.internal.databinding.provisional.viewers.ViewerLabelProvider;
import org.eclipse.jface.viewers.ListViewer;
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.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
/**
* Tests UpdatableSetContentProvider, ComputableValue, ControlUpdator,
* UpdatableFunction, and ConvertingSet.
*
* <p>
* This test displays a dialog with user-editable list of Doubles. It allows the
* user to select a math function to apply to the set, and displays the result
* in a new list. A line of text along the bottom of the dialog displays the sum
* of the elements from the transformed set. Although this dialog is rather
* silly, it is a good example of a dialog where a lot of things can change from
* many directions.
* </p>
*
* <p>
* An UpdatableSetContentProvider is used to supply the contents each
* ListViewer. ControlUpdators
*
* </p>
*
* @since 1.0
*/
public class StructuredContentProviderTest {
private static Realm realm;
/**
* Top-level shell for the dialog
*/
private Shell shell;
/**
* Random number stream. Used for the "add" button.
*/
protected Random random = new Random();
// Data model ////////////////////////////////////////////////////////
/**
* inputSet stores a set of Doubles. The user is allowed to add and remove
* Doubles from this set.
*/
private WritableSet inputSet;
/**
* currentFunction is an Integer, set to one of the SomeMathFunction.OP_*
* constants. It identifies which function will be applied to inputSet.
*/
private WritableValue currentFunction;
/**
* mathFunction is the transformation. It can multiply by 2, round down to
* the nearest integer, or do nothing (identity)
*/
private SomeMathFunction mathFunction;
/**
* Set of Doubles. Holds the result of applying mathFunction to the
* inputSet.
*/
private MappedSet outputSet;
/**
* A Double. Stores the sum of the Doubles in outputSet
*/
private IObservableValue sumOfOutputSet;
/**
* Creates the test dialog as a top-level shell.
*/
public StructuredContentProviderTest() {
// Initialize the data model
createDataModel();
shell = new Shell(Display.getCurrent(), SWT.SHELL_TRIM);
{ // Initialize shell
final Label someDoubles = new Label(shell, SWT.NONE);
someDoubles.setText("A list of random Doubles"); //$NON-NLS-1$
someDoubles.setLayoutData(new GridData(
GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_FILL));
Control addRemoveComposite = createInputControl(shell, inputSet);
GridData addRemoveData = new GridData(GridData.FILL_BOTH);
addRemoveData.minimumHeight = 1;
addRemoveData.minimumWidth = 1;
addRemoveComposite.setLayoutData(addRemoveData);
Group operation = new Group(shell, SWT.NONE);
{ // Initialize operation group
operation.setText("Select transformation"); //$NON-NLS-1$
createRadioButton(operation, currentFunction, "f(x) = x", //$NON-NLS-1$
new Integer(SomeMathFunction.OP_IDENTITY));
createRadioButton(operation, currentFunction, "f(x) = 2 * x", //$NON-NLS-1$
new Integer(SomeMathFunction.OP_MULTIPLY));
createRadioButton(operation, currentFunction,
"f(x) = floor(x)", new Integer( //$NON-NLS-1$
SomeMathFunction.OP_ROUND));
GridLayout layout = new GridLayout();
layout.numColumns = 1;
operation.setLayout(layout);
}
operation.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_FILL));
Control outputControl = createOutputComposite(shell);
GridData outputData = new GridData(GridData.FILL_BOTH);
outputData.minimumHeight = 1;
outputData.minimumWidth = 1;
outputData.widthHint = 300;
outputData.heightHint = 150;
outputControl.setLayoutData(outputData);
final Label sumLabel = new Label(shell, SWT.NONE);
new ControlUpdater(sumLabel) {
protected void updateControl() {
double sum = ((Double) sumOfOutputSet.getValue())
.doubleValue();
int size = outputSet.size();
sumLabel.setText("The sum of the above " + size //$NON-NLS-1$
+ " doubles is " + sum); //$NON-NLS-1$
}
};
sumLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_FILL));
GridLayout layout = new GridLayout();
layout.numColumns = 1;
shell.setLayout(layout);
}
}
/**
* Create the updatables for this dialog
*/
private void createDataModel() {
// Initialize data model. We will create a user-editable set of Doubles.
// The user can run
// a transformation on this set and view the result in a list viewer.
// inputSet will be a writable set of doubles. The user will add and
// remove entries from this set
// through the UI.
inputSet = new WritableSet(realm);
// currentFunction holds the ID currently selected function to apply to
// elements in the inputSet.
// We will allow the user to change the current function through a set
// of radio buttons
currentFunction = new WritableValue(realm, new Integer(
SomeMathFunction.OP_MULTIPLY), null);
// mathFunction implements the selected function
mathFunction = new SomeMathFunction(inputSet);
currentFunction.addValueChangeListener(new IValueChangeListener() {
public void handleValueChange(ValueChangeEvent event) {
mathFunction
.setOperation(((Integer) currentFunction.getValue())
.intValue());
}
});
mathFunction.setOperation(((Integer) currentFunction.getValue())
.intValue());
// outputSet holds the result. It displays the result of applying the
// currently-selected
// function on all the elements in the input set.
outputSet = new MappedSet(inputSet, mathFunction);
// sumOfOutputSet stores the current sum of the the Doubles in the
// output set
sumOfOutputSet = new ComputedValue(realm) {
protected Object calculate() {
double sum = 0.0;
for (Iterator iter = outputSet.iterator(); iter.hasNext();) {
Double next = (Double) iter.next();
sum += next.doubleValue();
}
return new Double(sum);
}
};
}
/**
* Creates a radio button in the given parent composite. When selected, the
* button will change the given SettableValue to the given value.
*
* @param parent
* parent composite
* @param model
* SettableValue that will hold the value of the
* currently-selected radio button
* @param string
* text to appear in the radio button
* @param value
* value of this radio button (SettableValue will hold this value
* when the radio button is selected)
*/
private void createRadioButton(Composite parent, final WritableValue model,
String string, final Object value) {
final Button button = new Button(parent, SWT.RADIO);
button.setText(string);
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
model.setValue(value);
super.widgetSelected(e);
}
});
new ControlUpdater(button) {
protected void updateControl() {
button.setSelection(model.getValue().equals(value));
}
};
button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_FILL));
}
private Control createOutputComposite(Composite parent) {
ListViewer listOfInts = new ListViewer(parent, SWT.BORDER
| SWT.V_SCROLL | SWT.H_SCROLL);
listOfInts.setContentProvider(new ObservableSetContentProvider());
listOfInts.setLabelProvider(new ViewerLabelProvider());
listOfInts.setInput(outputSet);
return listOfInts.getControl();
}
/**
* Creates and returns a control that will allow the user to add and remove
* Doubles from the given input set.
*
* @param parent
* parent control
* @param inputSet
* input set
* @return a newly created SWT control that displays Doubles from the input
* set and allows the user to add and remove entries
*/
private Control createInputControl(Composite parent,
final WritableSet inputSet) {
Composite addRemoveComposite = new Composite(parent, SWT.NONE);
{ // Initialize addRemoveComposite
ListViewer listOfInts = new ListViewer(addRemoveComposite,
SWT.BORDER);
listOfInts.setContentProvider(new ObservableSetContentProvider());
listOfInts.setLabelProvider(new ViewerLabelProvider());
listOfInts.setInput(inputSet);
final IObservableValue selectedInt = ViewersObservables.observeSingleSelection(listOfInts);
GridData listData = new GridData(GridData.FILL_BOTH);
listData.minimumHeight = 1;
listData.minimumWidth = 1;
listData.widthHint = 150;
listData.heightHint = 150;
listOfInts.getControl().setLayoutData(listData);
Composite buttonBar = new Composite(addRemoveComposite, SWT.NONE);
{ // Initialize button bar
Button add = new Button(buttonBar, SWT.PUSH);
add.setText("Add"); //$NON-NLS-1$
add.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
inputSet.add(new Double(random.nextDouble() * 100.0));
super.widgetSelected(e);
}
});
add.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_FILL));
final Button remove = new Button(buttonBar, SWT.PUSH);
remove.setText("Remove"); //$NON-NLS-1$
// Enable the Remove button if and only if there is currently an
// element selected.
new ControlUpdater(remove) {
protected void updateControl() {
// This block demonstrates auto-listening.
// When updateControl is running, the framework
// remembers each
// updatable that gets touched. Since we're calling
// selectedInt.getValue()
// here, this updator will be flagged as dependant on
// selectedInt. This
// means that whenever selectedInt changes, this block
// of code will re-run
// itself.
// The result is that the remove button will recompute
// its enablement
// whenever the selection in the listbox changes, and it
// was not necessary
// to attach any listeners.
remove.setEnabled(selectedInt.getValue() != null);
}
};
remove.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
inputSet.remove(selectedInt.getValue());
super.widgetSelected(e);
}
});
remove.setLayoutData(new GridData(
GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_FILL));
GridLayout buttonLayout = new GridLayout();
buttonLayout.numColumns = 1;
buttonBar.setLayout(buttonLayout);
} // End button bar
buttonBar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_BEGINNING));
GridLayout addRemoveLayout = new GridLayout();
addRemoveLayout.numColumns = 2;
addRemoveComposite.setLayout(addRemoveLayout);
}
return addRemoveComposite;
}
/**
* @param args
*/
public static void main(String[] args) {
Display display = Display.getDefault();
realm = SWTObservables.getRealm(display);
StructuredContentProviderTest test = new StructuredContentProviderTest();
Shell s = test.getShell();
s.pack();
s.setVisible(true);
while (!s.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private Shell getShell() {
return shell;
}
}