Bidirectional Data Binding from TableViewer to Detail Fields

SWT Designer allows you to create the views, editors, perspectives, pref pages, composites, etc. that comprise Eclipse SWT & RCP applications and plug-ins.

Moderators: Konstantin.Scheglov, gnebling, Alexander.Mitin, jwren, Eric Clayberg

Bidirectional Data Binding from TableViewer to Detail Fields

Postby Lawgers » Fri Jun 06, 2008 12:35 pm

Hello,

As a newcomer to the Instantiations Data Binding GUI, and Eclipse Data Binding in general, I'm beating my head against the wall with trying to get a table viewer to update detail fields (which works easily), and the detail fields to update the table as they're being edited. I've seen this work quite well in the PhoneBook example, but got to the point where TableViewer selections update the detail fields, and detail editing definitely changes the underlying model (checked with System.out statements and inspection in the debugger), but the TableViewer fields don't update while the detail is being edited.

I've distilled this down to the most simple example I could make--an SWT shell with a table viewer, two detail fields, a very simple underlying data model, and the appropriate (as far as I can determine) bindings. Can anyone point out what I'm sure is a very simple missing piece to this puzzle?

Here are the three classes:

SWT Shell:
Code: Select all
package lawrence;

import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeansObservables;
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.IObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import lawrence.SimpleModel;

public class SimpleTroubleShell extends Shell {

   private DataBindingContext m_bindingContext;
   private TableViewer simpleTableViewer;
   private Text integerText;
   private Text nameText;
   private Table table;
   public List<SimpleModel> smList = new ArrayList<SimpleModel>();

   public void initializeModels() {
      smList.add(new SimpleModel("First", 1));
      smList.add(new SimpleModel("Second", 2));
      smList.add(new SimpleModel("Third", 3));
   }
   
   public static void main(String args[])  {
      Display display = Display.getDefault();
      Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
         public void run() {
            try {
               Display display = Display.getDefault();
               SimpleTroubleShell shell = new SimpleTroubleShell(display,
                     SWT.SHELL_TRIM);
               shell.open();
               shell.layout();
               while (!shell.isDisposed()) {
                  if (!display.readAndDispatch())
                     display.sleep();
               }
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
   }


   public SimpleTroubleShell(Display display, int style) {
      super(display, style);
      createContents();
      setLayout(new FillLayout());
   }

   protected void createContents() {
      setText("Simple Trouble Demonstration");
      setSize(500, 375);

      final SashForm sashForm = new SashForm(this, SWT.VERTICAL);

      final Composite topComposite = new Composite(sashForm, SWT.NONE);
      topComposite.setLayout(new FillLayout());

      simpleTableViewer = new TableViewer(topComposite, SWT.BORDER);
      table = simpleTableViewer.getTable();
      table.setLinesVisible(true);
      table.setHeaderVisible(true);

      final TableColumn nameColumn = new TableColumn(table, SWT.NONE);
      nameColumn.setWidth(157);
      nameColumn.setText("Name");

      final TableColumn integerColumn = new TableColumn(table, SWT.NONE);
      integerColumn.setWidth(100);
      integerColumn.setText("Integer");

      final Composite bottomComposite = new Composite(sashForm, SWT.NONE);
      final GridLayout gridLayout = new GridLayout();
      gridLayout.numColumns = 2;
      bottomComposite.setLayout(gridLayout);

      final Label nameLabel = new Label(bottomComposite, SWT.NONE);
      nameLabel.setText("Name");

      nameText = new Text(bottomComposite, SWT.BORDER);
      final GridData gd_nameText = new GridData(SWT.FILL, SWT.CENTER, true, false);
      nameText.setLayoutData(gd_nameText);

      final Label integerLabel = new Label(bottomComposite, SWT.NONE);
      integerLabel.setText("Integer");

      integerText = new Text(bottomComposite, SWT.BORDER);
      final GridData gd_integerText = new GridData(SWT.FILL, SWT.CENTER, true, false);
      integerText.setLayoutData(gd_integerText);
      sashForm.setWeights(new int[] {1, 1 });
      initializeModels();
      m_bindingContext = initDataBindings();
      //
   }

   @Override
   protected void checkSubclass() {
      // Disable the check that prevents subclassing of SWT components
   }
   protected DataBindingContext initDataBindings() {
      IObservableValue simpleTableViewerSelectionObserveSelection_1 = ViewersObservables.observeSingleSelection(simpleTableViewer);
      IObservableValue simpleTableViewerSelectionObserveSelection = ViewersObservables.observeSingleSelection(simpleTableViewer);
      IObservableValue integerTextTextObserveWidget = SWTObservables.observeText(integerText, SWT.Modify);
      IObservableValue nameTextTextObserveWidget = SWTObservables.observeText(nameText, SWT.Modify);
      IObservableValue simpleTableViewerIntObserveDetailValue = BeansObservables.observeDetailValue(Realm.getDefault(), simpleTableViewerSelectionObserveSelection_1, "int", int.class);
      IObservableValue simpleTableViewerNameObserveDetailValue = BeansObservables.observeDetailValue(Realm.getDefault(), simpleTableViewerSelectionObserveSelection, "name", java.lang.String.class);
      //
      ObservableListContentProvider simpleTableViewerContentProviderList = new ObservableListContentProvider();
      simpleTableViewer.setContentProvider(simpleTableViewerContentProviderList);
      //
      IObservableMap[] simpleTableViewerLabelProviderMaps = BeansObservables.observeMaps(simpleTableViewerContentProviderList.getKnownElements(), SimpleModel.class, new String[]{"name", "int"});
      simpleTableViewer.setLabelProvider(new ObservableMapLabelProvider(simpleTableViewerLabelProviderMaps));
      //
      WritableList smListWritableList = new WritableList(smList, SimpleModel.class);
      simpleTableViewer.setInput(smListWritableList);
      //
      DataBindingContext bindingContext = new DataBindingContext();
      //
      bindingContext.bindValue(simpleTableViewerNameObserveDetailValue, nameTextTextObserveWidget, null, null);
      bindingContext.bindValue(simpleTableViewerIntObserveDetailValue, integerTextTextObserveWidget, null, null);
      //
      return bindingContext;
   }
}


Simple data model:
Code: Select all
package lawrence;

import lawrence.AbstractModelObject;

public class SimpleModel extends AbstractModelObject {

   public String myName;
   public int myInt;
   
   public SimpleModel() {
      super();
   }
   
   public SimpleModel(String newName, int newInt) {
      this();
      this.setName(newName);
      this.setInt(newInt);
   }
   
    public void setName(String newName) {
       String oldValue = myName;
       myName = newName;
      firePropertyChange("myName", oldValue, myName);
    }
   
    public String getName() {
        return myName;
    }

    public void setInt(int newInt) {
       int oldValue = myInt;
        myInt = newInt;
        firePropertyChange("myInt", oldValue, myInt);
    }
   
    public int getInt() {
        return myInt;
    }
}


Abstract Model with Java Bean support:
Code: Select all
package lawrence;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public abstract class AbstractModelObject {
   private final PropertyChangeSupport m_propertyChangeSupport = new PropertyChangeSupport(this);
   ////////////////////////////////////////////////////////////////////////////
   //
   // Property Support
   //
   ////////////////////////////////////////////////////////////////////////////
   public void addPropertyChangeListener(PropertyChangeListener listener) {
      m_propertyChangeSupport.addPropertyChangeListener(listener);
   }
   public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
      m_propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
   }
   public void removePropertyChangeListener(PropertyChangeListener listener) {
      m_propertyChangeSupport.removePropertyChangeListener(listener);
   }
   public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
      m_propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
   }
   public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
      m_propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
   }
}


Hopefully this isn't a frequently asked question--I've been searching for some time for help.

Thanks to any kind souls in advance,

Lawrence
Lawgers
 
Posts: 2
Joined: Fri Jun 06, 2008 9:20 am

Re: Bidirectional Data Binding from TableViewer to Detail Fields

Postby Eric Clayberg » Sat Jun 07, 2008 5:28 am

General questions about how to use Eclipse Data Binding should be addressed to the Eclipse newsgroups.

The problem with your example is that your model object is triggering the wrong property change events and therefore not updating the table.

Here is the correct version:

Code: Select all
package lawrence;

import lawrence.AbstractModelObject;

public class SimpleModel extends AbstractModelObject {

   public String myName;
   public int myInt;
   
   public SimpleModel() {
      super();
   }
   
   public SimpleModel(String newName, int newInt) {
      this();
      this.setName(newName);
      this.setInt(newInt);
   }
   
    public void setName(String newName) {
       String oldValue = myName;
       myName = newName;
      firePropertyChange("name", oldValue, myName);
    }
   
    public String getName() {
        return myName;
    }

    public void setInt(int newInt) {
       int oldValue = myInt;
        myInt = newInt;
        firePropertyChange("int", oldValue, myInt);
    }
   
    public int getInt() {
        return myInt;
    }
}
Eric Clayberg
Software Engineering Manager
Google
http://code.google.com/webtoolkit/download.html

Author: "Eclipse Plug-ins"
http://www.qualityeclipse.com
Eric Clayberg
Moderator
 
Posts: 4503
Joined: Tue Sep 30, 2003 6:39 am
Location: Boston, MA USA

Re: Bidirectional Data Binding from TableViewer to Detail Fields

Postby Lawgers » Sun Jun 08, 2008 11:18 pm

Many thanks for the response, and apologies for the incorrect posting. Sometimes, after pounding ones head against a wall for days (in my case, using the data binding features in RCP Developer/SWT Designer), one can't tell where the problem is coming from. From your answer, I can see how I just didn't fully grok the bean pattern and created my own problem. In any case, thanks for the help--I'm on to fighting drag-and-drop between viewers with my own models...
Lawgers
 
Posts: 2
Joined: Fri Jun 06, 2008 9:20 am

Re: Bidirectional Data Binding from TableViewer to Detail Fields

Postby Eric Clayberg » Mon Jun 09, 2008 3:50 am

When I ran your example, I saw that the model objects themselves were being updated when new values were typed in.

That meant that the problem had to be between the model objects and the table
Eric Clayberg
Software Engineering Manager
Google
http://code.google.com/webtoolkit/download.html

Author: "Eclipse Plug-ins"
http://www.qualityeclipse.com
Eric Clayberg
Moderator
 
Posts: 4503
Joined: Tue Sep 30, 2003 6:39 am
Location: Boston, MA USA


Return to SWT Designer

Who is online

Users browsing this forum: No registered users and 2 guests