Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » JFace » Table Editing with Pojo Databinding Eclipse 3.5(Table editing using Pojo based databinding does not refresh the cell values.)
Table Editing with Pojo Databinding Eclipse 3.5 [message #517887] Tue, 02 March 2010 13:02 Go to next message
Joga Singh is currently offline Joga SinghFriend
Messages: 7
Registered: March 2010
Junior Member
Dear All,
I am facing a problem with table editing based Pojo databinding using PojoObservables/PojoProperties in Eclipse 3.5. Somehow the modified values are not getting refreshed in the cell, however I can see that the values are getting copied to the model.

My expectation from the PojoObservables was that, I can use this in place of BeanObservables if my model does not implement PropertyChangeSupport. However, after looking at the net, it seems that it is just there to avoid Runtime exceptions thrown by the BeanObservables. It provides only one-way (target to model) synchronization. Is this correct or there are more to it?

Can somebody guide me if I am doing something wrong, or what is the best way to implement such behavior using Pojo based databinding? I am ready to spend some time writing/extending databinding classes for this.

Below is the modified code from Snippet032TableViewerColumnEditing example.

Thanks in advance.

Regards,

Joga

<code>


import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.IBeanValueProperty;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.beans.PojoProperties;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.value.IObservableVal ue;
import org.eclipse.core.databinding.property.Properties;
import org.eclipse.core.databinding.property.value.IValueProperty;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.databinding.viewers.CellEditorProperties;
import org.eclipse.jface.databinding.viewers.ObservableListContentP rovider;
import org.eclipse.jface.databinding.viewers.ObservableMapCellLabel Provider;
import org.eclipse.jface.databinding.viewers.ObservableValueEditing Support;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;

public class PojoTableViewerColumnEditing {
public static void main(String[] args) {
final Display display = new Display();
Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
public void run() {
ViewModel viewModel = new ViewModel();
Shell shell = new View(viewModel).createShell();

// The SWT event loop
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
});
}

static class Person {
String name;
String firstName;

public Person(String firstName, String name) {
this.name = name;
this.firstName = firstName;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}
}

static class ViewModel {
private List people = new LinkedList();
{
people.add(new Person("Dave", "Orme"));
people.add(new Person("Gili", "Mendel"));
people.add(new Person("Joe", "Winchester"));
people.add(new Person("Boris", "Bokowski"));
people.add(new Person("Brad", "Reynolds"));
people.add(new Person("Matthew", "Hall"));
}

public List getPeople() {
return people;
}
}

static class View {
private ViewModel viewModel;
private Table committers;
private Label selectedCommitterName;
private Label selectedCommitterFirstName;

public View(ViewModel viewModel) {
this.viewModel = viewModel;
}

public Shell createShell() {
// Build a UI
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(2, true));
committers = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
committers.setLinesVisible(true);
committers.setHeaderVisible(true);
GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
layoutData.horizontalSpan = 2;
committers.setLayoutData(layoutData);

GridData fieldLayoutData = new GridData(SWT.FILL, SWT.BEGINNING,
true, false);
selectedCommitterName = new Label(shell, SWT.NONE);
selectedCommitterName.setLayoutData(fieldLayoutData);

selectedCommitterFirstName = new Label(shell, SWT.NONE);
selectedCommitterFirstName.setLayoutData(fieldLayoutData);

DataBindingContext bindingContext = new DataBindingContext();
bindGUI(bindingContext);

// Open and return the Shell
shell.setSize(250, 300);
shell.open();
return shell;
}

protected void bindGUI(DataBindingContext bindingContext) {
// Since we're using a JFace Viewer, we do first wrap our Table...
TableViewer peopleViewer = new TableViewer(committers);

TableViewerColumn columnName = new TableViewerColumn(peopleViewer,
SWT.NONE);
columnName.getColumn().setText("Name");
columnName.getColumn().setWidth(100);

TableViewerColumn columnFirstName = new TableViewerColumn(
peopleViewer, SWT.NONE);
columnFirstName.getColumn().setText("FirstName");
columnFirstName.getColumn().setWidth(100);

// Bind viewer to model
IBeanValueProperty propName = PojoProperties.value(Person.class,
"name");
IBeanValueProperty propFirstname = PojoProperties.value(
Person.class, "firstName");

IValueProperty cellEditorControlText = CellEditorProperties
.control().value(WidgetProperties.text(SWT.Modify));

columnName.setEditingSupport(ObservableValueEditingSupport.c reate(
peopleViewer, bindingContext,
new TextCellEditor(committers), cellEditorControlText,
propName));
columnFirstName.setEditingSupport(ObservableValueEditingSupp ort
.create(peopleViewer, bindingContext, new TextCellEditor(
committers), cellEditorControlText, propFirstname));

ObservableListContentProvider contentProvider = new ObservableListContentProvider();
peopleViewer.setContentProvider(contentProvider);

// Bind the LabelProviders to the model and columns
IObservableMap[] result = Properties.observeEach(contentProvider
.getKnownElements(), new IBeanValueProperty[] { propName,
propFirstname });

columnName.setLabelProvider(new ObservableMapCellLabelProvider(
result[0]));
columnFirstName
.setLabelProvider(new ObservableMapCellLabelProvider(
result[1]));

peopleViewer.setInput(new WritableList(viewModel.getPeople(),
Person.class));

// bind selectedCommitter labels to the name and forname of the
// current selection
IObservableValue selection = ViewersObservables
.observeSingleSelection(peopleViewer);
bindingContext.bindValue(SWTObservables
.observeText(selectedCommitterName), PojoObservables
.observeDetailValue(selection, "name", String.class));
bindingContext.bindValue(SWTObservables
.observeText(selectedCommitterFirstName), PojoObservables
.observeDetailValue(selection, "firstName", String.class));
}
}
}

</code>
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #518098 is a reply to message #517887] Wed, 03 March 2010 02:36 Go to previous messageGo to next message
chengdong is currently offline chengdongFriend
Messages: 17
Registered: July 2009
Junior Member
The snippet code is only one-way observation - from. see following line:
IValueProperty cellEditorControlText = CellEditorProperties
.control().value(WidgetProperties.text());
The CellEditorProperties.control() return a CellEditorControlProperty, which does not hook up to the control (adaptListener() need reimplementation). So , when you apply the cell editor. The binding does not aware the changes, so it can not modify the Pojos.

You have to create your own CellEditorProperty to hook to the native control, which means, if you apply the cell editor, you will notify the changes to the binding, then the binding will notify the Pojo to update.

As an alternative, you can take a look at Snippet013TableViewerEditing to see how a text editor works.
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #518134 is a reply to message #518098] Wed, 03 March 2010 08:42 Go to previous messageGo to next message
Joga Singh is currently offline Joga SinghFriend
Messages: 7
Registered: March 2010
Junior Member
Dear Chengdong,
Thanks for the reply. However I am not able to understand your point completely. In the given example, binding is working from traget to model. I can see the modified value, when I move back to the modified cell. However it disappears when I move away from the cell. This means, my model is getting updated, but my viewer is not getting refreshed.

I tried the Snippet013TableViewerEditing also. After removing the PropertyChangeSupport from the model, it exhibit the same behavior as my given example.

Here the main thing is that I am using POJOs, not JavaBeans.

Regards,

Joga
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #518436 is a reply to message #518134] Thu, 04 March 2010 06:12 Go to previous messageGo to next message
Matthew Hall is currently offline Matthew HallFriend
Messages: 368
Registered: July 2009
Senior Member
Joga Singh wrote:
> Dear Chengdong,
> Thanks for the reply. However I am not able to understand your point
> completely. In the given example, binding is working from traget to
> model. I can see the modified value, when I move back to the modified
> cell. However it disappears when I move away from the cell. This means,
> my model is getting updated, but my viewer is not getting refreshed.
> I tried the Snippet013TableViewerEditing also. After removing the
> PropertyChangeSupport from the model, it exhibit the same behavior as my
> given example.
>
> Here the main thing is that I am using POJOs, not JavaBeans.
>
> Regards,
>
> Joga

You will not get this for free from DataBinding unless you convert your
POJO properties to bean properties. Without some sort of change
notification API, there is simply no way for DataBinding to pick up the
changes on your model object.

There are many examples in the DataBinding examples project
demonstrating a useful base class (AbstractModelObject) you can use as
the base class of your beans. Then the setters must be updated to fire
a change event.

Good luck,

Matthew
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #518701 is a reply to message #518436] Thu, 04 March 2010 19:16 Go to previous messageGo to next message
chengdong is currently offline chengdongFriend
Messages: 17
Registered: July 2009
Junior Member
Joga:

Sorry for the confuse. My previous comment is for Snippet032TableViewerColumnEditing.java, from which your code derived.

As regard to Pojo observables, as Matthew mentioned, there is really no way to observe the POJO set??? method, so the target can not listen to the domain model changes (however, domain model can listen to target changes, so cell editor binding can invoke set??? to update the POJO).

For more detail about the Pojo observables, plase refer to

https://bugs.eclipse.org/bugs/show_bug.cgi?id=198201

Pojo observable does everything that BeansObservables does except that it doesn't register PropertyChangeListeners. As a result it won't respond to changes in the POJO but it provides IObservable* implementations to be used in Bindings.
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #518723 is a reply to message #518701] Thu, 04 March 2010 19:56 Go to previous messageGo to next message
Joga Singh is currently offline Joga SinghFriend
Messages: 7
Registered: March 2010
Junior Member
Thanks Matthew and Chengdong,
So now at least one thing is clear that I am not doing something wrong.

Now regarding adding PropertyChangeSupport to my model, I am OK to derive my entities from an AbstractModelObject type of class. What I don't want to do is to have firePropertyChange() method calls in all my setter methods. Do you think it is possible to call firePropertyChange using Reflection etc., if I write my own Observable or something? Any ideas to implement, if it is possible?

Best Wishes,

Joga
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #518754 is a reply to message #518723] Thu, 04 March 2010 22:11 Go to previous messageGo to next message
chengdong is currently offline chengdongFriend
Messages: 17
Registered: July 2009
Junior Member
I do not think it is possible. There is no way to use reflection to do that either.
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #524311 is a reply to message #517887] Wed, 31 March 2010 13:53 Go to previous messageGo to next message
Joga Singh is currently offline Joga SinghFriend
Messages: 7
Registered: March 2010
Junior Member
Finally, I am able to achive the desired behavior with two approaches. 1st by writing some custom classes to exectue fireProprtyChange when the setter method is called from the databinding. 2nd by using AOP.

Offcourse both the solutions are not perfect. LImitation of the 1st option is that the UI is not updated when the model is updated outside the databinding. AOP option works in all cases, but adds dependency on AspectJ.

Please let me know if anyone needs more details.

Regards,

Joga
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #525246 is a reply to message #524311] Mon, 05 April 2010 16:00 Go to previous messageGo to next message
chengdong is currently offline chengdongFriend
Messages: 17
Registered: July 2009
Junior Member
The AOP implementation sounds interesting. Can you share more detail?
thanks
Re: Table Editing with Pojo Databinding Eclipse 3.5 [message #525436 is a reply to message #525246] Tue, 06 April 2010 15:03 Go to previous message
Joga Singh is currently offline Joga SinghFriend
Messages: 7
Registered: March 2010
Junior Member
Here is the working code. You will have to probably do the following steps to run it:

- Install AspectJ plugin.
- Create an AspectJ java project and change it to a Plugin Project.
- Create an Aspect named TableEditingAspectJWithoutPCS.
- Copy the below code into this file.
- Add necessary plugin dependencies.
- Add Plugin Dependencies in the Inpath of AspectJ Build Path by using the Add Variable button. It will take some time to weave all the dependencies. I used compile time weaving for this test. I think there are options to do runtime weaving also, which is probably much better.

Also you might want to look at another simple solution in thread http://www.eclipse.org/forums/index.php?t=msg&th=165081& amp;start=0&

<code>
package org.eclipse.jface.examples.databinding.snippets;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.beans.IBeanValueProperty;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.value.IObservableVal ue;
import org.eclipse.core.databinding.property.Properties;
import org.eclipse.core.databinding.property.value.IValueProperty;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.databinding.viewers.CellEditorProperties;
import org.eclipse.jface.databinding.viewers.ObservableListContentP rovider;
import org.eclipse.jface.databinding.viewers.ObservableMapCellLabel Provider;
import org.eclipse.jface.databinding.viewers.ObservableValueEditing Support;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;

public class TableEditingAspectJWithoutPCS {

public static void main(String[] args) {
final Display display = new Display();
Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
public void run() {
ViewModel viewModel = new ViewModel();
Shell shell = new View(viewModel).createShell();

// The SWT event loop
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
});
}

static class Person {
/**
*
*/
private static final long serialVersionUID = 1L;
String name;
String firstName;

public Person(String firstName, String name) {
this.name = name;
this.firstName = firstName;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}
}

static class ViewModel {
private List people = new LinkedList();
{
people.add(new Person("Dave", "Orme"));
people.add(new Person("Gili", "Mendel"));
people.add(new Person("Joe", "Winchester"));
people.add(new Person("Boris", "Bokowski"));
people.add(new Person("Brad", "Reynolds"));
people.add(new Person("Matthew", "Hall"));
}

public List getPeople() {
return people;
}
}

static class View {
private ViewModel viewModel;
private Table committers;
private Label selectedCommitterName;
private Label selectedCommitterFirstName;

public View(ViewModel viewModel) {
this.viewModel = viewModel;
}

public Shell createShell() {
// Build a UI
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(2, true));
committers = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
committers.setLinesVisible(true);
committers.setHeaderVisible(true);
GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
layoutData.horizontalSpan = 2;
committers.setLayoutData(layoutData);

GridData fieldLayoutData = new GridData(SWT.FILL, SWT.BEGINNING,
true, false);
selectedCommitterName = new Label(shell, SWT.NONE);
selectedCommitterName.setLayoutData(fieldLayoutData);

selectedCommitterFirstName = new Label(shell, SWT.NONE);
selectedCommitterFirstName.setLayoutData(fieldLayoutData);

DataBindingContext bindingContext = new DataBindingContext();
bindGUI(bindingContext);

// Open and return the Shell
shell.setSize(250, 300);
shell.open();
return shell;
}

protected void bindGUI(DataBindingContext bindingContext) {
Person p = (Person)viewModel.getPeople().get(1);
TableViewer peopleViewer = new TableViewer(committers);

TableViewerColumn columnName = new TableViewerColumn(peopleViewer,
SWT.NONE);
columnName.getColumn().setText("Name");
columnName.getColumn().setWidth(100);

TableViewerColumn columnFirstName = new TableViewerColumn(
peopleViewer, SWT.NONE);
columnFirstName.getColumn().setText("FirstName");
columnFirstName.getColumn().setWidth(100);

// Bind viewer to model
IBeanValueProperty propName = BeanProperties.value(Person.class,
"name");
IBeanValueProperty propFirstname = BeanProperties.value(
Person.class, "firstName");

IValueProperty cellEditorControlText = CellEditorProperties
.control().value(WidgetProperties.text(SWT.Modify));

columnName.setEditingSupport(ObservableValueEditingSupport.c reate(
peopleViewer, bindingContext,
new TextCellEditor(committers), cellEditorControlText,
propName));
columnFirstName.setEditingSupport(ObservableValueEditingSupp ort
.create(peopleViewer, bindingContext, new TextCellEditor(
committers), cellEditorControlText, propFirstname));

ObservableListContentProvider contentProvider = new ObservableListContentProvider();
peopleViewer.setContentProvider(contentProvider);

// Bind the LabelProviders to the model and columns
IObservableMap[] result = Properties.observeEach(contentProvider
.getKnownElements(), new IBeanValueProperty[] { propName,
propFirstname });

columnName.setLabelProvider(new ObservableMapCellLabelProvider(
result[0]));
columnFirstName
.setLabelProvider(new ObservableMapCellLabelProvider(
result[1]));

peopleViewer.setInput(new WritableList(viewModel.getPeople(),
Person.class));

// bind selectedCommitter labels to the name and forname of the
// current selection
IObservableValue selection = ViewersObservables
.observeSingleSelection(peopleViewer);
bindingContext.bindValue(SWTObservables
.observeText(selectedCommitterName), BeansObservables
.observeDetailValue(selection, "name", String.class));
bindingContext.bindValue(SWTObservables
.observeText(selectedCommitterFirstName), PojoObservables
.observeDetailValue(selection, "firstName", String.class));
}
}

/*
* Add bound properties and serialization to point objects
*/

static aspect BoundPoint {
/*
* privately introduce a field into Person to hold the property
* change support object. `this' is a reference to a Person object.
*/
private PropertyChangeSupport Person.support = new PropertyChangeSupport(this);

/*
* Introduce the property change registration methods into Person.
* also introduce implementation of the Serializable interface.
*/
public void Person.addPropertyChangeListener(PropertyChangeListener listener){
support.addPropertyChangeListener(listener);
}

public void Person.addPropertyChangeListener(String propertyName,
PropertyChangeListener listener){

support.addPropertyChangeListener(propertyName, listener);
}

public void Person.removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
support.removePropertyChangeListener(propertyName, listener);
}

public void Person.removePropertyChangeListener(PropertyChangeListener listener) {
support.removePropertyChangeListener(listener);
}

public void Person.hasListeners(String propertyName) {
support.hasListeners(propertyName);
}

declare parents: Person implements Serializable;


pointcut runReflectiveCall(Method run, Object obj, Object[] args): target(run) && args(obj, args)
&& call(Object Method.invoke(Object,..)) && if(run.getName().startsWith("set")); //&& if(Person.class.getName().equals(run.getDeclaringClass().get Name()));

Object around(Method run, Object obj, Object[] args) : runReflectiveCall(run, obj, args) {
//System.out.println("before reflective call " + thisJoinPoint);
//System.out.println("Method "+run.getDeclaringClass().getName());
String property = run.getName().substring(3,4).toLowerCase()+run.getName().sub string(4);
Method readMethod = getReaderMethod(obj.getClass(), property);
Object oldValue = null;
Object newValue = null;
Object retVal = null;
try {
oldValue = readMethod.invoke(obj);
retVal = proceed(run, obj, args);
newValue = readMethod.invoke(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

if (obj instanceof Person) {
Person p1 = (Person) obj;
p1.support.firePropertyChange(property,oldValue, newValue);
}
return retVal;
}
}

public static Method getWriterMethod(Class claz, String property) {
BeanInfo bf = null;
try {
bf = Introspector.getBeanInfo(claz);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
for (PropertyDescriptor pd: bf.getPropertyDescriptors()) {
if (pd.getName().equals(property)) {
return pd.getWriteMethod();
}
}
throw new IllegalArgumentException("No Writer method for class: "+claz.getSimpleName()+", property: "+property);
}

public static Method getReaderMethod(Class claz, String property) {
BeanInfo bf = null;
try {
bf = Introspector.getBeanInfo(claz);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
for (PropertyDescriptor pd: bf.getPropertyDescriptors()) {
if (pd.getName().equals(property)) {
return pd.getReadMethod();
}
}
throw new IllegalArgumentException("No Reader method for class: "+claz.getSimpleName()+", property: "+property);
}
}

</code>

Previous Topic:initial focus in wizard page
Next Topic:Customizable error area in a wizard
Goto Forum:
  


Current Time: Sat Apr 20 01:59:29 GMT 2024

Powered by FUDForum. Page generated in 0.04383 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top