Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "VIATRA/Addon/Databinding"

< VIATRA‎ | Addon
(New page: == Data binding overview == Data binding [1] is general technique that binds two data/information sources together and maintains synchronization of data. In UI data binding data objects ...)
 
 
(18 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 +
{{caution|Old information|This page is not updated anymore; for more up-to-date details look at the language specification at https://www.eclipse.org/viatra/documentation/addons.html instead.}}
 
== Data binding overview  ==
 
== Data binding overview  ==
  
Data binding [1] is general technique that binds two data/information sources together and maintains synchronization of data. In UI data binding data objects are bound to UI elements and if the binding is done in the proper manner the changes in the data will be automatically reflected on the UI elements (for example a label will be automatically refreshed with new contents).  
+
[http://en.wikipedia.org/wiki/Data_binding Data binding] is general technique that binds two data/information sources together and maintains synchronization of data. In UI data binding data objects are bound to UI elements and if the binding is done in the proper manner the changes in the data will be automatically reflected on the UI elements (for example a label will be automatically refreshed with new contents).  
  
EMF-IncQuery provides a simple data binding facility that can be used to bind pattern match parameters to UI elements. The feature is mainly intended to be used to integrate EMF-IncQuery queries to newly developed user interfaces, however, the Query Explorer component also uses some related annotations  
+
VIATRA provides a simple data binding facility that can be used to bind pattern matches to UI elements. The feature is mainly intended to be used to integrate VIATRA queries to newly developed user interfaces, however, the Query Explorer component also uses some related annotations. In summary, this document is intended to be used mainly by developers but the section dealing with data binding related annotations may be useful for VIATRA end-users too.
  
== The scope of this document  ==
+
== Data binding related pattern annotations  ==
 
+
This document is intended to be used mainly by developers but the section dealing with data binding related annotations may be useful for EMF-IncQuery end-users too.
+
 
+
== Data binding related annotations  ==
+
  
 
The following annotation can be used on patterns within the data binding context:  
 
The following annotation can be used on patterns within the data binding context:  
  
 
*'''@QueryExplorer:''' the message parameter of the Query explorer annotation defines the label feature of the selected match.  
 
*'''@QueryExplorer:''' the message parameter of the Query explorer annotation defines the label feature of the selected match.  
*'''@ObservableValue''': allows the developer to customize the appearance of a match inside the Details panel. It defines an observable value (as defined in JFace databinding) which can be bound to an Eclipse/JFace UI. This annotation will also trigger the generation of an additional .databinding side-project next to your EMF-IncQuery project, which includes some helper classes that you can use to ease the integration of EMF-IncQuery into your user interface. <br>Annotation parameter(s):  
+
*'''@ObservableValue''': allows the developer to customize the appearance of a match inside the Details panel. It defines an observable value (as defined in JFace databinding) which can be bound to an Eclipse/JFace UI. <br>Annotation parameter(s):  
 
**'''name '''(String): the name of the parameter  
 
**'''name '''(String): the name of the parameter  
**'''expression''' (String): the attribute definition without '$' marks. For example @ObservableValue(name = "Year",&nbsp;expression="Y.startingDate") The parameters of the pattern are considered the default observable values of the matcher. This means, it is not required to present values like @ObservableValue(name="Y" expression="Y"). However, it is possible to redefine these values by simply defining a new value, e.g. @ObservableValue(name="Y" expression="Y.startingDate"). It is possible to use the annotation without parameters: in this case, it only represents that a default Observable matcher object should be generated with the default observable values. The following example is from the school tutorial (see link on the bottom of this page under the 'Examples' section). Here, a pattern is given with various annotations.
+
**'''expression''' (String): the attribute definition without '$' marks. For example @ObservableValue(name = "Year",&nbsp;expression="Y.startingDate") <br>The parameters of the pattern are considered the default observable values of the matcher. This means, it is not required to present values like @ObservableValue(name="Y" expression="Y"). However, it is possible to redefine these values by simply defining a new value, e.g. @ObservableValue(name="Y" expression="Y.startingDate"). <br>It is also possible to use the annotation without parameters: in this case, it only represents that a default Observable matcher object should be generated with the default observable values.&nbsp;
**'''labelExpression''': TODO
+
**'''labelExpression''': this annotation makes it possible to create observable string properties such as @ObservableValue(name = "TeacherStudent", labelExpression = "Teacher $T.name$ teaches Student $S.name$"), which are useful for presentation purposes inside a JFace viewer component.
  
[gist:2790441:step7.java]
+
The following example is from the school tutorial (see link on the bottom of this page under the 'Examples' section). Here, a pattern is given with various annotations. <source lang="java">
 +
// Step 7: combine everything, @PatternUI, @ObservableValue, @Handler
 +
 +
  /*
 +
    *
 +
    * We want to find those years, which had courses taught by the busiest teacher
 +
    * and included the most sociable students
 +
    *
 +
    */
 +
    @QueryExplorer(message="The busiest teacher $T.name$ taught the most sociable student $S.name$ in $Y.startingDate$")
 +
    @ObservableValue(name = "Year", expression="Y.startingDate")
 +
    @ObservableValue(name = "Teacher", expression="T.name")
 +
    @ObservableValue(name = "Student", expression="S.name")
 +
    @ObservableValue(name = "TeacherStudent", labelExpression = "Teacher $T.name$ teaches Student $S.name$")
 +
    @Handler(fileExtension = "school")
 +
    pattern finalPattern(Y:Year,C:Course,T:Teacher,S:Student) = {
 +
    Year.schoolClasses.courses(Y,C);
 +
    Course.teacher(C,T);
 +
    Student.schoolClass.courses(S,C);
 +
   
 +
    find theOnesWithTheBiggestCircle(S);
 +
    find teachesTheMostCourses(T);
 +
    }
 +
</source>
  
The @QueryExplorer annotation will result that the match of the finalPattern (it has at most one match) pattern will have a label with the form of 'The busiest teacher $T.name$ taught the most sociable student $S.name$ in $Y.startingDate$' inside the Query Explorer. The attribute markers will be replaced with the appropriate attribute values based on the current pattern match.  
+
The @QueryExplorer annotation will result that the match of the finalPattern pattern will have a label with the form of 'The busiest teacher $T.name$ taught the most sociable student $S.name$ in $Y.startingDate$' inside the Query Explorer. The attribute markers will be replaced with the appropriate attribute values based on the current pattern match.  
  
For a more specific example on the @ObservableValue annotation see the next section.
+
== VIATRA Data Binding API  ==
  
== Generated data binding plug-in ==
+
VIATRA contains the "org.eclipse.viatra.addon.databinding.runtime" plug-in, which provides several useful features.
  
The .databinding side-project will only be generated if at least one pattern is annotated with @ObservableValue in your EMF-IncQuery project. In this case a $PatterName$DatabindingAdapter.java class will be generated which is a subclass of DatabindingAdapter.
+
=== ViatraObservables class ([http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/addon/plugins/org.eclipse.viatra.addon.databinding.runtime/src/org/eclipse/viatra/addon/databinding/runtime/api/ViatraObservables.java source]) ===
  
[gist:3293600]
+
=== Observing match values  ===
  
In the finalPattern context mentioned above, the three @ObservableValue annotations will result that a FinalPatternDatabindingAdapter class will be generated in a .databinding side-project. The getParameterNames method call will return the array of ["Year","Teacher","Student"]. For each of these parameters an IObservableValue can be obtained based on the given attribute expression and a specific match of the pattern.
 
  
Please note that if you are binding an IObservableValue instance obtained from the above mentioned class, it is important to pay attention on the binding's update strategy as you should not use a two-way updating strategy (because it would modify the pattern match parameter). For example if you use an org.eclipse.core.databinding.DatabindingContext instance's bindValue method to create the binding, the suggested UpdateValueStrategy is the following:  
+
The MatcherProperties class ([http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/addon/plugins/org.eclipse.viatra.addon.databinding.runtime/src/org/eclipse/viatra/addon/databinding/runtime/adapter/MatcherProperties.java source]) provides direct access to JFace observables based on the annotations provided for your pattern definition. '''Important note:''' if you are binding an IObservableValue instance obtained from the above mentioned class, it is important to pay attention on the binding's update strategy as '''you should not use a two-way updating strategy''' (because it would modify the pattern match parameter). For example if you use a DatabindingContext instance's bindValue method to create the binding, the suggested UpdateValueStrategy is the following:  
  
UpdateValueStrategy.POLICY_NEVER in the UI to pattern match parameter binding UpdateValueStrategy.POLICY_UPDATE in the pattern match parameter to UI binding Also worth noting that you must take care of the IObservableValue instances' life-cycle as the pattern match may be removed from the match set of the EMF-IncQuery matcher. The best way to receive notification about the match disappearance is to register a listener on the matcher and upon callback, process the delta monitor's matchFoundEvents and matchLostEvents.
+
*UpdateValueStrategy.POLICY_NEVER in the UI to pattern match parameter binding  
 +
*UpdateValueStrategy.POLICY_UPDATE in the pattern match parameter to UI binding
  
== Example and useful resources  ==
+
It is also worth noting that you must take care of the IObservableValue instances' life-cycle as the pattern match may be removed from the match set of the VIATRA query matcher (see "observing match sets" below).
  
*Please see the school example (https://viatra.inf.mit.bme.hu/incquery/new/examples/school) which demonstrates the usage of the above mentioned annotations.
+
=== Observing match sets  ===
*The following tutorial is an in depth document about JFace/SWT data binding: http://www.vogella.com/articles/EclipseDataBinding/article.html
+
*The org.eclipse.viatra2.emf.incquery.tooling.gui/src/org/eclipse/viatra2/emf/incquery/queryexplorer/content/detail/DetailObserver.java gives a hint how the generated data binding code can be used (in this case for the Query Explorer's Details view).
+
  
=== DetailObserver.java highlights ===
+
The ViatraObservables class  provides means to observe the entire match set (query result set) as an observable list or set. This is the recommended and very efficient way of tracking changes in the query result set efficiently. See [[VIATRA/Query/UserDocumentation/API#Tracking_changes_in_match_sets_efficiently|here]] for an example usage and further notes.
  
The DetailObserver class extends the AbstractObservableList class, thus can be used in data binding contexts. Within the EMF-IncQuery project it is used to server as the input for a TableViewer which diplays pattern match details. The TableViewer's content provider is ObservableListContentProvider, this way data binding is automatically created and maintained.  
+
== Example code ==
 +
=== Annotated patterns ===
 +
<source lang="java">
 +
@ObservableValue(name = "id", expression = "host.id")
 +
@ObservableValue(name = "node_ip", expression = "host.nodeIp")
 +
@ObservableValue(name = "current_cpu", expression = "host.availableCpu")
 +
@ObservableValue(name = "current_hdd", expression = "host.availableHdd")
 +
@ObservableValue(name = "current_ram", expression = "host.availableRam")
 +
@ObservableValue(name = "total_cpu", expression = "host.totalCpu")
 +
@ObservableValue(name = "total_hdd", expression = "host.totalHdd")
 +
@ObservableValue(name = "total_ram", expression = "host.totalRam")
 +
pattern hostInstances(host: HostInstance) {
 +
HostInstance(host);
 +
}
  
The cunstuctor initializes the data structures and registers the IValueChangleListener instance on all pattern match parameters which were declared with an @ObservableValue annotation, thus having a getter for its observable value in the appropriate DatabindingAdapter subclass.  
+
@ObservableValue(name = "id", expression = "app.id")
 +
@ObservableValue(name = "state", expression = "app.state")
 +
@ObservableValue(name = "db_user", expression = "app.dbUser")
 +
@ObservableValue(name = "db_pass", expression = "app.dbPassword")
 +
@ObservableValue(name = "allocatedTo", expression = "app.allocatedTo")
 +
pattern applicationInstances(app: ApplicationInstance) {
 +
ApplicationInstance(app);
 +
}
 +
</source>
  
[gist:3302089]
+
=== Using Databinding to populate a table ===
  
The addDetail and removeDetail methods modifiy the contents inside the view and notify (with the fireListChange call) the UI element that the backing content has changed.  
+
<source lang="java">
 +
//Initialize VIATRA query engine
 +
    ViatraQueryEngine engine = ViatraQueryEngine.on(new EMFScope(resourceSet));
 +
    DataBindingPatterns.instance().prepare(engine);
  
[gist:3302136]  
+
    //Get the matcher for the query to be observed (HostInstances pattern)
 +
        HostInstancesMatcher matcher = HostInstancesMatcher.on(engine);
 +
        //Create a generic databinding adapter for the query specification
 +
        //It is responsible for creating observable value properties based on the annotations of the pattern
 +
        //Bind the matches to the given TableViewer
 +
        ViewerSupport.bind(
 +
        //Specify the target table viewer
 +
                tableViewer,
 +
                //Get the matching results as an observable list
 +
                ViatraObservables.observeMatchesAsList(matcher),
 +
                //Specify observed proeprties
 +
                new IValueProperty[] {
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(), "id"),
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"node_ip"),
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"current_cpu"),
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"current_hdd"),
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"current_ram"),
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"total_cpu"),
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"total_hdd"),
 +
                MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"total_ram") });
 +
</source>
  
We have registered the IValueChangeListener instance on all pattern match parameters in the constructor. Upon attribute modification this listener will be called and the appropriate element can be changed in the details view.
+
=== Master - detail databinding with a list===
  
[gist:3302121]
+
The following code fragment is responsible for binding a list to the results of a VIATRA query, and also displays match details in text boxes. (Uses Master-detail binding)
 +
 
 +
<source lang="java">
 +
//Create new data binding context
 +
//It will be used for binding the pattern match details
 +
DataBindingContext dataBindingContext = new DataBindingContext();
 +
//Initialize VIATRA query engine
 +
ViatraQueryEngine engine = ViatraQueryEngine.on(new EMFScope(resourceSet));
 +
//Prepare target patterns
 +
DataBindingPatterns.instance().prepare(engine);
 +
//Get the matcher for the query to be observed (ApplicationInstances pattern)
 +
ApplicationInstancesMatcher matcher = ApplicationInstancesMatcher.on(engine);
 +
// Create a generic databinding adapter for the query specification
 +
// It is responsible for creating observable value properties based on
 +
// the annotations of the pattern
 +
//Bind the matches to the given ListViewer
 +
ViewerSupport.bind(listViewer, ViatraObservables.observeMatchesAsSet(matcher), MatcherProperties.getValueProperty(ApplicationInstancesMatcher.querySpecification(), "id"));
 +
 
 +
//At this point, the results of the given pattern will appear in the list Viewer, the details however still need to be implemented
 +
//Define target observable values for both textboxes
 +
IObservableValue dbUserTarget = WidgetProperties.text().observe(dbUser);
 +
IObservableValue dbPassTarget = WidgetProperties.text().observe(dbPass);
 +
 
 +
//Observe the changes in the list selection       
 +
IViewerObservableValue listSelection = ViewerProperties
 +
.singleSelection().observe(listViewer);
 +
 
 +
//Use the data binding context to bind the text property of the target textbox and the given property of the matcher. 
 +
dataBindingContext.bindValue(
 +
//Target textbox observable value
 +
dbPassTarget,
 +
//Get the source observable value from the adapter
 +
MatcherProperties.getValueProperty(ApplicationInstancesMatcher.querySpecification(), "db_pass").observeDetail(listSelection),
 +
//Define EMF update value strategy
 +
        //In this case its one directional
 +
new EMFUpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
 +
new EMFUpdateValueStrategy());
 +
 
 +
dataBindingContext.bindValue(dbUserTarget, adapter.getProperty("db_user").observeDetail(listSelection),
 +
new EMFUpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
 +
new EMFUpdateValueStrategy());
 +
</source>
 +
 
 +
== Other examples and useful resources  ==
 +
 
 +
*Please see the [http://incquery.net/incquery/new/examples/school school example] which demonstrates the usage of the above mentioned annotations.
 +
*The following tutorial is an in depth document about JFace/SWT data binding: http://www.vogella.com/articles/EclipseDataBinding/article.html
 +
*The DetailObserver class of the VIATRA Query Explorer gives a hint how the generated data binding code can be used (in this case for the Query Explorer's Details view). The DetailObserver class ([http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/query/plugins/org.eclipse.viatra.query.tooling.ui/src/org/eclipse/viatra/query/tooling/ui/queryexplorer/content/detail/DetailObserver.java source]) extends the AbstractObservableList class, thus can be used in data binding contexts. Within the VIATRA Queries project it is used to serve as the input for a TableViewer which displays pattern match details. The TableViewer's content provider is an ObservableListContentProvider, this way data binding is automatically created and maintained.
 +
**The constuctor initializes the data structures and registers the IValueChangeListener instance on all pattern match parameters which were declared with an @ObservableValue annotation, thus having a getter for its observable value in the appropriate DatabindingAdapter subclass.
 +
**The addDetail and removeDetail methods modifiy the contents inside the view and notify (with the fireListChange call) the UI element that the backing content has changed.
 +
**We have registered the IValueChangeListener instance on all pattern match parameters in the constructor. Upon attribute modification this listener will be called and the appropriate element can be changed in the details view.

Latest revision as of 09:35, 30 November 2017

Stop.png
Old information
This page is not updated anymore; for more up-to-date details look at the language specification at https://www.eclipse.org/viatra/documentation/addons.html instead.

Data binding overview

Data binding is general technique that binds two data/information sources together and maintains synchronization of data. In UI data binding data objects are bound to UI elements and if the binding is done in the proper manner the changes in the data will be automatically reflected on the UI elements (for example a label will be automatically refreshed with new contents).

VIATRA provides a simple data binding facility that can be used to bind pattern matches to UI elements. The feature is mainly intended to be used to integrate VIATRA queries to newly developed user interfaces, however, the Query Explorer component also uses some related annotations. In summary, this document is intended to be used mainly by developers but the section dealing with data binding related annotations may be useful for VIATRA end-users too.

Data binding related pattern annotations

The following annotation can be used on patterns within the data binding context:

  • @QueryExplorer: the message parameter of the Query explorer annotation defines the label feature of the selected match.
  • @ObservableValue: allows the developer to customize the appearance of a match inside the Details panel. It defines an observable value (as defined in JFace databinding) which can be bound to an Eclipse/JFace UI.
    Annotation parameter(s):
    • name (String): the name of the parameter
    • expression (String): the attribute definition without '$' marks. For example @ObservableValue(name = "Year", expression="Y.startingDate")
      The parameters of the pattern are considered the default observable values of the matcher. This means, it is not required to present values like @ObservableValue(name="Y" expression="Y"). However, it is possible to redefine these values by simply defining a new value, e.g. @ObservableValue(name="Y" expression="Y.startingDate").
      It is also possible to use the annotation without parameters: in this case, it only represents that a default Observable matcher object should be generated with the default observable values. 
    • labelExpression: this annotation makes it possible to create observable string properties such as @ObservableValue(name = "TeacherStudent", labelExpression = "Teacher $T.name$ teaches Student $S.name$"), which are useful for presentation purposes inside a JFace viewer component.
The following example is from the school tutorial (see link on the bottom of this page under the 'Examples' section). Here, a pattern is given with various annotations.
// Step 7: combine everything, @PatternUI, @ObservableValue, @Handler
 
   /*
    * 
    * We want to find those years, which had courses taught by the busiest teacher
    * and included the most sociable students
    * 
    */
    @QueryExplorer(message="The busiest teacher $T.name$ taught the most sociable student $S.name$ in $Y.startingDate$")
    @ObservableValue(name = "Year", expression="Y.startingDate")
    @ObservableValue(name = "Teacher", expression="T.name")
    @ObservableValue(name = "Student", expression="S.name")
    @ObservableValue(name = "TeacherStudent", labelExpression = "Teacher $T.name$ teaches Student $S.name$")
    @Handler(fileExtension = "school")
    pattern finalPattern(Y:Year,C:Course,T:Teacher,S:Student) = {
    	Year.schoolClasses.courses(Y,C);
    	Course.teacher(C,T);
    	Student.schoolClass.courses(S,C);
 
    	find theOnesWithTheBiggestCircle(S);
    	find teachesTheMostCourses(T);
    }

The @QueryExplorer annotation will result that the match of the finalPattern pattern will have a label with the form of 'The busiest teacher $T.name$ taught the most sociable student $S.name$ in $Y.startingDate$' inside the Query Explorer. The attribute markers will be replaced with the appropriate attribute values based on the current pattern match.

VIATRA Data Binding API

VIATRA contains the "org.eclipse.viatra.addon.databinding.runtime" plug-in, which provides several useful features.

ViatraObservables class (source)

Observing match values

The MatcherProperties class (source) provides direct access to JFace observables based on the annotations provided for your pattern definition. Important note: if you are binding an IObservableValue instance obtained from the above mentioned class, it is important to pay attention on the binding's update strategy as you should not use a two-way updating strategy (because it would modify the pattern match parameter). For example if you use a DatabindingContext instance's bindValue method to create the binding, the suggested UpdateValueStrategy is the following:

  • UpdateValueStrategy.POLICY_NEVER in the UI to pattern match parameter binding
  • UpdateValueStrategy.POLICY_UPDATE in the pattern match parameter to UI binding

It is also worth noting that you must take care of the IObservableValue instances' life-cycle as the pattern match may be removed from the match set of the VIATRA query matcher (see "observing match sets" below).

Observing match sets

The ViatraObservables class provides means to observe the entire match set (query result set) as an observable list or set. This is the recommended and very efficient way of tracking changes in the query result set efficiently. See here for an example usage and further notes.

Example code

Annotated patterns

@ObservableValue(name = "id", expression = "host.id")
@ObservableValue(name = "node_ip", expression = "host.nodeIp")
@ObservableValue(name = "current_cpu", expression = "host.availableCpu")
@ObservableValue(name = "current_hdd", expression = "host.availableHdd")
@ObservableValue(name = "current_ram", expression = "host.availableRam")
@ObservableValue(name = "total_cpu", expression = "host.totalCpu")
@ObservableValue(name = "total_hdd", expression = "host.totalHdd")
@ObservableValue(name = "total_ram", expression = "host.totalRam") 
pattern hostInstances(host: HostInstance) {
	HostInstance(host);
}
 
@ObservableValue(name = "id", expression = "app.id")
@ObservableValue(name = "state", expression = "app.state")
@ObservableValue(name = "db_user", expression = "app.dbUser")
@ObservableValue(name = "db_pass", expression = "app.dbPassword")
@ObservableValue(name = "allocatedTo", expression = "app.allocatedTo")
pattern applicationInstances(app: ApplicationInstance) {
	ApplicationInstance(app);
}

Using Databinding to populate a table

//Initialize VIATRA query engine
    	ViatraQueryEngine engine = ViatraQueryEngine.on(new EMFScope(resourceSet));
    	DataBindingPatterns.instance().prepare(engine);
 
    	//Get the matcher for the query to be observed (HostInstances pattern)
        HostInstancesMatcher matcher = HostInstancesMatcher.on(engine);
        //Create a generic databinding adapter for the query specification
        //It is responsible for creating observable value properties based on the annotations of the pattern
        //Bind the matches to the given TableViewer
        ViewerSupport.bind(
        		//Specify the target table viewer
                tableViewer,
                //Get the matching results as an observable list
                ViatraObservables.observeMatchesAsList(matcher),
                //Specify observed proeprties
                new IValueProperty[] { 
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(), "id"),
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"node_ip"),
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"current_cpu"),
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"current_hdd"),
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"current_ram"),
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"total_cpu"),
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"total_hdd"),
                		MatcherProperties.getValueProperty(HostInstancesMatcher.querySpecification(),"total_ram") });

Master - detail databinding with a list

The following code fragment is responsible for binding a list to the results of a VIATRA query, and also displays match details in text boxes. (Uses Master-detail binding)

//Create new data binding context
//It will be used for binding the pattern match details
DataBindingContext dataBindingContext = new DataBindingContext();
//Initialize VIATRA query engine
ViatraQueryEngine engine = ViatraQueryEngine.on(new EMFScope(resourceSet));
//Prepare target patterns
DataBindingPatterns.instance().prepare(engine);
//Get the matcher for the query to be observed (ApplicationInstances pattern)
ApplicationInstancesMatcher matcher = ApplicationInstancesMatcher.on(engine);
// Create a generic databinding adapter for the query specification
// It is responsible for creating observable value properties based on
// the annotations of the pattern
//Bind the matches to the given ListViewer
ViewerSupport.bind(listViewer, ViatraObservables.observeMatchesAsSet(matcher), MatcherProperties.getValueProperty(ApplicationInstancesMatcher.querySpecification(), "id"));
 
//At this point, the results of the given pattern will appear in the list Viewer, the details however still need to be implemented
//Define target observable values for both textboxes
IObservableValue dbUserTarget = WidgetProperties.text().observe(dbUser);
IObservableValue dbPassTarget = WidgetProperties.text().observe(dbPass);
 
//Observe the changes in the list selection        
IViewerObservableValue listSelection = ViewerProperties
	.singleSelection().observe(listViewer);
 
//Use the data binding context to bind the text property of the target textbox and the given property of the matcher.   
dataBindingContext.bindValue(
		//Target textbox observable value
		dbPassTarget, 
		//Get the source observable value from the adapter
		MatcherProperties.getValueProperty(ApplicationInstancesMatcher.querySpecification(), "db_pass").observeDetail(listSelection), 
		//Define EMF update value strategy
	        //In this case its one directional
		new EMFUpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
		new EMFUpdateValueStrategy());
 
dataBindingContext.bindValue(dbUserTarget, adapter.getProperty("db_user").observeDetail(listSelection), 
	new EMFUpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
	new EMFUpdateValueStrategy());

Other examples and useful resources

  • Please see the school example which demonstrates the usage of the above mentioned annotations.
  • The following tutorial is an in depth document about JFace/SWT data binding: http://www.vogella.com/articles/EclipseDataBinding/article.html
  • The DetailObserver class of the VIATRA Query Explorer gives a hint how the generated data binding code can be used (in this case for the Query Explorer's Details view). The DetailObserver class (source) extends the AbstractObservableList class, thus can be used in data binding contexts. Within the VIATRA Queries project it is used to serve as the input for a TableViewer which displays pattern match details. The TableViewer's content provider is an ObservableListContentProvider, this way data binding is automatically created and maintained.
    • The constuctor initializes the data structures and registers the IValueChangeListener instance on all pattern match parameters which were declared with an @ObservableValue annotation, thus having a getter for its observable value in the appropriate DatabindingAdapter subclass.
    • The addDetail and removeDetail methods modifiy the contents inside the view and notify (with the fireListChange call) the UI element that the backing content has changed.
    • We have registered the IValueChangeListener instance on all pattern match parameters in the constructor. Upon attribute modification this listener will be called and the appropriate element can be changed in the details view.

Back to the top