blob: 9b289940e95a6940cb4dd6a8d08af3b179bcef49 [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>
</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><a class="submenu" tabindex="-1" href="#par">Customize</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 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">Factories</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 class="divider"></li>
<li><a tabindex="-1" href="#par">RAP</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Introduction</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Setup</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Examples</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#par">Eclipse 4.x</a></li>
<li><a class="submenu" tabindex="-1" href="#par">First Example Setup</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Preparing for a pure e4</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Application</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Create an e4 Application</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Using a TreeComposite</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;into an e4 Part</a></li>
<li><a class="submenu" tabindex="-1" href="#par">Adding the dirty state</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;and Save command</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.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>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Customize</h2>
<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, currently the following are permitted:
</p>
<p>
</p>
<ul>
<li><strong>parts</strong> lets you define your View Parts: a file <strong>plugin.xml_emfparsley_gen</strong> will be generated
that is meant to be synchronized with your own <strong>plugin.xml</strong></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>
</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 generate a <strong>plugin.xml_emfparsley_gen</strong>
into the root folder of your project. Just copy this file into <strong>"plugin.xml"</strong>. Parsley
will never override your <strong>plugin.xml</strong> file; each time you modify the module file, the
<strong>plugin.xml_emfparsley_gen</strong> will be generated: it is up to you to keep the generated file
synchronized with your <strong>"plugin.xml"</strong>. The easiest way is to select to the files,
and use the context menu "Compare With" =&gt; "Each Other".
</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; "Wrote by:"
Writer : name -&gt; "Name:"
}
}
</pre>
<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>
<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>).
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; #[
actionAdd(
"New book",
(w.eContainer as Library).books,
factory.createBook,
[ book |
book.title = "A new book"
book.author = w
]
)
]
Book b -&gt; #[
actionAdd(
"New writer",
(b.eContainer as Library).writers,
factory.createWriter,
[ 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.
</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>
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>
</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 rapresentation 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 an initializer that can be used to create such a component, like in the code below.
Here you can see that can be configured only in 2 lines, the constructor phase and the build&amp;fill phase.
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject ViewerInitializer viewerInitializer;
(...)
treeViewer = new TreeViewer(parent);
viewerInitializer.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 rapresentation 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 the ViewerInitializer, 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 rapresentation 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.
</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, object, 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 context menu can be added to the viewer via the ViewerInitializer, 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>
</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="RAP">EMF Parsley RAP support</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 Prorvider 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.
</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"
}
}
</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 <strong>(TODO)</strong>.
<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.
</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 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.
<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">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>
<pre class="prettyprint lang-parsley" skin="desert">
featureCaptionProvider{
text{
Book:author -&gt; "Wrote 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 <strong>TODO (see Injection paragraph)</strong>, to customize the caption label on the
left of each control in a form 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 "Wrote by:";
}
public String text_Writer_name(final EStructuralFeature feature) {
return "Name:";
}
</pre>
<p>
</p>
</br>
<h3 class="featurette-heading text-parsley2">Form Feature Caption Provider<a id="FormFeatureCaptionProvider"></a></h3>
<p>
The <abbr title="org.eclipse.emf.parsley.ui.provider.FormFeatureCaptionProvider">FormFeatureCaptionProvider</abbr>
can be used if you want
to define the description only for the form. 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 control, 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>
If there is no customization in the <abbr title="org.eclipse.emf.parsley.ui.provider.FormFeatureCaptionProvider">FormFeatureCaptionProvider</abbr>
we fall back to <abbr title="org.eclipse.emf.parsley.ui.provider.FeatureCaptionProvider">FeatureCaptionProvider</abbr>
.
</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 viewer by using the <abbr title="org.eclipse.emf.parsley.menus.ViewerContextMenuHelper">ViewerContextMenuHelper</abbr>
.
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@Inject ViewerInitializer viewerInitializer;
(...)
treeActionBarContributor.initialize(editingDomain);
viewerInitializer.addContextMenu(treeFormComposite.getViewer(),
treeActionBarContributor, editingDomain, this);
treeFormComposite.getViewer().addSelectionChangedListener(treeActionBarContributor);
</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. In the <strong>emfMenus</strong> section, you can use
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>
IMPORTANT: do not initialize any reference feature of the created EObject
upon object creation; 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,
// WRONG: don't do that
EXTLibraryFactory.eINSTANCE.createBook =&gt; [
author = w
]
)
]
}
</pre>
<p>
</p>
<p>
Since the object is created when the contextual menu is created, NOT
when the menu is selected; if you do something like in the code above,
you will end up with a resource with dangling references (which cannot be
saved).
</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,
// CORRECT: the lambda will be executed when the menu
// is selected and the object has been added to
// the resource
[ book | book.author = w ]
)
]
}
</pre>
<p>
</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">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;
}
/**
* Returns the {@link EStructuralFeature} for the requestor
* @param requestor
* @return
*/
public EStructuralFeature eStructuralFeature(Object requestor) {
return null;
}
/**
* Returns the contents from the resource for the requestor
* @param requestor
* @param resource
* @return
*/
public Object contents(Object requestor, Resource resource) {
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>getContents</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 Object contents(MyView1 view1, Resource resource) {
return ...;
}
public Object contents(MyOtherView view, Resource resource) {
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>, while additional parameters can be accessed through their names,
as named in the original <abbr title="org.eclipse.emf.parsley.config.Configurator">Configurator</abbr>
class, e.g., <strong>resource</strong> for <strong>contents</strong>):
</p>
<p>
</p>
<pre class="prettyprint lang-parsley" skin="desert">
module my.project {
configurator {
resourceURI {
MyTreeFormView -&gt; {
return ...;
}
}
eClass {
MyTreeView -&gt; {
return ...;
}
}
eStructuralFeature {
MyTreeFormView -&gt; {
return ...;
}
MyFormView -&gt; {
return ...;
}
}
contents {
MyTreeView -&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 {
contents {
MyView -&gt; {
// TODO return the contents from the resource
// e.g., resource.^contents.get(0)
}
}
eClass {
MyView -&gt; {
// TODO return the EClass to represent
}
}
resourceURI {
MyView -&gt; {
// TODO create and return a org.eclipse.emf.common.util.URI
return null;
}
}
eStructuralFeature {
MyView -&gt; {
// TODO return the EStructuralFeature to get the elements to represent
}
}
}
}
</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>
</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">RAP</h1>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Introduction</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>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Setup</h2>
</br>
<h3 class="featurette-heading text-parsley2">Installing the RAP Tools<a id="installRapTools"></a></h3>
<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 (e.g. <strong>"http://download.eclipse.org/releases/luna"</strong>)</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>
</br>
<h3 class="featurette-heading text-parsley2">Setup the EMF Parsley RAP Target Platform<a id="rapSetTargetPlatform"></a></h3>
<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-2.3.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>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Examples</h2>
</br>
<h3 class="featurette-heading text-parsley2">Running the Parsley RAP UI Example<a id="rapFirstExample"></a></h3>
<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.CustomEmptyResourceInitializer</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>
</br>
<h3 class="featurette-heading text-parsley2">Running the Parsley RAP CDO Example<a id="rapCdoExample"></a></h3>
<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">Eclipse 4.x</h1>
<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>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">First Example Setup</h2>
<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>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Preparing for a pure e4 Application</h2>
<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>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Create an e4 Application</h2>
<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>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Using a TreeComposite into an e4 Part</h2>
<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 implements IMenuListener
//the parent composite
private Composite parent;
//the EMF Parley composite for showing a tree and a detail form
private TreeFormComposite treeFormComposite;
//the EMF Resource
private Resource resource;
//Guice injected EMF Parsley component for contributing to the tree context menu
private TreeActionBarContributor treeActionBarContributor = FirstexampleActivator.getDefault().getInjector()
.getInstance(TreeActionBarContributor.class);
//Guice injected EMF Parsley factory for the tree detail form
private TreeFormFactory treeFormFactory = FirstexampleActivator.getDefault().getInjector()
.getInstance(TreeFormFactory.class);
//Guice injected EMF Parsley Resource loader
private ResourceLoader resourceLoader = FirstexampleActivator.getDefault().getInjector()
.getInstance(ResourceLoader.class);
//Guice injected EMF Parsley editing domain
private AdapterFactoryEditingDomain editingDomain = FirstexampleActivator.getDefault().getInjector()
.getInstance(AdapterFactoryEditingDomain.class);
//Guice injected viewer initializer
private ViewerInitializer viewerInitializer = (ViewerInitializer) FirstexampleActivator.getDefault().getInjector()
.getInstance(ViewerInitializer.class);
//Guice injected save manager
private ResourceSaveManager resourceSaveManager = FirstexampleActivator.getDefault().getInjector()
.getInstance(ResourceSaveManager.class);
//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) {
this.parent = parent;
// Initialize TreeFormFactory &amp; ResourceLoader
init(treeFormFactory, resourceLoader);
// Prepare the menu action bar contributor upon the selection
treeFormComposite.getViewer().addSelectionChangedListener(treeActionBarContributor);
}
</pre>
<p>
</p>
<p>
and add the following methods:
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
public void init(TreeFormFactory treeFormFactory, ResourceLoader resourceLoader) {
//create the tree-form composite
treeFormComposite = treeFormFactory.createTreeFormMasterDetailComposite(parent, SWT.BORDER);
//load the resource
resource = resourceLoader.getResource(editingDomain, uri).getResource();
//update the composite
treeFormComposite.update(resource);
//initialize and bind the context menu to the tree-form composite
treeActionBarContributor.initialize(editingDomain);
viewerInitializer.addContextMenu(
treeFormComposite.getViewer(), treeActionBarContributor, editingDomain, this);
}
@Override
public void menuAboutToShow(IMenuManager manager) {
treeActionBarContributor.menuAboutToShow(manager);
}
</pre>
<p>
</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>
</div>
</br>
<div >
<h2 id="par" class="featurette-heading text-parsley1">Adding the dirty state and Save command</h2>
<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 dirtyable;
</pre>
<p>
</p>
<p>
initialize it in the <strong>@PostConstruct</strong> method
</p>
<p>
</p>
<pre class="prettyprint" skin="desert">
@PostConstruct
public void postConstruct(Composite parent, MDirtyable dirtyable) {
this.dirtyable = dirtyable;
this.dirtyable.setDirty(false);
</pre>
<p>
</p>
<p>
add to <strong>init</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 (dirtyable != null)
dirtyable.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 {
if (resourceSaveManager.save(resource)) {
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">
public class SaveHandler {
@Execute
void execute(EPartService partService, @Named(IServiceConstants.ACTIVE_PART) MPart part) {
partService.savePart(part, false);
}
}
</pre>
<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.4 to 0.5</h2>
<p>
</p>
<ul>
<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>
</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 style="border-right: 0 none;"><a href="support.html">Support</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|featuresProvider|features|formControlFactory|control|target|viewerContentProvider|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|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|eStructuralFeature|contents|bindings|type|provide|value', 'emfparsley');
</script>
</body>
</html>