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 appropriateid
andname
, and then enter a new class name in theclass
field. Note that this is where we diverge from standard CNF usage. Normally we would simply enter theorg.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 toorg.eclipse.ui.navigator.CommonNavigator
and clickFinish
. 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.
- 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 anIAdaptable
, and the simplest way to accomplish this is to have yourNavigatorRoot
extend thePlatformObject
class. Also create another simple bean calledParentBean
that has aname
attribute. Finally, add agetParentBeans
method to yourNavigatorRoot
class and have that method return a set of populatedParentBean
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 ofNavigatorRoot
. 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 anavigatorContent
element below it. Choose an appropriateid
andname
, and then enter class names for thecontentProvider
andlabelProvider
fields.
- Click on the
contentProvider
andlabelProvider
field labels to create the required providers. The content provider should take in aNavigatorRoot
as input and return an array ofParentBean
instances as children. The label provider should simply return the name of theParentBean
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 thenavigatorContent
element. UndertriggerPoints
, we’ll add aninstanceof
element and then enter yourNavigatorRoot
class in thevalue
field. This will cause your content to be added whenever aNavigatorRoot
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 aviewer
element to it. Enter the id of your view in theviewerId
field. Now add aviewerContentBinding
element below the extension. This element is what actually adds our content into the navigator. Again, enter your view id into theviewerId
field. Add anincludes
element below theviewerContentBinding
and then acontentExtension
element below that. Finally, in thepattern
field of thecontentExtension
element, enter the id of your navigator content.
You should now be able to run your application and see content appear in the navigator!
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!
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
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 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 …
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!
I got that, was easy thought, needed to refresh the viewer from the Common Navigator.
Thanks anyway, this is a good tutorial
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
Call myNavigator.getCommonViewer.refresh(). This should cause your new elements to appear.
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!
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
Hi Volker,
Try registering the actions in the makeActions method of your ActionBarAdvisor:
deleteAction = ActionFactory.DELETE.create(window);
register(deleteAction);
Cheers,
M
Hi Friends,
How can we add filters to the navigation view. (Ex: for hiding ‘.project’ file etc
Thanks Biju
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 anavigatorContent
element. The actual filter can be defined in the XML using afilterExpression
element or you can specify a subclass ofViewerFilter
.2. Bind the filter to your particular navigator with a
viewerContentBinding
entry.Hope this helps.
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
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.
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
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.
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
+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-
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
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
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.
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.
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
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
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
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
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
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
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
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
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.
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
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
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.
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
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!
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?
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.
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
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
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
Patrick,
Thanks for the reply that helped solve my issue. – Duncan
thank you for this tutorial
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.
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
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~~~^^