blob: 30de9d3755bd8b3d539c2173896c90cd74288e25 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="The website of Eclipse EMF Parsley, an open-source framework for development User Interfaces upon EMF models">
<meta name="author" content="Francesco Guidieri, Paolo Bachini">
<link rel="icon" href="/favicon.ico">
<title>EMF Parsley - Play with your UI and EMF!</title>
<link rel="SHORTCUT ICON" href="img/logo_nw.gif" />
<!-- styles -->
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/main.css" rel="stylesheet">
<!-- Animate CSS -->
<link href="css/animate.css" rel="stylesheet">
<!--[if lt IE 9]>
<link href="css/iebugs.css" rel="stylesheet" type='text/css'>
<![endif]-->
<!-- Custom styles for this template -->
<link href="carousel.css" rel="stylesheet">
<!-- Bootstrap Lightbox -->
<link href="bootstrap-lightbox/bootstrap-lightbox.min.css" rel="stylesheet">
<!--<script src="js/twitter.js" type="text/javascript"></script>-->
<!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<script src="assets/js/ie-emulation-modes-warning.js"></script>
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<script src="assets/js/ie10-viewport-bug-workaround.js"></script>
<!-- Run Prettify -->
<script src="prettify/run_prettify.js"></script>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-58549052-1', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>
<!-- ====== NAVBAR ====== -->
<body style="overflow-y: scroll; padding-top:185px;">
<div class="navbar-fixed-top" style="background:url(img/bg-100x100.jpg)">
<div class="container" style="width:1150px;">
<div class="navbar-header">
<a href="index.html"><img class="img-responsive" alt="" src="img/logo.gif"/></a>
</div>
</div>
<nav class="navbar navbar-default" role="navigation" style="background-color:transparent; border:0 none; margin:-31px 0px 3px 0px;min-height: 36px;">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" style="margin-bottom:2px;">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav pull-right mioli">
<li><a href="support.html">Contact Us</a></li>
<li><a href="http://www.eclipse.org">Eclipse.org</a></li>
<li style="border-right: 0 none;"><a target="_blank" href="https://twitter.com/EmfParsley" id="twitterli"><img style="width:25px;float:left;margin-top: 5px; margin-right:1px;" alt="" src="img/twitter.png"/>@EmfParsley</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div>
</nav>
<div style="background:url(img/bg1-100x100.jpg);">
<nav class="navbar navbar-default miomenubar" role="navigation" style="border-radius:0px; background: url('img/menu.jpg') no-repeat; border: 0 none; -webkit-box-shadow: 0px 3px 8px 0px rgba(171,209,173,1);-moz-box-shadow: 0px 3px 8px 0px rgba(171,209,173,1);box-shadow: 0px 3px 8px 0px rgba(171,209,173,1);margin-bottom:0;">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-2">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-2">
<ul class="nav navbar-nav pull-left miomenu">
<li><a href="index.html">Home</a></li>
<li><a href="download.html">Download</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="sources.html">Sources</a></li>
<li><a href="support.html">Support</a></li>
<li><a href="userReviews.html">UserReviews</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div>
</nav>
</div>
</div>
<!-- NAVBAR End -->
<!-- Marketing messaging and featurettes
================================================== -->
<!-- Wrap the rest of the page in another container to center all the content. -->
<style>
.row {
-webkit-animation: fadeInRightBig 1.5s;
-moz-animation: fadeInRightBig 1.5s;
-ms-animation: fadeInRightBig 1.5s;
-o-animation: fadeInRightBig 1.5s;
animation: fadeInRightBig 1.5s;
}
.dropdown-menu {
-webkit-animation: fadeInDownBig 1.5s;
-moz-animation: fadeInDownBig 1.5s;
-ms-animation: fadeInDownBig 1.5s;
-o-animation: fadeInDownBig 1.5s;
animation: fadeInDownBig 1.5s;
}
.scrollup {
background: url(img/up.png) no-repeat scroll 0 0 rgba(0, 0, 0, 0);
bottom: 6%;
display: none;
opacity: 0.35; /* modifica anche in mouseout */
position: fixed;
right: 4%;
z-index: 900;
width: 45px;
height: 45px;
}
</style>
<div class="containerdoc marketing">
<!-- SIDEBAR -->
<div style="position: fixed;" class="col-md-2">
<ul class="dropdown-menu" style="margin: 0px; max-width: 250px; display: block;box-shadow: 0 0px 7px rgba(0,0,0,.175);">
<li class="activemenu" ><a tabindex="-1" href="#par">Overview</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Parsley Components</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#par">First Example</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#par">Components</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Form Component</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Tree Component</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Tree Form Component</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Table Component</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Tree With Columns Component</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#par">Customizations</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Dependency Injection With</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Google Guice</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Providers</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Contextual Menu</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Drag and Drop</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Factories</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Editing Domain</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Resources</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Configurator</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Validation</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#par">Advanced Features</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Testing Framework</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Eclipse 4.x</a></li>
<li><a class="submenu" tabindex="-1" href="#par">RAP</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#par">Migration Guide</a></li>
<li><a class="submenu" tabindex="-1" href="#par">From 0.6.0 to 0.7.0</a></li>
<li><a class="submenu" tabindex="-1" href="#par">From 0.5.0 to 0.6.0</a></li>
<li><a class="submenu" tabindex="-1" href="#par">From 0.4 to 0.5</a></li>
<li><a class="submenu" tabindex="-1" href="#par">From 0.3 to 0.4</a></li>
<li class="divider"></li>
</ul>
</div>
<!-- START THE FEATURETTES -->
</br>
<!-- scrollup ICON -->
<a class="scrollup" href="#top"></a>
<!-- scrollup ICON -->
<div class="row featurette">
<div class="col-md-8 col-md-offset-3">
<h1 id="par" class="featurette-heading text-parsley">Overview</h1>
<p>
<strong>EMF Parsley</strong> is a lightweight framework that allows easy and quick UI development based
upon EMF. <strong>EMF Parsley</strong> is built on top of the EMF Edit framework and it implements features like Trees, Forms and Table builders with
standard JFace databinding, providing a complete component-based toolset.
EMF Parsley can be configured to use all kinds of EMF persistence
implementations (XMI, Teneo, CDO)
Moreover a DSL allows to easily customize several behaviors in each component.
</p>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Parsley Components</h2>
<p>
<strong>EMF Parsley</strong> aims to provide a complete set of components to visualize your model with the introspective EMF capabilities
and can be used to easily build forms, viewers or editors.
</p>
<p>
There are some components that can be used out-of-the-box and can be considered as a reference implementation
of the mechanisms that are the basis of <strong>EMF Parsley</strong> itslef.
</p>
<p>
</p>
<ul>
<li><strong>Trees</strong></li>
<li><strong>Forms</strong></li>
<li><strong>Tables</strong></li>
<li><strong>Editors</strong></li>
<li><strong>Search boxes</strong> (coming soon)</li>
</ul>
<p>
</p>
<p>
</p>
<img src="images/01-components.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Customize<a id="Customize"></a></h3>
<p>
The main feature of <strong>EMF Parsley</strong> is that you can customize all basic UI behaviours of the components with <strong>Dependency Injection</strong>
mechanisms (based on <a href="https://github.com/google/guice">Google Guice</a>).
You can get more info in the <a href="#addref" rel="Customizations">Customizations Section</a>, but you don't have to know all details
about the internal implementation to inject your own customization because
<strong>EMF Parsley</strong> provides a DSL to easy customize your UI, as explained in the next section.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Customize with the DSL<a id="Customizations_DSL"></a></h3>
<p>
You can use the DSL by creating a new project with the wizard "Create a new project" -&gt; "EMF Parsley DSL Based project"
</p>
<p>
</p>
<img src="images/01-new-project-dsl-wizard.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
Clicking the "Finish" button the wizard will open directly the DSL editor. You can use the content assistant
to discover all features.
</p>
<p>
</p>
<img src="images/01-dsl-content-assistant.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
The DSL allows to customize the most relevant behaviors. Here we list only a few of them:
</p>
<p>
</p>
<ul>
<li><strong>parts</strong> lets you define your View Parts: this will correspond to the standard Eclipse extension
points for the parts (see <a href="#PluginXml">How the DSL handles the plugin.xml</a>)</li>
<li><strong>bindings</strong> section lets you define which implementation will be used with Injection</li>
<li><strong>menu</strong> section lets you define the contextual menu for all viewers (<strong>trees</strong> and <strong>tables</strong>)</li>
<li><strong>features provider</strong> is used to retrieve the list of feature for a given EClass to build <strong>tables</strong>
and <strong>forms</strong></li>
<li><strong>viewer content provider</strong> mediates between the viewer's model and the viewer, to provide the
contents to be shown</li>
<li><strong>Label Provider</strong> is used to retrieve the image and text rapresentation of the objects of a
tree viewer</li>
<li><strong>Caption Provider</strong> provides captions for each feature (namely, EStructuredFeature) of the object shown in a form,
in a dialog or in a table row.
Different implementations can be defined for <strong>dialogs</strong>, <strong>forms</strong> and <strong>tables</strong>.</li>
<li><strong>Control Factory</strong> provides a custom implementation of the Controls for each feature shown in a form or a dialog.
Different implementations can be defined forfor <strong>dialogs</strong> and <strong>forms</strong></li>
</ul>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">The structure of an EMF Parsley project<a id="DslProjectStructure"></a></h3>
<p>
An EMF Parsley project, as created by the wizard, is an Eclipse plug-in project with a few
additional builders.
</p>
<p>
The <strong>emfparsley-gen</strong> source folder will contain all the Java files generated by the DSL
compiler. The contents of this folder should never be modified manually, since their contents
will be overwritten by the DSL compiler.
</p>
<p>
The <strong>src</strong> source folder will contain an <abbr title="org.eclipse.ui.plugin.AbstractUIPlugin">AbstractUIPlugin</abbr>
generated
by the wizard. This is generated only during the creation of the project and it can be safely modified
if you need to put other mechanisms in the activator.
</p>
<p>
IMPORTANT: it is crucial that the activator has the static method <strong>getDefault</strong>, so you must not remove
that method.
</p>
<p>
If you choose one of the templates provided by the wizard, the <strong>src</strong> folder will also contain
a Java class for the view, which extends the corresponding view of Parsley. This can be safely modified
if you need to add some additional mechanisms or contents to the view.
</p>
<p>
You can then create additional <strong>.parsley</strong> files in the same project.
</p>
</br>
<h3 class="featurette-heading text-parsley2">How the DSL handles the plugin.xml<a id="PluginXml"></a></h3>
<p>
If you specify any <strong>part</strong> in the DSL file, then
the Parsley DSL will generate a <strong>plugin.xml_emfparsley_gen</strong> in the <strong>emfparsley-gen</strong> folder,
in a directory named after the containing module. Then, the <strong>EMF Parsley builder</strong> will take
care of merging the generated content with the <strong>plugin.xml</strong> in the root folder of the current project.
If the <strong>plugin.xml</strong> does not exist it will create it. Subsequent changes to the DSL file
will regenerate <strong>plugin.xml_emfparsley_gen</strong> and the builder will merge it with <strong>plugin.xml</strong>.
The merging will overwrite in the <strong>plugin.xml</strong> only the elements that are specified in the DSL.
Any other elements in the <strong>plugin.xml</strong> will not be touched, so you can also add other extension points
manually in the <strong>plugin.xml</strong>.
</p>
<p>
This merging takes place ONLY if your project has the <strong>EMF Parsley builder nature</strong>.
Since version 0.6.1 this nature is automatically applied to the projects created with our wizard.
In existing projects, you have to enable the nature yourself by right-clicking on the project,
then "Configure" and then "Enable EMF Parsley builder.
</p>
<p>
Note that this merging will not consider possible removed <strong>part</strong> sections in the DSL file.
The merging relies on the <strong>id</strong>, so if you change the <strong>id</strong>, e.g., the <strong>viewid</strong>, in the DSL file, then you will end up
with two extension points in the <strong>plugin.xml</strong>. Thus, in general, if you removed a <strong>part</strong> section from
the DSL file, or if you rename an <strong>id</strong> in a <strong>part</strong> section, please make sure you manually modify
the <strong>plugin.xml</strong> accordingly. The easiest way is to select to the files,
and use the context menu "Compare With" =&gt; "Each Other". This way, you will soon detect the
changes that have to be manually applied.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Obtaining the Injector<a id="InjectorProvider"></a></h3>
<p>
Since we also generate the <strong>plugin.xml</strong> starting from the DSL file, we already make sure that the
views will be created via Google Guice injection mechanisms, using a generated
<strong>executable extension factory</strong>.
</p>
<p>
If you need to obtain an injector corresponding to a specific DSL file, you can use the
corresponding generated class <strong>injector provider</strong>. This is prefixed with the name of the module
(first letter capitalized). For example, given this DSL module
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
module org.eclipse.emf.parsley.examples.firstexample {
...
}
</pre>
<p>
</p>
<p>
The Java class for the injector provider will be <strong>org.eclipse.emf.parsley.examples.firstexample.FirstexampleInjectorProvider</strong>.
</p>
<p>
These injector providers have a static method <strong>getInjector()</strong> that will return the <strong>singleton</strong> injector
corresponding to that module:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
Injector injector = FirstexampleInjectorProvider.getInjector();
</pre>
<p>
</p>
<p>
The returned injector is <strong>singleton</strong> in the sense that it is the same injector used
to create instances of the view parts specified as extension points in the <strong>plugin.xml</strong>.
</p>
<p>
Obtaining the injector this way is useful, for example, when you develop a pure e4 application,
where you do not define views in the <strong>plugin.xml</strong>. See <a href="#addref" rel="Eclipse 4.x">Eclipse 4.x</a>.
</p>
</div>
</div>
</div>
<hr style="width:64.6%;margin-bottom:28px;margin-top:30px;" class="col-md-8 col-md-offset-3">
<div class="row featurette">
<div class="col-md-8 col-md-offset-3">
<h1 id="par" class="featurette-heading text-parsley">First Example</h1>
<p>
The purpose of this first example is to make use of the classical EMF Library Model example and
create a view for editing such models using an EMF Parsley enabled plug-in. We will use
one of the saveable views shipped with Parsley: a Tree Form View.
</p>
<p>
So let's start by creating the model plug-in with
</p>
<p>
</p>
<ol>
<li>File -&gt; New... -&gt; Example...</li>
<li>from Category "Eclipse Modeling Framework", select "Extended Library Model Example"</li>
<li>press Next and Finish</li>
</ol>
<p>
</p>
<p>
You will end up with three plug-ins:
</p>
<p>
</p>
<ul>
<li>org.eclipse.emf.examples.library (the model plug-in)</li>
<li>org.eclipse.emf.examples.library.edit (the edit plug-in)</li>
<li>org.eclipse.emf.examples.library.editor (the editor plug-in)</li>
</ul>
<p>
</p>
<p>
The editor plug-in project can be removed.
</p>
<p>
Please consider that here we are starting from this well known EMF model taken out-of-the-box from Eclipse,
but you can start from your EMF model (in that case you may probably omit the ".edit" and ".editor" plugins, depending on your model).
</p>
<p>
Now you can create your first example with the appropriate wizard.
</p>
<p>
</p>
<ol>
<li>select "File" -&gt; "New" -&gt; "Project..."</li>
<li>from the "Emf Parsley" category select "Emf Parsley Dsl based Project"
<img src="images/01-new-project-dsl-wizard.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;"></li>
<li>click "Next"</li>
<li>give a name to the project (e.g. "org.eclipse.emf.parsley.examples.firstexample")
and make sure the checkbox about using one of the templates is checked
<img src="images/01-new-project-dsl-wizard2.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;"></li>
<li>click "Next"</li>
<li>Select "Saveable Tree Form View"
<img src="images/01-new-project-dsl-wizard3.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;"></li>
<li>click "Finish"</li>
</ol>
<p>
The generated project has some classes and a <strong>module.parlsey</strong> file, which opens automatically:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
import org.eclipse.emf.parsley.examples.firstexample.FirstexampleSaveableTreeFormView
/* org.eclipse.emf.parsley.examples.firstexample Emf Parsley Dsl Module file */
module org.eclipse.emf.parsley.examples.firstexample {
parts {
viewpart org.eclipse.emf.parsley.examples.firstexample {
viewname "Firstexample"
viewclass FirstexampleSaveableTreeFormView
}
}
configurator {
resourceURI {
FirstexampleSaveableTreeFormView -&gt; {
// TODO create and return a org.eclipse.emf.common.util.URI
return null;
}
}
}
resourceManager {
initializeResource {
// Optional: initialize an empty Resource
// 'it' is of type Resource
// e.g., it.getContents += myFactory.createMyClass
}
}
}
</pre>
<p>
</p>
<p>
The <strong>viewpart</strong> corresponds to the standard Eclipse view part extension point; the Parsley
DSL will handle the generation and update of the <strong>plugin.xml</strong> file.
Please have a look at <a href="#PluginXml">How the DSL handles the plugin.xml</a> for further
details.
</p>
<p>
The wizard will also generate a view part class into the project
(in this example, <strong>FirstexampleSaveableTreeFormView</strong>); you can add other controls
into that view, or customize other behaviors. Note that the Parsley DSL will never
touch the files into the <strong>src</strong> source folder. On the contrary, files generated into
<strong>emfparsley-gen</strong> source folder must never be manually modified, since its contents will
be regenerated each time you modify the <strong>module.parsley</strong> file.
</p>
<p>
For example, let's change the view name into "My Library Tree Form":
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
module org.eclipse.emf.parsley.examples.firstexample {
parts {
viewpart org.eclipse.emf.parsley.examples.firstexample {
viewname "My Library Tree Form"
...
</pre>
<p>
</p>
<p>
Let's save the file, wait for Eclipse to rebuild, and update the
<strong>plugin.xml</strong> with the new <strong>plugin.xml_emfparsley_gen</strong>.
</p>
<p>
(Other <strong>viewpart</strong> sections can be created; content assist is available for that).
</p>
<p>
In the generated <strong>module.parsley</strong>, there is a <strong>configurator</strong> section, with
a <strong>TODO</strong> comment (The <strong>Configurator</strong> is detailed in the section <a href="#addref" rel="Configurator">Configurator</a>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
configurator {
resourceURI {
FirstexampleSaveableTreeFormView -&gt; {
// TODO create and return a org.eclipse.emf.common.util.URI
return null;
}
}
}
</pre>
<p>
</p>
<p>
Let's focus on the above <strong>resourceURI</strong>: our goal is allowing to manage
a library model instance which persists on a EMF <abbr title="org.eclipse.emf.ecore.resource.Resource">Resource</abbr>
.
So we must specify the <abbr title="org.eclipse.emf.common.util.URI">URI</abbr>
of the resource
that will be edited by our tree form view.
In this example we choose to use the EMF default persistence (XMI), but you can provide any URI
(e.g. using Teneo, CDO or any other EMF Resource Persistence implementation)
In particular here we choose to persist the Resource in a XMI file named <strong>"MyLibrary.library"</strong>
into the user home folder (you might want to change it with any other path).
To achieve this, we just need to create such a URI (recall that content assist is available
when typing Xbase expressions):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
configurator {
resourceURI {
FirstexampleSaveableTreeFormView -&gt; {
return URI.createFileURI( System.getProperty("user.home") + "/MyLibrary.library" );
}
}
}
</pre>
<p>
</p>
<p>
If you simply copy and paste the above return statement, you'll get an error about
unresolvable Java type URI; "Organize Imports" context menu (or its shortcut "Ctrl+Shift+O")
can be used to automatically add the missing import (make sure you select
<abbr title="org.eclipse.emf.common.util.URI">URI</abbr>
).
</p>
<p>
Note that the specified URI, will be used for loading the resource only for our specific
view (the resource will be automatically created if it does not exist).
</p>
<p>
In the <strong>module.parsley</strong> there is another section that has been generated by the wizard:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
resourceManager {
initializeResource {
// Optional: initialize an empty Resource
// 'it' is of type Resource
// e.g., it.getContents += myFactory.createMyClass
}
}
</pre>
<p>
</p>
<p>
We can use this section to initialize our resource when it is empty
(i.e., the first time the resource is created); (The <strong>resourceManager</strong>
is detailed in section <a href="#ResourceManager">Resource Manager</a>).
</p>
<p>
In this example, we want to initialize an empty resource with a
<strong>Library</strong> object; so
we first need a <strong>Dependency</strong> from the model plug-in: so open <strong>MANIFEST.MF</strong> file, go to <strong>Dependencies</strong>
tab, press <strong>"Add..."</strong> button in <strong>"Required Plug-ins"</strong> section and insert <strong>"org.eclipse.emf.examples.library"</strong>
among dependencies.
</p>
<p>
Now we can implement the <strong>initializeResource</strong> method
(as described in the comment, the <abbr title="org.eclipse.emf.ecore.resource.Resource">Resource</abbr>
to initialized is available through the parameter <strong>it</strong>); the Library object
is created using the standard EMF API: we need the factory of the library model:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
resourceManager {
initializeResource {
it.getContents += EXTLibraryFactory.eINSTANCE.createLibrary
}
}
</pre>
<p>
</p>
<p>
Again, use the content assist while typing, e.g., for automatically importing the
type <strong>EXTLibraryFactory</strong>, or use the "Organize Imports" functionality.
</p>
<p>
Now, we are ready to execute this example:
let's get back to the <strong>MANIFEST.MF</strong> and run the example
</p>
<p>
</p>
<img src="images/first-example-launch.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
As an Eclipse RCP developer you know, of course, that this will start another Eclipse instance (unless
you add an Application plug-in to the launch or define an Application in the current plug-in).
</p>
<p>
In this second Eclipse instance you can show the View in this way:
</p>
<ol>
<li><strong>Window -&gt; Show View -&gt; Other...</strong></li>
<li>from Category "Other", select "My Library Tree Form"</li>
<li>press <strong>OK</strong></li>
</ol>
<p>
</p>
<p>
</p>
<img src="images/first-example-run.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
With this simple view you can start editing the model instance. For example you can set the <strong>"name"</strong>
field; as soon as you start typing characters into this field you will notice that:
</p>
<ol>
<li>the View turns to a <strong>"dirty"</strong> state (an asterisk symbol appears on the view tab)</li>
<li>the <strong>"Save"</strong> toolbar button is enabled</li>
<li>the typed characters are reflected into the label correspondent to the Library icon</li>
</ol>
<p>
</p>
<p>
if you now perform a <strong>"Save"</strong> action the persistence mechanism will trigger and you will see that file
</p>
&lt;user.home&gt;/MyLibrary.library
<p>
is being created on the file system. From now on, this file will keep the state of the model object whenever
you change and save it.
</p>
<p>
To create a Writer into the Library just right-click on the Library object and select <strong>New Child -&gt; Writer</strong>
</p>
<p>
</p>
<img src="images/createWriter.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
Please note that you might see a slightly different content in the above context-menu in case you deleted
the .edit plugin when creating the model (e.g. <strong>"Writers Writer"</strong> instead of <strong>"Writer"</strong>, <strong>"Stock Book"</strong> instead of <strong>"Book"</strong> and
similar (this is because with EMF it is possible to customize labels also via .edit plugin).
</p>
<p>
Now set for instance the writer <strong>"name"</strong> field and save.
Now just play around creating Books, associating them to Writers and so on.
As you can see you can entirely manage the EMF model instance: creating, modifying and deleting elements.
</p>
<p>
Whenever the current selection on the upper side of the view changes, then the lower side shows the detail
of this selection.
</p>
<p>
</p>
<img src="images/first-example-default.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
However, up to this point, you have no control over the field to be shown and its order; for example
you may want just the <strong>"name"</strong> attribute for the Library and <strong>"name", "address" and "books"</strong> attributes
for Writers and maybe <strong>"title", "authors" and "category"</strong> for Books.
</p>
<p>
Well, it's indeed very easy to obtain this: just edit the <strong>module.parsley</strong> file,
adding the following import (without ending line with ";")
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
import org.eclipse.emf.examples.extlibrary.*
</pre>
<p>
</p>
<p>
and then defining the features to show (the <strong>featuresProvider</strong> is detailed
in section <a href="#FeaturesProvider">Features Provider</a>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
module ... {
...
featuresProvider {
features {
Library -&gt; name
Writer -&gt; name, address, books
Book -&gt; author, title, category
}
}
}
</pre>
<p>
</p>
<p>
Remeber that code completion is available, just exploit it since it helps a lot.
</p>
<p>
If you restart now the application you will see that, when selecting an object, only the features
specified in the above section will be shown for each specified classes.
Furthermore, they are shown in the specified order.
</p>
<p>
NOTE: Did you run the application in Debug mode? Well, then you can change fields and order, save and see the
changes without even restarting the application.
</p>
<p>
Do you want to change text used for attribute captions in the form for a specific
class? Just add the following
(<strong>featureCaptionProvider</strong> is detailed in section <a href="#FeatureCaptionProvider">Feature Caption Provider</a>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
featureCaptionProvider {
text {
Book : author -&gt; "Written by:"
Writer : name -&gt; "Name:"
}
}
</pre>
<p>
</p>
<p>
Or do you want to change the label shown on the tree nodes on the upper side and as detail title?
Maybe want to format the book label like this?
(<strong>labelProvider</strong> is detailed in section <a href="#ViewerLabelProvider">Viewer Label Provider</a>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
labelProvider {
text {
Book b -&gt; { '"' + b.title + '"' }
Writer w -&gt; { w.name }
}
}
</pre>
<p>
</p>
<p>
The result of all the above customizations is shown in the following screenshot
(compare it with the previous screenshot):
</p>
<p>
</p>
<img src="images/first-example-customized.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
Now, let's customize the context menus; by default,
Parsley will generate context menus using EMF.Edit:
</p>
<p>
</p>
<img src="images/first-example-default-menus.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
We will now customize the context menu for books and writers, using
the <strong>menuBuilder</strong> in the DSL (context menu customization is detailed
in section <a href="#addref" rel="Contextual Menu">Contextual Menu</a>).
</p>
<p>
What we want to achieve is to have a context menu for a <strong>Writer</strong>
to add a new book in the library, and set its author to the
selected writer (similarly, we want a context menu for a <strong>Book</strong>
to add a new writer in the library, and set the selected book as
one of the new writer's books):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
menuBuilder {
val factory = EXTLibraryFactory.eINSTANCE
emfMenus {
Writer w -&gt; #[
actionChange("New book", w.eContainer as Library,
[
library |
val book = factory.createBook
library.books += book
book.title = "A new book"
book.author = w
]
),
]
Book b -&gt; #[
actionChange("New writer", b.eContainer as Library,
[
library |
val writer = factory.createWriter
library.writers += writer
writer.name = "A new writer"
writer.books += b
]
)
]
}
}
</pre>
<p>
</p>
<p>
In this code we use Xbase features like list literals (<strong>#[...]</strong>) and
lambda expressions.
We use <strong>actionChange</strong> that allows to specify a menu performing some actions
on the model's elements, keeping track of such changes so that they can be
undone -- redo will work as well. The implementation of the menu is specified
in the lambda expression passed as the last argument of actionChange; this lambda
will receive as argument the model's element specified as the second argument.
Only those modifications performed in the lambda concerning such specified model's element
will be recorded for undo/redo.
</p>
<p>
If you now restart the application, you see that the new
context menu appears on writer elements:
</p>
<p>
</p>
<img src="images/first-example-custom-menus1.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
And selecting such a menu on a writer will add a new book, with
a title, and whose author is the selected writer:
</p>
<p>
</p>
<img src="images/first-example-custom-menus2.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
You may want to try the new context menu on a book as well.
</p>
<p>
We also add another context menu for books, using <strong>actionAdd</strong>:
specifying the label for the menu,
the containment list in the model, the object to add in such list
and a lambda expression that will be executed ONLY after the menu
has been selected. In this example, this menu available for
a book object will add a new book to the library with the same
name of the selected book:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
menuBuilder {
val factory = EXTLibraryFactory.eINSTANCE
emfMenus {
// ... as above
Book b -&gt; #[
actionChange(
// ... as above
),
actionAdd("New book (same title)",
(b.eContainer as Library).books,
factory.createBook,
[title = b.title]
)
]
}
}
</pre>
<p>
</p>
<p>
Now, let's customize the contents shown in the tree view: by default,
as you can see from the previous screenshots, the tree will show all
the contents of the library. If we want to show only the writers and
the books we can specify this section in the DSL
(the customization of the content provider is detailed in
section <a href="#ViewerContentProvider">Viewer Content Provider</a>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
viewerContentProvider {
children {
Library -&gt; {
writers + books
}
}
}
</pre>
<p>
</p>
<p>
and the result can be seen in the following screenshot:
</p>
<p>
</p>
<img src="images/first-example-custom-contents1.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
By default, double-clicking on a tree viewer of a saveable view will
show a dialog to edit that object (if you customized the
<strong>featuresProvider</strong>, the dialog will use your customized version);
by default, if you edit a field in such dialog, the modifications will
be applied immediately to the resource: this can be seen in the
labels of the tree which are automatically updated and in the dirty state of
the view:
</p>
<p>
</p>
<img src="images/first-example-default-dialog.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
Such a strategy for editing is delegated to an injected
<abbr title="org.eclipse.emf.parsley.edit.IEditingStrategy">IEditingStrategy</abbr>
, which is
implemented by default by <abbr title="org.eclipse.emf.parsley.edit.OnTheFlyEditingStrategy">OnTheFlyEditingStrategy</abbr>
.
</p>
<p>
One may want to avoid this automatic update of the resource, and
have the changes applied only when the "OK" dialog button is pressed
(if "Cancel" is pressed, no changes should be applied at all).
To achieve this behavior, it is enough to bind the alternative implementation
<abbr title="org.eclipse.emf.parsley.edit.UndoableEditingStrategy">UndoableEditingStrategy</abbr>
, in the Guice module.
This can be achieved in the DSL using the <strong>binding</strong> section
(Guice bindings are detailed in section <a href="#addref" rel="Dependency Injection With</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Google Guice">Guice Bindings</a>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
bindings {
type IEditingStrategy -&gt; UndoableEditingStrategy
}
</pre>
<p>
</p>
<p>
We strongly suggest you use the content assist to discover default
bindings, since they also show Javadoc for each default binding:
</p>
<p>
</p>
<img src="images/first-example-custom-binding1.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
Besides types, you can also bind (i.e., inject) specific values
that are used in the framework; for example, you can change the
orientation of the tree form sash as follows
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
...
bindings {
type IEditingStrategy -&gt; UndoableEditingStrategy
value int TreeFormSashStyle -&gt; SWT.HORIZONTAL
}
</pre>
<p>
</p>
<p>
and see the result:
</p>
<p>
</p>
<img src="images/first-example-custom-orientation.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
This ends the first tutorial.
</p>
</div>
</div>
<hr style="width:64.6%;margin-bottom:28px;margin-top:30px;" class="col-md-8 col-md-offset-3">
<div class="row featurette">
<div class="col-md-8 col-md-offset-3">
<h1 id="par" class="featurette-heading text-parsley">Components</h1>
<p>
This section describes the components that are provided to be used out-of-the-box, that are the foundations for all parts built upon <strong>EMF Parsley</strong>.
Afetr a brief description, for each component we present a set of customizations, just to give an idea of how it works. You can refer
to <a href="#addref" rel="Customizations">Customizations Section</a> for a complete list.
</p>
<p>
Components and viewers have to be created using the factories we provide
(e.g., for viewers we provide <abbr title="org.eclipse.emf.parsley.viewers.ViewerFactory">ViewerFactory</abbr>
);
such factories provide specific <strong>create</strong> methods that require all the needed parameters.
These factories must be injected.
</p>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Form Component</h2>
<p>
The <strong>Form Component</strong> can be used to rapresent an <abbr title="org.eclipse.emf.ecore.EObject">EObject</abbr>
in a form,
like in the image above.
</p>
<p>
</p>
<img src="images/03-components-form.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
<strong>EMF Parsley</strong> provides a factory that can be used to create such a component, like in the code below.
Here you can see that a form can be configured in 2 lines, the constructor phase and the build&amp;fill phase.
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject FormFactory formFactory;
(...)
formComposite = formFactory.createFormDetailComposite(parent, SWT.NONE);
formComposite.init(eObject);
</pre>
<p>
</p>
<p>
Most of the job is done by the second line of code, which gets the list of <abbr title="org.eclipse.emf.ecore.EStructuralFeature">EStructuralFeature</abbr>
defined
for the <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
(that is the type of the object to represent) and builds a row for each of them. Each row is composed
by a <strong>caption</strong> which defaults to the name of the feature and a <strong>control</strong> to access the data.
</p>
<p>
All these aspects can be customized in many ways, for example you can customize the feature list, the captions and the controls.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Feature List Customization<a id="FormComponent_features"></a></h3>
<p>
The <strong>list of features</strong> displayed on the form can be customized via the <a href="#FeaturesProvider">Feature Provider</a>
that returns the list of the features (in a given order).
</p>
</br>
<h3 class="featurette-heading text-parsley2">Caption Customization<a id="FormComponent_captions"></a></h3>
<p>
The captions of the features shown in the form can be customizzed via the <a href="#FormFeatureCaptionProvider">Form Feature Caption Provider</a>.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Control Customization<a id="FormComponent_controls"></a></h3>
<p>
The Controls in the form can be customized via the <a href="#FormControlFactory">Form Control Factory</a>.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Proposal Provider<a id="FormComponent_proposals"></a></h3>
<p>
Depending on the feature types, some fields can have predefined values (e.g. combo).
You can provide the exact proposal list via the <a href="#ProposalProvider">Proposal Provider</a>
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Tree Component</h2>
<p>
The <strong>Tree Component</strong> provides a tree representation of data that can be fed with an EResource, a
Resource URI, and a simple EObject. This component uses the EMF Meta-Model information to display objects in the tree.
</p>
<p>
</p>
<img src="images/03-components-tree.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
<strong>EMF Parsley</strong> provides a factory that can be used to create such a component, like in the code below:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject ViewerFactory viewerFactory;
(...)
treeViewer = new TreeViewer(parent);
viewerFactory.initialize(treeViewer, element);
</pre>
<p>
</p>
<p>
The <strong>Tree Component</strong>can be customized in several way via the standard EMF Edit facilities or with the EMF Parsley
codeinjection based mechanism. If you are familiar with Jface APIs, you can easily use the basic class with some facilties to define the specific implementation.
See the corrisponding sections for more details.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Content Provider<a id="Tree_ContentProvider"></a></h3>
<p>
An IContentProvider is used in Jface to retrieve the list of <strong>elements</strong> and <strong>children</strong> to be showed
in the tree viewer. The <a href="#ViewerContentProvider">Viewer Content Provider</a> is the <strong>EMF Parsley</strong> implementation of that interface,
and by default uses the containment mechanisms to provide children as in EMF Edit framework, but it can
be customized as weel.
</p>
</br>
<h3 class="featurette-heading text-parsley2">LabelProvider<a id="Tree_LabelProvider"></a></h3>
<p>
The <a href="#ViewerLabelProvider">Viewer Label Provider</a> is the implementation of an ILabelProvider interface
and is responsible to provide the text and image representation for each EObject visualized.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Adding Menu<a id="Tree_MenuBuilder"></a></h3>
<p>
The contextual menu can be added to the viewer via an injected
<abbr title="org.eclipse.emf.parsley.menus.ViewerContextMenuHelper">ViewerContextMenuHelper</abbr>
, as explained in the <a href="#addref" rel="Contextual Menu">Menu section</a>.
The <a href="#MenuBuilder">Menu Builder</a> allows to fully customize the menus.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Tree Form Component</h2>
<p>
The <strong>Tree Form Component</strong> contains a <a href="#addref" rel="Tree Component"></a> that provides a tree representation of data that can be fed with
an EResource, a Resource URI, and a simple EObject. This component uses the EMF Meta-Model information to display objects in
the tree. The component also combines a <a href="#addref" rel="Form Component"></a> detail that display the current selected object.
</p>
<p>
</p>
<img src="images/03-components-treeform.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
<strong>EMF Parsley</strong> provides a factory to create such a component.
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject TreeFormFactory treeFormFactory;
(...)
treeFormComposite = treeFormFactory.createTreeFormComposite(parent, SWT.BORDER);
treeFormComposite.update(application);
</pre>
<p>
</p>
<p>
Since <strong>Tree Form Component</strong> is a combination of <strong>Tree Component</strong> and <strong>Form Component</strong>, all their customizations
are avaible for it.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Table Component</h2>
<p>
The <strong>Table Component</strong> can rapresent data in a grid, once you have specified the type of objects to represent.
It uses metamodel information to build columns as needed, and a
<abbr title="org.eclipse.emf.parsley.edit.ui.provider.TableViewerContentProvider">TableViewerContentProvider</abbr>
to retrieve
the contents of the specified type (see also <a href="#TableViewerContentProvider"></a>).
</p>
<p>
</p>
<img src="images/03-components-table.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject ViewerFactory viewerFactory;
(...)
tableViewer = viewerFactory.createTableViewer(composite, SWT.BORDER | SWT.FULL_SELECTION, eClass);
</pre>
<p>
</p>
<p>
The class <abbr title="org.eclipse.emf.parsley.viewers.TableViewerColumnBuilder">TableViewerColumnBuilder</abbr>
has the responsibility to
build the columns of the Table, by using the <a href="#FeaturesProvider">Features Provider</a> to get the list
of features and the <a href="#FeatureCaptionProvider">Feature Caption Provider</a> for the column headers.
The class <abbr title="org.eclipse.emf.parsley.ui.provider.TableColumnLabelProvider">TableColumnLabelProvider</abbr>
can be used to specify
an implementation of ILabelProvider for each cell in the table.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Feature List Customization<a id="Table_features"></a></h3>
<p>
The <strong>list fo features</strong> displayed on the table can be customized via the <a href="#TableFeaturesProvider">Table Feature Provider</a>.
This list of features will be used for building the columns of the table.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Caption Customization<a id="Table_captions"></a></h3>
<p>
The headers of the table can be customizzed via the <a href="#FeatureCaptionProvider">Caption Provider</a>.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Column width Customization<a id="Table_columns_width"></a></h3>
<p>
All columns have the same size by default, but they can be customizzed via the <a href="#addref" rel="Configurator">Configurator</a>
for instance in the DSL, like in the example below.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
bindings{
value List&lt;Integer&gt; TableColumnWeights -&gt; #[10,20,30,40]
}
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Adding Menu<a id="Table_MenuBuilder"></a></h3>
<p>
The contextual menu can be added to the viewer via an injected
<abbr title="org.eclipse.emf.parsley.menus.ViewerContextMenuHelper">ViewerContextMenuHelper</abbr>
, as explained in the <a href="#addref" rel="Contextual Menu">Menu section</a>.
The <a href="#MenuBuilder">Menu Builder</a> allows to fully customize the menus.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Tree With Columns Component</h2>
<p>
The <strong>Tree With Columns Component</strong> provides a tree representation just like <a href="#addref" rel="Tree Component">Tree Component</a>,
but it also shows table columns representing the features of the specified <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
.
</p>
<p>
IMPORTANT: the <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
is used to retrieve the features to be shown, and
NOT to filter elements to be shown (as opposite to the <a href="#addref" rel="Table Component">Table Component</a>). If a given
row in the tree represents an object whose class does not have the feature for a given column, then the
corresponding table cell for that object will be empty.
</p>
<p>
For example, the following screenshot shows a tree with columns representing a library; the specified
<abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
is the <strong>Writer</strong> so the columns show the features of the
<strong>Writer</strong>'s class. Some of these features, e.g., <strong>address</strong>, <strong>firstName</strong> and <strong>lastName</strong>, are defined
in the superclasses of <strong>Writer</strong>. The objects of class <strong>Employee</strong> have these features as well, while
they don't have features that are specific of <strong>Writer</strong>, e.g., <strong>name</strong> and <strong>books</strong>, thus the corresponding
cells for employees will be empty.
</p>
<p>
</p>
<img src="images/03-components-treecolumns.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
<strong>EMF Parsley</strong> provides a factory that can be used to create such a component, like in the code below:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject ViewerFactory viewerFactory;
(...)
treeViewer = createTreeViewerWithColumns(parent, getEClass(), getContents());
</pre>
<p>
</p>
<p>
Since this component mixes the features of a tree and a table, the customizations are basically the
same shown in the subsections of <a href="#addref" rel="Tree Component"></a> and <a href="#addref" rel="Table Component"></a>.
</p>
</div>
</div>
</div>
<hr style="width:64.6%;margin-bottom:28px;margin-top:30px;" class="col-md-8 col-md-offset-3">
<div class="row featurette">
<div class="col-md-8 col-md-offset-3">
<h1 id="par" class="featurette-heading text-parsley">Customizations</h1>
<p>
In this chapter we will describe how <strong>EMF Parsley</strong> lets you customize the standard behaviours.
A DSL is provided to easily customize most common features, but you can also customize all aspects
manually (i.e., in directly Java).
As a matter of fact each customization is explained in a single section, with the details on how to do
that with the DSL (if available) and in Java.
</p>
<p>
If you want to provide a specific implementation in
Java, you can use the Google Guice injection mechanism, by overriding the specific class with your own
implementation. Note that in some cases an explicit constructor is needed, with the <strong>@Inject</strong> annotation to make Guice
correctly works; when this is the case, the base class will already have such a constructor and you will only
need to override it, but you will also need to add the <strong>@Inject</strong> annotation explicitly.
</p>
<p>
Although one can specify any Guice <abbr title="com.google.inject.Module">Module</abbr>
, <strong>EMF Parsley</strong> ships with
some default base class modules that should be used for specifying custom
Guice bindings. The default base class is
<abbr title="org.eclipse.emf.parsley.EmfParsleyGuiceModule">EmfParsleyGuiceModule</abbr>
that is suitable to be used
in an OSGI environment, like Eclipse itself or RAP (see also <a href="#addref" rel="Advanced Features">Eclipse 4.x &amp; RAP</a>).
Our project wizards will automatically use such module as the base class.
For CDO we have a specialized base module.
</p>
<p>
We also have a module to be used in a non OSGI environment, e.g., a pure Java environment:
<abbr title="org.eclipse.emf.parsley.EmfParsleyJavaGuiceModule">EmfParsleyJavaGuiceModule</abbr>
(this is the base class of
<abbr title="org.eclipse.emf.parsley.EmfParsleyGuiceModule">EmfParsleyGuiceModule</abbr>
). This is useful also for
testing purposes, for writing plain Junit tests (i.e., not Plug-in Junit tests).
This is also used in our testing framework (see <a href="#addref" rel="Testing Framework">EMF Parsley Testing Framework</a>).
</p>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Dependency Injection With Google Guice</h2>
<p>
All Parsley components are assembled by means of <strong>Dependency Injection (DI)</strong>.
This means that whenever some code is in need for functionality (or state)
from another component, one just declares the dependency rather then stating
how to resolve it, i.e. obtaining that component.
</p>
<p>
For example, when some code wants to use a label provider,
it just declares a field (or method or constructor) and adds the
<abbr title="com.google.inject.Inject">@Inject</abbr>
annotation:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
class MyView extends ViewPart {
@Inject
private ILabelProvider labelProvider;
}
</pre>
<p>
</p>
<p>
It is not the duty of the client code to care about where the
actual <abbr title="org.eclipse.jface.viewers.ILabelProvider">ILabelProvider</abbr>
comes from or
how it is created.
When the above class is instantiated, Guice sees that it requires an instance
of ILabelProvider and assigns it to the specified field or method parameter.
This of course only works, if the object itself is created by Guice.
In Parsley almost every instance is created that way and therefore the whole
dependency net is controlled and configured by the means of Google Guice.
</p>
<p>
Guice of course needs to know how to instantiate real objects for declared dependencies.
This is done in so called Modules. A <abbr title="com.google.inject.Module">Module</abbr>
defines a set of mappings from types to either existing instances,
instance providers or concrete classes.
Modules are implemented in Java. Here's an example:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public class MyGuiceModule extends AbstractGenericModule {
@Override
public void configure(Binder binder) {
super.configure(binder);
binder.bind(ILabelProvider.class).to(MyLabelProvider.class);
binder.bind(...
}
</pre>
<p>
</p>
<p>
With plain Guice modules one implements a method called configure and gets a
<abbr title="com.google.inject.Binder">Binder</abbr>
passed in.
That binder provides a fluent API to define the mentioned mappings.
This was just a very brief and simplified description.
We highly recommend to have a look at the <a href="https://github.com/google/guice">Google Guice</a>
website to learn more.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Module API<a id="ModuleAPI"></a></h3>
<p>
Parsley comes with a slightly enhanced module API
(this was inspired by Xtext, so, if you are already familiar with the
enhnaced Guice module API of Xtext, you can use Parsley API right away).
</p>
<p>
The enhancement we added to Guice's Module API is that we provide an abstract base class,
which reflectively looks for certain methods in order to find declared bindings.
The standard base class is <abbr title="org.eclipse.emf.parsley.EmfParsleyGuiceModule">EmfParsleyGuiceModule</abbr>
,
which can be used in a standard Eclipse OSGI environment. If you are using
CDO, it is better to use as base class <strong>CDOEmfParsleyModule</strong>, which has defaults
that better fit a CDO environment. If you do not need OSGI, you can use
<abbr title="org.eclipse.emf.parsley.EmfParsleyJavaGuiceModule">EmfParsleyJavaGuiceModule</abbr>
(e.g., to run tests
with plain Junit, see also <a href="#addref" rel="Testing Framework">Testing Framework</a>).
</p>
<p>
The most common kind of method is
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public Class&lt;? extends ILabelProvider&gt; bindILabelProvider() {
return MyLabelProvider.class;
}
</pre>
<p>
</p>
<p>
which would do the same as the code snippet above.
It simply declares a binding from ILabelProvider to MyLabelProvider.
That binding will make Guice instantiate and inject a new instance of
MyLabelProviderProvider whenever a dependency to ILabelProvider is declared.
</p>
<p>
There are two additional kinds of binding-methods supported.
The first one allows to configure a provider.
A <abbr title="com.google.inject.Provider">Provider</abbr>
is an interface with just one method:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public interface Provider&lt;T&gt; extends javax.inject.Provider&lt;T&gt; {
/**
* Provides an instance of {@code T}. Must never return {@code null}.
*/
T get();
}
</pre>
<p>
</p>
<p>
This one can be used if you need a hook whenever an instance of a certain type
is created. For instance if you want to provide lazy access to a singleton
or you need to do some computation each time an instance is created (i.e. factory).
If you want to point to a provider rather than to a concrete class you can
use the following binding method:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public Class&lt;? extends Provider&lt;ILabelProvider&gt;&gt; provideILabelProvider() {
return MyLabelProviderFactory.class;
}
</pre>
<p>
</p>
<p>
The last kind of binding allows to inject values in Parsley components;
here are some examples of such bindings implemented in the base class of
Parsley Guice module:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
/**
* The String constant for Content Assist Shortcut
*/
public String valueContentAssistShortcut() {
return "Ctrl+Space";
}
/**
* The String constant used as a ellipses for Iterable string representation
* when it is too long
*/
public String valueIterableStringEllipses() {
return "...";
}
/**
* The list of Integer weights for a table's columns
*/
public List&lt;Integer&gt; valueTableColumnWeights() {
return Collections.&lt;Integer&gt;emptyList();
}
/**
* The int constant defining the Sash style in a TreeFormComposite
*/
public int valueTreeFormSashStyle() {
return SWT.VERTICAL;
}
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Specify Guice Bindings in the DSL<a id="BindingsInTheDSL"></a></h3>
<p>
Guice bindings can be specified directly in the DSL, in the
<strong>bindings</strong> section.
</p>
<p>
In this section you can specify bindings of all the three above kinds with
<strong>type</strong>, <strong>provide</strong> and <strong>value</strong> respectively, e.g.,
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
bindings {
type ILabelProvider -&gt; MyLabelProvider
type ... -&gt; ...
provide ProposalCreator -&gt; MyProposalCreatorProvider
...
value int TreeFormSashStyle -&gt; SWT.HORIZONTAL
}
</pre>
<p>
</p>
<p>
We strongly suggest you use the content assist to discover default
bindings, since they also show Javadoc for each default binding:
</p>
<p>
</p>
<img src="images/first-example-custom-binding1.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Providers</h2>
</br>
<h3 class="featurette-heading text-parsley2">Viewer Label Provider<a id="ViewerLabelProvider"></a></h3>
<p>
The Jface Label Provider allows to specify the representation of a given Object. <strong>EMF Parsley</strong>
provides an implementation that uses the information provided via the DSL, as you can see in the snippet
below. We allow customization for text, image, font, and foreground and background color.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
labelProvider{
text {
Book -&gt; "Book:"+title
Borrower -&gt; "Borrower: "+firstName
}
image {
Book -&gt; "book.png"
}
font {
Book -&gt; // must return a org.eclipse.swt.graphics.Font
}
foreground {
Book -&gt; // must return a org.eclipse.swt.graphics.Color
}
background {
Book -&gt; // must return a org.eclipse.swt.graphics.Color
}
}
</pre>
<p>
</p>
<p>
However if you want to customize the label provider in Java, you need to provide an implementation of <abbr title="org.eclipse.jface.viewers.ILabelProvider">ILabelProvider</abbr>
and injecting it in the spefic module by overriding <strong>bindILabelProvider</strong>.
</p>
<p>
<strong>EMF Parsley</strong> provides such a base implementation with the class <abbr title="org.eclipse.emf.parsley.ui.provider.ViewerLabelProvider">ViewerLabelProvider</abbr>
that is meant to be subclassed by the programmer to provide specific implementations like in the example below.
Our label provider also implements <abbr title="org.eclipse.jface.viewers.IFontProvider">IFontProvider</abbr>
and
<abbr title="org.eclipse.jface.viewers.IColorProvider">IColorProvider</abbr>
, so that you can customize also the font, the foreground
and the background color.
</p>
<p>
This class, like many others in our framework, relies on the <strong>polymorphic dispatcher</strong> idiom to declaratively
specify text and image representations for objects. It boils down to the fact that the only thing you need to do is
to implement a method that matches a specific signature: <strong>text</strong> and <strong>image</strong> for the String representation and
the image, respectively. These methods will need to specify as parameter the type of the object to represent.
For the image, you can either specify an image filename or an Image object. File names for images are
assumed to refer to files in the <strong>icons</strong> folder of the containing plug-in.
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public class CustomLibraryLabelProvider extends ViewerLabelProvider {
@Inject
public CustomLibraryLabelProvider(AdapterFactoryLabelProvider delegate) {
super(delegate);
}
public String text(Book book) {
return "Book: " + book.getTitle();
}
public String image(Book book) {
return "book.png";
}
public Font font(Book book) {
return // must return a org.eclipse.swt.graphics.Font
}
public Color foreground(Book book) {
return // must return a org.eclipse.swt.graphics.Color
}
public Color background(Book book) {
return // must return a org.eclipse.swt.graphics.Color
}
public String text(Borrower b) {
return "Borrower: " + b.getFirstName();
}
}
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Viewer Content Provider<a id="ViewerContentProvider"></a></h3>
<p>
As in Jface, the Content Provider is used to get the elements to represent in a tree and their children
(as detailed in <a href="#TableViewerContentProvider">Table Viewer Content Provider</a>, for tables
we use a different content provider).
<strong>EMF Parsley</strong> provides an implementation that uses the DSL as in the code below.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
viewerContentProvider{
elements{
Library -&gt; books
}
children{
Library -&gt; books
Book b-&gt; {
new ArrayList()=&gt;[
add(b.author)
addAll(b.borrowers)
]
}
}
}</pre>
<p>
</p>
<p>
The developer can also provide a specific implementation of <abbr title="org.eclipse.jface.viewers.IContentProvider">IContentProvider</abbr>
by injecting it in the spefic module <strong>(TODO)</strong>. EMF Parsley provides a base implementation with the class
<abbr title="org.eclipse.emf.parsley.edit.ui.provider.ViewerContentProvider">ViewerContentProvider</abbr>
that can be easily used to
specify the children of all object on the tree, like in the example below (again, this uses the polymorphic dispatch idiom).
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public class CustomLibraryViewerContentProvider extends ViewerContentProvider {
@Inject
public CustomLibraryViewerContentProvider(AdapterFactory adapterFactory) {
super(adapterFactory);
}
public Object elements(Library library) {
return library.getBooks();
}
public Object children(Library library) {
return library.getBooks();
}
public Object children(Book book) {
ArrayList&lt;Object&gt; children = new ArrayList&lt;Object&gt;();
Writer author = book.getAuthor();
if (author != null) {
children.add(author);
}
children.addAll(book.getBorrowers());
return children;
}
}
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Table Viewer Content Provider<a id="TableViewerContentProvider"></a></h3>
<p>
For table viewers we use a customized content provider, which inherits from
the one described in <a href="#ViewerContentProvider">Viewer Content Provider</a>;
for tables we only need to specify how the root <strong>elements</strong> are computed
(no children are needed for tables).
</p>
<p>
This content provider, <abbr title="org.eclipse.emf.parsley.edit.ui.provider.TableViewerContentProvider">TableViewerContentProvider</abbr>
,
must be configured with the <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
of the objects that
will be shown in the table, so the <strong>setEClass</strong> must be called before this content provider is
used. This setup is already automatically performed in views that are shipped with Parsley; in
case you need to setup a table viewer yourself with this content provider, we strongly suggest
you inject a <abbr title="org.eclipse.emf.parsley.edit.ui.provider.TableViewerContentProviderFactory">TableViewerContentProviderFactory</abbr>
and use its method <strong>createTableViewerContentProvider(EClass type)</strong>.
</p>
<p>
With the information about the <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
this content provider
is able to automatically retrieve all the contents of that type from a <abbr title="org.eclipse.emf.ecore.resource.Resource">Resource</abbr>
or any <abbr title="org.eclipse.emf.ecore.EObject">EObject</abbr>
, by retrieving inspecting all the containment
references of that type, recursively in the model.
</p>
<p>
In case you want to optimize the retrieval of contents, or in case you want to
show elements of the specified type which are not contained in an <abbr title="org.eclipse.emf.ecore.EObject">EObject</abbr>
(because they are references with containment set to false), you can inject your own
custom <abbr title="org.eclipse.emf.parsley.edit.ui.provider.TableViewerContentProvider">TableViewerContentProvider</abbr>
and define <strong>elements</strong> methods (again, this uses the polymorphic dispatch idiom).
</p>
<p>
In the DSL this can be done using the specific section.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
tableViewerContentProvider{
elements{
Library lib -&gt; {
// this is just an optimization: since books are contained in the library
// the default content provider will retrieve them automatically
lib.books
}
Writer w {
// writers' books would not be retrieved by the default content provider
// since they are NOT 'contained' in a writer.
w.books
}
}
}</pre>
<p>
</p>
<p>
IMPORTANT: customizations specified in a <abbr title="org.eclipse.emf.parsley.edit.ui.provider.ViewerContentProvider">ViewerContentProvider</abbr>
will NOT be reused by a <abbr title="org.eclipse.emf.parsley.edit.ui.provider.TableViewerContentProvider">TableViewerContentProvider</abbr>
.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Table Label Provider<a id="TableLabelProvider"></a></h3>
<p>
The Jface Table Label Provider allows to specify the representation of a given cell in a table. <strong>EMF Parsley</strong>
provides an implementation that uses the information provided via the DSL, as you can see in the snippet
below. We allow customization for text, image, font, foreground and background color for a given object's feature
(which corresponds to a table cell), and also font, and foreground and background color for the entire row.
</p>
<p>
Concerning fonts and colors, a customization for a single cell has the precedence over the customization of an entire row.
</p>
<p>
Here's an example.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
tableLabelProvider {
text {
Library:name -&gt; 'Name' // constant
Library:books -&gt; 'Books' // constant
Writer:lastName -&gt; name.toFirstUpper // the implicit param is an EStructuralFeature
}
image {
Book: author -&gt;
if (author.name.nullOrEmpty)
"noname.gif"
else
new ImageData("writer.jpeg")
}
font {
Library : name -&gt; JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT)
}
foreground {
Library : books -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)
}
background {
Library : address -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_GREEN)
}
rowFont {
Library -&gt; JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT)
}
rowForeground {
Library -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)
}
rowBackground {
Library -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_GREEN)
}
}
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Features Provider<a id="FeaturesProvider"></a></h3>
<p>
<strong>EMF Parsley</strong> uses this kind of provider wherever a list of features is requested for a certain EClass.
The default is to return the list of all the features in the EClass, but the programmer can customize it (for instance,
by returning only a superset, or in a different order) on an EClass-based strategy.
Thus you can use the DSL to specify that list, as in the snipped below.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
featuresProvider{
features{
Book -&gt; title, author, category, pages
}
}
</pre>
<p>
If you want to customize it in Java, there are more ways to customize this behaviour, but we need to go deep in some
details of the <strong>Feature Provider</strong> implementation.
</p>
<p>
When the framework builds components according to the
<abbr title="org.eclipse.emf.ecore.EStructuralFeature">EStructuralFeature</abbr>
s of a given
<abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
it relies on an injected
<abbr title="org.eclipse.emf.parsley.ui.provider.FeaturesProvider">FeaturesProvider</abbr>
.
The default behavior is to simply return all the features of the a given EClass,
in the order they are defined in the EClass, as implemented by the method <strong>defaultFeatures</strong> in
<abbr title="org.eclipse.emf.parsley.ui.provider.FeaturesProvider">FeaturesProvider</abbr>
.
</p>
<p>
You can set the mappings, i.e., specify the structural
features you want to be used given an EClass, by implementing
the method <strong>buildMap</strong>, which receives the
<abbr title="org.eclipse.emf.parsley.ui.provider.FeaturesProvider$EClassToEStructuralFeatureMap">FeaturesProvider.EClassToEStructuralFeatureMap</abbr>
that can be filled with the method <strong>mapTo</strong>;
for instance, using the EMF extended library
example, this customization will return only the <strong>name</strong> and <strong>address</strong> features
for <strong>Library</strong>, the <strong>firstName</strong>, <strong>lastName</strong> and <strong>address</strong> for
<strong>Person</strong>, and the <strong>firstName</strong>, <strong>lastName</strong> and <strong>books</strong> (but
not <strong>address</strong>) for <strong>Writer</strong> (which inherits from <strong>Person</strong>).
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
import static org.eclipse.emf.examples.extlibrary.EXTLibraryPackage.Literals.*;
import org.eclipse.emf.parsley.ui.provider.EStructuralFeaturesProvider;
public class LibraryEStructuralFeaturesProvider extends
FeaturesProvider {
@Override
protected void buildMap(EClassToEStructuralFeatureMap map) {
super.buildMap(map);
map.mapTo(LIBRARY,
LIBRARY__NAME, ADDRESSABLE__ADDRESS);
map.mapTo(PERSON, PERSON__FIRST_NAME, PERSON__LAST_NAME, ADDRESSABLE__ADDRESS);
map.mapTo(WRITER, PERSON__FIRST_NAME, PERSON__LAST_NAME, WRITER__BOOKS);
}
}
</pre>
<p>
</p>
<p>
Another possibility is to build a map which relies on Strings
both for the <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
and for
the list of <abbr title="org.eclipse.emf.ecore.EStructuralFeature">EStructuralFeature</abbr>
;
note that the name of the <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
should
be obtained by using <strong>getInstanceClassName()</strong>; you can also
combine the two approaches.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Table Features Provider<a id="TableFeaturesProvider"></a></h3>
<p>
As an extension, you can use the <abbr title="org.eclipse.emf.parsley.ui.provider.TableFeaturesProvider">TableFeaturesProvider</abbr>
:
the customizations will be applied only to <a href="#addref" rel="Table Component">Tables</a>, not to <a href="#addref" rel="Form Component">Forms</a>.
</p>
<p>
If there are no specific customization in the <abbr title="org.eclipse.emf.parsley.ui.provider.TableFeaturesProvider">TableFeaturesProvider</abbr>
,
we fall back to <abbr title="org.eclipse.emf.parsley.ui.provider.FeaturesProvider">FeaturesProvider</abbr>
.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Feature Caption Provider<a id="FeatureCaptionProvider"></a></h3>
<p>
The <abbr title="org.eclipse.emf.parsley.ui.provider.FeatureCaptionProvider">FeatureCaptionProvider</abbr>
provides captions for
the features in <a href="#addref" rel="Table Component">Tables</a> and <a href="#addref" rel="Form Component">Forms</a>.
Here you can see an example of the DSL.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
featureCaptionProvider{
text{
Book:author -&gt; "Written by:"
Writer:name -&gt; "Name:"
}
}
</pre>
<p>
</p>
<p>
If you want to customize it in Java, you need to derive from
<abbr title="org.eclipse.emf.parsley.ui.provider.FeatureCaptionProvider">FeatureCaptionProvider</abbr>
.
It can be customized, with injection <a href="#addref" rel="Dependency Injection With</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Google Guice"></a>: this
way you can customize the caption label for controls in a form, dialog, and the headers in a table's column.
The framework uses a polimorphic mechanism to find customizations: it searches for
methods with a specific signature: the name is built by the string <strong>'text'</strong> followed by the EClass and the EStructuralFeature.
All parts of the name are separated by an underscore character and the method must accept a parameter of type EStructuralFeature.
</p>
<p>
In the following example we specify the caption text for the feature 'Author' of Book and the feature 'Name' for
Writer.
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public String text_Book_author(final EStructuralFeature feature) {
return "Written by:";
}
public String text_Writer_name(final EStructuralFeature feature) {
return "Name:";
}
</pre>
<p>
</p>
<p>
If no customization is provided, the text will be computed using the feature's name.
This will always be the default for table column headers (since no object is available
when building the table); while for form and dialog captions we use a slightly different
default strategy, as shown in <a href="#FormFeatureCaptionProvider">Form and Dialog Feature Caption Provider</a>.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Form and Dialog Feature Caption Provider<a id="FormFeatureCaptionProvider"></a></h3>
<p>
The <abbr title="org.eclipse.emf.parsley.ui.provider.FormFeatureCaptionProvider">FormFeatureCaptionProvider</abbr>
(<abbr title="org.eclipse.emf.parsley.ui.provider.DialogFeatureCaptionProvider">DialogFeatureCaptionProvider</abbr>
, respectively)
can be used if you want to define the description only for forms (for dialogs, respectively).
For example using the <a href="#addref" rel="Tree Form Component">Tree Form</a> your definition will not be used in the tree.
</p>
<p>
In this case you can also define a method the returns directly the
<abbr title="org.eclipse.swt.widgets.Label">Label</abbr>
, like in the example
below. In such methods there is another parameter that is the parent composite (that is automatically
passed by the framework).
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public Label label_Writer_name(Composite parent, EStructuralFeature feature) {
Label label = defaultLabel(parent, feature);
label.setBackground(getFormToolkit().getColors().getColor(IFormColors.TITLE));
return label;
}
</pre>
<p>
</p>
<p>
In the DSL you have the corresponding two sections available:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
formFeatureCaptionProvider{
text{
Book:author -&gt; "Written by:"
}
label{
Writer:name -&gt; createLabel(parent, "Name")
}
}
dialogFeatureCaptionProvider{
text{
Book:author -&gt; "Author:"
}
label{
Writer:name -&gt; createLabel(parent, "Writer's name")
}
}
</pre>
<p>
</p>
<p>
If there is no customization in the <abbr title="org.eclipse.emf.parsley.ui.provider.FormFeatureCaptionProvider">FormFeatureCaptionProvider</abbr>
(<abbr title="org.eclipse.emf.parsley.ui.provider.DialogFeatureCaptionProvider">DialogFeatureCaptionProvider</abbr>
, respectively),
the following steps are executed to create the text for the label:
</p>
<p>
</p>
<ul>
<li>we take possible customizations from <abbr title="org.eclipse.emf.parsley.ui.provider.FeatureCaptionProvider">FeatureCaptionProvider</abbr>
if available, otherwise:</li>
<li>we take the text from <abbr title="org.eclipse.emf.edit.provider.IItemPropertyDescriptor">IItemPropertyDescriptor</abbr>
if
the EObject provides it, otherwise:</li>
<li>we take the feature name</li>
</ul>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Proposal Provider<a id="ProposalProvider"></a></h3>
<p>
Some controls use a list of proposals to help the end user experince: for example a single value reference feature
will be rendered by default with a combo box, automatically filled with all the possible targets for
that reference; similarly for Enum features. You can customize the proposals, and you can specify proposals also
for simple text fields (a content assist dialog will show up for text fields).
</p>
<p>
For each feature you can specify a list of proposals via the DSL. In the example below, we first
compute the default proposals for that feature and then we filter the proposals.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
proposals{
Book:author -&gt; {
defaultProposals(feature).
filter(Writer).
filter[name.startsWith("F")].toList
}
}
</pre>
<p>
This customization can be done also in Java, by extending the class <abbr title="org.eclipse.emf.parsley.composite.ProposalCreator">ProposalCreator</abbr>
and implementing the method </p>
<pre class="prettyprint" skin="desert">public List&lt;?&gt; proposals_Book_author(Book book) {...}</pre>
<p>
. This
method follows the same convention on the signature name as explained in <a href="#FeatureCaptionProvider">Feature
Provider</a>.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Contextual Menu</h2>
<p>
A context menu can be added to any <abbr title="org.eclipse.jface.viewers.StructuredViewer">StructuredViewer</abbr>
by using an
injected <abbr title="org.eclipse.emf.parsley.menus.ViewerContextMenuHelper">ViewerContextMenuHelper</abbr>
. This provides some
methods for adding the context menu
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject ViewerContextMenuHelper contextMenuHelper;
(...)
// simplest form
contextMenuHelper.addViewerContextMenu(viewer);
// if you have an AdapterFactoryEditingDomain already
contextMenuHelper.addViewerContextMenu(viewer, editingDomain);
// if you're inside an IWorkbenchPart
contextMenuHelper.addViewerContextMenu(viewer, editingDomain, part);
</pre>
<p>
</p>
<p>
The contents of such menu are built automatically by the framework or customized by the programmer,
as shown in the next section.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Menu Builder<a id="MenuBuilder"></a></h3>
<p>
<strong>EMF Parsley</strong> uses the standard EMF.Edit features to build the contextual menus of
viewers (thus you will get by default the standard "New Child" and "New Sibling"
sections in the context menu).
</p>
<p>
You can customize context menus on a per class basis
by extending the <abbr title="org.eclipse.emf.parsley.edit.action.EditingMenuBuilder">EditingMenuBuilder</abbr>
(and injecting it in the Guice module). However, we suggest to use the
DSL for this task, as detailed in the following.
</p>
<p>
<strong>EMF Parsley</strong> logically separates the menu into 2 parts. The first section contains all common edit commands
such as <strong>copy</strong> and <strong>paste</strong>. The second section contains EMF specific commands, such as for example <strong>new child</strong>.
You can use the DSL to fully customize the menu, as in the example below.
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
menuBuilder{
menus{
Library-&gt; #[
submenu("Edit",#[
actionCopy,
actionCut,
separator,
actionPaste
])
]
}
emfMenus{
Library lib -&gt; #[
actionAdd("Add a new book", lib.books,
EXTLibraryFactory.eINSTANCE.createBook)
]
}
}
</pre>
<p>
</p>
<p>
For each EClass of your meta-model you can specify a list of menu items
(the #[] is the Xbase syntax for a list literal)
Content assist is available to select the editing actions, the separator and
also methods for EMF menu part.
</p>
<p>
In the <strong>emfMenus</strong> section, you can use some methods of
the <abbr title="org.eclipse.emf.parsley.edit.action.EditingMenuBuilder">EditingMenuBuilder</abbr>
class,
as detailed in the following.
</p>
<p>
The method <strong>actionAdd</strong>, specifying the label for the menu,
the containment list in the model, and the object to add in such list
when the menu is selected (Note that it is up to you to specify a
containment list); the DSL will issue an error if the object cannot be
added to the list (because it is not of the right type).
The object should be created using the standard EMF API (i.e., using
the EMF factory for your model).
</p>
<p>
If you want to specify further initialization instructions for the
created object you can pass a lambda expression as another argument
to <strong>actionAdd</strong>: that lambda will be executed ONLY after the menu
has been selected, i.e., ONLY after the created
object is part of the resource:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
emfMenus{
Writer w -&gt; #[
actionAdd("Add a new book for the writer",
(w.eContainer as Library).books,
EXTLibraryFactory.eINSTANCE.createBook,
[ book | book.title = "A new book" ]
)
]
}
</pre>
<p>
</p>
<p>
IMPORTANT: do not set any reference feature of the created EObject in the lambda,
i.e., do not do something like the following
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
emfMenus{
Writer w -&gt; #[
actionAdd("Add a new book for the writer",
(w.eContainer as Library).books,
EXTLibraryFactory.eINSTANCE.createBook,
// WRONG: don't do that
[ book | book.author = w ]
)
]
}
</pre>
<p>
</p>
<p>
This will not work if you undo the command: the writer that has been added
to the library will be removed, and the book.author will be a dangling reference!
as a consequence the resource cannot be saved.
</p>
<p>
If you want to implement more complex menu commands that do not
only add elements to a container, you can use the method
<strong>actionChange</strong>, specifying the label for the menu, the model's element
that will be affected by the changes specified as a lambda expression
(the third argument). The lambda expression will also get the specified
model's element as argument. The model's element can also be the whole
resource itself (formally, it can be any EMF <abbr title="org.eclipse.emf.common.notify.Notifier">Notifier</abbr>
).
</p>
<p>
It is crucial to specify the correct model's element to make undo/redo work
correctly: all the modifications performed in the lambda expression that concern the
specified element will be recorded, in order to implement undo/redo.
</p>
<p>
For example, this command, that will add a new book to the library, and sets
its author to the selected writer will work as expected, and selecting
undo will effectively remove the book from the writer's list and from the library:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
emfMenus{
Writer w -&gt; #[
actionChange("New book", w.eContainer as Library,
[
library |
val book = factory.createBook
library.books += book
book.title = "A new book"
book.author = w
]
)
]
}
</pre>
<p>
</p>
<p>
This works since we specify the containing library as the model's element, thus,
all modifications that concern the library will be recorded.
</p>
<p>
On the contrary, this variant, will perform exacty the same actions on the model, but selecting
undo will only remove the book from the writer's list, and the book will still
be present in the library:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
emfMenus{
Writer w -&gt; #[
// in this variant undo will only unset the book's author,
// but it will not remove the added code from the library
// since we record changes concerning the writer only
actionChange("New book (variant)", w,
[
writer |
val library = writer.eContainer as Library
val book = factory.createBook
library.books += book
book.title = "A new book"
book.author = w
]
)
]
}
</pre>
<p>
</p>
<p>
This happens since we specified the writer as the model's element, thus only
the changes that concern the writer will be undone.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Drag and Drop</h2>
<p>
Drag and drop can be added to any <abbr title="org.eclipse.jface.viewers.StructuredViewer">StructuredViewer</abbr>
by using an
injected <abbr title="org.eclipse.emf.parsley.edit.ui.dnd.ViewerDragAndDropHelper">ViewerDragAndDropHelper</abbr>
,
using its methods <strong>addDragAndDrop</strong>.
</p>
<p>
Currently, drag and drop is completely delegated to EMF.Edit.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Factories</h2>
</br>
<h3 class="featurette-heading text-parsley2">Widget Factory<a id="WidgetFactory"></a></h3>
<p>
The actual creation of text field, buttons, labels, etc. is delegated to an
implementation of <abbr title="org.eclipse.emf.parsley.widgets.IWidgetFactory">IWidgetFactory</abbr>
, which has several methods
like <strong>createText</strong>, <strong>createLabel</strong>, etc. We provide two implementations of such interface
</p>
<p>
</p>
<ul>
<li><abbr title="org.eclipse.emf.parsley.widgets.DialogWidgetFactory">DialogWidgetFactory</abbr></li>
<li><abbr title="org.eclipse.emf.parsley.widgets.FormWidgetFactory">FormWidgetFactory</abbr>
which is a specialization of the above,
specific for forms.</li>
</ul>
<p>
</p>
<p>
Usually, you do not need to customize such factories, which are used internally by the framework,
like in <a href="#FormControlFactory"></a> and <a href="#DialogControFactory"></a>.
</p>
<p>
You may want to customize such factories in case all your controls must have a specific style;
in such case, just inherit from our base classes
(there is no DSL section for such customizations, since they can be made in plain Java easily)
and bind such custom implementations in the Guice module.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Form Control Factory<a id="FormControlFactory"></a></h3>
<p>
<strong>EMF Parsley</strong> lets you customize the <strong>form controls</strong> via the DSL as in the following example.
</p>
<pre class="prettyprint lang-parsley" skin="desert">
formControlFactory {
control {
Library : name -&gt; { }
Writer : books -&gt;
createLabel(
books.map[title].join(", "))
Writer : name -&gt; { createLabel(parent, "") }
target { observeText }
Writer : firstName -&gt;
toolkit.createLabel(parent, "")
target observeText(SWT::Modify)
Borrower : firstName -&gt; {
createText(firstName, SWT::MULTI, SWT::BORDER,
SWT::WRAP, SWT::V_SCROLL)
}
}
}
</pre>
<p>
</p>
<p>
For each pair EClass, EStructuralFeature you can either simply return a Control or specify also the target
for the databinding (see some examples above).
If you want to customize the controls in Java, you can extend the class <abbr title="org.eclipse.emf.parsley.composite.FormControlFactory">FormControlFactory</abbr>
.
Using the same polimorphic mechanism of the labels, the programmer can write a method with the keyword <strong>'control'</strong>
followed by the EClass and EStructuralFeature undescore-character-separated. The method
must accept as parameters the <strong>DataBinding Context</strong> and the <strong>Feature Observable</strong> that can be used for databinding.
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public Control control_Writer_name(DataBindingContext dbc,IObservableValue featureObservable) {
//Creating the control
Text text = getToolkit().createText(getParent(), "");
text.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
text.setBackground(getToolkit().getColors().getColor(IFormColors.TITLE));
//Binding the control to the feature observable
dbc.bindValue(SWTObservables.observeText(text, SWT.Modify), featureObservable);
return text;
}
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Dialog Control Factory<a id="DialogControFactory"></a></h3>
<p>
If you want to customize controls in Dialog, you can use the specific DSL section <strong>dialogControlFactory</strong>:
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
dialogControlFactory {
control {
...
}
}
</pre>
<p>
</p>
<p>
This customization is exactly as in the case of the form of the previous section.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Editing Domain</h2>
<p>
The concept of <abbr title="org.eclipse.emf.edit.domain.EditingDomain">EditingDomain</abbr>
is crucial for editing
EMF models; we refer to the <strong>EMF.Edit</strong> <a href="http://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.emf.doc%2Freferences%2Foverview%2FEMF.Edit.html">documentation</a> for further details.
In particular, the editing domain keeps track of commands executed on an EMF model,
thus enabling undo/redo mechanisms and "dirty state" management for saveable parts.
</p>
<p>
EMF Parsley aims at hiding the management of the editing domain, so that
everything should work smoothly and as expected, in an automatic way. In particular,
it is rare that you need to perform customizations on this mechanisms.
However, there might be cases when you need to be aware of this concept, especially
if you need to use one of our customizations. Moreover, you need to be aware of some
of the assumptions that EMF Parsley automatic mechanisms rely on (we inherit these assumptions
from EMF.Edit itself).
</p>
<p>
First of all, all the EMF <abbr title="org.eclipse.emf.ecore.resource.Resource">Resource</abbr>
s that you want to edit with EMF Parsley must be
contained in a <abbr title="org.eclipse.emf.ecore.resource.ResourceSet">ResourceSet</abbr>
, which, in turn,
must be contained in an <abbr title="org.eclipse.emf.edit.domain.EditingDomain">EditingDomain</abbr>
.
This is achieved automatically when using our <strong>ResourceLoader</strong>, <a href="#ResourceLoader">Resource Loader</a>.
</p>
<p>
Two resources loaded with different resource loaders will be contained in two
different editing domains. Two resources loaded with the same resource loader will
be in the same resource set and use the same editing domain.
</p>
<p>
Our default implementation of editing domain uses the EMF <abbr title="org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain">AdapterFactoryEditingDomain</abbr>
,
so that all the EMF.Edit default mechanisms will work correctly. In particular,
our customization uses Google Guice mechanisms (see <a href="#addref" rel="Dependency Injection With</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Google Guice">Dependency Injection With Google
Guice</a>), thus if you need an editing domain in your own views all you have to do is
to inject it, e.g.,
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject
private EditingDomain editingDomain;
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Editing Domain Provider<a id="EditingDomainProvider"></a></h3>
<p>
If you need to provide a custom implementation of the editing domain
(for example, because you want to use a transactional editing domain), you need
to implement a custom Google Guice <abbr title="com.google.inject.Provider">Provider</abbr>
and
in your Guice module override this method:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public Class&lt;? extends Provider&lt;EditingDomain&gt;&gt; provideEditingDomain() {
return DefaultEditingDomainProvider.class;
}
</pre>
<p>
</p>
<p>
Such custom provider will then have to create an editing domain and return it.
</p>
<p>
We have some custom editing domain providers that might be useful in some
situations:
</p>
<p>
</p>
<ul>
<li><strong>GlobalAdapterFactoryEditingDomainProvider</strong>: all the injected
editing domains will be the same in the same JVM, thus all your
components will share exactly the same editing domain instances, and
all the resources will be contained in the same resource set of the same
editing domain.</li>
<li><strong>SingletonAdapterFactoryEditingDomainModule</strong>: similar to the previous
one, but according to the semantics of Google Guice <abbr title="com.google.inject.Singleton">@Singleton</abbr>
,
i.e., only those components injected with the same injector will share
the same editing domain. This basically means that all the components
created with the same Parsley Guice module will share the same editing domain.</li>
</ul>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Editing Domain Finder<a id="EditingDomainFinder"></a></h3>
<p>
All the EMF Parsley saveable views and editors will have their own
editing domain (modulo what we explained in <a href="#EditingDomainProvider">Editing Domain Provider</a>).
</p>
<p>
The EMF Parsley views that react on selection do NOT have a preset
editing domain, since they will represent (and possibly edit) EMF objects
selected in some other views, i.e., such objects can be contained in resources
of different resource sets (and different editing domains).
Thus, the editing domain of the currently shown object is dynamically
retrieved through an injected <strong>EditingDomainFinder</strong>. This default
implementation basically delegates to the standard EMF.Edit mechanisms
for retrieving the editing domain. In cases where the editing domain cannot
be found (e.g., because the object is not contained in a resource, or its resource
is not contained in a resource set, or its resource set is not contained in an
editing domain), then editing will not be possible (i.e., context menus <a href="#addref" rel="Contextual Menu"></a> and drag
and drop <a href="#addref" rel="Drag and Drop">Drag and Drop</a> will not work).
</p>
<p>
You can provide and bind a custom implementation of the <strong>EditingDomainFinder</strong>
which is particularly useful if you manage a transactional editing domain.
</p>
<p>
This is required only in some specific and advanced scenarios.
</p>
<p>
In standard situations you will not have to worry about that, and
editing mechanisms will work out of the box, including dragging an
element from one view into another view, provided they are in the
same resource set and such drag and drop makes sense.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Resources</h2>
<p>
</p>
<ul>
<li>If you need a machanism to fill some data for the first time you use a model, you can provide
a specific implementation of <a href="#ResourceManager">Resource Manager</a>.</li>
<li>If you want to interact with Resource Loading, you can provide a specific <a href="#ResourceLoader">Resource
Loader</a></li>
</ul>
<p>
</p>
<p>
Concerning saving objects, there are some specific parts that can be customized:
</p>
<p>
</p>
<ul>
<li><a href="#ResourceSaveStrategy">Resource Save Strategy</a>, if you want to manage the save.</li>
</ul>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Resource Loader<a id="ResourceLoader"></a></h3>
<p>
The class <abbr title="org.eclipse.emf.parsley.resource.ResourceLoader">ResourceLoader</abbr>
can be used to handle resource loading.
This class uses internally the <a href="#ResourceManager">Resource Manager</a>.
</p>
</br>
<h3 class="featurette-heading text-parsley2">Resource Manager<a id="ResourceManager"></a></h3>
<p>
Tasks concerning an EMF <abbr title="org.eclipse.emf.ecore.resource.Resource">Resource</abbr>
are
delegated to <abbr title="org.eclipse.emf.parsley.resource.ResourceManager">ResourceManager</abbr>
.
</p>
<p>
One of such tasks is initializing the resource, e.g., when, after loading, it is
found empty. You can derive from this class (and bind it in the Guice module) and provide a custom implementation
of the method <strong>initialize</strong>.
</p>
<p>
Saving a resource is also delegated to this class, using the method <strong>save</strong>,
which is expected to return a boolean value representing whether saving
has succeeded (the default implementation simply saves the resource and returns true).
</p>
<p>
In the DSL, you can specify a <strong>resourceManager</strong> block, and within that block
you can specify <strong>initializeResource</strong> and <strong>saveResource</strong>, which correspond to
<strong>inizialize</strong> and <strong>save</strong> methods, respectively. In both cases, inside the
block expression, the resource is available with the name <strong>it</strong>; for example
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
import org.eclipse.emf.parsley.examples.library.EXTLibraryFactory
...
resourceManager {
val EXTLibraryFactory libraryFactory = EXTLibraryFactory.eINSTANCE;
initializeResource {
// it is of type org.eclipse.emf.ecore.resource.Resource
it.getContents() += libraryFactory.createLibrary
}
saveResource {
// it is of type org.eclipse.emf.ecore.resource.Resource
it.save(null)
return true
}
}
...
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Resource Save Strategy<a id="ResourceSaveStrategy"></a></h3>
<p>
Resource saving is delegated to <abbr title="org.eclipse.emf.parsley.resource.ResourceSaveStrategy">ResourceSaveStrategy</abbr>
which, by defaults only saves the passed <abbr title="org.eclipse.emf.ecore.resource.Resource">Resource</abbr>
,
by delegating to <abbr title="org.eclipse.emf.parsley.resource.ResourceManager">ResourceManager</abbr>
(see <a href="#ResourceManager"></a>).
You can inject your own save strategy and customize the saving strategy, for
instance, you may want to validate the resource before saving
(a usable example of this strategy is
<abbr title="org.eclipse.emf.parsley.resource.ValidateBeforeSaveStrategy">ValidateBeforeSaveStrategy</abbr>
,
see also section <a href="#addref" rel="Validation">Validation</a>).
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Configurator</h2>
<p>
In Parsley, instead of using abstract classes, we often provide concrete
classes that implement superclass' abstract methods (or interface methods)
by delegating to an injected <abbr title="org.eclipse.emf.parsley.config.Configurator">Configurator</abbr>
.
Such configurator calls methods in its hierarchy using polymorphic dispatch;
in particular, the first argument passed to these methods is the object
requesting that specific service to the configurator; typically it will be
a UI object, e.g., a view part.
</p>
<p>
These are the methods that can be customized declaratively:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
/**
* Returns the {@link URI} of the resource for the requestor for any use the requestor may need it
* @param requestor
* @return
*/
public URI resourceURI(Object requestor) {
return null;
}
/**
* Returns the {@link EClass} for the requestor
* @param requestor
* @return
*/
public EClass eClass(Object requestor) {
return null;
}
</pre>
<p>
</p>
<p>
The idea is that clients that use such an injected instance should call
the <strong>get</strong> methods, e.g., <strong>getEClass</strong>, while the customization should be defined
using polymorphic dispatch, e.g.,
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
class MyConfigurator extends Configurator {
public EClass eClass(MyView1 view1) {
return ...;
}
public EClass eClass(MyOtherView view) {
return ...;
}
}
</pre>
<p>
</p>
<p>
In the DSL, you can specify a <strong>configurator</strong> section, e.g.,
(the requestor object can be accessed using the implicit variable
<strong>it</strong>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
module my.project {
configurator {
resourceURI {
MyTreeFormView -&gt; {
return ...;
}
MyTableView -&gt; {
return ...;
}
}
eClass {
MyTableView -&gt; {
return ...;
}
MyTableFormView -&gt; {
return ...;
}
}
}
}
</pre>
<p>
</p>
<p>
The project wizard will generate in the <strong>module.parsley</strong> the
required <strong>configurator</strong> sections, depending on the specific template chosen,
with some <strong>// TODO</strong> comments to help implementing them, e.g.,
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
module my.project {
configurator {
eClass {
MyView -&gt; {
// TODO return the EClass of objects to be shown
}
}
resourceURI {
MyView -&gt; {
// TODO create and return a org.eclipse.emf.common.util.URI
return null;
}
}
}
}
</pre>
<p>
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Validation</h2>
<p>
EMF Parsley supports standard EMF validation automatically, e.g., via the context menu
"Validate"; thus, if you already have constraints implemented for your meta-model, the
validation action will check them.
</p>
<p>
EMF validation can also be triggered manually using an injected <abbr title="org.eclipse.emf.parsley.validation.ValidationRunner">ValidationRunner</abbr>
,
which provides methods for validating a single <abbr title="org.eclipse.emf.ecore.EObject">EObject</abbr>
or an entire
<abbr title="org.eclipse.emf.ecore.resource.Resource">Resource</abbr>
. These <strong>validate</strong> methods return an EMF
<abbr title="org.eclipse.emf.common.util.Diagnostic">Diagnostic</abbr>
that can be used to find out possible errors, warnings
and infos collected during the validation.
</p>
<p>
There are overloaded versions of <strong>validate</strong> methods that also take an
<abbr title="org.eclipse.emf.parsley.validation.IssueReporter">IssueReporter</abbr>
:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
/**
* Validates, reports diagnostics through the passed {@link IssueReporter}
* and returns the list of reported diagnostics.
*
* @param eObject
* @param reporter
* @return
*/
public List&lt;Diagnostic&gt; validate(EObject eObject, IssueReporter reporter) {
return reporter.report(validate(eObject));
}
/**
* Validates, reports diagnostics through the passed {@link IssueReporter}
* and returns the list of reported diagnostics.
*
* @param resource
* @param reporter
* @return
*/
public List&lt;Diagnostic&gt; validate(Resource resource, IssueReporter reporter) {
return reporter.report(validate(resource));
}
</pre>
<p>
</p>
<p>
The reporter is asked to report the collected diagnostic and it is expected to return
the list of issues effectively reported. For example, an issue reporter can
report only errors (e.g., diagnostic whose severity is <strong>Diagnostic.ERROR</strong>), while
ignoring warnings and other diagnostic information.
</p>
<p>
We provide a utility class that can be injected, <abbr title="org.eclipse.emf.parsley.validation.DiagnosticUtil">DiagnosticUtil</abbr>
,
with utility methods, like flattening diagnostic into a list (EMF diagnostic are typically nested in
a tree form), to quickly select only the errors, and to have a string representation.
</p>
<p>
The default implementation of <abbr title="org.eclipse.emf.parsley.validation.IssueReporter">IssueReporter</abbr>
is <abbr title="org.eclipse.emf.parsley.validation.DialogErrorReporter">DialogErrorReporter</abbr>
, which uses an EMF
dialog to report ONLY errors. Another implementation that can be used for testing purposes
is <abbr title="org.eclipse.emf.parsley.validation.LogIssueReporter">LogIssueReporter</abbr>
, which logs diagnostic using
the corresponding log4j methods (i.e., <strong>error</strong>, <strong>warn</strong>, <strong>info</strong>).
</p>
<p>
An example of use of the above classes can be found in <abbr title="org.eclipse.emf.parsley.resource.ValidateBeforeSaveStrategy">ValidateBeforeSaveStrategy</abbr>
(see section <a href="#ResourceSaveStrategy">Resource Save Strategy</a>):
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public class ValidateBeforeSaveStrategy extends ResourceSaveStrategy {
@Inject
private ValidationRunner validationRunner;
@Inject
private IssueReporter issueReporter;
@Override
public boolean save(Resource resource) throws IOException {
if (!precondition(resource)) {
return false;
}
return super.save(resource);
}
protected boolean precondition(Resource resource) {
return validationRunner.validate(resource, issueReporter).size() == 0;
}
}
</pre>
<p>
</p>
<p>
Thus, if you use a <abbr title="org.eclipse.emf.parsley.resource.ValidateBeforeSaveStrategy">ValidateBeforeSaveStrategy</abbr>
,
with the default Guice bindings, upon saving, if validation finds errors, it will
cancel the saving and it will show a dialog with errors.
</p>
</div>
</div>
</div>
<hr style="width:64.6%;margin-bottom:28px;margin-top:30px;" class="col-md-8 col-md-offset-3">
<div class="row featurette">
<div class="col-md-8 col-md-offset-3">
<h1 id="par" class="featurette-heading text-parsley">Advanced Features</h1>
<p>
In this chapter we describe some advanced features.
</p>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Testing Framework</h2>
<p>
We provide some utility classes for testing <strong>EMF Parsley</strong> components in the feature
"Emf Parsley Junit4 Support". By deriving from one of the abstract classes in our
testing bundle, you will be able to write tests that are meant to be run as Junit test,
that is to say, NOT as Plug-in Junit tests. Thus, you will not need a running Eclipse product
to execute such tests: they will be much faster. Indeed, many parts of Parsley can
be tested even without a running Eclipse.
</p>
<p>
</p>
<ul>
<li><abbr title="org.eclipse.emf.parsley.junit4.AbstractEmfParsleyTest">AbstractEmfParsleyTest</abbr>
: this provides
a few utility methods, e.g., for creating an <abbr title="com.google.inject.Injector">Injector</abbr>
.</li>
<li><abbr title="org.eclipse.emf.parsley.junit4.AbstractEmfParsleyShellBasedTest">AbstractEmfParsleyShellBasedTest</abbr>
: this allows
to run Junit tests that require a <abbr title="org.eclipse.swt.widgets.Display">Display</abbr>
and a
<abbr title="org.eclipse.swt.widgets.Shell">Shell</abbr>
.</li>
<li><abbr title="org.eclipse.emf.parsley.junit4.AbstractEmfParsleyControlBasedTest">AbstractEmfParsleyControlBasedTest</abbr>
: an extension
of the previous class for tests that also require databinding capabilities, e.g.,
tests for <abbr title="org.eclipse.swt.widgets.Control">Control</abbr>
elements; this provides many assert
methods for several kinds of controls, such as <strong>assertCheckbox</strong>, <strong>assertCombo</strong>, etc.</li>
</ul>
<p>
</p>
<p>
We use these classes for testing most of our classes; you might want to have a look
at the project <strong>org.eclipse.emf.parsley.tests</strong> for some usage examples.
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Eclipse 4.x</h2>
<p>
Instead of using the Extension Point mechanism, EMF Parsley leverages from DSL and Google Guice Injection.
</p>
<p>
Because of this, it is very easy to use it with Eclipse 4.x (e4).
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>First Example Setup</strong>
</p>
<p>
If you followed the steps described in section <a href="#addref" rel="First Example">First Example</a> you will have already
what we need to begin. Otherwise the following wizard will bring you to that point.
</p>
<p>
</p>
<ol>
<li>File -&gt; New... -&gt; Example...</li>
<li>from Category "Emf Parsley Examples", select "Emf Parsley First Example"</li>
<li>press Next and Finish</li>
</ol>
<p>
</p>
<p>
You will end up with three plug-ins:
</p>
<p>
</p>
<ul>
<li>org.eclipse.emf.parsley.examples.firstexample (the EMF Parsley example plug-in)</li>
<li>org.eclipse.emf.examples.library (the model plug-in)</li>
<li>org.eclipse.emf.examples.library.edit (the model.edit plug-in)</li>
</ul>
<p>
</p>
<p>
As a reminder, in section <a href="#addref" rel="First Example">First Example</a> we reached the point where we launched a second Eclipse
instance (but, of course, just defining a product you could have a standalone 3.x application) with a
view (called "My Library Tree Form") that allowed to manage the model.
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Preparing for a pure e4 Application</strong>
</p>
<p>
What we will do now is starting from the previous step and create an e4 Application (on top of
the previous plug-ins) that gets to the same result, but now with a pure e4 Part.
</p>
<p>
In order to do this we need to export the <strong>"org.eclipse.emf.parsley.examples.firstexample"</strong> package from the first plug-in.
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Create an e4 Application</strong>
</p>
<p>
Now let's create a new, empty, e4 application, e.g. <strong>"org.eclipse.emf.parsley.examples.firstexample.application"</strong>
(you can find details on how to create e4 applications in <a href="http://www.rcp-vision.com/?p=4694&lang=en">our
tutorials</a>).
</p>
<p>
Create a Part and ensure that the application starts.
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Using a TreeComposite into an e4 Part</strong>
</p>
<p>
In the just created plug-in we need dependencies from the previous plug-ins: so open the <strong>org.eclipse.emf.parsley.examples.firstexample.application/MANIFEST.MF</strong> file, go to <strong>Dependencies</strong>
tab and add the three previous plug-ins. Add also <strong>"org.eclipse.emf.parsley"</strong> plug-in.
Don't forget to add the previous, and the required plug-ins, also to the Product.
</p>
<p>
Open the Part java class and make the following changes:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
// Use these imports during Organizing Imports operation
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.swt.widgets.Composite;
// The part implements IMenuListener for context menu handling
public class MyEclipse4Part {
//the EMF Parley composite for showing a tree and a detail form
private TreeFormComposite treeFormComposite;
//the EMF Resource
private Resource resource;
//URI for EMF Resource
private URI uri = URI.createFileURI(System.getProperty("user.home")
+ "/MyLibrary.library");
</pre>
<p>
</p>
<p>
Modify the <strong>@PostConstruct</strong> method with this code:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@PostConstruct
public void postConstruct(Composite parent) throws Exception {
// Guice injector
private Injector injector = FirstexampleInjectorProvider.getInjector();
// The EditingDomain is needed for context menu and drag and drop
EditingDomain editingDomain = injector.getInstance(EditingDomain.class);
ResourceLoader resourceLoader = injector.getInstance(ResourceLoader.class);
//load the resource
resource = resourceLoader.getResource(editingDomain, uri).getResource();
TreeFormFactory treeFormFactory = injector.getInstance(TreeFormFactory.class);
//create the tree-form composite
treeFormComposite = treeFormFactory.createTreeFormComposite(parent, SWT.BORDER);
// Guice injected viewer context menu helper
ViewerContextMenuHelper contextMenuHelper = injector.getInstance(ViewerContextMenuHelper.class);
// Guice injected viewer drag and drop helper
ViewerDragAndDropHelper dragAndDropHelper = injector.getInstance(ViewerDragAndDropHelper.class);
// set context menu and drag and drop
contextMenuHelper.addViewerContextMenu(treeFormComposite.getViewer(), editingDomain);
dragAndDropHelper.addDragAndDrop(treeFormComposite.getViewer(), editingDomain);
//update the composite
treeFormComposite.update(resource);
}
</pre>
<p>
</p>
<p>
The Google Guice Injector (not to be confused with the Eclipse e4 Injector) is retrieved
using the injector provider class generated by the DSL compiler
(see also <a href="#InjectorProvider">Obtaining the Injector</a>).
</p>
<p>
If you now run the application you will be able to manage the model:
</p>
<p>
</p>
<img src="images/07-eclipse4-part.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
but you will notice that it is not possible to persist the changes to the model.
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Adding the dirty state and Save command</strong>
</p>
<p>
In order to allow persisting the model changes we have to add the dirty state handling to the part and
the Save command to the application.
Let's start with adding the following attribute to the part
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject
MDirtyable dirty;
</pre>
<p>
</p>
<p>
add to <strong>@PostConstruct</strong> method the following code in order to update the dirty state
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
editingDomain.getCommandStack().addCommandStackListener(
new CommandStackListener() {
public void commandStackChanged(EventObject event) {
if (dirty != null)
dirty.setDirty(true);
}
});
</pre>
<p>
</p>
<p>
and add the <strong>@Persist</strong> method, which will be called when the part is saved
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Persist
public void save(MDirtyable dirty) throws IOException {
resource.save(null);
if (dirty != null) {
dirty.setDirty(false);
}
}
</pre>
<p>
</p>
<p>
and, in the end, add the <strong>Save</strong> handler along with the correspondent <strong>Command</strong> and <strong>Menu</strong>
(you can find how to create handlers, commands and menus in an e4 applications in <a href="http://www.rcp-vision.com/?p=4972&lang=en">our
tutorials</a>)
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
import javax.inject.Named;
public class SaveHandler {
@Execute
void execute(EPartService partService, @Named(IServiceConstants.ACTIVE_PART) MPart part) {
partService.savePart(part, false);
}
}
</pre>
<p>
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">RAP</h2>
<p>
As you may know <a href="http://eclipse.org/rap/">RAP (Remote Application Platform)</a> is a technology that allows you to run an Eclipse RCP application over the web.
</p>
<p>
In order to obtain this goal you have to setup a specific RAP Target Platform, for instance the one that RAP itself provides once you install it.
</p>
<p>
However when you want to use an Eclipse RCP framework over the RAP Platform, you generally have to deal with
dependencies, since not all Eclipse frameworks are ready-to-use with RAP, especially those related with the SWT layer.
</p>
<p>
EMF Parsley provides a proper RAP Target Platform that allows you to start leveraging Parsley potentials to the web the same way you have
learned to do with desktop (RCP) development.
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Installing the RAP Tools</strong>
</p>
<p>
To begin with, you need to install the RAP Tools into the IDE.
This can be accomplished with the following steps:
</p>
<ol>
<li>Help -&gt; Install New Software ...</li>
<li>select the main Eclipse Update site</li>
<li>expand category "Web, XML, Java EE and OSGi Enterprise Development"</li>
<li>select "RAP Tools" and complete the installation, restarting the IDE at the end</li>
<li>after IDE restarts just close the Welcome page</li>
</ol>
<p>
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Setup the EMF Parsley RAP Target Platform</strong>
</p>
<p>
After having installed EMF Parsley as described <a href="https://www.eclipse.org/emf-parsley/download.html">here</a> and
created a new workspace, you can setup the EMF Parsley RAP Target Platform in the following way:
</p>
<ol>
<li>File -&gt; New... -&gt; Example...</li>
<li>from Category "Emf Parsley Examples", select "Emf Parsley Rap Target Platform Example"</li>
<li>press Next and Finish</li>
<li>open the Target Definition file <strong>emf-parsely-rap.target</strong></li>
<li>wait until the "Resolving Target Definition" job is done (check the status bar)</li>
<li>when finished, click on hyperlink "Set as Target Platform"</li>
</ol>
<p>
</p>
<p>
You will end up with a RAP-enabled workspace, enhanced by EMF and Parsley!
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Running the Parsley RAP UI Example</strong>
</p>
<p>
Here is the fastest way to get a working web application with all the stuff put togheter:
</p>
<ol>
<li>File -&gt; New... -&gt; Example...</li>
<li>from Category "Emf Parsley Examples", select "Emf Parsley Rap Example"</li>
<li>press Next and Finish</li>
<li>expand plug-in <strong>"org.eclipse.emf.parsley.examples.rap.ui"</strong></li>
<li>right-click "Emf_Parsley_RAP_UI_Example.launch" and click "Run as" "Emf_Parsley_RAP_UI_Example"</li>
</ol>
<p>
</p>
<p>
What you will get is a web application that allows you to interact with the model instance as you would
do in a desktop (RCP) environment.
</p>
<p>
</p>
<img src="images/08-rap-ui-example-running.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
In this web application you can see two views:
</p>
<ul>
<li>the one on the left is a read-only view; it just reflects the model content, but it does not react to changes (the classic Eclipse dirty indicator is not triggered
by changes) and you are not able to save. Its model is created in class <strong>org.eclipse.emf.parsley.examples.rap.ui.GuiceModule.CustomResourceManager</strong>
and is not persisted</li>
<li>the view on the right is instead a Saveable view and therefore it not only triggers the dirty state after
a change, but also allows you to save the modifications with the automatic dirty state reset. Its model
is persisted in file <strong>System.getProperty("java.io.tmpdir")+"/My.model")</strong></li>
</ul>
<p>
</p>
<p>
Of course, since this is a web application, you can also open a browser on another pc or device on the same network and type the address,
replacing 127.0.0.1 with the IP of the machine where the application was launched.
</p>
<p>
</p>
<ol>
</ol>
<p>
</p>
<p>
<strong>Running the Parsley RAP CDO Example</strong>
</p>
<p>
The EMF default XMI persistence is certainly very handy to start with, but as soon as you want a more
production-ready EMF persistence architecture, well, <a href="http://wiki.eclipse.org/CDO">CDO</a> is for sure the way to go.
In fact with CDO you basically have an EMF model instance shared between clients, that also allows the
clients to be synchronized with the model changes.
</p>
<p>
In this example, in order to keep things simple, we will use CDO with an in-memory store (MEMStore) whose contents will be lost once the server is stopped.
However CDO can be configured for usage with RDBMS, Object-oriented or NO-SQL databases (see <a href="http://eclipse.org/cdo/documentation/">here</a> for details)
</p>
<p>
To start with we need a CDO Server running and we can obtain it with an example plugin that can be used
both in an RCP and in a RAP workspace.
</p>
<p>
</p>
<ol>
<li>File -&gt; New... -&gt; Example...</li>
<li>from Category "Emf Parsley Examples", select "Emf Parsley Cdo Server Example"</li>
<li>press Next and Finish</li>
<li>expand plug-in <strong>"org.eclipse.emf.parsley.examples.cdo.server"</strong></li>
<li>right-click "CDOServerExample.launch" and click "Run as" "CDOServerExample"</li>
<li>a message on the Console <strong>"Repository[demo] started!"</strong> informs that the CDO Server instance
is started!</li>
</ol>
<p>
</p>
<p>
Now we can create the web application that will use the CDO server just started.
</p>
<p>
</p>
<ol>
<li>File -&gt; New... -&gt; Example...</li>
<li>from Category "Emf Parsley Examples", select "Emf Parsley Rap Cdo Example"</li>
<li>press Next and Finish</li>
</ol>
<p>
</p>
<p>
The plug-in projects created are:
</p>
<p>
</p>
<ul>
<li>the Model (org.eclipse.emf.parsley.examples.cdo.model)</li>
<li>a Parsley plug-in with a TreeForm (org.eclipse.emf.parsley.examples.cdo.treeform)</li>
<li>the webapp (org.eclipse.emf.parsley.examples.cdo.rap)</li>
</ul>
<p>
</p>
<p>
Then let's start the application
</p>
<p>
</p>
<ol>
<li>expand plug-in <strong>"org.eclipse.emf.parsley.examples.cdo.rap"</strong></li>
<li>right-click "EMF-Parsley_Library_RAP.launch" and click "Run as" "EMF-Parsley_Library_RAP"</li>
</ol>
<p>
</p>
<p>
If you happen to see this
</p>
<p>
</p>
<img src="images/08-rap-refresh.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
just press the refresh button and should see the following
</p>
<p>
</p>
<img src="images/08-rap-cdo-1.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
<p>
Now feel free to open the same address from more browsers window (yes, on different machines or devices, possibly)
and see the power of this technology stack at work!
</p>
<p>
</p>
<img src="images/08-rap-cdo-2.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;">
<p>
</p>
</div>
</div>
</div>
<hr style="width:64.6%;margin-bottom:28px;margin-top:30px;" class="col-md-8 col-md-offset-3">
<div class="row featurette">
<div class="col-md-8 col-md-offset-3">
<h1 id="par" class="featurette-heading text-parsley">Migration Guide</h1>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">From 0.6.0 to 0.7.0</h2>
<p>
</p>
<ul>
<li><strong>Multiple DSL files in the same project</strong>: thanks to the radical change to the structure
of EMF Parsley projects, detailed in the following, it is now possible to define several
<strong>.parsley</strong> files in the same project.</li>
<li><strong>Structure of projects</strong>: the structure of EMF Parsley projects has radically changed
(see <a href="#DslProjectStructure">The structure of an EMF Parsley project</a>).
If you have existing projects you need to perform these steps to adjust the compilation errors you will
get:<ol>
<li>Remove the executable extension factory class from the <strong>src</strong> folder (the DSL will now generate it in the
<strong>emfparsley-gen</strong> source folder)
<img src="images/project-migration-exec-ext-fact.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;"></li>
<li>Remove the guice module from the <strong>src</strong> folder, in the example above, it is <strong>FirstexampleGuiceModule</strong></li>
<li>Modify the activator: instead of extending <strong>EmfParsleyAbstractActivator</strong> it must extend the
standard <abbr title="org.eclipse.ui.plugin.AbstractUIPlugin">AbstractUIPlugin</abbr>
; then remove the method<pre class="prettyprint" skin="desert">
public EmfParsleyGuiceModule createModule()
</pre></li>
<li>Manually remove all the contents of the <strong>emfparsley-gen</strong> folder (the name of the generated
classes are now prefixed with the module name, but the previously generated ones might still be there)
<img src="images/project-migration-clean-gen.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;"></li>
<li>Perform a "clean" on the project (so that the contents of <strong>emfparsley-gen</strong> are generated)</li>
<li>Read the next part about <strong>plugin.xml</strong></li>
</ol></li>
<li><strong>The plugin.xml and the new EMF Parsley builder</strong>: the way we handle the
<strong>plugin.xml</strong> has improved, and we also automatically merge subsequent changes in the
DSL file <strong>parts</strong> section. Please have a look at <a href="#PluginXml">How the DSL handles the plugin.xml</a> for
the details.IMPORTANT: This merging takes place ONLY if your project has the <strong>EMF Parsley builder nature</strong>.
Since version 0.6.1 this nature is automatically applied to the projects created with our wizard.
In existing projects, you have to enable the nature yourself by right-clicking on the project,
then "Configure" and then "Enable EMF Parsley builder.Once you added this new nature, please remove the <strong>plugin.xml_emfparsley_gen</strong> from the root
of your project, and perform a clean of the project.</li>
<li><strong>InjectorProvider</strong>: the activator generated by the project wizard does not provide
anymore a means to retrieve the injector. This functionality is now implemented by an <strong>InjectorProvider</strong>
class which is automatically generated for each DSL module (see <a href="#InjectorProvider">Obtaining the Injector</a>).For example, in the first example,
<a href="#addref" rel="First Example">First Example</a>, instead of doing<pre class="prettyprint" skin="desert">
FirstexampleActivator.getDefault().getInjector();
</pre>you need to do<pre class="prettyprint" skin="desert">
FirstexampleInjectorProvider.getInjector();
</pre></li>
</ul>
<p>
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">From 0.5.0 to 0.6.0</h2>
<p>
</p>
<ul>
<li>The way we handle the <abbr title="org.eclipse.emf.edit.domain.EditingDomain">EditingDomain</abbr>
is
changed and improved to some extent. In standard scenarios this should not
require any modifications. In advanced scenarios this will provide complete
control on the editing domain. We refer to the new section in the documentation,
<a href="#addref" rel="Editing Domain">Editing Domain</a>.</li>
<li><strong>Tree With Columns</strong>: a new component has been added:The <strong>Tree With Columns Component</strong> provides a tree representation just like <a href="#addref" rel="Tree Component">Tree Component</a>,
but it also shows table columns representing the features of the specified <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
.IMPORTANT: the <abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
is used to retrieve the features to be shown, and
NOT to filter elements to be shown (as opposite to the <a href="#addref" rel="Table Component">Table Component</a>). If a given
row in the tree represents an object whose class does not have the feature for a given column, then the
corresponding table cell for that object will be empty.For example, the following screenshot shows a tree with columns representing a library; the specified
<abbr title="org.eclipse.emf.ecore.EClass">EClass</abbr>
is the <strong>Writer</strong> so the columns show the features of the
<strong>Writer</strong>'s class. Some of these features, e.g., <strong>address</strong>, <strong>firstName</strong> and <strong>lastName</strong>, are defined
in the superclasses of <strong>Writer</strong>. The objects of class <strong>Employee</strong> have these features as well, while
they don't have features that are specific of <strong>Writer</strong>, e.g., <strong>name</strong> and <strong>books</strong>, thus the corresponding
cells for employees will be empty.<img src="images/03-components-treecolumns.png" class="img-responsive centered" style="margin-top:10px;margin-bottom:10px;"><strong>EMF Parsley</strong> provides a factory that can be used to create such a component, like in the code below:<pre class="prettyprint" skin="desert">
@Inject ViewerFactory viewerFactory;
(...)
treeViewer = createTreeViewerWithColumns(parent, getEClass(), getContents());
</pre>Since this component mixes the features of a tree and a table, the customizations are basically the
same shown in the subsections of <a href="#addref" rel="Tree Component"></a> and <a href="#addref" rel="Table Component"></a>.</li>
<li><strong>EmfSelectionHelper</strong> only deals with selection element; utility methods for events is now
delegated to <strong>EmfEventHelper</strong>.</li>
<li>label provider for trees and table label providers for tables can now specify declaratively custom
fonts, foreground and background colors.For tables, you can customize the font, foreground and background color for the entire row or for a single
cell.Here are some examples:<pre class="prettyprint lang-parsley" skin="desert">
labelProvider{
...
font {
Book -&gt; // must return a org.eclipse.swt.graphics.Font
}
foreground {
Book -&gt; // must return a org.eclipse.swt.graphics.Color
}
background {
Book -&gt; // must return a org.eclipse.swt.graphics.Color
}
}
</pre><pre class="prettyprint lang-parsley" skin="desert">
tableLabelProvider {
...
font {
Library : name -&gt; JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT)
}
foreground {
Library : books -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)
}
background {
Library : address -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_GREEN)
}
rowFont {
Library -&gt; JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT)
}
rowForeground {
Library -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)
}
rowBackground {
Library -&gt; Display.getCurrent().getSystemColor(SWT.COLOR_GREEN)
}
}
</pre></li>
</ul>
<p>
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">From 0.4 to 0.5</h2>
<p>
</p>
<ul>
<li><strong>ViewerInitializer</strong> has been removed: all creation and initialization of viewers
is performed using <abbr title="org.eclipse.emf.parsley.viewers.ViewerFactory">ViewerFactory</abbr>
; its API has been
revised and simplified.</li>
<li>the packages <strong>factories</strong> and <strong>builders</strong> have been removed
and their classes have been moved to other packages.
If you get compiler errors, a simple "Organize Imports" should fix
the imports. If you use the DSL a simple regeneration should fix things.</li>
<li><strong>IViewerMouseListener</strong> has been moved from the <strong>listeners</strong>
package to the <strong>viewers</strong> package.</li>
<li>classes in <strong>editor.outline</strong> have been moved into <strong>editors</strong>
package.</li>
<li>The creation of caption labels for forms and dialogs has slightly
changed, concerning the default behavior
(<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=472691">https://bugs.eclipse.org/bugs/show_bug.cgi?id=472691</a>):
we take the text from <abbr title="org.eclipse.emf.edit.provider.IItemPropertyDescriptor">IItemPropertyDescriptor</abbr>
if
the EObject provides it. (This does not happen for table column headers, since we don't have
any EObject when we build the table columns).
If you used to call this method on a
<abbr title="org.eclipse.emf.parsley.ui.provider.FormFeatureCaptionProvider">FormFeatureCaptionProvider</abbr>
or
<abbr title="org.eclipse.emf.parsley.ui.provider.DialogFeatureCaptionProvider">DialogFeatureCaptionProvider</abbr><pre class="prettyprint" skin="desert">
public Label getLabel(Composite parent, EClass eClass, EStructuralFeature feature)
</pre>be warned that this method has changed its signature into<pre class="prettyprint" skin="desert">
public Label getLabel(Composite parent, EObject o, EStructuralFeature feature)
</pre>and of course also its semantics, since you need to pass an EObject not its EClass.</li>
<li>a new method is available in <abbr title="org.eclipse.emf.parsley.edit.action.EditingMenuBuilder">EditingMenuBuilder</abbr>
,
<strong>actionChange</strong>: If you want to implement more complex menu commands that do not
only add elements to a container, you can use the method
<strong>actionChange</strong>, specifying the label for the menu, the model's element
that will be affected by the changes specified as a lambda expression
(the third argument). The lambda expression will also get the specified
model's element as argument. (This is related to
<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=475188">https://bugs.eclipse.org/bugs/show_bug.cgi?id=475188</a>).
Please also have a look at the updated documentation of section <a href="#addref" rel="Contextual Menu">Contextual Menu</a>:
the already existing <strong>actionAdd</strong> should be used with care, since it might leave the model
with dangling references -- with that respect we also updated the first example
<a href="#addref" rel="First Example">First Example</a>, so that
it uses <strong>actionChange</strong> to implement correctly what we used to achieve with <strong>actionAdd</strong>.</li>
<li>Adding context menu to a viewer has been extremely simplified
(<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=455727">https://bugs.eclipse.org/bugs/show_bug.cgi?id=455727</a>):
A context menu can be added to any <abbr title="org.eclipse.jface.viewers.StructuredViewer">StructuredViewer</abbr>
by using an
injected <abbr title="org.eclipse.emf.parsley.menus.ViewerContextMenuHelper">ViewerContextMenuHelper</abbr>
. This provides some
methods for adding the context menu<pre class="prettyprint" skin="desert">
@Inject ViewerContextMenuHelper contextMenuHelper;
(...)
// simplest form
contextMenuHelper.addViewerContextMenu(viewer);
// if you have an AdapterFactoryEditingDomain already
contextMenuHelper.addViewerContextMenu(viewer, editingDomain);
// if you're inside an IWorkbenchPart
contextMenuHelper.addViewerContextMenu(viewer, editingDomain, part);
</pre></li>
<li>Drag and drop support has been separated from context menu support
(<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=475914">https://bugs.eclipse.org/bugs/show_bug.cgi?id=475914</a>):
thus, adding context menu does NOT automatically add drag and drop.Drag and drop can be added to any <abbr title="org.eclipse.jface.viewers.StructuredViewer">StructuredViewer</abbr>
by using an
injected <abbr title="org.eclipse.emf.parsley.edit.ui.dnd.ViewerDragAndDropHelper">ViewerDragAndDropHelper</abbr>
,
using its methods <strong>addDragAndDrop</strong>.</li>
<li>Saveable table views and table views reacting on selection
do not require an implementation of the method
<strong>getContents()</strong>, which has also been removed from the API, from the
<abbr title="org.eclipse.emf.parsley.config.Configurator">Configurator</abbr>
methods, and from
the <strong>configurator</strong> section in the DSL: contents retrieval is completely
delegated to the new <abbr title="org.eclipse.emf.parsley.edit.ui.provider.TableViewerContentProvider">TableViewerContentProvider</abbr>
,
whose default implementation is able to automatically retrieve all the
contents of a given type (i.e., EClass) automatically.
The DSL provides the new <strong>tableViewerContentProvider</strong> specification,
see the new section <a href="#TableViewerContentProvider">Table Viewer Content Provider</a>.</li>
<li>Similarly, table views reacting on selection
do not require an implementation of the method
<strong>getEStructuralFeature()</strong>: they require an implementation of
<strong>getEClass()</strong> which specifies the type of the objects to be
shown in the table.
<strong>getEStructuralFeature()</strong> has also been removed from the API, from the
<abbr title="org.eclipse.emf.parsley.config.Configurator">Configurator</abbr>
methods, and from
the <strong>configurator</strong> section in the DSL: contents retrieval is not
performed using a feature (which is limitative): it is completely
delegated to the new <abbr title="org.eclipse.emf.parsley.edit.ui.provider.TableViewerContentProvider">TableViewerContentProvider</abbr>
,
whose default implementation is able to automatically retrieve all the
contents of a given type (i.e., EClass) automatically.</li>
</ul>
<p>
</p>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">From 0.3 to 0.4</h2>
<p>
</p>
<ul>
<li><strong>EmptyResourceInitializer</strong> has been removed: you should now use
<abbr title="org.eclipse.emf.parsley.resource.ResourceManager">ResourceManager</abbr>
,
see section <a href="#ResourceManager">Resource Manager</a></li>
<li><strong>ResourceSaveManager</strong> has been removed: you should now use
<abbr title="org.eclipse.emf.parsley.resource.ResourceSaveStrategy">ResourceSaveStrategy</abbr>
,
see section <a href="#ResourceSaveStrategy">Resource Save Strategy</a></li>
<li>Project wizards have been redesigned: they generate a <strong>module.parsley</strong>
that uses the <strong>configurator</strong> for specifying required information
(see section <a href="#addref" rel="Configurator">Configurator</a> and the updated
first example, section <a href="#addref" rel="First Example">First Example</a>)</li>
</ul>
<p>
</p>
</div>
</div>
</div>
</br></br></br></br></br></br></br>
<!-- /END THE FEATURETTES -->
</div>
<!-- FOOTER -->
<footer style="z-index: 1001;position:relative;background-color:#35414C;-webkit-box-shadow: 0px -3px 8px 0px rgba(171,209,173,1);-moz-box-shadow: 0px -3px 8px 0px rgba(171,209,173,1);box-shadow: 0px -3px 8px 0px rgba(30,51,72,1);margin-top:1.3%;">
<img width="100%" alt="" src="img/footer.jpg" />
<nav class="navbar navbar-default" role="navigation" style="background-color:transparent; border:0 none; margin:-97px 0px 31px 0px;min-height: 36px;">
<div class="container" style="width:37.6%;">
</div>
</nav>
<nav class="navbar navbar-default" role="navigation" style="background-color:transparent; border:0 none; margin:-18px 0px 0px 0px;min-height: 36px;">
<div class="container" style="width:57%;">
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-4">
<ul class="nav navbar-nav miolifooter">
<li><a href="index.html">Home</a></li>
<li><a href="download.html">Download</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="sources.html">Sources</a></li>
<li><a href="support.html">Support</a></li>
<li style="border-right: 0 none;"><a href="userReviews.html">UserReviews</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div>
</nav>
<p class="terms" style="margin:0px;padding:21px 0px 6px 20px;"><a target="_blank" href="http://www.eclipse.org/legal/privacy.php">Privacy Policy</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp;<a target="_blank" href="http://www.eclipse.org/legal/termsofuse.php">Terms of Use</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp;<a target="_blank" href="http://www.eclipse.org/legal/copyright.php">Copyright Agent</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp;<a target="_blank" href="http://www.eclipse.org/legal/">Legal</a><a class="pull-right" style="z-index: 1001;position:relative;margin:-38px 4% 0px 0px;" href="#top" id="topbutton"><img alt="Back to top" src="img/arrow_up.png"/></a></p>
</footer>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<!--<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>-->
<script src="js/vendor/jquery.min.js"></script>
<script src="js/vendor/jquery.scrollstop.js"></script>
<script src="js/vendor/bootstrap.min.js"></script>
<!-- Open lightbox-content image -->
<script type="text/javascript">
$('.featurette-image').click(function(){
$('.lightbox-content').empty();
$($(this).parents('div').html()).appendTo('.lightbox-content');
$('#myModal').modal({show:true});});
</script>
<script type="text/javascript">
$('#twitterli').mouseover(function() {
$('a#twitterli > img').attr('src','img/twitter_h1.png');
});
$('#twitterli').mouseout(function() {
$('a#twitterli > img').attr('src','img/twitter.png');
});
$('#twitterfooter').mouseover(function() {
$('a#twitterfooter > img').attr('src','img/twitter_h2.png');
});
$('#twitterfooter').mouseout(function() {
$('a#twitterfooter > img').attr('src','img/twitter.png');
});
$('#topbutton').mouseover(function() {
$('a#topbutton > img').attr('src','img/arrow_up_h.png');
});
$('#topbutton').mouseout(function() {
$('a#topbutton > img').attr('src','img/arrow_up.png');
});
$('.scrollup').mouseover(function() {
$('a.scrollup').css('opacity', '1');
});
$('.scrollup').mouseout(function() {
$('a.scrollup').css('opacity', '0.35');
});
//gestione scroll verticale
$(function() {
$('a[href*=#]').click(function() {
if(this.hash=="#top"){
$('html,body').animate({scrollTop:0}, 800);
return false;
} else {
var arrivo = $(this.hash);
if (arrivo.length) {
arrivo=arrivo.offset().top;
$('html,body').animate({scrollTop:arrivo-205}, 500);
return false;
}
}
});
});
$(window).scroll(function() {
var y = $(this).scrollTop();
if (y < 800)
$('a.scrollup').fadeOut();
else
$('a.scrollup').fadeIn();
});
//prevscroll
var prevscroll = 0;
$(window).on("scrollstop", function() {
var scrollposition = $('html,body').scrollTop()+210;
if(/chrome/.test(navigator.userAgent.toLowerCase()))
scrollposition = $("body").scrollTop()+210;
var mieipar = $("[id^='par']");
mieipar.each(function(idx) {
if(idx==mieipar.length-1 && scrollposition>=$(this).offset().top){
var parid = $(this).attr('id').match(/\d+/);
$('.activemenu').removeClass("activemenu");
$("a[href='#par"+parid+"']").parent().addClass("activemenu");
} else if(scrollposition>=$(this).offset().top && scrollposition<mieipar.eq(idx + 1).offset().top){
var parid = $(this).attr('id').match(/\d+/);
$('.activemenu').removeClass("activemenu");
$("a[href='#par"+parid+"']").parent().addClass("activemenu");
}
});
//inizio prevscroll
//Gestione scroll del menu laterale in base alla posizione della pagina
var menuScrollSize = '-250px';
var pageScrollThreshold = 16730;
if($(window).height()<$(".dropdown-menu").height()+190){
if(prevscroll<scrollposition){
if(scrollposition>pageScrollThreshold)
$(".dropdown-menu").css('top', menuScrollSize);
} else
$(".dropdown-menu").css('top', '0px');
prevscroll=scrollposition;
} else if($(".dropdown-menu").css('top')!=null && $(".dropdown-menu").css('top')==menuScrollSize){
$(".dropdown-menu").css('top', '0px');
}
//fine prevscroll
});
$(document).ready(function() {
//Setto link attivo nel menu
var mieili = $('.miomenu li');
mieili.each(function(idx) {
var indirizzo = $(this).children().attr('href');
if(indirizzo!=null && indirizzo.length>0 && (window.location.href.indexOf(indirizzo)>0 || (window.location.href=='http://www.eclipse.org/emf-parsley/' || window.location.href=='https://www.eclipse.org/emf-parsley/' && indirizzo.indexOf('index')>0))){
$(this).addClass('mioactive');
return false;
}
});
//Setto link attivo nel footer
mieili = $('.miolifooter li');
mieili.each(function(idx) {
var indirizzo = $(this).children().attr('href');
if(indirizzo!=null && indirizzo.length>0 && (window.location.href.indexOf(indirizzo)>0 || (window.location.href=='http://www.eclipse.org/emf-parsley/' || window.location.href=='https://www.eclipse.org/emf-parsley/' && indirizzo.indexOf('index')>0))){
$(this).children().addClass('mioactivefooter');
return false;
}
});
//Setto gli indici per l'effertto hover del dropdown-menu
var mieiidx = $(".dropdown-menu a[href='#par']");
var mieipar = $("[id^='par']");
mieiidx.each(function(idx) {
$(this).attr('href','#par'+idx);
if(idx<mieipar.length)
mieipar.eq(idx).attr('id','par'+idx);
});
//Setto le references #addref
var mieiaddref = $("a[href='#addref']");
mieiaddref.each(function(idx) {
var ref = $(".dropdown-menu a:contains("+$(this).attr('rel')+")").attr('href');
if(ref!=null && ref.length>0)
$(this).attr('href',ref);
});
});
//Levo il blur da tutti i link
$("a").focus(
function () {
if ($(this).blur) $(this).blur();
}
);
$('#questiondiv').mouseover(function() {
$('#questiondiv').css('background-color','#D7EFDA');
});
$('#questiondiv').mouseout(function() {
$('#questiondiv').css('background-color','#e8f9ea');
});
$('#bugdiv').mouseover(function() {
$('#bugdiv').css('background-color','#F0F2C6');
});
$('#bugdiv').mouseout(function() {
$('#bugdiv').css('background-color','rgb(246, 247, 227)');
});
$('#suppdiv').mouseover(function() {
$('#suppdiv').css('background-color','#E8E8E8');
});
$('#suppdiv').mouseout(function() {
$('#suppdiv').css('background-color','rgb(242, 242, 242)');
});
$('#twdiv').mouseover(function() {
$('#twdiv').css('background-color','#CFE5F7');
});
$('#twdiv').mouseout(function() {
$('#twdiv').css('background-color','#e8f3fc');
});
</script>
<script type="text/javascript" src="google-code-prettify/lang-common.js"></script><script type="text/javascript">
registerLanguage('import|module|parts|labelProvider|text|image|elements|label|featuresProvider|features|formControlFactory|control|target|viewerContentProvider|tableViewerContentProvider|children|viewpart|viewname|viewclass|viewcategory|for|new|switch|default|boolean|do|if|this|double|throw|null|true|false|it|as|byte|else|case|enum|instanceof|return|featureCaptionProvider|formFeatureCaptionProvider|dialogFeatureCaptionProvider|val|var|catch|extends|int|short|try|char|void|finally|long|float|super|while|proposals|dialogControlFactory|menuBuilder|menus|emfMenus|resourceManager|initializeResource|saveResource|configurator|resourceURI|eClass|bindings|type|provide|value|font|foreground|background|tableLabelProvider|rowFont|rowForeground|rowBackground', 'emfparsley');
</script>
</body>
</html>