We had EMF generated model classes and a Util class with lot of helper methods. Both were exposed to clients as an API. Most of the methods in the Util classes were like:
//API - Util class
Book getBook(Writer writer, String title);
//Customer code
Util.getBook(daveSteinberg, "Eclipse Modeling Framework");
These methods would have been more appropriate in the Writer class itself rather than in a Util class, and it will be more natural to code like:
daveSteinberg.getBook("Eclipse Modeling Framework");
This tip is about how to add such methods in the generated code.
The first way is simple. Just edit the generated java code and add these methods. EMF is smart enough to identify this method and keeps it safe during regeneration of code. But if you were like me, who consider the generated Java files are as good as class files and don't want them checked into the repository, you can follow the second way.
In the eCore Editor for your model, right click the EClass and add a new child EOperation.
Go to the Properties view and specify the name, this will be the name of your method. The EType represents the return type of the method.
If your method has any parameters, then add EParameter children to the EOperation & specify their types and names.

To add the code, add an EAnnotation to the EOperation.
In the properties view, set the Source to "http://www.eclipse.org/emf/2002/GenModel".
Add a details entry to the EAnnotation.
In the properties view set the key to 'body' and value to the code that you want to be generated.
Reload your .genmodel from .ecore and generate the code:
May 5, 2008
Adding util methods to the generated EMF classes
Posted by
Prakash G.R.
at
10:26 PM
0
comments
Labels: eclipse, EMF, guidelines
May 3, 2008
Single column TableViewer and TableColumnLayout
If you have a single column TableViewer (which is commonly used because ListViewer won't show you the images), the single coloumn won't take the entire space. For example if you run the TableViewer snippet, the output is like this:
To get rid of the other spurious coloum that appears on the right, you have to use the TableColumnLayout. Modifying the code to use that:
public Snippet001TableViewer(Shell shell) {
Composite tableComposite = new Composite(shell, SWT.NONE);
final TableViewer v = new TableViewer(tableComposite);
v.setLabelProvider(new LabelProvider());
v.setContentProvider(new MyContentProvider());
MyModel[] model = createModel();
v.setInput(model);
v.getTable().setLinesVisible(true);
TableColumn singleColumn = new TableColumn(v.getTable(), SWT.NONE);
TableColumnLayout tableColumnLayout = new TableColumnLayout();
tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(100));
tableComposite.setLayout(tableColumnLayout);
}
Remember, the TableColumnLayout should be applied on the composite that holds the Table. And the composite should contain only the table and nothing else. Here is the result:
Posted by
Prakash G.R.
at
12:58 PM
0
comments
Labels: guidelines, jface, swt
Apr 24, 2008
Save hours of EMF coding ...
Questions:
- How would you perform a deep copy an EObject with all it references?
- How would you resolve all the proxies of an EObject?
- How would you find whether one EObject is a child of other (directly/indirectly)?
- How would you get the root containder of a given EObject?
These are common problems which you would face in your EMF code. Before you try to write the generic code using powerful EMF reflections, resist yourself. Somehow in between posting 5 millionth news group message and shooting 100k photographs (both the numbers are my guess, and true values should be more than that :-P ), Ed Merks finds time to do all that work for us. This nice solution, which is available in EMF itself: ECoreUtil.
Take a look at the other methods in the class. Will surely come handy sometimes.
Posted by
Prakash G.R.
at
3:27 PM
0
comments
Labels: EMF
Apr 23, 2008
Window Title in an RCP app
In Eclipse IDE, you can see the window title in the format: perspective - editPart name - Eclipse SDK - workspace. But in an RCP app, the title is usually the Product Name defined in the *.product file. This tip explains how to change it dynamically like IM clients - where the window title should be product name - user name.
Window title is *not* set on the IWorkbenchWindow. You need to do it on the IWorkbenchWindowConfigurer.
Whenever the user performs a login/logout, you need to set the window title. The details are sketchy, as its left to you whether to pass the instance of the windowConfigurer to the Login/LogoutAction or implement some sort of event listener for login/logout and do the title change there. But in general:
IWorkbenchWindowConfigurer windowConfigurer = ...;
String title = Platform.getProduct().getName();
if(loggedIn)
title = title + " - " + userName;
windowConfigurer.setTitle(title);
In case you were wondering where to get the instance of the windowConfigurer, it will be passed to your application thru the WorkbenchAdvisor.createWorkbenchWindowAdvisor() method.
Posted by
Prakash G.R.
at
10:40 AM
0
comments
Labels: guidelines, RCP
Apr 1, 2008
Content type Specific File icons
Eclipse 3.4 M6 is out. It has lots of wonderful features like p2 and the installer. But one small change that is going to save a lot of developers time is the content type specific file icons. Earlier if I had to contribute an icon for a specific file, I've to write my own label decorator. Now Eclipse comes with a label decorator that does the same.
All you have to do is to define the content type and associate an editor with that content type. If you were wondering writing an editor is not a trivial task, don't worry, you can reuse the existing ones.
Assume that in my app, I have some files with extension 'config'. They are nothing but normal properties files. I would like to invoke the Properties editor on this extension and give a different icon. Here is how I create a new content type for the extension associated the Properties editor for that.
<extension point="org.eclipse.core.contenttype.contentTypes">
<content-type base-type="org.eclipse.core.runtime.properties"
file-extensions="config"
id="in.cypal.eclipse.myConfig"
name="My Config File"
priority="normal">
</content-type>
</extension>
<extension point="org.eclipse.ui.editors">
<editor class="org.eclipse.jdt.internal.ui.propertiesfileeditor.PropertiesFileEditor"
default="false"
extensions="config"
icon="icons/sample.gif"
id="in.cypal.eclipse.editors.myConfigEditor"
name="My Config Editor">
<contentTypeBinding contentTypeId="in.cypal.eclipse.myConfig">
</contentTypeBinding>
</editor>
</extension>
Content types are not just based on file names/extensions. If you have an xml file, you can use the XMLContentDescriber to find the content type based on the root element; create an editor extension; specify the Text Editor/XML Editor class; associate the content id and add the icon to the editor. You are done. All of this without writing a single line of code!
Mar 18, 2008
Exporting GEF figure to an image
Quite often you need to export the current contents of a GEF editor to an image. Here is the simple code to do that:
GraphicalViewer graphicalViewer = ...; // get it from your editor
String saveLocation = ...; // get it thru a FileDialog
ScalableFreeformRootEditPart rootEditPart = (ScalableFreeformRootEditPart) graphicalViewer.getEditPartRegistry().get(LayerManager.ID);
IFigure rootFigure = ((LayerManager) rootEditPart).getLayer(LayerConstants.PRINTABLE_LAYERS);
Rectangle rootFigureBounds = rootFigure.getBounds();
Control figureCanvas = graphicalViewer.getControl();
Image img = new Image(Display.getDefault(), rootFigureBounds.width, rootFigureBounds.height);
GC imageGC = new GC(img);
figureCanvas.print(imageGC); // This is Eclipse 3.4 only API
ImageLoader imgLoader = new ImageLoader();
imgLoader.data = new ImageData[] { img.getImageData() };
imgLoader.save(saveLocation, SWT.IMAGE_JPEG);
imageGC.dispose();
img.dispose();
Just in case you need, here is a nice image
to represent this Action :-)
Posted by
Prakash G.R.
at
10:44 PM
3
comments
Labels: gef
Mar 15, 2008
How does EMF finds the right parser?
ResourceSet resourceSet = new ResourceSetImpl();
Resource resource = resourceSet.createResource(someUri);
The API can't get any simpler. But the implementation details behind this is not simple. Resources are generally loaded by Resource.Factory. Your ECore model would have generated an appropriate Factory. You can find it in the util package with the name {your model name}ResourceFactoryImpl. Lets take a journey from the ResourceSet to this Factory.
ResourceSetImpl class delegates the job of finding the right Factory to the Resource.Factory.Registry. The default implementation of the registry (ResourceFactoryRegistryImpl) tries to find the factory by:
* lookup in the protocol map for the uri
* lookup in the extension map for the uri
* lookup in the content type map for the uri
* lookup in the extension map for the default extension (*)
* lookup in the content type map for the default content type (*)
If the above lookups did not find a factory then the delegatedGetFactory() method is called.
All three maps (protocol, extension & content type) are by default empty in the ResourceFactoryRegistryImpl. Either you can subclass and initialize in your constructor or call the resourceFactory.get{map type}ToFactoryMap().put({key}, {value}) to add your entries.
Since we have not added any entries in the registry, the delegatedGetFactory() method is called. The ResourceSetImpl overrides that method (thru an anonymous subclass of ResourceFactoryRegistryImpl) and calls again the getFactory() method with the maps from Resource.Factory.Registry.INSTANCE. BTW, all three maps in that instance are filled with the details from the extension points:
org.eclipse.emf.ecore.protocol_parser
org.eclipse.emf.ecore.extension_parser
org.eclipse.emf.ecore.content_parser
You should be using these extensions to register the right parser (the generated ResourceFactoryImpl) for your resource.
Phew! If you think its done, you should look into the EMF code. All the above said stuff are optimized to the core. The ResourceSetImpl creates the ResourceFactoryRegistryImpl instance only when the getResourceFactoryRegistry() is called for the first time; all the above lookups are performed only when the map is not empty; and so on. EMF takes all the pain and finally we end up with:
ResourceSet resourceSet = new ResourceSetImpl();
Resource resource = resourceSet.createResource(someUri);
See, you got to love EMF. Or in general, Eclipse for making our life easier :-)
Related:
EMF Packing changes in 2.4
Using EMF with XML Catalog
Converting EMF Resource to Platform Resource (IFile)
Posted by
Prakash G.R.
at
9:18 PM
0
comments
