The project implementation is just a simplified extract from our own code (we have Subversion integration and a lot of stuff that is only relevant to our product). We would probably be better off using the Project API / Filesystem API, but I didn't have the time to look into that.
The EMF version is 2.5.0. The generated EMF classes come from the EXTLibrary example from the EMF plugin in Eclipse, which models a simple book library. The model and its generated Eclipse editors can be tested in Eclipse (for reference) by opening up the projects under model/emfworkspace.
Note: A project has been requested under a BSD license at https://nb-emf.dev.java.net for further development of the example discussed in this article. Until the project is approved, you can get the source code for this article by clicking here.
- EmfNbm (Platform Application)
- - branding (branding module)
- - lib (external libraries)
- - model (standard Java project)
- - project (main module)
- - wrapper-model (wrapper to bring the model into the model suite)
The steps below outline the general approach taken in creating the example described above.
- Create a standard Java project in NetBeans with the following source folders:
- model/emfworkspace/org.eclipse.emf.examples.library/src: the actual model files
- model/emfworkspace/org.eclipse.emf.examples.library.edit/src: the "edit" classes / item providers
The third folder, org.eclipse.emf.examples.library.editor is Eclipse specific and can't be used in NetBeans. I've included the code anyway since it is good for reference of how things are done in Eclipse.
I created a standard Java project instead of a NetBeans Platform module because of the multiple source roots (platform modules do not support this). (I could of course have created a platform module for each of the source roots, but that is not all straight forward since NetBeans is not too helpful when importing from external project models.)
- Create a library wrapper module for the model project. Modify the build script and the project metadata to make it work:
- Override the "release" target in the build file to manually copy the jar file from the model project
- Change the <class-path-extension> in the project metadata to point to the jar file of the model project
A weakness of using a wrapper like this, is that changes to the class files in the model project won't be detected when compiling the module suite. So it has to be built manually and then the wrapper needs to be cleaned.
Move plugin.properties in the "edit" project from the root folder into the source folder. This file is used for providing texts for the model.
The class EXTLibraryEditPlugin has been modified to reflect this change. (It is the class that all generated item providers delegate to when looking up resources.)
Create a ModuleInstaller in the "project" module that registers a dummy registry provider for Equinox. It also boots up the transaction and validation plugins and loads our generated model.
Create the class emfnbm.project.Project. It is a simple class that is used to load and save XML files (with a custom extension that is registered in the static constructor of the class), and to provide an adapter factory and an editing domain.
Also create the class emfnbm.project.ProjectManager which is used to manage a single open project. (Could probably use the Project API for this, but we still haven't found time to check it out.)
The main node implementation is emfnbm.nodes.EmfNode. It uses the AdapterFactory from the Project to get/adapt labels, icons, children and property descriptors, and it has support for drag and drop. It uses cookie sets and should probably be rewritten to using Lookups directly instead.
The drag and drop support reveals a problem in TreeView which can be noteworthy. Check out the following bug report (which sadly has never been addressed):
I have also supplied a general purpose FilterNode implementation that uses EMF predicates to determine the visibility of children. I haven't created a usage example yet, but have a look at the comments in EmfFilterNode#updateChildren() and EmfFilterNode#createNodeListener() in regards to correctly switching the children factory from LEAF to a regular factory.