Archive

Posts Tagged ‘getText’

Writing an Eclipse Plug-in (Part 7): Creating a Custom Navigator

October 18, 2009 29 comments

[October 23, 2009 - I updated some of the code to reflect suggestions made by Simon Zambrovski: the CustomProjectWorkbenchRoot no longer inherits from PlatformObject and, by extension, CustomNavigator.getInitialInput() now returns Object. The downloadable code also reflects the change.]

(This is going to be a long one.)

I know I keep harping on this, but I’m going to do it again: so far we have created:

  • a plug-in project that created a new project wizard to get the name and location of a new project
  • a plug-in project that creates a navigator to display the project information
  • a testable class that created the actual project and tests to go with it

Even though we have two plug-in projects we have only 7 classes, one of which just loads strings, 2 which are Activators and the others are mostly empty.

The custom navigator will change that…slightly…well, more than slightly.

Create a Category for the Custom Navigator

First task: before creating a true custom navigator let’s create a category for it. Why? Because the last time I did it second and this time I want to do it first. In fact, I expect to be doing such forward thinking a lot in the future. Especially when I get to think about things for about a week and sketch out all the things I want to do first. Like creating a custom navigator and then give it a category. Only configure the category first.

Okay, let’s go to the customnavigator plugin.xml file Extensions tab.

Create the category:

  1. Right click on org.eclipse.ui.views –> New –> Category
  2. Enter the following:
    • id: customnavigator.category
    • name: Custom Projects
  3. Save plugin.xml.

Notice the lack of code.

To bind the category to the custom navigator:

  1. Select Custom Plug-in Navigator (view).
  2. In the Category field to the right enter:
    • Category: customnavigator.category
  3. Save plugin.xml.

Of course, I can’t let this one go by without an icon so…create another 16×16 image and store it in the customnavigator icons folder (what? You don’t have an icons folder in the Plug-in project? Create one. After that create an image and store it in the icons folder. All I did was copy the perspective.png from the customproject plug-in and rename it navigator.png).

To add the icon go to the Extensions tab:

  1. Select Custom Plug-in Navigator (view).
  2. In the icon field to the right enter:
    • icon: icons/navigator.png
  3. Save plugin.xml.

Start the runtime workbench for the customnavigator plug-in. From the runtime workbench, starting from the main menu, open Window –> Show View –> Other –> Custom Projects. Look! The Custom Navigator! And it has a pretty icon!

Okay, exit the runtime workbench.

Did I mention that we didn’t have to write any code?

Refactor plugin.xml and MANIFEST.ML

Time for some plug-in project hygiene. The plugin.xml file has some strings that need to be externalized and the MANIFEST.ML file has both a string that need to be externalized and packages that should be declared as exported. Naughty, naughty (I know: we need to do the same for customplugin. Next time).

Luckily, this is easily solved.

if you scroll down In the Overview tab, you will find a link labeled Externalize Strings Wizard. Click on the link, accept everything, and click Finish at your earliest possible opportunity.

The Externalize Strings Wizard will create a file named OSGI-INF/I10n/bundle.properties. Seems like a long name for such a few strings, but it will serve us well as we add/subtract strings over time. If you prefer you could instead create a file named plugin.properties that contains the same properties. If you do that please make sure to add the plugin.properties file to the build.properties bin.includes property or else the plug-in will not know where to find the externalized strings.

To see the effect of the externalization close plugin.xml and reopen it. Viola! The perfect soufflé!

One last thing: if you go to the MANIFEST.ML tab you will notice that there is a warning icon in the top left hand corner at the top of the file. If you click on the icon it will open a window with a single suggestion for fixing the warning: Add Missing Packages. Double click Add Missing Packages. The manifest editor will add a line at the end of the file:

...
Export-Package: customnavigator

Save the MANIFEST.ML file to see the warning go away.

Alright, enough fooling around. Let’s get down to business.

Create a Custom Navigator

Creating a navigator using the Common Navigator Framework (CNF) is not hard (once you know what the hell you are doing), but it is not trivial either (someone once told me that using the word but in sentence basically negates everything said in the phrase before it. Perhaps using but is shorthand for damning with faint praise).

Here are the 6 7 8 6 5 steps to success (with lots of spackle in between so I’m not wrong by too often):

  1. Subclass CommonNavigator
  2. Create a root PlatformObject
  3. Add Extension navigatorContent and bind it to the navigator
  4. Implement the Custom Folder and File Types, ContentProvider and LabelProvider
  5. Add a ResourceListener

However, all of the above has to be understood in context of:

  • how the navigator behaves when it is first instantiated
  • how the navigator behaves after instantiation and the workspace changes

So the overlay to the 6 7 8 6 5 steps above is:

  • Implement the Common Navigator and its behavior upon instantiation
    1. Subclass CommonNavigator
    2. Create a root PlatformObject
    3. Add Extension navigatorContent and bind it to the navigator
    4. Implement the Custom Folder and File Types, ContentProvider and LabelProvider
  • Register a listener that will be called when the workspace changes and the view needs to be updated
    1. Add a ResourceListener

Subclass CommonNavigator

In Eclipse you have many ways to create a new class. For the purposes of this example, let’s define the CustomNavigator within plugin.xml and use its infrastructure to keep everything in sync.

  • Open plugin.xml –> Extensions –> Custom Plug-in Navigator (view)
  • Change the Class entry from the default CommonNavigator class to

Class: customnavigator.navigator.CustomNavigator
Just type it in. The class doesn’t exist yet.

  • Click on Class link to open the New Java Class Wizard.
  • Click Browse for Superclass and choose type CommonNavigator. Click OK.
  • Click Finish to close the New Java Class Wizard.

When the editor opens delete the CustomNavigator constructor and its comment.

Override getInitialInput() with the following code and return an object of a type we haven’t defined yet: CustomProjectWorkbenchRoot.

public class CustomNavigator extends CommonNavigator {
    @Override
    protected Object getInitialInput() {
        return new CustomProjectWorkbenchRoot();
    }
}

Damn, that was a lot of code.

Create a Root PlatformObject

Based on advice from Simon Zambrovski the CustomProjectWorkbenchRoot should not inherit from PlatformObject any more. Who am I to argue (if you like you can read up on at Simon’s site)?

Create the class CustomProjectWorkbenchRoot any way you like. I typically move the cursor to the offending line, press Ctrl+1, and select Create Class. I also created it in the same package as the CustomNavigator.

Leave CustomProjectWorkbenchRoot empty.

Run the runtime workbench if you like; open the Custom Navigator, create a Java project, create a file to go with it and the project and class file should appear in the Custom Navigator. Makes you kinda proud doesn’t it?

Of course, if all we wanted to do was create a clone of the Resource Navigator it would be easier to just go out for a walk until the feeling passed (yawn). The real goal is to have the Custom Navigator only display projects of type CustomProject (and a few other things, but one thing at a time).

Add Extension navigatorContent

Time to add a new Extension. This extension will define what content will appear in the navigator. Its name is, you guessed it, navigatorContent.

In plugin.xml go to Extensions and click Add. When the Extensions dialog opens type nav and select org.eclipse.ui.navigator.navigatorContent. Click Finish.

Right click on org.eclipse.ui.navigator.navigatorContent and select New –> navigatorContent. Enter the following:

  • id: customnavigator.navigatorContent
  • name: Custom Navigator Content
  • contentProvider: customnavigator.navigator.ContentProvider
  • labelProvider: customnavigator.navigator.LabelProvider

If the goal is to only display projects of type CustomProject then we need content/label providers that only recognize those resource types. Time to write some more code.

Click on the contentProvider link to open the New Java Class wizard. We like what we see. Click Finish.

Do the same for labelProvider.

Display Only Custom Nature Projects

This is where we perform a lobotomy, or more accurately an extension-ectomy, to the configuration of the Custom Navigator to get it to display projects of type Custom Project.

Let’s clean up the non-essential extensions:

  • Open plugin.xml –> Extensions
  • Open org.eclipse.ui.navigator.viewer –> customnavigator.navigator (viewerContentBinding) –> (includes)
  • Delete all of the nodes under (includes) (but NOT (includes))
  • Save plugin.xml

Now add the extension that binds the navigatorContent to the navigator:

  • Go back to org.eclipse.ui.navigator.viewer –> customnavigator.navigator (viewerContentBinding) –> (includes)
  • Right click on (includes) and select New –> contentExtension
  • Enter the id of the Custom Navigator Content extension in the pattern field:
    • pattern: customnavigator.navigatorContent

To see a Custom Project in the Custom Navigator we need to add the triggerPoints that tell CNF which resources we care about (there is more to it than that, but that explanation will have to do):

  • Open org.eclipse.ui.navigator.navigatorContent –> Custom Navigator Content (navigatorContent)
  • Select Custom Navigator Content (navigatorContent) –> New –> triggerPoints
  • Select triggerPoints –> New –> or
  • Select or –> New –> instanceOf
  • In the value field click Browse and select customnavigator.navigator.CustomProjectWorkbenchRoot.

We’ve actually done quite a bit. If we were to add print statements in the ContentProvider and LabelProvider classes, start the runtime workbench, and create a Custom Project you would see output in the Console view. Very cool, but still not quite what we are looking for especially since the Custom Navigator does not know how to update itself when new resources are created.

Implement the Custom Folder and File Types, ContentProvider and LabelProvider

(Yeah, long title because a whole bunch of things have to be done first before we can turn on the switch and see the navigator returning custom content.)

Now that our ContentProvider and LabelProvider are being called what should they return? If we only want to display CustomProjects then the ContentProvider needs to return only CustomProject information and the LabelProvider has to know how to talk to our CustomProject objects to return the proper label information.

Let’s look at the ContentProvider first. We don’t want it talking to an object that is not a Custom Project (I hate double negatives) so we have to put an isInstance() check for objects of type CustomProjectWorkbenchRoot (we’ll add CustomProjectParent later). Why CustomProjectWorkbenchRoot? The call to getElements()/getChildren() will return the CustomProjectParent objects that will be queried for their text and displayable image.

Once the ContentProvider is sure that an object of the proper type is available it can do the following:
– if this is the first time in retrieve all the projects from the workbench (hence the call to initializeParent() if _customProjectParents is null)
– wrap each Custom Project in a CustomProjectParent object

From ContentProvider.java

public class ContentProvider implements ITreeContentProvider {

    private static final Object[] NO_CHILDREN = {};
    private CustomProjectParent[] _customProjectParents;

    @Override
    public Object[] getChildren(Object parentElement) {
        Object[] children = null;
        if (CustomProjectWorkbenchRoot.class.isInstance(parentElement)) {
            if (_customProjectParents == null) {
                _customProjectParents = initializeParent(parentElement);
            }

            children = _customProjectParents;
        } else {
            children = NO_CHILDREN;
        }

        return children;
    }

    ...

    private CustomProjectParent[] initializeParent(Object parentElement) {
        IProject [] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
        CustomProjectParent[] result = new CustomProjectParent[projects.length];
        for (int i = 0; i < projects.length; i++) {
            result[i] = new CustomProjectParent(projects[i]);
        }

        return result;
    }
}

In initializeParent() we ask the workspace for its current contents and we gratuitously wrap all the IProjects in a CustomProjectParent.

We have the veritable chicken and egg problem: without knowing what the parent should do how do we implement it? Using the YAGNI rule we create it and leave it empty…until the next complaint: the constructor to take in the IProject is missing. So, add that and store the IProject reference. We’ll need it later.

public class CustomProjectParent {

    private IProject _project;

    public CustomProjectParent(IProject iProject) {
        _project = iProject;
    }

    public String getProjectName() {
        return _project.getName();
    }
}

The LabelProvider needs to:
– make sure the incoming object is a CustomProjectParent and if it is:
– get the name of the project and return it
– get the image associated with CustomProjects and return it

Both of these tasks are going to be delegated to the CustomProjectParent otherwise the LabelProvider is going to be a tangle of wires as we add more and more types to the navigator tree.

LabelProvider.java

public class LabelProvider implements ILabelProvider {
    ...

    @Override
    public String getText(Object element) {
        String text = "";
        if (CustomProjectParent.class.isInstance(element)) {
            text = ((CustomProjectParent)element).getProjectName();
        }

        return text;
    }

    ...
}

The above code is going to change, but it is always instructional to see the evolution of the code.

Run a test:
– Start the runtime workbench
– Close the Welcome window
– Create a Java project
– Create a Custom Project
– When the Open Associated Perspective dialog opens click No
– Open Window –> Show View –> Other –> Custom Projects –> Custom Plug-in Navigator
Both projects will appear in the Custom Navigator as labels but no images.

Next task: exclude all the projects that are not members of our club. We do that in he ContentProvider.

ContentProvider.java

    private CustomProjectParent[] initializeParent(Object parentElement) {
        IProject [] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();

        List<CustomProjectParent> list = new Vector<CustomProjectParent>();
        for (int i = 0; i < projects.length; i++) {
            try {
                if (projects[i].getNature(ProjectNature.NATURE_ID) != null) {
                    list.add(new CustomProjectParent(projects[i]));
                }
            } catch (CoreException e) {
                // Go to the next IProject
            }
        }

        CustomProjectParent[] result = new CustomProjectParent[list.size()];
        list.toArray(result);

        return result;
    }

Oh, oh! We are out of sync with ourselves. The navigator plug-in is referencing customplugin.natures.ProjectNature which is not on its classpath or dependency list. In the customnavigator plug-in:

  • plugin.xml –> Dependencies –> Add
  • Select A Plug-in: customplugin
  • Click OK
  • Save plugin.xml

The LabelProvider should compile cleanly.

Run the (decidely) manual test again and now the Custom Project will be the only project displayed in the Custom Navigator.

[This needs a packaged test. In my haste to present how to configure the navigator I skipped a standard-practice step. Rather than interrupt the flow, which I am doing right now, I will present the steps to run the first series of tests on the navigator in the next post.]

The LabelProvider needs one more thing: an image to display along with the label. Copy the project-folder.png from customplugin or whatever image you decided to use in customplugin. We will take advantage of Eclipse’s property handling capabilities to centralize this functionality (besides, other plug-ins do the same thing. Who am I to rock the boat?).

Add this to CustomProjectParent:

CustomProjectParent.java

    private Image _image;

    ...

    public Image getImage() {
        if (_image == null) {
            _image = Activator.getImage("icons/project-folder.png"); //$NON-NLS-1$
        }

        return _image;
    }

[Hey! I just noticed that the folder to hold the icons is called icon instead of icons. Select it in the Package Explorer, press F2 and rename icon to icons.]

No, Activator.getImage() doesn’t exist. Press Ctrl+1 to auto-create it in the Activator class. Put in the code below.

Activator.java

    public static Image getImage(String imagePath) {
        ImageDescriptor imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, imagePath);
        Image image = imageDescriptor.createImage();

        return image;
    }

Yes, AbstractUIPlugin will take care of loading the image for us. Sweet.

Back to LabelProvider:

LabelProvider.java

    public Image getImage(Object element) {
        System.out.println("LabelProvider.getImage: " + element.getClass().getName());
        Image image = null;

        if (CustomProjectParent.class.isInstance(element)) {
            image = ((CustomProjectParent)element).getImage();
        }
        // else ignore the element

        return image;
    }

Run the manual test again. The screen capture below is a little different than you are probably seeing from the comfort of your own home, but shows two projects in the Project Explorer vs one in the Custom Plug-in Navigator.

custom-navigator-with-custom-project

Display a List of Categories per Project

A CustomProject displayed in the CustomNavigator will have two categories one of which has 3 sub-categories:

  • Schema
    • tables
    • views
    • filters
  • Stored Procedures

Tables, views and filters will list individual entries and Stored Procedures will list individual stored procs.

As usual the categories are bogus, but give us something to work with rather than parent1 and parent2.

This next list is going be somewhat daunting. These items need to be implemented/modified for the Custom Navigator to be of any value:

  • ContentProvider.getChildren() – return the children of CustomProjectParents
  • ContentProvider.getParent() – return the parent of CustomProjectParents and their children
  • ContentProvider.hasChildren() – return true if the incoming element has children. CustomProjectWorkbenchRoot will return true if any CustomProjects exist, CustomProjectParents will always return true since they will have Schema and Stored Proc children, Schema will return true as it has 3 children, Stored Procedures will return true if it has any entries.
  • LabelProvider.getImage() – check the object type to retrieve the proper image
  • LabelProvider.getText() – check the object type to retrieve the proper text
  • CustomProjectParent.getChildren() – will always return children (Schema and Stored Procedures)
  • CustomProjectSchema – implement getText(), getImage(), getParent(), getChildren() and a constructor that instantiates the Tables, Views and Filters children using the contents of an IProject
  • CustomProjectStoredProcedures – implement getText(), getImage(), getParent(), getChildren() and a constructor that will create children to represent file entries
  • CustomProjectSchemaTables – Display tables from an XML file
  • CustomProjectSchemaViews – Display views from an XML file
  • CustomProjectSchemaFilters – Display filters from an XML file
  • ICustomProjectElement – an interface used by all of the parents and children (except CustomProjectWorkbenchRoot) to make sure they all define getText() and get Image(). This should make the logic in LabelProvider.get[Text|Image]() a little simpler

(When I said this post was going to be long I wasn’t kidding.)

Due to the length of this post you can download the code up to this point instead of cutting-and-pasting until your fingers start to bleed.

In any case, let’s see what it will take to do a sampling of the above.

ContentProvider.getChildren()

Modifying ContentProvider.getChildren() to support CustomProjectParent means changing:

  • ContentProvider.getChildren()
  • CustomProjectParent.getChildren()
  • LabelProvider.getText()
  • LabelProvider.getImage()

and creating:

  • CustomProjectSchema.getChildren()
  • CustomProjectSchemaTables.getChildren()
  • CustomProjectSchemaViews.getChildren()
  • CustomProjectSchemaFilters.getChildren()
  • CustomProjectStoredProcedures.getChildren()

The above entailed passing in the parent reference through the constructor, creating children if appropriate and using the parent reference to find the reference to the IProject. Having the IProject reference means we can work out the leaf nodes of the categories created above.

I created a common interface, ICustomProjectElement, to the various parent and children to make their use in ContentProvider and LabelProvider simpler.

The interface did not come to me full blown. I grew it as I wrote the code for the children and it became obvious which methods were needed.

public interface ICustomProjectElement {

    public Image getImage();

    public Object[] getChildren();

    public String getText();

    public boolean hasChildren();

    public IProject getProject();

    public Object getParent();
}

In ContentProvider I changed getChildren() to reflect the use of ICustomProjectElement:

    public Object[] getChildren(Object parentElement) {
        Object[] children = null;
        if (CustomProjectWorkbenchRoot.class.isInstance(parentElement)) {
            if (_customProjectParents == null) {
                _customProjectParents = initializeParent(parentElement);
            }

            children = _customProjectParents;
        } else if (ICustomProjectElement.class.isInstance(parentElement)) {
            children = ((ICustomProjectElement) parentElement).getChildren();
        } else {
            children = NO_CHILDREN;
        }

        return children;
    }

LabelProvider gained from the use of the interface as well:

    public String getText(Object element) {
        String text = ""; //$NON-NLS-1$
        if (ICustomProjectElement.class.isInstance(element)) {
            text = ((ICustomProjectElement)element).getText();
        }
        // else ignore the element

        return text;
    }

Since the CustomProjectParent category will always have 2 children the code is also reasonable straightforward:

public class CustomProjectParent implements ICustomProjectElement {

    ...

    public ICustomProjectElement[] getChildren() {
        if (_children == null) {
            _children = initializeChildren(_project);
        }
        // else we have already initialized them

        return _children;
    }

    ...

    private ICustomProjectElement[] initializeChildren(IProject project) {
        ICustomProjectElement[] children = {
                new CustomProjectSchema(this),
                new CustomProjectStoredProcedures(this)
        };

        return children;
    }
}

Starting the runtime workbench and creating a custom project gives us a strong beginning to giving our folder-centric project a category-based view.

custom-navigator-end-of-part-7

All of the child nodes, CustomProjectSchema, CustomProjectStoredProcedures, CustomProjectSchemaTables, etc., will have code that looks suspiciously similar. It will all be refactored in the post after the navigator is mostly done. Something I learned in my years as a consultant/instructor/mentor is that you can’t test your way to learning. We’re still learning here. The thing to bear in mind is that until you know what you don’t know, you don’t know. Worry about duplicate/sloppy code at refactoring time.

[This is where the explanation for how to take an existing project structure, automatically categorize files located in arbitrary folders, and display elements from one of the XML files as information under one of the categories. As this post has gone on longer than I had planned, and I expected it to go pretty long, I will complete those last two steps in the next post. Rest easy; the hard part is over...I think.]

Rewind

So what just happened?

  1. I managed to clean up the look of the custom wizard and custom perspective by adding icon images to them.
  2. After much twisting and shouting the Custom Navigator displays only Custom Projects and the CustomProject is displayed in a way that will eventually categorizes things within the project in a more intuitive way.

I am sure you are walking away feeling like you don’t know much more about how to program/configure the CNF than you did when you started. That’s okay. There are plenty of other sources for that sort of boring information. Depth of knowledge is overrated…until it’s not. Then you’re screwed.

Download the code up to this point. Let me know if it helps.

(BTW, I cheated like there was no tomorrow. I had print statements, books, web pages…anything I thought would give me some insight into how the CNF works. This is not an easy framework. But it is cool!)

The cat is alive, but barely.

Links

Resources

http://www.eclipse.org/articles/Article-TreeViewer/TreeViewerArticle.htm
http://www.techjava.de/topics/2009/04/eclipse-common-navigator-framework/

Icons

filter – http://www.iconspedia.com/icon/document-2454.html
binoculars – http://www.clker.com/clipart-2908.html
database – http://www.clker.com/clipart-14651.html
schema – http://www.clker.com/clipart-1780.html
tables – http://www.clker.com/clipart-3493.html

Code

CustomNavigator.java

/**
 * Coder beware: this code is not warranted to do anything.
 * Copyright Oct 16, 2009 Carlos Valcarcel
 */
package customnavigator.navigator;

import org.eclipse.ui.navigator.CommonNavigator;

/**
 * @author carlos
 */
public class CustomNavigator extends CommonNavigator {
    @Override
    protected Object getInitialInput() {
        return new CustomProjectWorkbenchRoot();
    }
}

ContentProvider.java

/**
 * Coder beware: this code is not warranted to do anything.
 * Copyright Oct 17, 2009 Carlos Valcarcel
 */
package customnavigator.navigator;

import java.util.List;
import java.util.Vector;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

import customplugin.natures.ProjectNature;

/**
 * @author carlos
 */
public class ContentProvider implements ITreeContentProvider {

    private static final Object[]   NO_CHILDREN = {};
    private ICustomProjectElement[] _customProjectParents;

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.
     * Object)
     */
    @Override
    public Object[] getChildren(Object parentElement) {
        Object[] children = null;
        if (CustomProjectWorkbenchRoot.class.isInstance(parentElement)) {
            if (_customProjectParents == null) {
                _customProjectParents = initializeParent(parentElement);
            }

            children = _customProjectParents;
        } else if (ICustomProjectElement.class.isInstance(parentElement)) {
            children = ((ICustomProjectElement) parentElement).getChildren();
        } else {
            children = NO_CHILDREN;
        }

        return children;
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object
     * )
     */
    @Override
    public Object getParent(Object element) {
        System.out.println("ContentProvider.getParent: " + element.getClass().getName()); //$NON-NLS-1$
        Object parent = null;
        if (ICustomProjectElement.class.isInstance(element)) {
            parent = ((ICustomProjectElement)element).getParent();
        }
        return parent;
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.
     * Object)
     */
    @Override
    public boolean hasChildren(Object element) {
        boolean hasChildren = false;

        if (CustomProjectWorkbenchRoot.class.isInstance(element)) {
            hasChildren = _customProjectParents.length > 0;
        } else if (ICustomProjectElement.class.isInstance(element)) {
            hasChildren = ((ICustomProjectElement)element).hasChildren();
        }
        // else it is not one of these so return false
        
        return hasChildren;
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java
     * .lang.Object)
     */
    @Override
    public Object[] getElements(Object inputElement) {
        // This is the same as getChildren() so we will call that instead
        return getChildren(inputElement);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.viewers.IContentProvider#dispose()
     */
    @Override
    public void dispose() {
        System.out.println("ContentProvider.dispose"); //$NON-NLS-1$
        // TODO Auto-generated method stub

    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface
     * .viewers.Viewer, java.lang.Object, java.lang.Object)
     */
    @Override
    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        System.out
                .println("ContentProvider.inputChanged: old: " + oldInput.getClass().getName() + " new: " + newInput.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$
        // TODO Auto-generated method stub

    }

    private ICustomProjectElement[] initializeParent(Object parentElement) {
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();

        List<CustomProjectParent> list = new Vector<CustomProjectParent>();
        for (int i = 0; i < projects.length; i++) {
            try {
                if (projects[i].getNature(ProjectNature.NATURE_ID) != null) {
                    list.add(new CustomProjectParent(projects[i]));
                }
            } catch (CoreException e) {
                // Go to the next IProject
            }
        }

        CustomProjectParent[] result = new CustomProjectParent[list.size()];
        list.toArray(result);

        return result;
    }

}

LabelProvider.java

/**
 * Coder beware: this code is not warranted to do anything.
 *
 * Copyright Oct 17, 2009 Carlos Valcarcel
 */
package customnavigator.navigator;

import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.swt.graphics.Image;

/**
 * @author carlos
 *
 */
public class LabelProvider implements ILabelProvider {

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
     */
    @Override
    public Image getImage(Object element) {
        Image image = null;
        
        if (ICustomProjectElement.class.isInstance(element)) {
            image = ((ICustomProjectElement)element).getImage();
        }
        // else ignore the element
        
        return image;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
     */
    @Override
    public String getText(Object element) {
        String text = ""; //$NON-NLS-1$
        if (ICustomProjectElement.class.isInstance(element)) {
            text = ((ICustomProjectElement)element).getText();
        }
        // else ignore the element
        
        return text;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
     */
    @Override
    public void addListener(ILabelProviderListener listener) {
        System.out.println("LabelProvider.addListener: " + listener.getClass().getName()); //$NON-NLS-1$
        // TODO Auto-generated method stub

    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
     */
    @Override
    public void dispose() {
        System.out.println("LabelProvider.dispose"); //$NON-NLS-1$
        // TODO Auto-generated method stub

    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
     */
    @Override
    public boolean isLabelProperty(Object element, String property) {
        System.out.println("LabelProvider.isLabelProperty: " + element.getClass().getName()); //$NON-NLS-1$
        // TODO Auto-generated method stub
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
     */
    @Override
    public void removeListener(ILabelProviderListener listener) {
        System.out.println("LabelProvider.removeListener: " + listener.getClass().getName()); //$NON-NLS-1$
        // TODO Auto-generated method stub

    }

}

Follow

Get every new post delivered to your Inbox.

Join 3,185 other followers