What is this document?
This document wants to be an effective starting point for all Eclipse-RCP-developers new to the CNF.It provides you with a brief introduction of what it is and what it is useful for.
It provides some sample code that could be found here. The aim of the sample code is to concentrate on how to use the CNF in RCP-Applications and how to contribute content to one CNF-based view from different plug-ins. All of the sample code sticks to the very basics and should only give you the core-idea of why it could be useful for you.
For everything more advanced you should take a look on the further reading section, the sample code section and the real life example section.
What is the CNF?
In short: It is a view containing a special treeviewer that could be used in Eclipse based applications. The treeviewers degree of details is dynamically configurable via extensions. So one plug-in could create the initial view and a lot of other plugins can change the details that should be displayed.For example it solves the view-explosion-problem: A view is existing and displays some data. Now you find it usable to view some other details for the already displayed objects. Without the CNF you need to create a new view that duplicates the already visible data appended with the details you need. That “duplication” is at least needed, when the original code of the view could not be changed by you. Let’s say because the view is contributed by another plug-in, from another company.
For more details take a look at the section “further reading”.
A real life example – the Project Explorer
The maybe most famous example is the Project Explorer View within the Eclipse IDE. You can open it’s plugin.xml easily due the "Plug-ins" View with a double-click on org.eclipse.ui.navigator.resources.
Package Explorer View and Project Explorer View
Another example is the Eclipse Web Tools Platform (WTP).
Hints:
- Some Contributions to the Project Explorer View can be found in the plugin.xml of the Plug-in org.eclipse.jdt.ui .
- The definition of the Resources Perspective (which the Project Explorer belongs to) could be found in the Plug-in org.eclipse.ui.ide.application.
- The Package Explorer View within Eclipse is not based on the CNF, although some people name it as an example for the CNF.
- The Project Explorer View is based on the CNF and provides nearly the same features as the Package Explorer View does. It seems that the Project Explorer View was intended to replace the Package Explorer View someday, but for now there are still pieces of code that only relay on the Package Explorer…
Short history of CNF
- Created by Michael Elder
- Originally created for IBM Rational Application Developer (RAD)
- CNF is new with Eclipse 3.2
My cnfdemo sample code
Tested with: Eclipse 3.4, Eclipse 3.5Is available for download here
The aim of the sample code is to concentrate on how to use the CNF in RCP-Applications and how to contribute content to one CNF-based view from different plug-ins. All of the sample code sticks to the very basics and should only give you the core-idea of why it could be useful for you.
The cnfdemo consists of 4 very small plugin-projects that you could easily import with the Import-Wizard of the Eclipse IDE. (File - Import - Existing Projects into Workspace)
Hint:
- The CNF-Plug-in (org.eclipse.ui.navigator) is not included in the RCP Target Platform. If you are just using the Eclipse installation as your Target Platform (which is the normal setup) you don’t need to care about that detail.
cnfdemo.core – contains the application and the workbench. More interesting for CNF it also contains the plugin.xml configuration for the CNF-View. It also contains an interface that all Elements of the CNF-treeview should implement.
cnfdemo.fruits – contains model-classes for fruits (bananas and apples). Via plugin.xml this plugin contributes to the CNF-based view and makes the new business-objects visible in the CNF-view. It contains a LabelProvider and a ContentProvider for the fruits.
cnfdemo.geometric – same like cnfdemo.fruits just with some completely different business-objects (geometric forms).
cnfdemo.details – adds a detailed LabelProvider and ContentProvider that makes some details visible for the already displayed business-objects. For apples it shows the weight, for rectangls it shows the length of the sides a and b.
snippets: cnfdemo.core
plugin.xml (cnfdemo.core)NavigatorRoot.java
public class NavigatorRoot extends PlatformObject { private ListcnfTreeObjects = new LinkedList (); public NavigatorRoot(){ cnfTreeObjects.add(new ICnfTreeObject(){ @Override public ICnfTreeObject getParent() { return null; } @Override public String getText() { return "dummy - ICnfTreeObject"; } }); } public void addCnfTreeObject(ICnfTreeObject cnfTreeObject){ cnfTreeObjects.add(cnfTreeObject); } public List getCnfTreeObjects() { return cnfTreeObjects; } public void addgetCnfTreeObject(ICnfTreeObject cnfTreeObject) { cnfTreeObjects.add(cnfTreeObject); } }
ICnfTreeObject.java
public interface ICnfTreeObject { ICnfTreeObject getParent(); String getText(); }
ParentBeanContentProvider.java
public class ParentBeanContentProvider implements ITreeContentProvider { public Object[] getChildren(Object parentElement) { if (parentElement instanceof NavigatorRoot) { return ((NavigatorRoot) parentElement).getCnfTreeObjects().toArray(); } return new Object[0]; } public Object getParent(Object element) { return null; } public boolean hasChildren(Object element) { return this.getChildren(element).length > 0; } public Object[] getElements(Object inputElement) { return this.getChildren(inputElement); } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } }
ParentBeanLabelProvider.java
public class ParentBeanLabelProvider implements ILabelProvider { public Image getImage(Object element) { return null; } public String getText(Object element) { if (element instanceof ICnfTreeObject) { return ((ICnfTreeObject) element).getText(); } return new String(); } public void addListener(ILabelProviderListener listener) { } public void dispose() { } public boolean isLabelProperty(Object element, String property) { return false; } public void removeListener(ILabelProviderListener listener) { } }
snippets: cnfdemo.detail
plugin.xml (cnfdemo.detail)ldren>
DetailContentProvider.java
public class DetailContentProvider implements ITreeContentProvider { public Object[] getChildren(Object parentElement) { if (parentElement instanceof Rectangle){ LinkedListlinkedList = new LinkedList (); linkedList.add(new Detail((ICnfTreeObject) parentElement, "side a: " + new Integer(((Rectangle)parentElement).getA()).toString())); linkedList.add(new Detail((ICnfTreeObject) parentElement, "side b: " + new Integer(((Rectangle)parentElement).getB()).toString())); return linkedList.toArray(); } if (parentElement instanceof Circle){ LinkedList linkedList = new LinkedList (); linkedList.add(new Detail((ICnfTreeObject) parentElement, "radius: " + new Integer(((Circle)parentElement).getRadius()).toString())); return linkedList.toArray(); } if (parentElement instanceof Apple){ LinkedList linkedList = new LinkedList (); linkedList.add(new Detail((ICnfTreeObject) parentElement, "weight: " + new Integer(((Apple)parentElement).getWeight()).toString())); return linkedList.toArray(); } if (parentElement instanceof Banana){ LinkedList linkedList = new LinkedList (); linkedList.add(new Detail((ICnfTreeObject) parentElement, "weight: " + new Integer(((Banana)parentElement).getWeight()).toString())); return linkedList.toArray(); } return new Object[0]; } public Object getParent(Object element) { if (element instanceof ICnfTreeObject) return ((ICnfTreeObject)element).getParent(); return null; } public boolean hasChildren(Object element) { return this.getChildren(element).length > 0; } public Object[] getElements(Object inputElement) { return this.getChildren(inputElement); } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } }
DetailLabelProvider.java
public class DetailLabelProvider implements ILabelProvider { public Image getImage(Object element) { return null; } public String getText(Object element) { if (element instanceof Detail) { return ((Detail) element).getText(); } return new String(); } public void addListener(ILabelProviderListener listener) { } public void dispose() { } public boolean isLabelProperty(Object element, String property) { return false; } public void removeListener(ILabelProviderListener listener) { } }
Avanced Topic: Override existing Content-Contributions
With the CNF it is possible to replace content that has already been contributed by another plugin, with some content we consider more valuable. cnfdemo.volume – this plug-in uses the possibility provided by the CNF to override existing content-contributions. It removes the sides a and b that are displayed so far due the cnfdemo.details-plug-in and adds the volume instead.relevant code-snippets
plugin.xml (cnfdemo.volume)VolumeContentProvider.java
public class VolumeContentProvider implements IPipelinedTreeContentProvider { @Override public Object[] getChildren(Object parentElement) { System.out.println("VolumeContentProvider.getChildren() - parentElement.getClass(): " + parentElement.getClass()); if (parentElement instanceof Rectangle) { LinkedListlinkedList = new LinkedList (); linkedList.add(new Volume((ICnfTreeObject) parentElement, "volume: " + new Integer(((Rectangle) parentElement).getA() * ((Rectangle) parentElement).getB()).toString())); return linkedList.toArray(); } return new Object[0]; } public Object getParent(Object element) { if (element instanceof ICnfTreeObject) return ((ICnfTreeObject) element).getParent(); return null; } public boolean hasChildren(Object element) { return this.getChildren(element).length > 0; } public Object[] getElements(Object inputElement) { return this.getChildren(inputElement); } @Override public void getPipelinedChildren(Object aParent, Set theCurrentChildren) { // When this method is called theCurrentChildren are instances // of Detail. // We replace that with instances of Volume. // // GUI representation without doing the replacement: // side a: 10 // side b: 20 // // GUI representation after doing the replacement: // volume: 200 theCurrentChildren.clear(); Object[] children = getChildren(aParent); for (int i = 0; i < children.length; i++) { theCurrentChildren.add(children[i]); } } … }
VolumeLabelProvider.java
public class VolumeLabelProvider implements ILabelProvider { @Override public String getText(Object element) { if (element instanceof Volume) { return ((Volume) element).getText(); } return null; } … }Sample code for education (created by other people)