DataBinding and tables [message #447763] |
Fri, 14 April 2006 08:14  |
Eclipse User |
|
|
|
Originally posted by: alexixlebaulois.yahoo.fr
Hi,
I'm using Eclipse 3.2M6 and I would like to use JFace DataBinding to populate a table (the table must be editable). My problem is that I cannot find any resource about it. Does anybody know how to do that ? Thanks
Alexis
|
|
|
|
|
|
|
Re: DataBinding and tables [message #448206 is a reply to message #447976] |
Wed, 19 April 2006 01:18   |
Eclipse User |
|
|
|
------=_Part_207_32404958.1145424028429
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
For posterity I'm attaching an example of how to implement editing with the current 3.2m6 code with a TableViewer. This is just meant as an example, not a recommendation. There were a few workarounds employed, which are documented in the file, in order to make this work. Use at your own risk. There are no guarantees on the quality or the ability to run this code when Data Binding is officially released. Basically if you have problems don't blame me.
I believe the plan is to integrate support for editing as it existed in the 3.2m5 code but just hasn't yet been ported to 3.2m6.
-brad
------=_Part_207_32404958.1145424028429
Content-Type: application/octet-stream;
name=BoundEditableTableViewerExample.java
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename=BoundEditableTableViewerExample.java
package org.eclipse.jface.examples.databinding.nestedselection;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.internal.databinding.provisional.BindSpec;
import org.eclipse.jface.internal.databinding.provisional.DataBindi ngContext;
import org.eclipse.jface.internal.databinding.provisional.descripti on.Property;
import org.eclipse.jface.internal.databinding.provisional.descripti on.TableModelDescription;
import org.eclipse.jface.internal.databinding.provisional.observabl e.IObservable;
import org.eclipse.jface.internal.databinding.provisional.validatio n.IDomainValidator;
import org.eclipse.jface.internal.databinding.provisional.validatio n.ValidationError;
import org.eclipse.jface.internal.databinding.provisional.viewers.V iewersProperties;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
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.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
/**
* Quick and dirty example to show how editing of a TableViewer can be
* accomplished while using Data Binding code that exists in 3.2m6. This class
* depends upon Model data that can be found in the
* org.eclipse.jface.examples.databinding project.
* <p>
* DISCLAIMER: this is only to show how this can be accomplished with the
* provisional code. Use at your own risk as there are no guarantees that it is
* bug free, covers every scenario, or will work with the official release of
* Data Binding.
* </p>
* <p>
* Deviations from common practices (workarounds) employed:
* <ul>
* <li>Used an IDomainValidator to stop the updating of the domain when
* dismissal of the editor wasn't done with [Enter] or [Tab].
* TextObservableValue fires change events on lost focus which is normally
* desired but when editing a Table we only want the update to occur in these
* cases to be consistent with normal TableViewer editing.</li>
* <li>In the ICellModifier for the bound TableViewer getValue() returns the
* value currently in the editor. Because of binding the editor will contain the
* correct value at this point. If getValue() were to return <code>null</code>
* the viewer would throw an assertion. To get around this we're just returning
* the current value of the editor.</li>
* <li>In the ICellModifier for the bound TableViewer there is no
* implementation for modify(). Because of binding the value automatically gets
* sent to the model (unless canceled by the IDomainValidator workaround).</li>
* </ul>
* </p>
*
* @author Brad Reynolds
*/
public class BoundEditableTableViewerExample {
/**
* @param args
*/
public static void main(String[] args) {
new BoundEditableTableViewerExample().run();
}
private static final String[] columnHeaders = new String[] {
"Name", "State" }; //$NON-NLS-1$//$NON-NLS-2$
private void run() {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(2, true));
Label label = new Label(shell, SWT.NONE);
label.setText("Bound"); //$NON-NLS-1$
label = new Label(shell, SWT.NONE);
label.setText("Not Bound"); //$NON-NLS-1$
final Table table1 = setup(new Table(shell, SWT.FULL_SELECTION));
final Table table2 = setup(new Table(shell, SWT.FULL_SELECTION));
final Model model1 = new Model();
final Model model2 = new Model();
final TableViewer boundViewer = createBoundViewer(table1, model1);
final TableViewer normalViewer = createNormalViewer(table2, model2);
packColumns(table1);
packColumns(table2);
// Show that invoking edit on the viewer behaves the same (edit sets
// selection thus updating the editors with the selection)
Button button = new Button(shell, SWT.PUSH);
button.setText("Edit"); //$NON-NLS-1$
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
boundViewer.editElement(model1.getPersonList().get(0), 0);
}
});
button = new Button(shell, SWT.PUSH);
button.setText("Edit"); //$NON-NLS-1$
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
normalViewer.editElement(model2.getPersonList().get(0), 0);
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
/**
* Sets up a Table.
*
* @param table
* @return table
*/
private Table setup(Table table) {
table.setHeaderVisible(true);
table.setLinesVisible(true);
for (int i = 0; i < 2; i++) {
new TableColumn(table, SWT.NONE).setText(columnHeaders[i]);
}
table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
return table;
}
private void packColumns(Table table) {
for (int i = 0; i < table.getColumnCount(); i++) {
table.getColumn(i).pack();
}
}
private TableViewer createBoundViewer(Table table, Model model) {
DataBindingContext dbc = BindingFactory.createContext(table);
final TableViewer viewer = new TableViewer(table);
dbc.bind(viewer, new TableModelDescription(new Property(model,
"personList", Person.class, Boolean.TRUE), new Object[] { //$NON-NLS-1$
"name", "state" }), null); //$NON-NLS-1$ //$NON-NLS-2$
IObservable selectedPerson = dbc.createObservable(new Property(viewer,
ViewersProperties.SINGLE_SELECTION));
TextCellEditor editor = new TextCellEditor(viewer.getTable());
// hack... use a domain validator to cancel the updating of the model
// when escape is pressed.
BindSpec spec = new BindSpec();
final CancelUpdateValidator validator = new CancelUpdateValidator();
spec.setDomainValidator(validator);
Text text = (Text) editor.getControl();
text.addListener(SWT.Traverse, new Listener() {
public void handleEvent(Event event) {
if (event.detail == SWT.TRAVERSE_RETURN
|| event.detail == SWT.TRAVERSE_TAB_NEXT) {
validator.allow = true;
}
}
});
dbc.bind(editor.getControl(), new Property(selectedPerson, "name", //$NON-NLS-1$
String.class, Boolean.FALSE), spec);
viewer.setCellEditors(new CellEditor[] { editor, null });
viewer.setColumnProperties(new String[] { "name", null }); //$NON-NLS-1$
viewer.setCellModifier(new BoundCellModifier(viewer));
return viewer;
}
/**
* Provides a not so elegant way to prevent the updating of the domain.
*/
private class CancelUpdateValidator implements IDomainValidator {
private boolean allow = false;
public ValidationError isValid(Object value) {
ValidationError result = null;
try {
if (!allow) {
result = ValidationError.error("canceling update..."); //$NON-NLS-1$
}
} finally {
allow = false;
}
return result;
}
}
/**
* Constructs a normal viewer without data binding.
*
* @param table
* @return viewer
*/
private TableViewer createNormalViewer(Table table, Model model) {
final TableViewer viewer = new TableViewer(table);
viewer.setContentProvider(new IStructuredContentProvider() {
public void dispose() {
// do nothing
}
public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
// not needed for demo
}
public Object[] getElements(Object inputElement) {
return ((List) inputElement).toArray();
}
});
viewer.setLabelProvider(new ITableLabelProvider() {
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
public String getColumnText(Object element, int columnIndex) {
Person person = (Person) element;
switch (columnIndex) {
case 0:
return person.getName();
case 1:
return person.getState();
default:
return null;
}
}
public void addListener(ILabelProviderListener listener) {
// not needed for demo
}
public void dispose() {
// not needed for demo
}
public boolean isLabelProperty(Object element, String property) {
return "name".equals(property); //$NON-NLS-1$
}
public void removeListener(ILabelProviderListener listener) {
// not needed for demo
}
});
viewer.setInput(new ArrayList(model.getPersonList()));
viewer.setCellEditors(new CellEditor[] { new TextCellEditor(table),
null });
viewer.setColumnProperties(new String[] { "name", null }); //$NON-NLS-1$
viewer.setCellModifier(new ICellModifier() {
public boolean canModify(Object element, String property) {
return "name".equals(property); //$NON-NLS-1$
}
public Object getValue(Object element, String property) {
return "name".equals(property) ? ((Person) element).getName() : null; //$NON-NLS-1$
}
public void modify(Object element, String property, Object value) {
if (element instanceof Item) {
element = ((Item) element).getData();
}
if ("name".equals(property)) { //$NON-NLS-1$
((Person) element).setName((String) value);
viewer.update(element, new String[] { property });
}
}
});
return viewer;
}
/**
* ICellModifier implementation to be used when binding editors to model
* selection.
*/
private class BoundCellModifier implements ICellModifier {
private final TableViewer viewer;
private BoundCellModifier(TableViewer viewer) {
if (viewer == null)
throw new NullPointerException("The 'viewer' is null."); //$NON-NLS-1$
this.viewer = viewer;
}
/**
* Returns the editor for the property.
*
* @param property
* if <code>null</code> assumes no editor
* @return editor <code>null</code> if undefined
*/
private CellEditor getEditor(String property) {
if (property == null)
return null;
CellEditor editor = null;
Object[] properties = viewer.getColumnProperties();
for (int i = 0; i < properties.length; i++) {
if (property.equals(properties[i])) {
editor = viewer.getCellEditors()[i];
break;
}
}
return editor;
}
/**
* Makes the assumption that if an editor exists for the column with the
* property it's modifiable.
*/
public boolean canModify(Object element, String property) {
return getEditor(property) != null;
}
/**
* Returns the value that is already in the editor. This is a bit of a
* workaround to make things work. Because selection sets the value in
* the editor it will technically already have the right value when this
* method is invoked.
*/
public Object getValue(Object element, String property) {
CellEditor editor = getEditor(property);
return editor != null ? editor.getValue() : null;
}
/**
* Does nothing. Because of the binding the value will be copied to the
* model regardless of what we do here.
*/
public void modify(Object element, String property, Object value) {
// not needed, the binding takes care of it
}
}
}
------=_Part_207_32404958.1145424028429--
|
|
|
|
|
|
|
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.40127 seconds