Difference between revisions of "Tutorial: Model Development"

From Developer Documents
Jump to navigation Jump to search
 
(140 intermediate revisions by 4 users not shown)
Line 1: Line 1:
__NOTOC__
 
 
In this part of the tutorial we will focus on implementing the basic functionality for the following parts of the UI:
 
In this part of the tutorial we will focus on implementing the basic functionality for the following parts of the UI:
 
* ''Model Browser'' for modelling movie production cases
 
* ''Model Browser'' for modelling movie production cases
 
** Basic context menu actions for the browser
 
** Basic context menu actions for the browser
 
*** Add > Movie Project
 
*** Add > Movie Project
*** Add > Casting Plan
 
 
*** Add > Role
 
*** Add > Role
* ''Property View'' for editing properties of model entities
+
* ''Property Page'' for editing properties of model entities
 
* ''Movie Database Library'' for searching available movies, actors, directors, etc.
 
* ''Movie Database Library'' for searching available movies, actors, directors, etc.
  
== Step 1: Customize Model Browser ==
 
To customize the model browser for the movie production case, we cannot directly use the existing view added to the perspective in the previous part of the tutorial. We need to create a new ''view'' extension to parametrize the view properly.
 
  
Lets add the new view extension.
+
== Step 1: Model Browser ==
 +
 
 +
=== Dependencies ===
 +
 
 +
To get the model browser working, UI plugin needs some more plug-ins, add dependencies.
 +
* Open '''com.acme.movie.ui''' / '''META-INF/MANIFEST.MF''' >> '''Dependencies'''
 +
* In the ''Required Plug-ins'' section, add dependencies on
 +
** '''org.simantics.ui'''
 +
** '''org.simantics.browsing.ui.platform'''
 +
** '''org.simantics.layer0'''
 +
** '''com.acme.movie.ontology'''
 +
 
 +
=== Enable Browser Contributions  ===
 +
At this point, the browser is empty since there is neither data to be shown nor the contributions for producing the data to show.
 +
 
 +
Before going into the contributions themselves, we need to make our Productions browser capable of receiving contributions. This can be achieved by adding a '''browseContext''' argument for the view extension. A ''browseContext'' is simply any unique string identifier to which contributions are bound. The set of browseContexts used by the browser view will therefore define which contributions are used.
 
* Open '''com.acme.movie.ui''' / '''META-INF/MANIFEST.MF''' >> '''Extensions'''
 
* Open '''com.acme.movie.ui''' / '''META-INF/MANIFEST.MF''' >> '''Extensions'''
* Add a new extension, ''org.eclipse.ui.views''
+
* Find the Productions view extension: '''org.eclipse.ui.views''' >> '''Productions (view)'''
* Add ''view category''
+
* Append the following to the class attribute value:
** '''org.eclipse.ui.views''' >> right click >> '''new''' >> '''category'''
+
** ''':<span style="color:green" title="Key of 1st argument to ViewPart implementation">browseContext</span>=<span style="color:blue" title="Value of 1st argument to ViewPart implementation"><nowiki>http://www.acme.com/Movie-1.0/Productions</nowiki></span>'''
** id = ''com.acme.movie.ui.category''
+
** Note that the ':' character at the beginning is required - it is a separator between the class name and the rest of the parameter string. The rest of the string is interpreted as arguments. See the tip below for details.
** name = ''Movie Production''
+
 
* Add ''view''
 
** '''org.eclipse.ui.views''' >> right click >> '''new''' >> '''view'''
 
** id = ''com.acme.movie.ui.productions''
 
** name = ''Productions''
 
** category = ''com.acme.movie.ui.category''
 
** class = '''<span style="color:#666666" title="ViewPart implementation class ">org.simantics.browsing.ui.swt.GraphExplorerView</span>:<span style="color:green" title="Key of 1st argument to ViewPart implementation">browseContext</span>=<span style="color:blue" title="Value of 1st argument to ViewPart implementation"><nowiki>http://com.acme/Movie-1.0/Productions</nowiki></span>'''
 
*** The '''<span style="color:#666666">first</span>''' part is the ViewPart implementation class
 
*** Everything that comes after the first '<b>:</b>' character is an argument for the ViewPart implementation. Arguments are simple '''<span style="color:green">key</span>=<span style="color:blue">value</span>''' pairs, separated by '''&''' characters.
 
  
 +
<blockquote style="background-color: #eff5fa; border: solid thin lightgrey; padding: 1ex">
 +
{| cellpadding="4"
 +
|-
 +
| [[file:Tip.png]]
 +
|Arguments can be specified to extensions, such as views, through the ''class'' attribute of the extension. The general format of the class attribute is
 +
<blockquote>'''<span style="color:#666666"><class name></span>''':'''<span style="color:green"><arguments></span>'''</blockquote>
  
In the same extension editor, modify the existing view perspective extension to use the new view.
+
The <span style="color:green">arguments</span> part of the attribute value is specified similarly to [[wikipedia:URI scheme#Generic syntax|URI scheme query strings]]. Individual arguments are separated by semicolons (''';''') and specified either as plain strings or as '''<span style="color:green">key</span>=<span style="color:blue">value</span>''' pairs.
* Find the extension in the tree:<br/>
 
*: '''org.eclipse.ui.perspectiveExtensions''' >><br/>
 
*:: '''com.acme.movie.ui.perspective (perspectiveExtension)''' >><br/>
 
*::: '''org.simantics.structural.ui.modelBrowser'''
 
* Modify ''org.simantics.structural.ui.modelBrowser'' to ''com.acme.movie.ui.productions''
 
  
 +
The arguments supported by ''org.simantics.browsing.ui.platform.GraphExplorerView'' are:
 +
; browseContext=ID: For specifying ''browse contexts'' for the view. This will determine which contributions the view will use. 0 to many browse contexts may be defined. Not defining browse contexts will always result in zero contributions.
 +
; uiContext=ID: For specifying ID's of [http://wiki.eclipse.org/Org.eclipse.ui.context org.eclipse.ui.context] extensions to be activated for the view. 0 to many UI contexts may be defined.
 +
; contextMenuId=ID: Specifies the ID of the context menu to register for this browser view. Only one ID can be specified, the last one specified is used.
 +
; hideComparatorSelector: Hides the comparator selector combo box from the UI.
 +
; hideViewpointSelector: Hides the viewpoint selector combo box from the UI.
 +
; hideFilter: Hides the filter control from the UI.
 +
; propertyBrowseContext=ID: Specified a browse context for the property page provided by this browser view. When the view is requsted for an ''IPropertyPage'' a new [[svn:foundation/browsing/trunk/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/StandardPropertyPage.java|StandardPropertyPage]] will be created with all defined propertyBrowseContexts. If this implementation does not suit your needs, see ''propertyPageClass'' argument.
 +
; propertyPageClass=class-name: Defines the property page that will be created by the view when requested for it. The class-name must point to an [[svn:foundation/browsing/trunk/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/IPropertyPage.java|IPropertyPage]] implementation.
 +
|}
 +
</blockquote>
  
Time to test the Movie product again. Launch it and you will see the old ''Model Browser'' view and not your new ''Productions'' view. This happens because the application remembers the state of the UI between sessions. This includes the layout of the perspective. To get your new layout visible select from main menu '''Window''' >> '''Reset Perspective...''' This will reset your perspective's layout according to the current perspective extension specifications.
+
=== Getting data to show - Adding new movies ===
 +
In order to be able to see our contributions working we need to be able to create data in the browser. For this reason we take a little step to the side to add a context menu action for creating new movie projects into the active project.
  
== Step 2: Add Context Menu Actions for Model Browser ==
+
Workbench context menus are contribution-based. Each context menu is given a unique ID and popup contributions are then bound to that ID. For the ''Productions'' view, we will select '''<span style="color:blue">#ProductionsPopup</span>''' as the menu ID.
Workbench context menus are contribution-based. Each context menu is given a unique ID and popup contributions are then bound to that ID. For the ''Productions'' view, we will select '''<span style="color:green">#ProductionsPopup</span>''' as the menu ID.
 
  
 
First the context menu for the ''Productions'' browser needs to be registered with this ID. This can be achieved by once again modifying the class attribute of our view extension.
 
First the context menu for the ''Productions'' browser needs to be registered with this ID. This can be achieved by once again modifying the class attribute of our view extension.
 
* Find our production view extension: '''org.eclipse.ui.views''' >> '''Productions (view)'''
 
* Find our production view extension: '''org.eclipse.ui.views''' >> '''Productions (view)'''
* Append a new argument to the ''class'' attribute: '''&<span style="color:green">contextMenuId</span>=<span style="color:blue">#ProductionsPopup</span>'''
+
* Append a new argument to the ''class'' attribute: ''';<span style="color:green">contextMenuId</span>=<span style="color:blue">#ProductionsPopup</span>'''
  
Now your browser should have a context menu registered with the specified ID. You can check this by launching the movie product, activating the ''Productions'' view and pressing ''Control+Shift+F1''. A ''Plug-in Spy'' window should pop up and give information on the view. It should say:  
+
Now your browser should have a context menu registered with the specified ID. You can check this by launching the movie product, activating the ''Productions'' view and pressing ''Alt+Shift+F1''. A ''Plug-in Spy'' window should pop up and give information on the view. It should say:  
 
  The active menu contribution identifiers:
 
  The active menu contribution identifiers:
 
     #ProductionsPopup
 
     #ProductionsPopup
  
== Step 3: Add Property View for Model Browser ==
+
==== Add command extensions ====
 +
The next thing to do is to add ''org.eclipse.ui.command'' extensions for each separate action to be performed.
 +
 
 +
* Open the ''Extensions'' tab of our plug-in's plugin.xml editor. Add ''org.eclipse.ui.command'' extension plug-in: '' '''Add...''' >> '''org.eclipse.ui.command''' ''
 +
* Right-click ''org.eclipse.ui.command'' in the the extension tree, select '''New''' >> '''command''', set attribute values:
 +
** id = ''com.acme.movie.ui.addMovie''
 +
** name = ''Add Movie''
 +
** defaultHandler="com.acme.movie.ui.browser.handlers.AddMovie"
 +
* Add another command with the attributes:
 +
** id = ''com.acme.movie.ui.addRole''
 +
** name = ''Add Role''
 +
** defaultHandler="com.acme.movie.ui.browser.handlers.AddRole"
 +
 
 +
This should give you the following things in the plugin.xml file whose contents can be seen from the '''plugin.xml''' tab of the editor.
 +
<div style="background-color:#f8f8f8; border: 1px dashed #cccccc; padding: 1ex; margin-left:2em; margin-top: 1em; margin-bottom:1em;">
 +
<syntaxhighlight lang="java">
 +
  <extension
 +
        point="org.eclipse.ui.commands">
 +
      <command
 +
            defaultHandler="com.acme.movie.ui.browser.handlers.AddMovie"
 +
            id="com.acme.movie.ui.addMovie"
 +
            name="Add Movie">
 +
      </command>
 +
      <command
 +
            defaultHandler="com.acme.movie.ui.browser.handlers.AddRole"
 +
            id="com.acme.movie.ui.addRole"
 +
            name="Add Role">
 +
      </command>
 +
  </extension>
 +
</syntaxhighlight>
 +
</div>
 +
 
 +
==== Add handler stub code ====
 +
In the '''Extensions''' tab of the editor select the addMovie command extension. On the right panel, press ''defaultHandler'' label link to create the '''AddMovie''' class. In the '''New Java Class''' wizard that is presented, set ''Superclass'' to ''org.eclipse.core.commands.AbstractHandler'' and press '''Finish'''.
 +
 
 +
Do the same for the '''Add Role''' command.
 +
 
 +
==== Add menu extensions ====
 +
 
 +
The next thing to do is to add an ''org.eclipse.ui.menus'' extension to populate our #ProductionsPopup context menu.
 +
 
 +
* Open the ''Extensions'' tab of our plug-in's plugin.xml editor. Add ''org.eclipse.ui.menus'' extension plug-in: '' '''Add...''' >> '''org.eclipse.ui.menus''' ''
 +
* Right-click ''org.eclipse.ui.menus'' in the the extension tree, select '''New''' >> '''menuContribution''', set locationURI = ''popup:#ProductionsPopup''
 +
 
 +
Next comes the actual menu population:
 +
* Right-click the newly created ''menuContribution'', select '''New''' >> '''command''', set id = ''com.acme.movie.ui.addMovie''
 +
* Repeat the same for the ''com.acme.movie.ui.addRole'' command
 +
 
 +
==== Add code to create new movies ====
 +
 
 +
Open the handler classes previously created, AddMovie and AddRole.
 +
 
 +
To create a new movie we need to:
 +
* Create a new movie instance and add it to the project.
 +
* Set a fresh name for the new movie, in this case automatically without asking the user.
 +
 
 +
Download the handler code to do this ([[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/handlers/AddMovie.java|AddMovie.java]]) and replace the stub AddMovie class with it.
 +
 
 +
==== Check your work ====
 +
 
 +
So far we should have the same empty browser UI, except now you should be able to open a context menu from it that contains two actions: '''Add Movie''' and '''Add Role''' as shown in the figure
 +
 
 +
[[Image:Productions-browser-context-menu-1.png|frame|center|Productions browser after adding the first context menu actions.]]
 +
 
 +
Selecting the "Add Movie" action at this point will not produce visible results since we have not added any browser contributions to actually show the data. We'll go into this next.
  
The '''Productions''' browser is responsible for contributing its own property page. To do this, two things must be done:
+
=== Showing the data - Add browsing contributions ===
# An implementation of ''IPropertyPage'' must be created
 
# Once again, the ''class'' attribute of our ''Productions'' view extensions must be modified to offer our IPropertyPage implementation.
 
  
Here's the ''IPropertyPage'' implementation we will be using:
+
Now let's focus on adding some basic contributions for making data visible to the user.
  
 +
There are several kinds of contributions that can to be added to make data visible in the browser. The most important contributions are ''viewpoints'', i.e. the contributions that produce the contents for the browser tree. Take another look at the previous tutorial's [[Tutorial:_Project_Development#sketch|UI sketch]]. We will need contributions for doing the following things in the browser:
 +
* Content production (&sim;ViewpointContribution):
 +
** Show all movie productions in the active project
 +
** Show a '''Casting''' node for a movie
 +
** Show all roles cast for a movie under the '''Casting''' node
 +
* Content labeling (&sim;LabelerContribution):
 +
** Movie: '''movie title''' or '''no title''' if title is not defined
 +
*** Movie title with property relation ''MO.HasTitle''
 +
** Casting: show fixed name '''Casting'''
 +
** Role: show
 +
*** '''role name - no actor''' if no actor is specified for role
 +
*** '''role name - actor name''' if an actor has been specified for role
 +
* Giving images for contents (&sim;ImagerContribution)
 +
** Movies: [[File:Film.png]] ([[Media:Film.png|download]])
 +
** Casting: [[File:Casting.png]] ([[Media:Casting.png|download]])
 +
** Role: [[File:Role.png]] ([[Media:Role.png|download]])
 +
** Create a new folder '''icons''' in your ''com.acme.movie.ui'' plug-in and download the images shown above into that directory.
 +
** Modify your Activator class code to match [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/Activator.java|this version]]. This will allow us to use the images in the contributions to be created next.
 +
 +
Start by creating a new java package for the contributions:
 +
* Select '''File''' >> '''New''' >> '''Package'''
 +
* Specify package '''com.acme.movie.ui.browser.contributions'''
 +
 +
==== Viewpoint Contributions ====
 +
The ''com.acme.movie.ui.browser.contributions.Movies'' contribution takes care of contributing all movie resources when given a ''Project'' resource as input. It will also contribute the movies in the previously created movie library ontology. Download [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/Movies.java|the source]] and put it into the contributions package.
 +
 +
One more thing needs to be done in order to put the Movies contribution to use: define an extension for binding it to the ''browsing context'' of the Productions browser.
 +
* Open '''com.acme.movie.ui''' / '''META-INF/MANIFEST.MF''' >> '''Extensions'''
 +
* Add a new extension, ''org.simantics.browsing.ui.common.viewpointContributionBinding''
 +
* A node will appear, select it and set browseContext=<span style="color:blue">http://www.acme.com/Movie-1.0/Productions</span>
 +
* Select '''http://www.acme.com/Movie-1.0/Productions''' >> right click '''New''' >> '''implementation'''. Select it and set the attributes:
 +
** class = ''com.acme.movie.ui.browser.contributions.Movies''
 +
** preference = 1
 +
 +
Create another package '''com.acme.movie.ui.browser.nodes''' as before and download these files into that package: [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/nodes/CastingNode.java|Casting node class]], [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/nodes/CastNode.java|Cast Role class]]
 +
 +
Do the same, i.e. download and add extensions for the remaining two viewpoint contributors:
 +
* [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/Casting.java|Casting node contributor]]
 +
* [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/Roles.java|Role node contributor]]
 +
 +
If you test your application now, the browser will not show any human readable labels for movie instances. This is because we have not contributed any logic that is able to label a movie. By default the system will only use Java ''Object.toString()'' for the label.
 +
 +
==== Labeler Contributions ====
 +
Next, we need to define custom labeling algorithms: one for generic resource labeling, one for movie instances, one for Casting nodes and one for cast role nodes. Download [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/ResourceLabeler.java|ResourceLabeler.java]], [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/MovieLabeler.java|MovieLabeler.java]], [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/CastingLabeler.java|CastingLabeler.java]] and [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/CastLabeler.java|CastLabeler.java]] and put them into the contributions package. Review the implementations at this point. They are highly trivial.
 +
* Open '''com.acme.movie.ui''' / '''META-INF/MANIFEST.MF''' >> '''Extensions'''
 +
* Add a new extension, ''org.simantics.browsing.ui.common.labelerBinding''
 +
* A node will appear, select it and set browseContext=<span style="color:blue">http://www.acme.com/Movie-1.0/Productions</span>
 +
* Select '''http://www.acme.com/Movie-1.0/Productions''' >> and add four implementations through right click '''New''' >> '''implementation'''. For the first implementation set attributes:
 +
** class = ''com.acme.movie.ui.browser.contributions.ResourceLabeler''
 +
** preference = 1
 +
* For the second implementation, set attributes:
 +
** class = ''com.acme.movie.ui.browser.contributions.MovieLabeler''
 +
** preference = 2
 +
* 3rd:
 +
** class = ''com.acme.movie.ui.browser.contributions.CastingLabeler''
 +
** preference = 2
 +
* 4th:
 +
** class = ''com.acme.movie.ui.browser.contributions.CastLabeler''
 +
** preference = 2
 +
 +
Now we have one custom labeler that will work for any Resource input and one that will be preferred over the Resource labeler for use with ''MO.Movie'' instances only.
 +
 +
==== Imager Contributions ====
 +
Next, we need to define custom imager algorithms: one for movie instances, one for Casting nodes and one for cast role nodes. Download [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/MovieImager.java|MovieImager.java]], [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/CastingImager.java|CastingImager.java]] and [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/CastImager.java|CastImager.java]] and put them into the contributions package. Review the implementations at this point. They are also highly trivial.
 +
* Open '''com.acme.movie.ui''' / '''META-INF/MANIFEST.MF''' >> '''Extensions'''
 +
* Add a new extension, ''org.simantics.browsing.ui.common.imagerBinding''
 +
* A node will appear, select it and set browseContext=<span style="color:blue">http://www.acme.com/Movie-1.0/Productions</span>
 +
* Select '''http://www.acme.com/Movie-1.0/Productions''' >> and add three implementations through right click '''New''' >> '''implementation'''. For the first implementation set attributes:
 +
** class = ''com.acme.movie.ui.browser.contributions.MovieImager''
 +
** preference = 1
 +
* For the second implementation, set attributes:
 +
** class = ''com.acme.movie.ui.browser.contributions.CastingImager''
 +
** preference = 1
 +
* 3rd:
 +
** class = ''com.acme.movie.ui.browser.contributions.CastImager''
 +
** preference = 1
 +
 +
=== Model Browser Summary ===
 +
 +
So far we've achieved two things: contributing contents and actions to the Productions browser. Here's a screenshot of what we have so far. Not much yet, but we're just getting started!
 +
 +
 +
[[Image:Productions-browser-content-1.png|frame|center|A screenshot of the current state of the application. The context menu can be used to create new movies and add dummy castings without roles or actors to movies.]]
 +
 +
== Step 2: Add Property Page for Model Browser ==
 +
 +
The goal in this step is to get the so-far-quite-useless '''Selection properties''' view to show a useful property editing UI every time a meaningful selection is made in the model browser.
 +
 +
For example recall that the ontology created in the previous tutorial steps is capable of stating for a movie:
 +
* title
 +
* director
 +
* producer
 +
* castings
 +
Minimally we want to edit the title of the movie from the property view. Director and producer should also be editable through properties, castings will be made editable through other means.
 +
 +
=== Provide an Empty Property Page ===
 +
 +
The '''Productions''' browser is responsible for contributing its own property page.
 +
 +
In this case we will make use of the platform's common tabbed property page that makes it possible to contribute '''selection processors'''. They are responsible for processing each incoming workbench selection and deciding which property tabs to contribute to the property page for a particular selection.
 +
 +
The simplest way to achieve this is to:
 +
* Find the production view extension: '''org.eclipse.ui.views''' >> '''Productions (view)'''
 +
* Modify the ''class'' attribute of our ''Productions'' view extensions to offer a common IPropertyPage implementation with specific browse contexts by appending the following argument:
 +
** ''';<span style="color:green">propertyBrowseContext</span>=<span style="color:blue">http://com.acme/Movie-1.0/Productions/Properties</span>'''
 +
 +
 +
{{tip|The property view is a generic view. It's contents follow the active workbench part, i.e. the active view or editor. When a view or editor is activated, the property view will notice this and request for the activated part to provide an ''IPropertyPage'' implementation through the Eclipse platform's ''IAdaptable'' interface.}}
 +
 +
=== Contribute a SelectionProcessor ===
 +
 +
The specified property browse context will now allow us to make '''SelectionProcessor''' contributions. SelectionProcessors can be bound to browse contexts in exactly the same manner as viewpoint, labeler, and all the other browsing framework contributions.
 +
 +
* Create a new java package: '''File''' >> '''New''' >> '''Package''': ''com.acme.movie.ui.property''
 +
* Add the following SelectionProcessor stub implementation to the created package. It will merely print each incoming selection it receives but serves as a good starting point.
 
<div style="background-color:#f8f8f8; border: 1px dashed #cccccc; padding: 1ex; margin-left:2em; margin-top: 1em; margin-bottom:1em;">
 
<div style="background-color:#f8f8f8; border: 1px dashed #cccccc; padding: 1ex; margin-left:2em; margin-top: 1em; margin-bottom:1em;">
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
package com.acme.movie.ui;
+
package com.acme.movie.ui.property;
  
 +
import java.util.Collection;
 
import java.util.Collections;
 
import java.util.Collections;
import java.util.Set;
 
 
import org.eclipse.ui.IWorkbenchPartSite;
 
import org.simantics.browsing.ui.swt.StandardPropertyPage;
 
  
public class ProductionsPropertyPage extends StandardPropertyPage {
+
import org.simantics.browsing.ui.SelectionProcessor;
 +
import org.simantics.databoard.util.ObjectUtils;
 +
import org.simantics.db.ReadGraph;
  
    public ProductionsPropertyPage(IWorkbenchPartSite site) {
+
public class ProductionBrowserSelectionProcessor implements SelectionProcessor<Object, ReadGraph> {
        super(site);
 
    }
 
  
 
     @Override
 
     @Override
     protected Set<String> getContexts() {
+
     public Collection<?> process(Object selection, ReadGraph backend) {
         return Collections.singleton("http://com.acme/Movie-1.0/Productions/Properties");
+
         System.out.println(getClass().getSimpleName() + " incoming selection: " + ObjectUtils.toString(selection));
 +
        return Collections.emptyList();
 
     }
 
     }
  
}
+
}</syntaxhighlight>
 +
</div>
 +
* Add a new '''org.simantics.browsing.ui.common.selectionProcessorBinding''' extension to the com.acme.movie.ui plug-in
 +
* Open context menu for '''org.simantics.browsing.ui.common.selectionProcessorBinding''', select '''New''' >> '''binding'''.
 +
* Select binding and set ''browseContext'' = ''http://www.acme.com/Movie-1.0/Productions/Properties".
 +
* All this should give you the following snippet in your plugin.xml:
 +
<div style="background-color:#f8f8f8; border: 1px dashed #cccccc; padding: 1ex; margin-left:2em; margin-top: 1em; margin-bottom:1em;">
 +
<syntaxhighlight lang="xml">
 +
  <extension
 +
        point="org.simantics.browsing.ui.common.selectionProcessorBinding">
 +
      <binding
 +
            browseContext="http://www.acme.com/Movie-1.0/Productions/Properties">
 +
        <implementation class="com.acme.movie.ui.property.ProductionBrowserSelectionProcessor" />
 +
      </binding>
 +
  </extension>
 
</syntaxhighlight>
 
</syntaxhighlight>
 
</div>
 
</div>
  
Now we modify the view extension to use this implementation.
+
Now, restart your movie application and test your selection processor by looking at what it prints to get a feeling for how the incoming data relates to what your viewpoint contributions provide. You should discover that the incoming data contains your viewpoint contributed data, only in a bit of wrapping. You should use <code>ISelectionUtils.getPossibleKeys/getSinglePossibleKey</code> to process the incoming data.
* Find the production view extension: '''org.eclipse.ui.views''' >> '''Productions (view)'''
+
 
* Append a new argument to the ''class'' attribute: '''&<span style="color:green">propertyPageClass</span>=<span style="color:blue">com.acme.movie.ui.ProductionsPropertyPage</span>'''
+
For more information on the common tabbed property page, see [[Org.simantics.browsing.ui_Manual#Tabbed_Selection_View|tabbed selection view manual]].
 +
 
 +
=== Add Basic Contributions for Properties View ===
 +
 
 +
Create a new package '''com.acme.movie.ui.property''' and download everything from [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/property|com.acme.movie.ui.property SVN]]. This will give us some basic implementations to get working on property tabs.
 +
 
 +
Replace your selection processor extension class with '''ProductionBrowserSelectionProcessor''' with '''ProductionBrowserSelectionProcessorFinal''' to give us some basic contributions for the Productions property pages.
 +
 
 +
Now you should be able to select movies and be able to edit the movie title, director and producer.
 +
 
 +
=== Adding functionality to property browsing ===
 +
 
 +
{{warning|'''TODO''':
 +
* Add editing possibility for '''MO.HasGender''' and '''MO.HasYearOfBirth''' for Persons
 +
* Guide for adding property tabs for editing movie casting instances
 +
}}
 +
 
 +
== Step 3: Add Content for Symbols View ==
  
=== Technical Details ===
+
{{warning|'''This step is still work-in-progress, sorry.'''
The property view is a generic view. It's contents follow the active workbench part, i.e. the active view or editor. When a view or editor is activated, the property view will see this and request for the activated part to provide an ''IPropertyPage'' implementation through the platform's ''IAdaptable'' interface.
 
  
== Step 4: Add Content for Movie Database Library ==
 
  
Things TODO:
+
Things to do:
 
* Implement the fixed set of ISymbolGroups for movies, actors and characters.
 
* Implement the fixed set of ISymbolGroups for movies, actors and characters.
 
* Add code to the project feature that contributes a fixed set of ISymbolGroups into the ISymbolManager.KEY_SYMBOL_GROUPS hint of IProject
 
* Add code to the project feature that contributes a fixed set of ISymbolGroups into the ISymbolManager.KEY_SYMBOL_GROUPS hint of IProject
* Add new symbol group interface for adding a filtered version of the symbol group getItems() method. This is needed for making the view such results are only shown if a search criterion is specified.
+
* Add new symbol group interface for adding a filtered version of the symbol group getItems() method. This is needed for making the view such results are only shown if a search criterion is specified.}}
 +
 
 +
== Step 4: Final Tweaking ==
 +
 
 +
Last we remove the comparator and viewpoint selector combo boxes and the filter area from the Productions browser since they are not needed for this tutorial. Once again the removal happens by adding the following arguments to the ''Productions'' view extension:
 +
* '''<span style="color:green">hideComparatorSelector</span>'''
 +
* '''<span style="color:green">hideViewpointSelector</span>'''
 +
* '''<span style="color:green">hideFilter</span>'''
 +
 
 +
=== Add Sorting for Productions Browser ===
 +
 
 +
You may have noticed so far that your movies appear in the Productions browser in seemingly random order. This happens because we have not defined any sorting algorithm for them. The following will add a simple alphanumeric sorter that provides somewhat natural sorting.
 +
 
 +
Download [[svn:tutorials/trunk/com.acme.movie.ui/src/com/acme/movie/ui/browser/contributions/AlphanumericSorter.java|AlphanumericSorter.java]], put it in '''com.acme.movie.ui.contributions''' and add an extension for it:
 +
* Add new extension in the MANIFEST.MF editor: '''org.simantics.browsing.ui.common.comparableContextBinding'''
 +
* Right-click the extension >> '''New''' >> '''binding''', set browseContext = '''http://www.acme.com/Movie-1.0/Productions'''
 +
* Right-click '''binding''' >> '''New''' >> '''implementation''', set:
 +
** class = '''com.acme.movie.ui.browser.contributions.AlphanumericSorter'''
 +
** preference = 1.0
 +
 
 +
Now your Productions browser will sort the everything in ascending alphanumeric order.
 +
 
  
 
<hr />
 
<hr />
[[file:handshake.png]] '''Congratulations''' You have now created the first parts of a functional UI.
+
{{handshake| '''Good Job''' You have now created the basic parts of a functional UI.}}
  
In the next part you will be developing a diagram editor. [[file:wink_16.png]]<br/>
+
In the next part you will be developing a diagram editor.<br/>
 
[[file:next.png]] [[Tutorial: Diagram Development|Tutorial 4: Diagram Development]]
 
[[file:next.png]] [[Tutorial: Diagram Development|Tutorial 4: Diagram Development]]
 +
 +
[[Category: Model Development]]
 +
[[Category: Tutorials]]

Latest revision as of 08:02, 21 June 2012

In this part of the tutorial we will focus on implementing the basic functionality for the following parts of the UI:

  • Model Browser for modelling movie production cases
    • Basic context menu actions for the browser
      • Add > Movie Project
      • Add > Role
  • Property Page for editing properties of model entities
  • Movie Database Library for searching available movies, actors, directors, etc.


Step 1: Model Browser

Dependencies

To get the model browser working, UI plugin needs some more plug-ins, add dependencies.

  • Open com.acme.movie.ui / META-INF/MANIFEST.MF >> Dependencies
  • In the Required Plug-ins section, add dependencies on
    • org.simantics.ui
    • org.simantics.browsing.ui.platform
    • org.simantics.layer0
    • com.acme.movie.ontology

Enable Browser Contributions

At this point, the browser is empty since there is neither data to be shown nor the contributions for producing the data to show.

Before going into the contributions themselves, we need to make our Productions browser capable of receiving contributions. This can be achieved by adding a browseContext argument for the view extension. A browseContext is simply any unique string identifier to which contributions are bound. The set of browseContexts used by the browser view will therefore define which contributions are used.

  • Open com.acme.movie.ui / META-INF/MANIFEST.MF >> Extensions
  • Find the Productions view extension: org.eclipse.ui.views >> Productions (view)
  • Append the following to the class attribute value:
    • :browseContext=http://www.acme.com/Movie-1.0/Productions
    • Note that the ':' character at the beginning is required - it is a separator between the class name and the rest of the parameter string. The rest of the string is interpreted as arguments. See the tip below for details.


Tip.png Arguments can be specified to extensions, such as views, through the class attribute of the extension. The general format of the class attribute is

<class name>:<arguments>

The arguments part of the attribute value is specified similarly to URI scheme query strings. Individual arguments are separated by semicolons (;) and specified either as plain strings or as key=value pairs.

The arguments supported by org.simantics.browsing.ui.platform.GraphExplorerView are:

browseContext=ID
For specifying browse contexts for the view. This will determine which contributions the view will use. 0 to many browse contexts may be defined. Not defining browse contexts will always result in zero contributions.
uiContext=ID
For specifying ID's of org.eclipse.ui.context extensions to be activated for the view. 0 to many UI contexts may be defined.
contextMenuId=ID
Specifies the ID of the context menu to register for this browser view. Only one ID can be specified, the last one specified is used.
hideComparatorSelector
Hides the comparator selector combo box from the UI.
hideViewpointSelector
Hides the viewpoint selector combo box from the UI.
hideFilter
Hides the filter control from the UI.
propertyBrowseContext=ID
Specified a browse context for the property page provided by this browser view. When the view is requsted for an IPropertyPage a new StandardPropertyPage will be created with all defined propertyBrowseContexts. If this implementation does not suit your needs, see propertyPageClass argument.
propertyPageClass=class-name
Defines the property page that will be created by the view when requested for it. The class-name must point to an IPropertyPage implementation.

Getting data to show - Adding new movies

In order to be able to see our contributions working we need to be able to create data in the browser. For this reason we take a little step to the side to add a context menu action for creating new movie projects into the active project.

Workbench context menus are contribution-based. Each context menu is given a unique ID and popup contributions are then bound to that ID. For the Productions view, we will select #ProductionsPopup as the menu ID.

First the context menu for the Productions browser needs to be registered with this ID. This can be achieved by once again modifying the class attribute of our view extension.

  • Find our production view extension: org.eclipse.ui.views >> Productions (view)
  • Append a new argument to the class attribute: ;contextMenuId=#ProductionsPopup

Now your browser should have a context menu registered with the specified ID. You can check this by launching the movie product, activating the Productions view and pressing Alt+Shift+F1. A Plug-in Spy window should pop up and give information on the view. It should say:

The active menu contribution identifiers:
    #ProductionsPopup

Add command extensions

The next thing to do is to add org.eclipse.ui.command extensions for each separate action to be performed.

  • Open the Extensions tab of our plug-in's plugin.xml editor. Add org.eclipse.ui.command extension plug-in: Add... >> org.eclipse.ui.command
  • Right-click org.eclipse.ui.command in the the extension tree, select New >> command, set attribute values:
    • id = com.acme.movie.ui.addMovie
    • name = Add Movie
    • defaultHandler="com.acme.movie.ui.browser.handlers.AddMovie"
  • Add another command with the attributes:
    • id = com.acme.movie.ui.addRole
    • name = Add Role
    • defaultHandler="com.acme.movie.ui.browser.handlers.AddRole"

This should give you the following things in the plugin.xml file whose contents can be seen from the plugin.xml tab of the editor.

<syntaxhighlight lang="java">

  <extension
        point="org.eclipse.ui.commands">
     <command
           defaultHandler="com.acme.movie.ui.browser.handlers.AddMovie"
           id="com.acme.movie.ui.addMovie"
           name="Add Movie">
     </command>
     <command
           defaultHandler="com.acme.movie.ui.browser.handlers.AddRole"
           id="com.acme.movie.ui.addRole"
           name="Add Role">
     </command>
  </extension>

</syntaxhighlight>

Add handler stub code

In the Extensions tab of the editor select the addMovie command extension. On the right panel, press defaultHandler label link to create the AddMovie class. In the New Java Class wizard that is presented, set Superclass to org.eclipse.core.commands.AbstractHandler and press Finish.

Do the same for the Add Role command.

Add menu extensions

The next thing to do is to add an org.eclipse.ui.menus extension to populate our #ProductionsPopup context menu.

  • Open the Extensions tab of our plug-in's plugin.xml editor. Add org.eclipse.ui.menus extension plug-in: Add... >> org.eclipse.ui.menus
  • Right-click org.eclipse.ui.menus in the the extension tree, select New >> menuContribution, set locationURI = popup:#ProductionsPopup

Next comes the actual menu population:

  • Right-click the newly created menuContribution, select New >> command, set id = com.acme.movie.ui.addMovie
  • Repeat the same for the com.acme.movie.ui.addRole command

Add code to create new movies

Open the handler classes previously created, AddMovie and AddRole.

To create a new movie we need to:

  • Create a new movie instance and add it to the project.
  • Set a fresh name for the new movie, in this case automatically without asking the user.

Download the handler code to do this (AddMovie.java) and replace the stub AddMovie class with it.

Check your work

So far we should have the same empty browser UI, except now you should be able to open a context menu from it that contains two actions: Add Movie and Add Role as shown in the figure

Productions browser after adding the first context menu actions.

Selecting the "Add Movie" action at this point will not produce visible results since we have not added any browser contributions to actually show the data. We'll go into this next.

Showing the data - Add browsing contributions

Now let's focus on adding some basic contributions for making data visible to the user.

There are several kinds of contributions that can to be added to make data visible in the browser. The most important contributions are viewpoints, i.e. the contributions that produce the contents for the browser tree. Take another look at the previous tutorial's UI sketch. We will need contributions for doing the following things in the browser:

  • Content production (∼ViewpointContribution):
    • Show all movie productions in the active project
    • Show a Casting node for a movie
    • Show all roles cast for a movie under the Casting node
  • Content labeling (∼LabelerContribution):
    • Movie: movie title or no title if title is not defined
      • Movie title with property relation MO.HasTitle
    • Casting: show fixed name Casting
    • Role: show
      • role name - no actor if no actor is specified for role
      • role name - actor name if an actor has been specified for role
  • Giving images for contents (∼ImagerContribution)
    • Movies: Film.png (download)
    • Casting: Casting.png (download)
    • Role: Role.png (download)
    • Create a new folder icons in your com.acme.movie.ui plug-in and download the images shown above into that directory.
    • Modify your Activator class code to match this version. This will allow us to use the images in the contributions to be created next.

Start by creating a new java package for the contributions:

  • Select File >> New >> Package
  • Specify package com.acme.movie.ui.browser.contributions

Viewpoint Contributions

The com.acme.movie.ui.browser.contributions.Movies contribution takes care of contributing all movie resources when given a Project resource as input. It will also contribute the movies in the previously created movie library ontology. Download the source and put it into the contributions package.

One more thing needs to be done in order to put the Movies contribution to use: define an extension for binding it to the browsing context of the Productions browser.

  • Open com.acme.movie.ui / META-INF/MANIFEST.MF >> Extensions
  • Add a new extension, org.simantics.browsing.ui.common.viewpointContributionBinding
  • A node will appear, select it and set browseContext=http://www.acme.com/Movie-1.0/Productions
  • Select http://www.acme.com/Movie-1.0/Productions >> right click New >> implementation. Select it and set the attributes:
    • class = com.acme.movie.ui.browser.contributions.Movies
    • preference = 1

Create another package com.acme.movie.ui.browser.nodes as before and download these files into that package: Casting node class, Cast Role class

Do the same, i.e. download and add extensions for the remaining two viewpoint contributors:

If you test your application now, the browser will not show any human readable labels for movie instances. This is because we have not contributed any logic that is able to label a movie. By default the system will only use Java Object.toString() for the label.

Labeler Contributions

Next, we need to define custom labeling algorithms: one for generic resource labeling, one for movie instances, one for Casting nodes and one for cast role nodes. Download ResourceLabeler.java, MovieLabeler.java, CastingLabeler.java and CastLabeler.java and put them into the contributions package. Review the implementations at this point. They are highly trivial.

  • Open com.acme.movie.ui / META-INF/MANIFEST.MF >> Extensions
  • Add a new extension, org.simantics.browsing.ui.common.labelerBinding
  • A node will appear, select it and set browseContext=http://www.acme.com/Movie-1.0/Productions
  • Select http://www.acme.com/Movie-1.0/Productions >> and add four implementations through right click New >> implementation. For the first implementation set attributes:
    • class = com.acme.movie.ui.browser.contributions.ResourceLabeler
    • preference = 1
  • For the second implementation, set attributes:
    • class = com.acme.movie.ui.browser.contributions.MovieLabeler
    • preference = 2
  • 3rd:
    • class = com.acme.movie.ui.browser.contributions.CastingLabeler
    • preference = 2
  • 4th:
    • class = com.acme.movie.ui.browser.contributions.CastLabeler
    • preference = 2

Now we have one custom labeler that will work for any Resource input and one that will be preferred over the Resource labeler for use with MO.Movie instances only.

Imager Contributions

Next, we need to define custom imager algorithms: one for movie instances, one for Casting nodes and one for cast role nodes. Download MovieImager.java, CastingImager.java and CastImager.java and put them into the contributions package. Review the implementations at this point. They are also highly trivial.

  • Open com.acme.movie.ui / META-INF/MANIFEST.MF >> Extensions
  • Add a new extension, org.simantics.browsing.ui.common.imagerBinding
  • A node will appear, select it and set browseContext=http://www.acme.com/Movie-1.0/Productions
  • Select http://www.acme.com/Movie-1.0/Productions >> and add three implementations through right click New >> implementation. For the first implementation set attributes:
    • class = com.acme.movie.ui.browser.contributions.MovieImager
    • preference = 1
  • For the second implementation, set attributes:
    • class = com.acme.movie.ui.browser.contributions.CastingImager
    • preference = 1
  • 3rd:
    • class = com.acme.movie.ui.browser.contributions.CastImager
    • preference = 1

Model Browser Summary

So far we've achieved two things: contributing contents and actions to the Productions browser. Here's a screenshot of what we have so far. Not much yet, but we're just getting started!


A screenshot of the current state of the application. The context menu can be used to create new movies and add dummy castings without roles or actors to movies.

Step 2: Add Property Page for Model Browser

The goal in this step is to get the so-far-quite-useless Selection properties view to show a useful property editing UI every time a meaningful selection is made in the model browser.

For example recall that the ontology created in the previous tutorial steps is capable of stating for a movie:

  • title
  • director
  • producer
  • castings

Minimally we want to edit the title of the movie from the property view. Director and producer should also be editable through properties, castings will be made editable through other means.

Provide an Empty Property Page

The Productions browser is responsible for contributing its own property page.

In this case we will make use of the platform's common tabbed property page that makes it possible to contribute selection processors. They are responsible for processing each incoming workbench selection and deciding which property tabs to contribute to the property page for a particular selection.

The simplest way to achieve this is to:

  • Find the production view extension: org.eclipse.ui.views >> Productions (view)
  • Modify the class attribute of our Productions view extensions to offer a common IPropertyPage implementation with specific browse contexts by appending the following argument:


Tip.png The property view is a generic view. It's contents follow the active workbench part, i.e. the active view or editor. When a view or editor is activated, the property view will notice this and request for the activated part to provide an IPropertyPage implementation through the Eclipse platform's IAdaptable interface.

Contribute a SelectionProcessor

The specified property browse context will now allow us to make SelectionProcessor contributions. SelectionProcessors can be bound to browse contexts in exactly the same manner as viewpoint, labeler, and all the other browsing framework contributions.

  • Create a new java package: File >> New >> Package: com.acme.movie.ui.property
  • Add the following SelectionProcessor stub implementation to the created package. It will merely print each incoming selection it receives but serves as a good starting point.

<syntaxhighlight lang="java"> package com.acme.movie.ui.property;

import java.util.Collection; import java.util.Collections;

import org.simantics.browsing.ui.SelectionProcessor; import org.simantics.databoard.util.ObjectUtils; import org.simantics.db.ReadGraph;

public class ProductionBrowserSelectionProcessor implements SelectionProcessor<Object, ReadGraph> {

   @Override
   public Collection<?> process(Object selection, ReadGraph backend) {
       System.out.println(getClass().getSimpleName() + " incoming selection: " + ObjectUtils.toString(selection));
       return Collections.emptyList();
   }

}</syntaxhighlight>

  • Add a new org.simantics.browsing.ui.common.selectionProcessorBinding extension to the com.acme.movie.ui plug-in
  • Open context menu for org.simantics.browsing.ui.common.selectionProcessorBinding, select New >> binding.
  • Select binding and set browseContext = http://www.acme.com/Movie-1.0/Productions/Properties".
  • All this should give you the following snippet in your plugin.xml:

<syntaxhighlight lang="xml">

  <extension
        point="org.simantics.browsing.ui.common.selectionProcessorBinding">
     <binding
           browseContext="http://www.acme.com/Movie-1.0/Productions/Properties">
        <implementation class="com.acme.movie.ui.property.ProductionBrowserSelectionProcessor" />
     </binding>
  </extension>

</syntaxhighlight>

Now, restart your movie application and test your selection processor by looking at what it prints to get a feeling for how the incoming data relates to what your viewpoint contributions provide. You should discover that the incoming data contains your viewpoint contributed data, only in a bit of wrapping. You should use ISelectionUtils.getPossibleKeys/getSinglePossibleKey to process the incoming data.

For more information on the common tabbed property page, see tabbed selection view manual.

Add Basic Contributions for Properties View

Create a new package com.acme.movie.ui.property and download everything from com.acme.movie.ui.property SVN. This will give us some basic implementations to get working on property tabs.

Replace your selection processor extension class with ProductionBrowserSelectionProcessor with ProductionBrowserSelectionProcessorFinal to give us some basic contributions for the Productions property pages.

Now you should be able to select movies and be able to edit the movie title, director and producer.

Adding functionality to property browsing

Warning.png TODO:
  • Add editing possibility for MO.HasGender and MO.HasYearOfBirth for Persons
  • Guide for adding property tabs for editing movie casting instances

Step 3: Add Content for Symbols View

Warning.png This step is still work-in-progress, sorry.


Things to do:

  • Implement the fixed set of ISymbolGroups for movies, actors and characters.
  • Add code to the project feature that contributes a fixed set of ISymbolGroups into the ISymbolManager.KEY_SYMBOL_GROUPS hint of IProject
  • Add new symbol group interface for adding a filtered version of the symbol group getItems() method. This is needed for making the view such results are only shown if a search criterion is specified.

Step 4: Final Tweaking

Last we remove the comparator and viewpoint selector combo boxes and the filter area from the Productions browser since they are not needed for this tutorial. Once again the removal happens by adding the following arguments to the Productions view extension:

  • hideComparatorSelector
  • hideViewpointSelector
  • hideFilter

Add Sorting for Productions Browser

You may have noticed so far that your movies appear in the Productions browser in seemingly random order. This happens because we have not defined any sorting algorithm for them. The following will add a simple alphanumeric sorter that provides somewhat natural sorting.

Download AlphanumericSorter.java, put it in com.acme.movie.ui.contributions and add an extension for it:

  • Add new extension in the MANIFEST.MF editor: org.simantics.browsing.ui.common.comparableContextBinding
  • Right-click the extension >> New >> binding, set browseContext = http://www.acme.com/Movie-1.0/Productions
  • Right-click binding >> New >> implementation, set:
    • class = com.acme.movie.ui.browser.contributions.AlphanumericSorter
    • preference = 1.0

Now your Productions browser will sort the everything in ascending alphanumeric order.



Handshake.png Good Job You have now created the basic parts of a functional UI.

In the next part you will be developing a diagram editor.
Next.png Tutorial 4: Diagram Development