Galileo: EMF-Databinding – Part 3


Setting up a TreeViewer with EMF-Databinding

The RCP-Application
With this article we are starting to write our RCP-Application which uses Eclipse-Databinding. I’m not going into detail how you create an RCP-Application (I simply use the PDE-Wizard) but assume that you are familiar with this kind of thing.

Still I’d like to describe the application design and the reason behind decisions I made a bit. The first and most important thing is that I’m not a fan of EditorPart and I think for none-file resources the IEditorInput stuff simply doesn’t make a lot of sense so all applications I’ve written since I develop RCP are ViewParts.

A misconception I often see when I say that my RCP-Applications are free from editors is that people ask: “How are you going to be part of Workbench-Dirty/Save-Lifecyle if you use a ViewPart?”.

The answer is quite simple the only thing you have to do is to make your ViewPart implement ISaveablePart2 and then your view is part of the workbench-dirty state lifecycle.

Application Parts

The screen shot from above shows that how the applications UI code is broken up in smaller logical parts:

  • ProjectAdminViewPart:
    This is the main UI area which is subclassing ViewPart and registered into the workbench usin the views-Extension-Point.
  • ProjectExplorerPart:
    This class makes up the left part of the application showing a TreeViewer to select project, create subprojects, … . The internals of this part are described in more detail in this blog post later on.
  • ProjectFormAreaPart:
    This class makes up the right upper part showing a set of input controls who act as a detail part of the ProjectExplorerPart. The internals of this part are explained in detail in Part 4 of this blog series.
  • ProjectCommittersPart:
    This class makes up the right lower part showing a TableViewer. The internals of this part are explained in detail in Part 5 of this blog series.

Before we dive into the main topic of this blog post I’d like to show some interesting code found inside the ProjectAdminViewPart because it shows some interesting RCP features and introduces a small but often forgotten databinding stuff leading to memory leaks in conjunction with databinding.

Restoring view state information
The first interesting thing is that the content of the main area is created using a SashForm to give the user the possibility to define how much space the left part should occupy. The user naturally expects that when he starts the application the next time that the UI comes up in the same state it’s been when shutting down so we need to store the sash-weights when shutting down and restore them on the next start up.

The Eclipse-RCP-Framework provides a possibility to make this happen by using an IMemento to persist informations across application launches the only thing you to do is to use the API:

public class ProjectAdminViewPart 
  extends ViewPart implements ISaveablePart2
{
  private float divider = 0.2f;
  private SashForm sashForm;

  @Override
  public void init(final IViewSite site, IMemento memento) 
    throws PartInitException
  {
    super.init(site, memento);
    if (memento != null 
      && memento.getFloat(DIVIDER_KEY) != null)
    {
      divider = memento.getFloat(DIVIDER_KEY);
    }

    listener = new PartListenerImpl(site);
    site.getPage().addPartListener(listener);
  }

  @Override
  public void saveState(IMemento memento)
  {
    super.saveState(memento);
    int total = sashForm.getWeights()[0] 
                       + sashForm.getWeights()[1];
    memento.putFloat(
      DIVIDER_KEY, 
      sashForm.getWeights()[0] * 1.f / total);
  }

  @Override
  public void createPartControl(Composite parent)
  {
    // ...
    sashForm = new SashForm(parent, SWT.HORIZONTAL);
    // ...
    int left = (int)(100 * divider);
    sashForm.setWeights(new int []{ left, 100 - left });
  }
}

Avoid listener leaking
There’s something I very often see in databinding code from various people (even those who have a lot of databinding knowledge) is that they are not diposing their observables once not more needed which leads to memory leaks. This means that we have to remember all observables created and dispose them manually when not needed any more.

An exception to this are observables created for SWT-Widgets because they dispose themselves when the SWT-Widget is disposed but for all others the rule is the one who created it has to dispose it. Databinding provides a class named ObservablesManager which helps you with this.

In 3.5 EMF-Databinding added new API to ObservableManager which would make collecting observables very easy but apparently a bug was found very late in the release cycle and so the API is not useable currently. The API in question is used like this:

ObservablesManager mgr = new ObservablesManager();
mgr.runAndCollect(new Runnable()
  {
    public void run()
    {
      // your code which creates observables
    }
  });

Though the default API is broken for EMF-Databinding we can add an easy fix so that the API at least collects all IEMFObservable so that we only have to deal with things like ComputedValue and such stuff because as stated above SWT-Observables dispose themselves when the SWT-Widget is disposed.

So our code looks like this:

  @Override
  public void createPartControl(Composite parent)
  {
    // ...
    /* 
     * Track the creation of observables so that we 
     * don't leak listeners when the view part is closed
     */
    mgr = new EMFObservablesManager();
    defaultMgr = new ObservablesManager();
    mgr.runAndCollect(new Runnable()
      {

        public void run()
        {
          projectExplorer = new ProjectExplorerPart(
            getViewSite(), 
            sashForm, 
            toolkit, 
            resource.getFoundation(), 
            defaultMgr);

          projectDataForm = new ProjectFormAreaPart(
            getViewSite(),
            sashForm,
            toolkit,
            resource,
            defaultMgr,
            projectExplorer.getProjectObservable());
        }
      });
    // ...
  }

Setting up a TreeViewer
Enough about the generic stuff and let’s now concentrate on the main topic of this blog.
Project Explorer
Though I guess most of you know how to set up a standard TreeViewer here a short description:

  1. Set a CellLabelProvider: Responsible to translate the model object into a visual representation (text,colors,image,…). The CellLabelProvider-API was introduced in 3.3 and on top it JFace provides many cool new features like StyledText-Support (different fonts and colors in one cell) and ToolTip-Support. It’s worth revisiting your old code and replace LabelProvider through CellLabelProvider subclasses
  2. Set an ITreeContentProvider: Responsible to translate the input into a tree-structure.
  3. Set an input: Any input the ITreeContentProvider can handle

Createing the content provider
The Eclipse-RCP-Platform comes with a plugin named org.eclipse.jface.databinding which provides databinding support and implementation classes for SWT and JFace controls. One of those classes is ObservableListTreeContentProvider which is a class implementing the ITreeContentProvider and makes setting up an observed tree quite easily.

The ObservableListTreeContentProvider can’t do all the work on its own but expects us to provide it helper classes:

  • TreeFactory: responsible to create IObservableLists to observe the childitems of a treenode
  • TreeStructureAdvisor: responsible to provide informations on how to access the model parent of an item and helping to make the decision if an item has child-items

Looking at the picture above shows us that our structure is a bit of an virtual one when we compare it to the domain instance where we would only see the project-subprojects relation on the first sight.
Project Class
Our viewer though displays to different multi-value features as children in the Tree:

  • subprojects whose elements are of type Project
  • committerships whose elements are of type CommitterShip

Displaying different Object-Types was not supported in 3.4 and is a new feature in the new Databinding implementation as well as the possibility to combine 2 multi-value features into a single observable list which is for me personally one of the coolest features in the Properties-API.

  private static class TreeFactoryImpl 
    implements IObservableFactory
  {
    private IEMFListProperty multi = EMFProperties.multiList(
      ProjectPackage.Literals.PROJECT__SUBPROJECTS,
      ProjectPackage.Literals.PROJECT__COMMITTERS);

    public IObservable createObservable(final Object target)
    {
      if (target instanceof IObservableList)
      {
        return (IObservable)target;
      }
      else if (target instanceof Project)
      {
        return multi.observe(target);
      }

      return null;
    }
  }

  private static class TreeStructureAdvisorImpl 
    extends TreeStructureAdvisor
  {
    @Override
    public Object getParent(Object element)
    {
      if (element instanceof Project)
      {
        return ((Project)element).getParent();
      }

      return null;
    }

    @Override
    public Boolean hasChildren(Object element)
    {
      if (element instanceof Project 
        && (
          ((Project)element).getCommitters().size() > 0 
          || ((Project)element).getSubprojects().size() > 0
        )
      )
      {
        return Boolean.TRUE;
      }
      return super.hasChildren(element);
    }
  }

and used like this

private TreeViewer init(Composite parent, 
  Foundation foundation)
{
  TreeViewer viewer = new TreeViewer(parent);
  ObservableListTreeContentProvider cp = 
    new ObservableListTreeContentProvider(
      new TreeFactoryImpl(), 
      new TreeStructureAdvisorImpl()
  );
  viewer.setContentProvider(cp);
  
  // rest of viewer setup
}

Createing the CellLabelProvider
To get such a nice looking tree we can’t use a simple CellLabelProvider (e.g. ColumnLabelProvider is a simple implementation of it) but need one with more features. Another CellLabelProvider implementation is the StyledCellLabelProvider which uses owner-draw to draw StyledText-Strings in the tree.

JFace-Databinding doesn’t provide an implementation for StyledCellLabelProvider out of the box so I had to write my own one but that’s not too hard. The only thing which has to be done is to attach a listener to IObservableMap(s) to observe attributes of all tree elements and update the viewer if one of them changes.

private class TreeLabelProviderImpl 
  extends StyledCellLabelProvider
{
  private IMapChangeListener mapChangeListener = 
    new IMapChangeListener()
    {
      public void handleMapChange(MapChangeEvent event)
      {
        Set<?> affectedElements = 
          event.diff.getChangedKeys();
        if (!affectedElements.isEmpty())
        {
          LabelProviderChangedEvent newEvent = 
            new LabelProviderChangedEvent(
              TreeLabelProviderImpl.this, 
              affectedElements.toArray()
          );
          fireLabelProviderChanged(newEvent);
        }
      }
    };

  public TreeLabelProviderImpl(
    IObservableMap... attributeMaps)
  {
    for (int i = 0; i < attributeMaps.length; i++)
    {
      attributeMaps[i].addMapChangeListener(
        mapChangeListener
      );
    }
  }

  @Override
  public String getToolTipText(Object element)
  {
    return "#dummy#";
  }

  @Override
  public void update(ViewerCell cell)
  {
    if (cell.getElement() instanceof Project)
    {
      Project p = (Project)cell.getElement();

      StyledString styledString = new StyledString(
        p.getShortname()!=null ? p.getShortname():"*noname*",
        null
      );
      String decoration = " (" + 
        p.getCommitters().size() + " Committers)";
      styledString.append(
        decoration, 
        StyledString.COUNTER_STYLER
      );
      cell.setText(styledString.getString());
      cell.setImage(projectImage);
      cell.setStyleRanges(styledString.getStyleRanges());
    }
    else if (cell.getElement() instanceof CommitterShip)
    {
      Person p = (
        (CommitterShip)cell.getElement()
      ).getPerson();
      String value = "*noname*";
      if (p != null)
      {
        value = p.getLastname() + ", " + p.getFirstname();
      }
      StyledString styledString = new StyledString(
        value, null);
      cell.setText(styledString.getString());
      cell.setForeground(
        cell.getControl().getDisplay().getSystemColor(
          SWT.COLOR_DARK_GRAY
        )
      );
      cell.setImage(committerImage);
      cell.setStyleRanges(styledString.getStyleRanges());
    }
  }
}

and used like this

private TreeViewer init(Composite parent, 
  Foundation foundation)
{
  TreeViewer viewer = new TreeViewer(parent);
  ObservableListTreeContentProvider cp = 
    new ObservableListTreeContentProvider(
      new TreeFactoryImpl(), 
      new TreeStructureAdvisorImpl()
  );
  viewer.setContentProvider(cp);

  IObservableSet set = cp.getKnownElements();
  IObservableMap[] map = new IObservableMap [4];

  map[0] = EMFProperties.value(
    ProjectPackage.Literals.PROJECT__SHORTNAME
  ).observeDetail(set);

  map[1] = EMFProperties.value(
    ProjectPackage.Literals.PROJECT__COMMITTERS
  ).observeDetail(set);

  map[2] = EMFProperties.value(
      FeaturePath.fromList(
        ProjectPackage.Literals.COMMITTER_SHIP__PERSON,
        ProjectPackage.Literals.PERSON__FIRSTNAME)
      ).observeDetail(set);

  map[3] = EMFProperties.value(
      FeaturePath.fromList(
        ProjectPackage.Literals.COMMITTER_SHIP__PERSON, 
        ProjectPackage.Literals.PERSON__LASTNAME)
      ).observeDetail(set);

  viewer.setLabelProvider(new TreeLabelProviderImpl(map));
  // Further viewer setup

The last step is to set the input of the viewer which has to be an IObservableList which is in our example all top-level projects who are restored in the foundation instance.

IEMFListProperty projects = EMFProperties.list(
  ProjectPackage.Literals.FOUNDATION__PROJECTS
);
viewer.setInput(projects.observe(foundation));

There is even more code in the ProjectExplorerPart e.g. a customized ColumnViewerToolTipSupport to create the nice looking ToolTips when hovering items of the tree as well as some RCP-Code to allow plugin.xml to contribute a context menu but that’s standard JFace and RCP code.

This entry was posted in EMF, Tutorials. Bookmark the permalink.

39 Responses to Galileo: EMF-Databinding – Part 3

    • Marc says:

      Thanks for this nice tutorial Tom.

      I recently just got into the Adapter implementation in the rcp, meaning instead of creating my own Label-/Contentprovide I use
      viewer.setContentProvider(new BaseWorkbenchContentProvider());
      viewer.setLabelProvider(new WorkbenchLabelProvider());

      Is it possible to utilize the features from the CellLabelProvider.

      And one more thing. Databing is often used in the MVP pattern (which I am currently trying to setup). Right now (and this would also be the case in your code) the presenter needs a reference to the model in order to be able to distinguish between the instances

      element instanceof Project

      This problem only occurs with viewers, for more simple widgets the presenter can just send down simple strings to the view.

      Do you have any suggestions/tutorials that address this problem?

  1. Pingback: Galileo: EMF-Databinding – Part 4 « Tomsondev Blog

  2. Pingback: Galileo: Improved EMF-Databinding-Support « Tomsondev Blog

  3. Pingback: Galileo: EMF-Databinding – Part 5 « Tomsondev Blog

  4. Will says:

    Thanks for this series Tom. I have not used ObservableListTreeContentProvider but it looks great. Is this the recommended way to set up a tree for EMF model objects, or are there cases where you would still use AdapterFactoryContentProvider and the generated ItemProviderAdapters?

    • tomeclipsedev says:

      There’s no particular advantage but I’m not very familiar with the EMF-Edit stuff generated for you because all my UIs are created by hand and JFace-Databinding gives you a lot of freedom in this respect.

  5. Dear Tom,

    I’m getting trouble performing data-binding using SWT-Designer with Galileo. So I decided to jump right into your article. Unfortunately, I’m having a hard time to figure out how to put all this together. I would really appreciate to get access to your Project Manager example source code if that is possible. I searched for a link to to that example with no success. After that I’ll be more at ease to read again your article and have a better understanding of EMF and databinding.

    Regard,
    Pierre Francis

    • tomeclipsedev says:

      All the sources are available from the EMF-CVS:

      server: dev.eclipse.org
      path: /cvsroot/modeling
      modules: org.eclipse.emf/org.eclipse.emf/examples/*project*

  6. Andy says:

    Tom,

    Thanks for posting the series, it’s been very helpful. I’ve been able to get the databinding to work in my applications when using the attributes from a concrete class in my model. So far I have not determined how to access the EStructuralFeature for an attribute within a modeled class that is inherited from a modeled interface. For example ModelPackage.Literals.CLASS__ATTRIBUTE works, but I haven’t figured out how to make it work when that attribute is a part of an inherited interface.

    Thanks,

    Andy

  7. canty says:

    Hi,
    i’m a newbie for using treeviewer, from your code what must i change if i have structure like :
    mailbox have list of folder and folder have a subfolder ?

    Thanks,
    CanA

  8. Mark says:

    Tom,

    I am working/looking at your databinding tutorial, thanks btw, and in
    the interest of time I grabbed the source from the cvs repo. However, I
    can not seem to make this work. I have stepped through with the debugger
    and it seems that the resource is not loading. I have not seen the osgi
    services before, but it appears that there is no service returned by the
    serviceTracker for loading the resource. Can you give me a quick pointer
    at what to look at..?

    Thanks

  9. Mark says:

    That was it Tom, thanks.

    Now that I have your app running I am having trouble understanding something. How would you modify your code to cause the count of comtitters on a project in the tree to update when you add a new committer. When I add a new committer the tree updates to show the committer, but the label of the parent node, the project, does not update.

    Thanks again.
    Mark.

  10. Mark says:

    Tom, here is a quickly modified label provider that makes it work.

    private class TreeLabelProviderImpl extends StyledCellLabelProvider
    {
    private TreeViewer myViewer = null;

    private IMapChangeListener mapChangeListener = new IMapChangeListener()
    {
    public void handleMapChange(MapChangeEvent event)
    {
    Set addedElements = event.diff.getAddedKeys();
    if (!addedElements.isEmpty())
    {
    for(Object e: addedElements)
    {
    if(e instanceof CommitterShip)
    {
    CommitterShip c = (CommitterShip)e;
    LabelProviderChangedEvent newEvent = new LabelProviderChangedEvent(
    TreeLabelProviderImpl.this, c.getProject());
    fireLabelProviderChanged(newEvent);
    }
    }
    }

    Set removedElements = event.diff.getRemovedKeys();
    if (!removedElements.isEmpty())
    {
    for(Object e: removedElements)
    {
    if(e instanceof CommitterShip)
    {
    myViewer.refresh();
    }
    }
    }

    Set affectedElements = event.diff.getChangedKeys();
    if (!affectedElements.isEmpty())
    {
    LabelProviderChangedEvent newEvent = new LabelProviderChangedEvent(TreeLabelProviderImpl.this, affectedElements.toArray());
    fireLabelProviderChanged(newEvent);
    }
    }
    };

    public TreeLabelProviderImpl(TreeViewer aViewer, IObservableMap[] attributeMaps)
    {
    myViewer = aViewer;
    for (int i = 0; i < attributeMaps.length; i++)
    {
    attributeMaps[i].addMapChangeListener(mapChangeListener);
    }
    }

  11. Teddy says:

    I am having problem getting the code, getting the following error:
    In C:\DOCUME~1\clermot\LOCALS~1\Temp\: “C:\Program Files\CVSNT\cvs.exe” -q -Q co -c
    CVSROOT=:pserver:dev.eclipse.org:c:/code

    Error connecting to host dev.eclipse.org: No such host is known.

    Error, CVS operation failed

    In C:\DOCUME~1\clermot\LOCALS~1\Temp\: “C:\Program Files\CVSNT\cvs.exe” -q -Q ls -q /
    CVSROOT=:pserver:dev.eclipse.org:c:/code

    Error connecting to host dev.eclipse.org: No such host is known.

    • tomeclipsedev says:

      Why not using Eclipse-CVS-Support to check out the code. BTW I thing CVSROOT-Path /cvsroot/modeling and not C:/code. It also looks like your DNS is not working because dev.eclipse.org is a valid host

  12. Teddy says:

    Hey Tom,

    I loaded the 3 projects from CVS but keep getting the same error when I run it:
    Cannot loacate JRE definition: “JVM 1.6”. Laucn aborted.

    Under the Windows .. preferences..java .. install JRE
    I have pointed to jdk16.0_18\jre

    also, all three projects points to the the same jre for the excution environments

    Thanks for your help

  13. TV says:

    Hi Tom,

    I loaded the 3 Projects form CVS and was able to launch the application. But every time I try to open a XMI-Ressource or to create one, I get an unexpected exception and on the console appears “!Message Model loading service is not available”. Don’t know what I’ m doing wrong.

    Thanks for your help.

    • tomeclipsedev says:

      Most likely you forgot to add equinox.ds to your launch config which is needed because the model loading services are contributed through DS (Declarative Services)

  14. Chandresh Gandhi says:

    Tom,

    Thanks a lot for very useful article on EMF Databinding along with real-time application. I’d have one doubt / query on same that I can relate with your attached RCP application on Project ECore model.

    In your RCP application, for example multiplicity for person role is 0..* instead of 0..1 then How can we handle EMF Databinding, specifically LabelProvider to show multiple Committers for a Project

    Please help me on this.

    Thanks,
    Chandresh Gandhi (Skype: chandreshgandhi)

  15. chris says:

    Tom,

    thanks for this amazing article!

    I downloaded the sources via CVS and tried to get the example running but for some reason it does not work. I added the required bundles in the launch configuration and double checked that the DS bundle is included.

    It is strange but the application does not show up in the list of available applications in the launch config dialog’s dropdown list. Therefore I can not start the example through the launch config dialog. Using the “App.launch” file I consequently get the following error:

    !SESSION 2010-04-23 18:45:43.281 ———————————————–
    eclipse.buildId=unknown
    java.version=1.6.0_07
    java.vendor=Sun Microsystems Inc.
    BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=de_DE
    Framework arguments: -application org.eclipse.emf.examples.databinding.project.ui.rcp.application
    Command-line arguments: -application org.eclipse.emf.examples.databinding.project.ui.rcp.application -data E:\DGSleak/../runtime-org.eclipse.emf.examples.databinding.project.ui.rcp.application -dev file:E:/DGSleak/.metadata/.plugins/org.eclipse.pde.core/App/dev.properties -clean -os win32 -ws win32 -arch x86 -consoleLog

    !ENTRY org.eclipse.osgi 4 0 2010-04-23 18:45:45.718
    !MESSAGE Application error
    !STACK 1
    java.lang.RuntimeException: Application “org.eclipse.emf.examples.databinding.project.ui.rcp.application” could not be found in the registry. The applications available are: org.eclipse.equinox.app.error, org.eclipse.ant.core.antRunner, org.eclipse.equinox.p2.metadata.repository.mirrorApplication, org.eclipse.equinox.p2.artifact.repository.mirrorApplication.
    at org.eclipse.equinox.internal.app.EclipseAppContainer.startDefaultApp(EclipseAppContainer.java:242)
    at org.eclipse.equinox.internal.app.MainApplicationLauncher.run(MainApplicationLauncher.java:29)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1287)

    I do not think this is a problem of missing bundles. It seems that the application is not in the registry for some reason.

    Any advice would be highly appreciated.

    Thanks,

    chris

    P.S: I am still quite a newbie to eclipse and rcp so please do not get mad at me in case I am making a trivial mistake …

    • tomeclipsedev says:

      It’s quite likely that the .launch is not correct for your Eclipse installation:
      a) Open the Run Configurations …
      b) Select the App.launch
      c) Select the Plug-ins Tab
      d) Click Add Required Plug-ins
      e) Select Configuration Tab
      f) Check Clear the configuration area before launching

      • chris says:

        Tom – thanks for the extremely quick answer!

        I already tried before what you suggested.
        However I meanwhile got it running finally.
        The problem had a completely different cause.
        It seems that I did not check out the CVS resource properly before. I still do not know what was wrong but I re-checked out and now it just works.

        I have another short question:
        I would like to bind an edit field to a single value of a multi-valued feature. The index of the value to bind is known when binding. Is there an easy way to do that or do have to create a custom control and make it updatable myself ?

        Is there an example anywhere for this?

        Thanks again,

        chris

      • tomeclipsedev says:

        Currently the only way to do this is to create a volatile, transient feature which reflects the value at the know index

  16. chris says:

    Hi Tom,

    I have created a binding between an edit field and its corresponding model feature.

    Now I have the problem that the validator check depends on the value of another feature and therefore the check must not only be executed when the corresponding model feature changes but also when the other feature changes. What is the recommended way to implement this behaviour?

    Thanks in advance,

    chris

  17. chris says:

    Hi Tom,

    I meanwhile found out that a MultiValidator seems to be the way to go.
    However I can not get it running. The examples of “org.eclipse.jface.examples.databinding.snippets” are working but if I use my EMFObservables the validate-method is never called. Are there any known bugs or so ?

    I did:
    bindingContext.addValidationStatusProvider(new MyMultiValidator(…

    and as far as I understood the validate method should then be called whenever any of the observables accessed by MyMultiValidator are modified.

    MyMultiValidator uses just a single EMF observable:
    private final IObservableValue myEMFObservable;

    which is created in the constructor:
    myEMFObservable = EMFObservables.observeValue(myModel, myModelPackage.Literals.VALUE);

  18. Pingback: 2010 in review « Tomsondev Blog

  19. Daniel says:

    Hi there,

    is the bug you mentioned with the ObservablesManager gone by now (3.6 release)? How would the code look like without your workaround?
    cheers, Daniel

    • Tom Schindl says:

      I have to confess that I’ve not tried but you can give it a try yourself. Simply change EMFObservableManager to ObservableManager. The rest should be the same.

  20. Mahmoud says:

    Hi Tom
    it was really informative blog. I have a question regarding memory leak point; you said “we can add an easy fix so that the API at least collects all IEMFObservable so that we only have to deal with things like ComputedValue”, but I don’t know how you fixed it; where in the code you disposed ComputedValue & similar objects

  21. Jens Li says:

    About the status of the observable leak in `ObservablesManager`:

    The source code of runAndCollect still has this in its Javadoc:

    NOTE: As of 1.2 (Eclipse 3.5), there are unresolved problems with this API, see https://bugs.eclipse.org/278550

    But the bug report on that page is marked as “fixed”.

    The current status of the bug seems most unclear…

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.