Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » JFace » [DataBinding] ComboViewer binding Items and Text in Master/Detail
[DataBinding] ComboViewer binding Items and Text in Master/Detail [message #648581] Thu, 13 January 2011 15:10 Go to next message
Frank Benoit is currently offline Frank BenoitFriend
Messages: 179
Registered: July 2009
Senior Member
Hi,

I want to bind a Combo with detail data.

There is a list where the user selects an item.
Then the combo items and the text shall be loaded.

// Master list
IObservableMap attributeMap = BeansObservables.observeMap(
	Observables.staticObservableSet(new HashSet<PartNumber>( model.getPartNumbers() )), PartNumber.class, "name");
lstPartNumbers.setContentProvider(new ArrayContentProvider());
lstPartNumbers.setLabelProvider(new ObservableMapLabelProvider(attributeMap));

IObservableValue selectedPn = ViewersObservables.observeSingleSelection(lstPartNumbers);

// Detail combos dropdown list data (1)
bindingContext.bindList(
		SWTObservables.observeItems( cmbSerials.getCombo() ),
		BeansObservables.observeDetailList(selectedPn, "serialNumbers", String.class),
		new UpdateListStrategy(UpdateListStrategy.POLICY_NEVER),
		new UpdateListStrategy(UpdateListStrategy.POLICY_UPDATE));
// Detail combos text data (2)
bindingContext.bindValue(
		SWTObservables.observeText( cmbSerials.getCombo() ),
		BeansObservables.observeDetailValue(selectedPn, "serial", String.class));


When I use (1) OR (2) the update of the data works fine. But together it seems like it gets confused. If I select a new text from the drop down and change the selected list item, the stored combos text data is set to empty. If I print out the calls to my model set/get methods, I see that they are mixed while changing the master selection and the text for the old detail is set to empty.

Can someone see the problem in my binding code?

Frank


Re: [DataBinding] ComboViewer binding Items and Text in Master/Detail [message #648880 is a reply to message #648581] Fri, 14 January 2011 21:25 Go to previous messageGo to next message
Frank Benoit is currently offline Frank BenoitFriend
Messages: 179
Registered: July 2009
Senior Member
Here is a complete example.
The left side is a list of Partnumbers. This is the master. Depending on the selection the serial number shall be stored and the combo drop down shall work as a history of serial number used earlier.
But if selecting from the dropdown and then switching the partnumber, the serial number gets lost.

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.Observables;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
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.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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;


public class ComboBinding extends ApplicationWindow {
	public static void main(String[] args){
		Display d = new Display();
		Realm.runWithDefault(SWTObservables.getRealm(d), new Runnable() {
			public void run() {
				try {
					ComboBinding wnd;
					wnd = new ComboBinding(null);
					wnd.setBlockOnOpen(true);
					wnd.open();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	private static final String PREF = "DlgEolStarter.";
	private static final String SELECTED_PARTNUMBER = "SelectedPartNumber";
	private static final String SELECTED_TESTERS = "SelectedTesters";
	private static final String SERIALNUMBERS = "SerialNumbers";
	private static final String SELECTED_SERIALNUMBER = "SelectedSerialNumber";
	private static final String CREATE_PARAMFILE = "CreateParamfile";
	
	private static final String RIGHT_SF_WEIGTH_1 = "RightSF.Weigth.1";
	private static final String RIGHT_SF_WEIGTH_0 = "RightSF.Weigth.0";
	private static final String SF_WEIGTH_1 = "SF.Weigth.1";
	private static final String SF_WEIGTH_0 = "SF.Weigth.0";
	private static final String WND_POS_Y = "Wnd.Pos.Y";
	private static final String WND_POS_X = "Wnd.Pos.X";
	private static final String WND_SIZE_H = "Wnd.Size.H";
	private static final String WND_SIZE_W = "Wnd.Size.W";
	

	private DataBindingContext bindingContext;
	private final File file;


	private final PreferenceStore prefs;
	private SashForm mainSashForm;
	
	private Model model;
	private Button btnCreateParamFile;
	private ComboViewer cmbSerials;

	private ListViewer lstPartNumbers;
	public  static abstract class AbstractModelObject {
		private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this);

		public void addPropertyChangeListener(PropertyChangeListener listener) {
			propertyChangeSupport.addPropertyChangeListener(listener);
		}

		public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
			propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
		}

		public void removePropertyChangeListener(PropertyChangeListener listener) {
			propertyChangeSupport.removePropertyChangeListener(listener);
		}

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

		protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
			propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
		}
	}
	class PartNumber extends AbstractModelObject {
		private final String pnpref;
		private final String name;

		LinkedList<String> serialNumbers = new LinkedList<String>();
		String selectedSerial = "";
		boolean createParamFile;
		protected Binding binding;
		
		public PartNumber(String name) {
			this.name = name;
			pnpref = PREF + name + ".";
			serialNumbers.add(name+"_1");
			serialNumbers.add(name+"_2");
		}
		

		public String getName() {
			return name;
		}
		public String toString() {
			return "PN_"+name;
		}
		public LinkedList<String> getSerialNumbers() {
			System.out.printf("PN %s getSerialNumbers\n", name);
			return serialNumbers;
		}
		public String getSelectedSerial() {
			System.out.printf("PN %s getSelectedSerial %s\n", name, selectedSerial);
			return selectedSerial;
		}
		public void setSelectedSerial(String selectedSerial) {
			System.out.printf("PN %s setSelectedSerial %s\n", name, selectedSerial);
			this.selectedSerial = selectedSerial;
			firePropertyChange("selectedSerial", null, null);
		}
		public boolean getCreateParamFile() {
			return createParamFile;
		}
		public void setCreateParamFile(boolean createParamFile) {
			boolean old = this.createParamFile;
			this.createParamFile = createParamFile;
			firePropertyChange("createParamFile", old, createParamFile);
		}
		public void load() {
			prefs.setDefault(pnpref+CREATE_PARAMFILE, true);
			
			selectedSerial = prefs.getString(pnpref+SELECTED_SERIALNUMBER);
			for( String sn : prefs.getString(pnpref+SERIALNUMBERS).split(";")){
				if( serialNumbers.contains(sn)) continue;
				serialNumbers.add(sn);
			}
			createParamFile = prefs.getBoolean(pnpref+CREATE_PARAMFILE);
		}
		public void save() {
			StringBuilder sns = new StringBuilder(); 
			if( selectedSerial != null && selectedSerial.length() > 0 && !serialNumbers.contains(selectedSerial)){
				sns.append(selectedSerial);
			}
			for( String sn : serialNumbers ){
				if( sns.length() > 0 ) sns.append(";");
				sns.append(sn);
			}
			prefs.setValue(pnpref+SERIALNUMBERS, sns.toString());
			prefs.setValue(pnpref+SELECTED_SERIALNUMBER, selectedSerial == null ? "" : selectedSerial );
			prefs.setValue(pnpref+CREATE_PARAMFILE, createParamFile);
		}
	}
	
	class Model extends AbstractObservableList {
		String testers;
		LinkedList<PartNumber> partNumbers = new LinkedList<PartNumber>();
		PartNumber selectedPartNumber;
		public String getTesters() {
			return testers;
		}
		public void setTesters(String testers) {
			this.testers = testers;
		}
		
		public PartNumber getSelectedPartNumber() {
			return selectedPartNumber;
		}
		public void setSelectedPartNumber(PartNumber pn) {
			selectedPartNumber = pn;
		}
		public void load(String[] availablePartNumbers) {
			
			
			testers = prefs.getString(PREF+SELECTED_TESTERS);
			String selectedPartNumberStr = prefs.getString(PREF+SELECTED_PARTNUMBER);

			for( String s : availablePartNumbers ){
				PartNumber pn = new PartNumber(s);
				partNumbers.add(pn);
				if( s.equals(selectedPartNumberStr)){
					selectedPartNumber = pn;
				}
			}
			if( selectedPartNumber == null ){
				selectedPartNumber = partNumbers.getFirst();
			}
			for( PartNumber pn : partNumbers ){
				pn.load();
			}
		}
		public void save() {
			
			prefs.setValue(PREF+SELECTED_PARTNUMBER, selectedPartNumber.getName());
			prefs.setValue(PREF+SELECTED_TESTERS, testers);

			for( PartNumber pn : partNumbers ){
				pn.save();
			}

		}
		@Override
		public Object getElementType() {
			return PartNumber.class;
		}
		@Override
		protected int doGetSize() {
			return partNumbers.size();
		}
		@Override
		public Object get(int index) {
			return partNumbers.get(index);
		}
		public Collection<PartNumber> getPartNumbers() {
			return partNumbers;
		}
		
	}
	

	public ComboBinding(Shell parentShell) throws Exception {
		super(parentShell);

		prefs = new PreferenceStore();
		file = new File("prefs.ini");
		if( file.canRead()){
			prefs.load(new FileInputStream(file));
		}
		prefs.setDefault(PREF+WND_SIZE_W, 600);
		prefs.setDefault(PREF+WND_SIZE_H, 500);
		prefs.setDefault(PREF+WND_POS_X, 100);
		prefs.setDefault(PREF+WND_POS_Y, 100);
		
		prefs.setDefault(PREF+SF_WEIGTH_0, 50	);
		prefs.setDefault(PREF+SF_WEIGTH_1, 50	);
		prefs.setDefault(PREF+RIGHT_SF_WEIGTH_0, 25	);
		prefs.setDefault(PREF+RIGHT_SF_WEIGTH_1, 75	);

	}

	
	@Override
	protected Point getInitialSize() {
		return new Point( prefs.getInt(PREF+WND_SIZE_W), prefs.getInt(PREF+WND_SIZE_H));
	}
	
	@Override
	protected Point getInitialLocation(Point initialSize) {
		return new Point( prefs.getInt(PREF+WND_POS_X), prefs.getInt(PREF+WND_POS_Y));
	}

	@Override
	protected void configureShell(Shell newShell) {
		newShell.setText("ComboBinding");
		super.configureShell(newShell);
	}

	@Override
	protected Control createContents(Composite parent) {
		
		mainSashForm = new SashForm(parent, SWT.HORIZONTAL);
		mainSashForm.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
		
		lstPartNumbers = new ListViewer(mainSashForm, SWT.BORDER);
		
		{
			Composite comp = new Composite(mainSashForm, SWT.NONE);
			comp.setLayout(new GridLayout( 2, false ));
			
			new Label( comp, SWT.NONE ).setText("Tester:");
			
			Group grp = new Group(comp, SWT.NONE);
			grp.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
			grp.setText("Options");
			grp.setLayout(new GridLayout( 2, false ));
			Button btn;
			
			btn = btnCreateParamFile = new Button( grp, SWT.CHECK );
			btn.setText( "Create Parameter File");
			GridDataFactory.generate(btn, 2, 1 );

			cmbSerials = new ComboViewer(grp, SWT.DROP_DOWN);
			GridDataFactory.generate(cmbSerials.getCombo(), 2, 1 );

		}
		
		mainSashForm.setWeights(new int[]{
				prefs.getInt(PREF+SF_WEIGTH_0),
				prefs.getInt(PREF+SF_WEIGTH_1)});

		this.model = new Model();
		String partNumbers[] = new String[]{"AAA", "123"};
		model.load(partNumbers );
		
		bindControls();
		

		lstPartNumbers.setInput(model);
		lstPartNumbers.getList().setFocus();
		
		lstPartNumbers.setSelection(new StructuredSelection(model.getSelectedPartNumber()), true);
		return mainSashForm;
	}
	
	private void bindControls() {
		
		bindingContext = new DataBindingContext();

		IObservableMap attributeMap = BeansObservables.observeMap(
			Observables.staticObservableSet(new HashSet<PartNumber>( model.getPartNumbers() )), PartNumber.class, "name");
		lstPartNumbers.setContentProvider(new ArrayContentProvider());
		lstPartNumbers.setLabelProvider(new ObservableMapLabelProvider(attributeMap));
		
		IObservableValue selectedPn = ViewersObservables.observeSingleSelection(lstPartNumbers);
		
		bindingContext.bindList(
				SWTObservables.observeItems( cmbSerials.getCombo() ),
				BeansObservables.observeDetailList(selectedPn, "serialNumbers", String.class));

		bindingContext.bindValue(
				SWTObservables.observeText( cmbSerials.getCombo() ),
				BeansObservables.observeDetailValue(selectedPn, "selectedSerial", String.class));

		bindingContext.bindValue(
				SWTObservables.observeSelection( btnCreateParamFile ),
				BeansObservables.observeDetailValue(selectedPn, "createParamFile", Boolean.class));

	}


	@Override
	public boolean close() {
		Rectangle bounds = getShell().getBounds();
		prefs.setValue(PREF+WND_SIZE_W, bounds.width);
		prefs.setValue(PREF+WND_SIZE_H, bounds.height);
		prefs.setValue(PREF+WND_POS_X, bounds.x);
		prefs.setValue(PREF+WND_POS_Y, bounds.y);
		
		int[] weights;
		weights = mainSashForm.getWeights();
		prefs.setValue(PREF+SF_WEIGTH_0, weights[0] );
		prefs.setValue(PREF+SF_WEIGTH_1, weights[1] );
		model.save();
		try {
			prefs.save(new FileOutputStream(file), "");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return super.close();
	}


	

}
Re: [DataBinding] ComboViewer binding Items and Text in Master/Detail [message #648917 is a reply to message #648880] Sat, 15 January 2011 13:27 Go to previous messageGo to next message
Frank Benoit is currently offline Frank BenoitFriend
Messages: 179
Registered: July 2009
Senior Member
Hi,

I was more thinking about my approach...
Instead of a combo to have a history available, it is perhaps much better to have a simple text field with autocompletion support.

So finally, I am no more searching for a solution for the problem above.
Sorry for the noise Smile

Frank
Re: [DataBinding] ComboViewer binding Items and Text in Master/Detail [message #653289 is a reply to message #648581] Wed, 09 February 2011 09:02 Go to previous messageGo to next message
Stef  is currently offline Stef Friend
Messages: 1
Registered: February 2011
Junior Member
Can I bump this issue please?

I'm having the exact same problem. When clicking on another master selection the model field behind the combo is being cleared.

It's complicated by the fact that my combo is populated from a list of items bound on each child object.

// Bind the list of items in the combo to the available property of the selected <model object>.
IObservableValue selectionObservable = ViewersObservables.observeSingleSelection(myTableViewer);
IObservableList comboListSWTObservable = SWTObservables.observeItems(myWidgetCombo);
IObservableList comboListBeanObservable =  BeansObservables.observeDetailList(selectionObservable, <model object property - list of combo values>, <model object>.class);
		
// Create a master-detail binding between the <model object property> and myWidgetCombo.
IObservableValue comboValueBeanObservable = BeansObservables.observeDetailValue(selectionObservable, <model object property - value to select in combo>, <model object>.class);
IObservableValue comboValueSWTObserveable = SWTObservables.observeText(myWidgetCombo);

// Bind all the observables now.
DataBindingContext bindingContext = new DataBindingContext();
bindingContext.bindList(comboListSWTObservable, comboListBeanObservable);
bindingContext.bindValue(comboValueSWTObserveable, comboValueBeanObservable, new ToModelUpdateValueStrategy(), new FromModelUpdateValueStrategy());

Re: [DataBinding] ComboViewer binding Items and Text in Master/Detail [message #653296 is a reply to message #653289] Wed, 09 February 2011 09:12 Go to previous message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 6651
Registered: July 2009
Senior Member
Hi,

This is a known problem and the only solution is to dispose the
binding-value binding at the beginning of the master change and recreate
it afterwards.

Tom

Am 09.02.11 10:03, schrieb Stef:
> Can I bump this issue please?
> I'm having the exact same problem. When clicking on another master
> selection the model field behind the combo is being cleared.
>
> It's complicated by the fact that my combo is populated from a list of
> items bound on each child object.
>
>
> // Bind the list of items in the combo to the available property of the
> selected <model object>.
> IObservableValue selectionObservable =
> ViewersObservables.observeSingleSelection(myTableViewer);
> IObservableList comboListSWTObservable =
> SWTObservables.observeItems(myWidgetCombo);
> IObservableList comboListBeanObservable =
> BeansObservables.observeDetailList(selectionObservable, <model object
> property - list of combo values>, <model object>.class);
>
> // Create a master-detail binding between the <model object property>
> and myWidgetCombo.
> IObservableValue comboValueBeanObservable =
> BeansObservables.observeDetailValue(selectionObservable, <model object
> property - value to select in combo>, <model object>.class);
> IObservableValue comboValueSWTObserveable =
> SWTObservables.observeText(myWidgetCombo);
>
> // Bind all the observables now.
> DataBindingContext bindingContext = new DataBindingContext();
> bindingContext.bindList(comboListSWTObservable, comboListBeanObservable);
> bindingContext.bindValue(comboValueSWTObserveable,
> comboValueBeanObservable, new ToModelUpdateValueStrategy(), new
> FromModelUpdateValueStrategy());
>
>
Previous Topic:[DataBinding] add non-model intermediary elements with ObservableListTreeContentProvider
Next Topic:Only display one child of under a parent node in treeviewer
Goto Forum:
  


Current Time: Thu Apr 25 11:41:40 GMT 2024

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

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

Back to the top