Common Navigator Tutorial 1: Hello World

The Commons Navigator Framework is one of the more complex parts of the Eclipse API. It can be difficult to get started with the framework, and one of the hardest parts is simply getting a basic navigator to appear with custom content. This tutorial is designed to get you to that point so that you can start exploring the framework on your own.

There are quite a few steps, but it’s not as bad as it looks. So let’s get started!

  • Before creating a navigator, it’s first necessary to have something to place it in. If you don’t have an existing RCP application to work with, create a new one using the “Hello RCP” template. Also, if you have a custom target platform, you’ll need to add the org.eclipse.ui.navigator plug-in to that target. Finally, you’ll need to add the navigator plug-in as a dependency in the appropriate manifest.
  • Now that the preparations are out of the way, we can create the navigator itself. Because CNF navigators are also regular views, the first step is to create an org.eclipse.ui.views extension. Enter in an appropriate id and name, and then enter a new class name in the class field. Note that this is where we diverge from standard CNF usage. Normally we would simply enter the org.eclipse.ui.navigator.CommonNavigator class in this field. To learn why we are not, check out my previous post on the subject.
  • Click on the class field label to launch the New Java Class wizard. Change the superclass to org.eclipse.ui.navigator.CommonNavigator and click Finish. We now have our main navigator class, and we’ll return to it a little later. You can now also add your view to a perspective either programmatically or through a perspective extension. At this point, you should be able to run your application and see an empty navigator appear.

CNF Tutorial 1

  • Now for some content. Create a NavigatorRoot class that will serve as the root node in your navigator. Note that this element will not appear in the navigator, the children of the root node will be the first to appear. The class representing the navigator root must be an IAdaptable, and the simplest way to accomplish this is to have your NavigatorRoot extend the PlatformObject class. Also create another simple bean called ParentBean that has a name attribute. Finally, add a getParentBeans method to your NavigatorRoot class and have that method return a set of populated ParentBean instances.
  • The navigator root can now be added to the navigator class we created above. In that class, override the getInitialInput method and simply return a new instance of NavigatorRoot. Note that in a real-world implementation, the navigator root would probably be a singleton or returned by a factory class. Also note that these few lines of code are all that are required in the navigator subclass. While subclassing the CNF navigator is not ideal, this approach is far from risky.
  • The next step is to declare an org.eclipse.ui.navigator.navigatorContent extension. This extension point is used to define many navigator elements, including content (of course), filters and actions. It’s important to understand that this extension point defines content in a navigator independent way. You will later need to bind this content to a specific navigator to get the content to appear. So create this extension and add a navigatorContent element below it. Choose an appropriate id and name, and then enter class names for the contentProvider and labelProvider fields.
  • Click on the contentProvider and labelProvider field labels to create the required providers. The content provider should take in a NavigatorRoot as input and return an array of ParentBean instances as children. The label provider should simply return the name of the ParentBean as the display text.
  • We now need to specify what will cause our content to appear. The simplest way to do this is to specify what type of parent element should trigger our content and cause our content/label providers to be called. In our example, we’ll add a triggerPoints element below the navigatorContent element. Under triggerPoints, we’ll add an instanceof element and then enter your NavigatorRoot class in the value field. This will cause your content to be added whenever a NavigatorRoot instance is encountered in the tree.
  • The final step (we’re almost there!) is to bind the content to the navigator. To do that, we need to declare an org.eclipse.ui.navigator.viewer extension. This extension point registers our view as a navigator and allows us to bind different types of content to it. Create the extension and first add a viewer element to it. Enter the id of your view in the viewerId field. Now add a viewerContentBinding element below the extension. This element is what actually adds our content into the navigator. Again, enter your view id into the viewerId field. Add an includes element below the viewerContentBinding and then a contentExtension element below that. Finally, in the pattern field of the contentExtension element, enter the id of your navigator content.

You should now be able to run your application and see content appear in the navigator!

CNF Tutorial 2

As you can see, even the simplest CNF example requires a fair number of steps to get working. It’s also rare for the navigator to appear correctly on the first try, and it can be extremely frustrating to debug the CNF when things go wrong. So much of the CNF is wired using extension points that any small typo can cause you a lot of grief. For that reason, I recommend that when working with the CNF you make small, incremental changes and verify functionality after each change.

Because it can be a real pain to get all the linkages working the first time, I’ve created some sample code (Eclipse 3.2, Eclipse 3.3) that will get you up to speed more quickly. Good luck!

About these ads

46 Responses to Common Navigator Tutorial 1: Hello World

  1. Hi Patrick,

    Great article! It seems like one of the biggest pain points for RCP is getting the initial input into the viewer. I don’t do alot of RCP development, so perhaps you could offer some advice on what you would like to see for this to be easier?

    It also seems that getting started in general is something you believe takes too many steps. Could you offer some advice on what you think would make it easier for developers to get started with this framework?

    There’s also a series of articles available at the following link. I’m working with IBM Developer Works to get these formalized and published. I’ll make it a point to ensure that one of the first ones has an RCP example in it as well.

    http://scribbledideas.blogspot.com/2006/07/pdf-versions-now-available.html

  2. pjpaulin says:

    Hi Michael,

    Thanks for commenting and also for all the work you did on the CNF. I really appreciate it!

    As for discovering the root, I would suggest that the getInitialInput method rely on something other than the getPage().getInput() method. Perhaps there could be a way to declaratively describe an initial input factory as an element under the org.eclipse.ui.navigator.viewer extension? I imagine it wouldn’t be too hard for the Resource Navigator to use a factory like this to get the same input it does now. The key for RCP developers is to allow anything to be the initial input so that the CNF can be used anywhere (even multiple times in the same perspective).

    When it comes to the number of steps involved, I think that’s the price you pay for the flexibility you get with the framework. It just looks like a lot of steps to get a very simple example running (you might as well not use the CNF in that case). But I understand why the complexity is there and it makes sense.

    The problem is some people give up because they think that if even the simplest case is hard, then the framework is too complex. I disagree, and hopefully this tutorial will help at least a little.

    — Patrick

  3. 3.3 is just about shutdown, but I’ll see what we can do in 3.4 to make some of this a little more polished.

    Perhaps a new RCP sample wizard to create a CNF based view …

  4. Thiago Arakaki says:

    Hi there,

    I was looking your tutorials and I must say: They’re very good!
    Developing RCP Applications is tricky like you said, you got to understand or just know something about all that plugin.xml and where to put your code right.

    I was trying to replicate this tutorial and then building something more complicated, with a dynamic content. I was wondering, how can I add new children to the Navigator Root updating the view content dynamiclly?

    Thanks in advance!

  5. Thiago Arakaki says:

    I got that, was easy thought, needed to refresh the viewer from the Common Navigator.

    Thanks anyway, this is a good tutorial

  6. if says:

    Hi!

    Great tutorial, but I have problems with refreshing my view when default actions are called (like new file, folder, project…). Can You please provide some more information about how to solve this problem?

    if

  7. pjpaulin says:

    Call myNavigator.getCommonViewer.refresh(). This should cause your new elements to appear.

  8. Volker Schilling says:

    Hi!

    Great tutorial! I like to build my own IDE using RCP and I like to use the CNF.
    I need some help with the shortcuts provided by the popup menu from the contentActionBinding “org.eclipse.ui.navigator.resources.*”. The popup menu is shown corect and all commands are working but only if I selecht them with the mouse from the popup menu. Shortcust for example (delete) didn’t work. I also see that the menues were not be contributet to the main menu bar!

    Thanks in advance!

  9. pjpaulin says:

    Hi Volker,

    You should look at the relevant help docs on key binding. Also, the main menu is constructed independently of navigator menus. See the docs for the org.eclipse.ui.menus extension point for information on contributing to the main menu bar.

    Good luck!

    — Patrick

  10. M Eken says:

    Hi Volker,

    Try registering the actions in the makeActions method of your ActionBarAdvisor:

    deleteAction = ActionFactory.DELETE.create(window);
    register(deleteAction);

    Cheers,

    M

  11. Biju says:

    Hi Friends,

    How can we add filters to the navigation view. (Ex: for hiding ‘.project’ file etc

    Thanks Biju

  12. pjpaulin says:

    Hi Biju,

    I’m planning on covering filters in an upcoming post, but the short answer is that you should do the following:

    1. Define a commonFilter element as a child of a navigatorContent element. The actual filter can be defined in the XML using a filterExpression element or you can specify a subclass of ViewerFilter.

    2. Bind the filter to your particular navigator with a viewerContentBinding entry.

    Hope this helps.

  13. Biju says:

    Hi pjpaulin,

    Thanks for your reply..

    Please help me to know, with some sample code, how to

    1. define a filter in XML using a filterExpression ?

    2. bind the filter to my navigator with a viewerContentBinding entry

    Thanks again

    Biju

  14. pjpaulin says:

    Hi Biju,

    1. There are some samples in the Eclipse help. Check out:

    http://help.eclipse.org/stable/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/extension-points/org_eclipse_ui_navigator_navigatorContent.html

    2. You bind the filter just as you bind any other content. Each filter has an id and those ids can bound to your navigator. Check out the tutorial above to see how this is done.

  15. Biju says:

    Hi pjpaulin,

    Thanks for your reply..

    I will work on it as you suggested. Now I am facing another problem, that is in my rcp application, after creating the projects if I close and reopen the Navigator, a fresh navigator view is shown. I am not able to see the projects created earlier in it..

    Any Idea to solve this.

    Thanks again

    Biju

  16. pjpaulin says:

    Hi Biju,

    How you manage your model layer is outside the scope of this tutorial. Typically, you would have some sort of persistence manager that allows you to save and access model elements. A navigator would just display whatever models the persistence manager presented to the navigator’s content provider.

    If a fresh navigator is not displaying current data, I would look at your persistence management code to see why the navigator’s content provider contains stale information.

  17. boris says:

    In the final step of “Common Navigator Tutorial 1: Hello World” – to bind the content to the navigator, we need to declare an org.eclipse.ui.navigator.viewer extension.
    But we do not need to add a viewer element to it.
    Only add a viewerContentBinding element below the extension.Enter your view id into the viewerId field. Add an includes element and then a contentExtension element below that. Enter in the pattern field the id of your navigator content.

    Boris Starchev teacher
    Ruse Bulgaria
    bstarchev@ru.acad.bg

  18. boris says:

    +extension
    point=”org.eclipse.ui.navigator.navigatorContent”-
    +navigatorContent
    contentProvider=”bis.souee.rcptotalbeginners.views.TreeContentProvider”
    id=”bis.souee.rcptotalbeginners.treeContent”
    labelProvider=”bis.souee.rcptotalbeginners.views.LabelProvider”
    name=”Tree Content”-
    +triggerPoints-
    +instanceof
    value=”bis.souee.rcptotalbeginners.model.NavigatorRoot”-
    +/instanceof-
    +/triggerPoints-
    +/navigatorContent-
    +/extension-
    +extension
    point=”org.eclipse.ui.navigator.viewer”-
    +viewerContentBinding
    viewerId=”bis.souee.rcptotalbeginners.views.navigator”-
    +includes-
    +contentExtension
    pattern=”bis.souee.rcptotalbeginners.treeContent”-
    +/contentExtension-
    +/includes-
    +/viewerContentBinding-
    +/extension-

  19. Chandra says:

    Hi Michael,

    I have small issue in Common Navigator with RCP.

    I have included the following ,
    1) I have introduced my own projectnature(Ex: myNature is the name of the projectNature) and created project with that nature.
    2) Defined commonfilter to filter non-myNature projects.
    Now the issue is, the projects which are in closed state are not shown in the navigator at all.

    Can any one help me in this.

    Thanks,
    Chandra M

  20. pjpaulin says:

    Hi Chandra,

    I’m not too familiar with the Resource Navigator and how it filters projects. I’m sure you’d have better luck if you asked this question on either the Platform or RCP newsgroups.

    http://www.eclipse.org/newsgroups

  21. Anoop says:

    Great Tutorial.

    Are you active in any forums? I wanted to clear a doubt regarding a RCP application that I am developing.Since its not related navigator not that keen to post it here.

  22. pjpaulin says:

    The best place by far to get your RCP questions answered is the eclipse.platform.rcp newsgroup which you can access from the Eclipse web site. I try to answer some questions there but have been buried with work lately.

    If you don’t get an answer there, feel free to email me. I’d be happy to help.

  23. Hello

    i found a smal clear solution to get the CNF working without subclasing it! The only thing to get the initial input to work ist to write one method in the ApplicationWorkbenchAdvisor.

    public IAdaptable getDefaultPageInput() {
    return ResourcesPlugin.getWorkspace().getRoot();
    }

    With this method you are able to use it like it is intended without subclasin CommonNavigator

  24. Patrick says:

    Hi Volker,

    Unfortunately, your solution ties an RCP app to both the resources plug-in (which is not part of the core RCP) and also the concept of a workspace. Many RCP developers want to use the CNF to display customized tree hierarchies which have nothing to do with the concept of a workspace.

    Some have tried to replace the workspace with their own custom root objects, but there have been issues with this as well:

    http://www.eclipsezone.com/eclipse/forums/t79254.html?start=0

    But if you want to tie the navigator to a workspace and you need the resources plug-in, your solution works fine.

    — Patrick

  25. Fabio Mancinelli says:

    Hi,

    I was playing with CNF and trying to make it display my application Workspace content. I overrode the getDefaultPageInput() as mentioned by Volker Schilling, but even though the workspace has some projects inside, the Navigator doesn’t display them. Your subclassing trick doesn’t help to solve the problem.

    The plugin, on the other hand, works fine when run in the IDE.

    Do you have any hint about why this is happening? (Tried with Eclipse 3.3 and 3.4M6)

    Thanks and kudos for the blog!
    Fabio

  26. Patrick says:

    Hi Fabio,

    I don’t have experience getting the CNF to display workspace content, though that is obviously what is was designed to do. I

    I would leave getInitialInput as it is to start out, and debug what the page.getInput method is returning inside the IDE and then in your RCP app.

    Let me know if you find the answer. I’m curious to know why this is happening myself.

    — Patrick

  27. Steve Orobec says:

    Hi Patrick

    Thanks for the article, using this plus the Michael Elder articles I have now got 2 GMF
    generated editors working from CN in a RCP. (GMF automatically generates the content/label and view providers). I had a similar problem to Fabio above but the problem was that when you initially launch the CN view the default filters are set to hide some content and I need to reset them.

    I used your subclassing trick by the way

    regards
    Steve

  28. Fabio Mancinelli says:

    Hi Patrick,

    sorry for the late reply…
    Anyway, the problem was that the icons needed by the CNF for displaying Workspace resources were missing.

    Actually you must initialize them in your WorkbenchAdvisor initialize method, as the IDE does.

    By doing the same thing that is done in
    org.eclipse.ui.internal.ide.application.IDEWorkbenchAdvisor#declareWorkbenchImages()
    things start to be displayed correctly.

    Cheers,
    Fabio

  29. Des says:

    Patrick,

    Thanks for this great tutorial, I really hope you follow it up with some more CNF articles, your writing is clear, informative and thorough. Ideas on how to integrate the CNF parts with an editor would be a good follow-on.

    Cheers,
    Des

  30. Patrick says:

    HI Des,

    Thanks for the kind words. I’ve been meaning to get back to posting about the CNF, and hopefully I’ll be able to get something up soon.

    — Patrick

  31. Raajesh Kashyap says:

    Is it possible to have the viewer portion of the CNF inside a composite, or inside a dialog? If yes, how can this be done? The extensions for the viewerContentBinding and the viewer seem to always need a view ID. I couldn’t figure out if its possible to just place the viewer inside a composite/dialog.

  32. Patrick says:

    Hi Raajesh,

    I think that currently the CNF must be implemented as a single view as the CommonNavigator class extends ViewPart.

    You could check with Francis Upton, who is the new Platform UI committer working on the CNF. Also, he has a wiki page requesting new use cases for the CNF, and it sounds like you’ve found one! Here’s the address:

    http://wiki.eclipse.org/Common_Navigator_Framework_Use_Cases

    Hope this helps,

    — Patrick

  33. Hi Raajesh,

    I’m not sure if it will work, but you might try subclassing CommonNavigator and overriding the createCommonViewer() method. CommonViewer is a public class so you should be able to create it where you want it. However, I’m not sure how things will deal with the issue of the view id since you will not be creating this in a ViewPart. Please file an enhancement request in bugzilla for this so we can track this.

    Francis

  34. Raajesh Kashyap says:

    Hi Francis and Patrick,

    Sorry for not writing back here earlier, but I found how to do it after posting here. After reading the documentation for INavigatorContentService, I found this is quite easy to do. I created a dialog in the sample project that I had and was able to embed the same content that shows in the view, into a dialog. Here are the steps:

    1) Create your dialog – whichever way it is instantiated. In my case, I used the menus/commands/handlers mechanism in 3.3 to create a menu entry in the view’s local pull down menu, and then added a handler for it, which creates the dialog. My dialog just extends from the JFace Dialog class.

    2) In the createDialogArea( Composite parent ) method, instantiate the CommonViewer with a specific ID, as below:

    CommonViewer commonViewer = new CommonViewer( ID, composite, SWT.BORDER );

    (where ID is some string like “com.rbk.xyz”)

    3) Next, add the lines below, before returning the “parent” composite in this createDialogArea() method:

    INavigatorContentService contentService = NavigatorContentServiceFactory.INSTANCE
    .createContentService(ID, commonViewer);

    contentService.createCommonContentProvider();
    contentService.createCommonLabelProvider();

    commonViewer.setInput( new NavigatorRoot() );

    (where NavigatorRoot is an object similar to the one described in the tutorial on this page).

    4) Now, in the extension points (plugin.xml), add a “viewer” extension specifying the common viewer ID used in the code above, similar to what is done for the view in this tutorial.

    5) Add a “viewerContentBinding” element, just as it is done for the view in this tutorial, but use the common viewer ID that is used in this code instead. The only difference is that the ID of the common viewer used in the code here will become the viewer ID in the content binding.

    6) That’s it. The viewer should show up in the dialog. It binds to the extension points for the content and label providers through the navigator content service.

    Hope this helps anyone planning to use it in the same way.

  35. Patrick says:

    Hi Raajesh,

    That’s great news! I’m sure this information will help others using the CNF. You should really contact Francis about getting this on his CNF wiki pages somewhere.

    Thanks!

    — Patrick

  36. Jessica says:

    Wow, I just started a new job where we are using RCP and it’s incredibly complex. I’m so thankful for this blog post though as this is exactly what I need to do for my first assignment. Daunting but hopefully manageable!

  37. Duncan Krebs says:

    Wow, been in eclipse for a while and I have always hated this framework and as always there is a balance between flexibility and ease of use. I just had to read that post twice to logically understand everything. Was a little confused why a viewer has to bind viewerContent to it because woul;nt there be cases in when another plugin developer wants to add a viewerContent to your viewer and would then have to go into your extension of and do the binding or is there something I’m missing?

  38. Duncan Krebs says:

    One other question I had, is that when you use the CommonNavigator in an RCP app but you don’t want all the other actions to show up such as “Restore from Local History” because say for example its a user application and that should not be visible but you depend on the plugins that are contribuating those actions, how can you override them and say ” please don’t show these actions” in other words prevent other plugins viewerContent additions to not be displayed.

  39. Patrick says:

    Hi Duncan,

    I definitely agree that this framework is difficult to use, but as you say, this is the price we pay for flexibility.

    I also agree that it seems odd to bind content directly to a centralized viewer extension. One way around this is to specify the content bindings using a regular expression so that you can choose later on which viewerContent additions will match.

    This regular expression syntax may also solve your second problem. You can specify both includes and excludes that match content and action providers, so you should be able to exclude the actions that you don’t want.

    — Patrick

  40. Paolo says:

    Hello, I’m about to override/implement methods on an already working cnf view, in our eclipse rcp app. I have to configure it in order to hide some commands from the “right-click popup menu” but I do not know where to put my hands.
    To disable the “deleteAction” via debug I found menu.contribution[..]delete something and I’m quite sure that I can hide it programmatically checking how many “slashes” are in the path of selected node and removing that contribution right in the commonActionProvider->fillContextMenu override I’ve found. But I’m not sure this is the way cnf is meant to work, is there a better way to configure these things? For instance by plugin.xml modification..
    Thanks in advance

  41. Patrick says:

    Hi Paolo,

    I haven’t done this myself, but my guess is that you should be able to use a visibleWhen element in combination with the Core Expression Framework to achieve this. But if you’re trying to hide a command that has been created by someone else, then that may not work.

    The person who could really help you here is Francis Upton, who is the Platform committer responsible for the CNF. If you ask this question on the Eclipse newsgroup, he’ll probably respond pretty quickly. Or you can check out his blog at:

    http://dev.eclipse.org/blogs/francis/

    Sorry I can’t give you a better answer directly, and I’d be interested to hear what you come up with.

    — Patrick

  42. Duncan Krebs says:

    Patrick,
    Thanks for the reply that helped solve my issue. – Duncan

  43. mikel says:

    thank you for this tutorial

  44. Felix says:

    Thanks for this tutorial. Everything worked fine, but one thing I either did wrong or not understand:

    My LabelProvider is called one time with the NavigatorRoot object as the parameter.

  45. Patrick says:

    Hi Felix,

    I see what you mean. It appears that the label provider is getting called when the navigator is attempting to generate the navigator view tooltip (displayed when you hover over the view’s tab).

    The logic appears to be that the a search is made for label providers attached to elements that are valid parents of the input element (NavigatorRoot). But NavigatorRoot has no valid parents, only children, so I’m not sure why the match is being made.

    The problem may be related to our hacking the navigator class to provide a root object in a non-standard way. This might be a good thing to take up with Francis Upton (the CNF committer) to verify what’s supposed to be happening here.

    — Patrick

  46. lopiter says:

    thank you fot your tutorial

    i never develop with plugin ver.3.4

    it is really useful to me ^^

    i add this site to my favorite ^^

    i think , i often connect this site ^^

    thank you~~~^^

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: