# First Example

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.

So let's start by creating the model plug-in with

1. File -> New... -> Example...
2. from Category "Eclipse Modeling Framework", select "Extended Library Model Example"
3. press Next and Finish

You will end up with three plug-ins:

- org.eclipse.emf.examples.library (the model plug-in)
- org.eclipse.emf.examples.library.edit (the edit plug-in)
- org.eclipse.emf.examples.library.editor (the editor plug-in)

The editor plug-in project can be removed.

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).

Now you can create your first example with the appropriate wizard.

1. select "File" -> "New" -> "Project..."
2. from the "EMF Parsley" category select "EMF Parsley Dsl based Project"
3. click "Next"
4. 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
5. click "Next"
6. Select "Saveable Tree Form View"
7. click "Finish"

The generated project has some classes and a module.parlsey file, which opens automatically:

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 -> {
// 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
}
}
}

The viewpart corresponds to the standard Eclipse view part extension point; the Parsley DSL will handle the generation and update of the plugin.xml file. Please have a look at How the DSL handles the plugin.xml for further details.

The wizard will also generate a view part class into the project (in this example, FirstexampleSaveableTreeFormView); you can add other controls into that view, or customize other behaviors. Note that the Parsley DSL will never touch the files into the src source folder. On the contrary, files generated into emfparsley-gen source folder must never be manually modified, since its contents will be regenerated each time you modify the module.parsley file.

For example, let's change the view name into "My Library Tree Form":

...
module org.eclipse.emf.parsley.examples.firstexample {
parts {
viewpart org.eclipse.emf.parsley.examples.firstexample {
viewname "My Library Tree Form"
...

Let's save the file, wait for Eclipse to rebuild, and update the plugin.xml with the new plugin.xml_emfparsley_gen.

(Other viewpart sections can be created; content assist is available for that).

In the generated module.parsley, there is a configurator section, with a TODO comment (The Configurator is detailed in the section Configurator):

configurator {
resourceURI {
FirstexampleSaveableTreeFormView -> {
// TODO create and return a org.eclipse.emf.common.util.URI
return null;
}
}
}

Let's focus on the above resourceURI: our goal is allowing to manage a library model instance which persists on a EMF Resource (src). So we must specify the URI (src) 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 "MyLibrary.library" 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):

configurator {
resourceURI {
FirstexampleSaveableTreeFormView -> {
return URI.createFileURI( System.getProperty("user.home") + "/MyLibrary.library" );
}
}
}

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 URI (src)).

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).

In the module.parsley there is another section that has been generated by the wizard:

resourceManager {
initializeResource {
// Optional: initialize an empty Resource
// 'it' is of type Resource
// e.g., it.getContents += myFactory.createMyClass
}
}

We can use this section to initialize our resource when it is empty (i.e., the first time the resource is created); (The resourceManager is detailed in section Resource Manager).

In this example, we want to initialize an empty resource with a Library object; so we first need a Dependency from the model plug-in: so open MANIFEST.MF file, go to Dependencies tab, press "Add..." button in "Required Plug-ins" section and insert "org.eclipse.emf.examples.library" among dependencies.

Now we can implement the initializeResource method (as described in the comment, the Resource (src) to initialized is available through the parameter it); the Library object is created using the standard EMF API: we need the factory of the library model:

resourceManager {
initializeResource {
it.getContents += EXTLibraryFactory.eINSTANCE.createLibrary
}
}

Again, use the content assist while typing, e.g., for automatically importing the type EXTLibraryFactory, or use the "Organize Imports" functionality.

Now, we are ready to execute this example: let's get back to the MANIFEST.MF and run the example

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).

In this second Eclipse instance you can show the View in this way:

1. Window -> Show View -> Other...
2. from Category "Other", select "My Library Tree Form"
3. press OK

With this simple view you can start editing the model instance. For example you can set the "name" field; as soon as you start typing characters into this field you will notice that:

1. the View turns to a "dirty" state (an asterisk symbol appears on the view tab)
2. the "Save" toolbar button is enabled
3. the typed characters are reflected into the label correspondent to the Library icon

if you now perform a "Save" action the persistence mechanism will trigger and you will see that file <user.home>/MyLibrary.library 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.

To create a Writer into the Library just right-click on the Library object and select New Child -> Writer

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. "Writers Writer" instead of "Writer", "Stock Book" instead of "Book" and similar (this is because with EMF it is possible to customize labels also via .edit plugin).

Now set for instance the writer "name" 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.

Whenever the current selection on the upper side of the view changes, then the lower side shows the detail of this selection.

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 "name" attribute for the Library and "name", "address" and "books" attributes for Writers and maybe "title", "authors" and "category" for Books.

Well, it's indeed very easy to obtain this: just edit the module.parsley file, adding the following import (without ending line with ";")

import org.eclipse.emf.examples.extlibrary.*

and then defining the features to show (the featuresProvider is detailed in section Features Provider):

module ... {
...
featuresProvider {
features {
Library -> name
Writer -> name, address, books
Book -> author, title, category
}
}
}

Remeber that code completion is available, just exploit it since it helps a lot.

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.

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.

Do you want to change text used for attribute captions in the form for a specific class? Just add the following (featureCaptionProvider is detailed in section Feature Caption Provider):

...
featureCaptionProvider {
text {
Book : author -> "Written by:"
Writer : name -> "Name:"
}
}

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? (labelProvider is detailed in section Viewer Label Provider):

...
labelProvider {
text {
Book b -> { '"' + b.title + '"' }
Writer w -> { w.name }
}
}

The result of all the above customizations is shown in the following screenshot (compare it with the previous screenshot):

Now, let's customize the context menus; by default, Parsley will generate context menus using EMF.Edit:

We will now customize the context menu for books and writers, using the menuBuilder in the DSL (context menu customization is detailed in section Contextual Menu).

What we want to achieve is to have a context menu for a Writer to add a new book in the library, and set its author to the selected writer (similarly, we want a context menu for a Book to add a new writer in the library, and set the selected book as one of the new writer's books):

...
menuBuilder {
val factory = EXTLibraryFactory.eINSTANCE
emfMenus {
Writer w -> #[
actionChange("New book", w.eContainer as Library,
[
library |
val book = factory.createBook
library.books += book
book.title = "A new book"
book.author = w
]
),
]
Book b -> #[
actionChange("New writer", b.eContainer as Library,
[
library |
val writer = factory.createWriter
library.writers += writer
writer.name = "A new writer"
writer.books += b
]
)
]
}
}

In this code we use Xbase features like list literals (#[...]) and lambda expressions. We use actionChange that allows to specify a menu performing some actions on the model's elements, keeping track of such changes so that they can be undone -- redo will work as well. The implementation of the menu is specified in the lambda expression passed as the last argument of actionChange; this lambda will receive as argument the model's element specified as the second argument. Only those modifications performed in the lambda concerning such specified model's element will be recorded for undo/redo.

If you now restart the application, you see that the new context menu appears on writer elements:

And selecting such a menu on a writer will add a new book, with a title, and whose author is the selected writer:

You may want to try the new context menu on a book as well.

We also add another context menu for books, using actionAdd: specifying the label for the menu, the containment list in the model, the object to add in such list and a lambda expression that will be executed ONLY after the menu has been selected. In this example, this menu available for a book object will add a new book to the library with the same name of the selected book:

...
menuBuilder {
val factory = EXTLibraryFactory.eINSTANCE
emfMenus {
// ... as above
Book b -> #[
actionChange(
// ... as above
),
actionAdd("New book (same title)",
(b.eContainer as Library).books,
factory.createBook,
[title = b.title]
)
]
}
}

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 Viewer Content Provider):

...
viewerContentProvider {
children {
Library -> {
writers + books
}
}
}

and the result can be seen in the following screenshot:

By default, double-clicking on a tree viewer of a saveable view will show a dialog to edit that object (if you customized the featuresProvider, 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:

Such a strategy for editing is delegated to an injected IEditingStrategy (src), which is implemented by default by OnTheFlyEditingStrategy (src).

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 UndoableEditingStrategy (src), in the Guice module. This can be achieved in the DSL using the binding section (Guice bindings are detailed in section Guice Bindings):

...
bindings {
type IEditingStrategy -> UndoableEditingStrategy
}

We strongly suggest you use the content assist to discover default bindings, since they also show Javadoc for each default binding:

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

...
bindings {
type IEditingStrategy -> UndoableEditingStrategy
value int TreeFormSashStyle -> SWT.HORIZONTAL
}

and see the result:

This ends the first tutorial.