Binding DOM and UI

Dans cette section, on va apprendre a synchroniser les valeurs des attributs du DOM avec le UI. On veut écrire ceci :
<MyPage xmlns="http://tk-ui.sourceforge.net/MyXMLMarkup" >
	<MyTextbox text="bla bla bla" />
</MyPage>

et obtenir le rendu SWT suivant :

Plus exactement l'attribut text de l'element MyTextbox doit être bindé avec la propriété Text de la widget SWT Text. Apres avoir chargé la description XML MyPage, la widget SWT Text aurra la propriété Text renseigné avec "bla bla bla" (Binding DOM vers UI). Lorsque l'utilisateur renseignera le champs SWT Text, l'attribut text sera mise à jour avec la valeur tappée de la widget (Binding UI vers DOM). Pour gérer le binding DOM <-> UI, TK-UI utilise JFace Databinding.

Vous pourrez trouver l'exemple de cette section dans le projet Eclipse org.akrogen.tkui.samples.myxmlmarkup-2 stocké sur SVN.

Binding

Le binding entre le DOM et l'UI s'appuie sur JFace DataBinding . Si vous ne connaissez pas JFace Databinding, veuillez vous reporter à cette section pour une explication très brève de JFace DataBinding.

DatabindingContext

JFace Databinding est basé sur le pattern Observeur. Dans notre cas, il faut :

  • créer un observeur sur l'attribut text de l'élement MyTextbox.
  • créer un observeur sur la propriété text de la widget SWT Text.
Ces 2 observeurs sont mis en liens à l'aide d'une instance JFace DatabindingContext qui gère le binding, autrement dit si l'attribut text est modifié, l'instance DatabindingContext appelle l'observeur de la widget SWT Text qui met a jour la propriété Text de la widget et inversement. Une instance DatabindingContext doit etre créé à un moment pour mettre en lien ces 2 observeurs. Ceci peut s'effectuer dans le toolkit SWT. Pour cela modifier la méthode getDataBindingContext de la classe MySWTToolkit comme ceci :
...
	public DataBindingContext getDataBindingContext(Object nativeWidgetRoot) {
		Widget widget = (Widget) nativeWidgetRoot;
		Realm realm = SWTObservables.getRealm(widget.getDisplay());
		return new DataBindingContext(realm);
	}

Ce qui donne

package org.akrogen.tkui.samples.myxmlmarkup.ui.toolkit;

import org.akrogen.tkui.core.IConfiguration;
import org.akrogen.tkui.core.ui.toolkit.IUIToolkit;
import org.akrogen.tkui.impl.core.ui.toolkit.AbstractUIToolkitImpl;
import org.akrogen.tkui.samples.myxmlmarkup.ui.MySWTElementFactoryImpl;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.swt.widgets.Widget;

public class MySWTToolkit extends AbstractUIToolkitImpl {

	private static final IUIToolkit toolkit = new MySWTToolkit();

	public static IUIToolkit getDefaultToolkit() {
		return toolkit;
	}

	protected void registerUIElementFactories(IConfiguration configuration) {
		configuration.registerUIElementFactory(MySWTElementFactoryImpl
				.getInstance());
	}

	public String getDefaultUIElementFactoryId() {
		return MySWTElementFactoryImpl.getInstance().getId();
	}

	public DataBindingContext getDataBindingContext(Object nativeWidgetRoot) {
		Widget widget = (Widget) nativeWidgetRoot;
		Realm realm = SWTObservables.getRealm(widget.getDisplay());
		return new DataBindingContext(realm);
	}

}

Binding DOM/UI

Le binding DOM et UI s'effectue en modifiant la méthode applyBindins de MyTextboxElementImpl :
protected void applyBindings() {
	DataBindingContext dataBindingContext = getDataBindingContext();
	// Observe text property from SWT text widget
	Text swtText = (Text) getUIElement().getNativeWidget();
	IObservableValue uiObservableValue = SWTObservables.observeText(
			swtText, SWT.Modify);
	// Observe attribute text from element MyTextboxElementImpl
	IObservableValue domObservableValue = DOMObservables.observeAttrValue(
			dataBindingContext.getValidationRealm(), this, "text", null);
	// Bind the DOM and UI Observale value
	dataBindingContext.bindValue(uiObservableValue, domObservableValue,
			null, null);
}
Vous pouvez relancer le test TestMyPageWithPlatform. la widget doit etre renseigne avec "bla bla bla".

Test DOM/UI

Il est difficile de voir que le binding s'effectue lorsque la widget SWT Text est modifié. Pour tester que l'attribut text se modifie bien lorsque l'on renseigne la widget SWT Text, nosu allons créer une textarea SWT qui observe le contenu du DOM Document. Pour cela nous allons utiliser JFace Databinding qui binde la textarea au DOM Document. Pour cela modifier le code TestMyPageWithPlatform comme ceci :
package org.akrogen.tkui.samples.myxmlmarkup;

import org.akrogen.tkui.core.dom.bindings.IDOMDocumentBindable;
import org.akrogen.tkui.core.platform.IPlatform;
import org.akrogen.tkui.samples.myxmlmarkup.platform.MySWTPlatform;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.ufacekit.core.databinding.dom.DOMObservables;
import org.ufacekit.core.databinding.dom.conversion.xerces.StringToXercesDocumentConverter;
import org.ufacekit.core.databinding.dom.conversion.xerces.XercesDocumentToStringConverter;

public class TestMyPageWithPlatform {

	public static void main(String[] args) {
		try {
			Display display = new Display();
			Shell shell = new Shell(display, SWT.SHELL_TRIM);
			shell.setLayout(new FillLayout());
			
			// Get MySWTPlatform
			IPlatform platform = MySWTPlatform.getDefaultPlatform();
			IDOMDocumentBindable document = platform.createDocument(shell,
					null, null);
			// Load MyPage into TK-UI DOM Document
			platform.loadDocument(TestMyPageWithPlatform.class
					.getResourceAsStream("page.myxmlmarkup"), document);

			// Observe DOM Content
			Text textarea = new Text(shell, SWT.MULTI | SWT.BORDER
					| SWT.V_SCROLL);

			DataBindingContext context = document.getDataBindingContext();
			Realm realm = context.getValidationRealm();
			context
					.bindValue(
							SWTObservables.observeText(textarea, SWT.Modify),
							DOMObservables.observeDocumentContent(realm,
									document),
							new UpdateValueStrategy()
									.setConverter(new StringToXercesDocumentConverter()),
							new UpdateValueStrategy()
									.setConverter(new XercesDocumentToStringConverter()));
			shell.pack();
			shell.open();

			while (!shell.isDisposed()) {
				if (!display.readAndDispatch())
					display.sleep();
			}

			shell.dispose();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Binding DOM/UI (2)

applyBindings a ete implemente avec JFace Databinding. Le probleme c'est que MyTextboxElementImpl est fortement lie a SWT du a la gestion du binding. Il est impossible avec ce code de gerer un renderer Swing par exemple. Dans la prochaine etape nous allons rendre plus generique le binding DOM et UI.