Wednesday, December 29, 2010

Building a Workspace Resources-powered Common Navigator Framework (CNF) View

Common Navigator Framework (CNF) View is a very useful and flexible component to display structure of any object in an Eclipse RCP Application.

There are two ways to use CNF :

  1. Displaying Eclipse Resources inside Workspace
  2. Displaying custom content (non-resources)
The good news is the two ways can be mixed.
If you use Resources you can extend it with "custom content" underneath (using Navigator Content Extensions aka NCEs).

The bad news is even on the current milestone of Eclipse Indigo 3.7 it's still not straightforward to use CNF with Resources.
Again the good news is that there is a solution. :-)

I'll focus on displaying workspace resources (folders and files inside the workspace physical directory) in CNF because it's not obvious how to do it inside Eclipse RCP.
Note that if you use the IDE Application (at least the IDE WorkbenchAdvisor) it just works by default. But in Eclipse RCP you have to do some preparatory work.

The steps are outlined in Eclipse Help > Common Navigator Framework > Content and Action Binding, as follows.

Please note, that using CNF inside of your own RCP requires three additional steps.

  1. Add the
org.eclipse.ui.ide as dependent plug-in
  • To get the resource workspace root (
  • IWorkspaceRoot) as default page input, override the WorkbenchAdvisor.getDefaultPageInput() method in your WorkbenchAdvisor:
    public IAdaptable getDefaultPageInput()         {                 return ResourcesPlugin.getWorkspace().getRoot();         }
  • Hook the workbench adapters correctly before they are used, so add this code to the
  • WorkbenchAdvisor.initialize(IWorkbenchConfigurer) method:
    public void initialize(IWorkbenchConfigurer configurer)         {                 IDE.registerAdapters();         }

    This will display workspace resources with labels but there are no icons yet.

    To display icons you still need to "steal" the internal declareWorkbenchImages() from org/eclipse/ui/internal/ide/application/IDEWorkbenchAdvisor.java in org.eclipse.ide.ui.application plugin.

    So the complete relevant parts become like this:

    import org.eclipse.core.resources.IWorkspaceRoot;
    import org.eclipse.core.resources.ResourcesPlugin;
    import org.eclipse.core.runtime.FileLocator;
    import org.eclipse.core.runtime.IAdaptable;
    import org.eclipse.core.runtime.Path;
    import org.eclipse.core.runtime.Platform;
    import org.eclipse.jface.resource.ImageDescriptor;
    import org.eclipse.ui.application.IWorkbenchConfigurer;
    import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
    import org.eclipse.ui.application.WorkbenchAdvisor;
    import org.eclipse.ui.application.WorkbenchWindowAdvisor;
    import org.eclipse.ui.ide.IDE;
    import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
    import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
    import org.osgi.framework.Bundle;
    ...
    @Override
    public void initialize(IWorkbenchConfigurer configurer) {
    super.initialize(configurer);
    //configurer.setSaveAndRestore(true); // if you want
    IDE.registerAdapters();
    declareWorkbenchImages();
    }
    ...
    /**
    * Declares all IDE-specific workbench images. This includes both "shared"
    * images (named in {@link IDE.SharedImages}) and internal images (named in
    * {@link org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages}).
    *
    * @see IWorkbenchConfigurer#declareImage
    */
    private void declareWorkbenchImages() {

    final String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$
    final String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; // Enabled //$NON-NLS-1$

    // toolbar
    // icons.
    final String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; // Disabled //$NON-NLS-1$
    // //$NON-NLS-1$
    // toolbar
    // icons.
    final String PATH_ETOOL = ICONS_PATH + "etool16/"; // Enabled toolbar //$NON-NLS-1$
    // //$NON-NLS-1$
    // icons.
    final String PATH_DTOOL = ICONS_PATH + "dtool16/"; // Disabled toolbar //$NON-NLS-1$
    // //$NON-NLS-1$
    // icons.
    final String PATH_OBJECT = ICONS_PATH + "obj16/"; // Model object //$NON-NLS-1$
    // //$NON-NLS-1$
    // icons
    final String PATH_WIZBAN = ICONS_PATH + "wizban/"; // Wizard //$NON-NLS-1$
    // //$NON-NLS-1$
    // icons

    // View icons
    final String PATH_EVIEW= ICONS_PATH + "eview16/"; //$NON-NLS-1$


    Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH);

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL
    + "build_exec.gif", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER,
    PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED,
    PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL
    + "search_src.gif", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER,
    PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED,
    PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL
    + "next_nav.gif", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL
    + "prev_nav.gif", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN
    + "newprj_wiz.png", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ,
    PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN
    + "newfile_wiz.png", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ,
    PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ,
    PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ,
    PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ,
    PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ,
    PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN
    + "saveas_wiz.png", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN
    + "quick_fix.png", false); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT,
    PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT
    + "cprj_obj.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER,
    PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$


    // Quick fix icons
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED,
    PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED,
    PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_FIXABLE_WARNING,
    PATH_OBJECT + "quickfix_warning_obj.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_FIXABLE_ERROR,
    PATH_OBJECT + "quickfix_error_obj.gif", true); //$NON-NLS-1$


    // task objects
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK,
    // PATH_OBJECT+"hprio_tsk.gif");
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_MPRIO_TSK,
    // PATH_OBJECT+"mprio_tsk.gif");
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK,
    // PATH_OBJECT+"lprio_tsk.gif");

    declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK,
    PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK,
    PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT
    + "complete_tsk.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT
    + "incomplete_tsk.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT
    + "welcome_item.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT
    + "welcome_banner.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT
    + "error_tsk.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT
    + "warn_tsk.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT
    + "info_tsk.gif", true); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL
    + "flatLayout.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT,
    PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY,
    PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$

    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEMS_VIEW,
    PATH_EVIEW + "problems_view.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEMS_VIEW_ERROR,
    PATH_EVIEW + "problems_view_error.gif", true); //$NON-NLS-1$
    declareWorkbenchImage(ideBundle,
    IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEMS_VIEW_WARNING,
    PATH_EVIEW + "problems_view_warning.gif", true); //$NON-NLS-1$

    // synchronization indicator objects
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT,
    // PATH_OVERLAY+"wbet_stat.gif");
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_SBET_STAT,
    // PATH_OVERLAY+"sbet_stat.gif");
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_CONFLICT_STAT,
    // PATH_OVERLAY+"conflict_stat.gif");

    // content locality indicator objects
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_NOTLOCAL_STAT,
    // PATH_STAT+"notlocal_stat.gif");
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LOCAL_STAT,
    // PATH_STAT+"local_stat.gif");
    // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_FILLLOCAL_STAT,
    // PATH_STAT+"filllocal_stat.gif");
    }

    /**
    * Declares an IDE-specific workbench image.
    *
    * @param symbolicName
    *            the symbolic name of the image
    * @param path
    *            the path of the image file; this path is relative to the base
    *            of the IDE plug-in
    * @param shared
    *            <code>true</code> if this is a shared image, and
    *            <code>false</code> if this is not a shared image
    * @see IWorkbenchConfigurer#declareImage
    */
    private void declareWorkbenchImage(Bundle ideBundle, String symbolicName,
    String path, boolean shared) {
    URL url = FileLocator.find(ideBundle, new Path(path), null);
    ImageDescriptor desc = ImageDescriptor.createFromURL(url);
    getWorkbenchConfigurer().declareImage(symbolicName, desc, shared);
    }

    Additional resources:

    12 comments:

    1. Nice article, thanks. We're considering using CNF to create a "navigator" view to which other teams can contribute root nodes. Our contribution will be a database-backed virtual file system. What I'm not sure of is whether to go with a completely custom model, or IResources with EFS, or some combination. Any suggestions?

      ReplyDelete
    2. @CraigFoote. You're welcome.

      With regard to CNF, it doesn't matter.

      I would strongly suggest using EMF though, and simply use the EMF-provided AdapterFactory-Content/Label-Providers for your CNF. You'll save lots of boilerplate code that way.

      See http://eclipsedriven.blogspot.com/2010/12/reusing-emfedit-generated-itemproviders.html for proof.

      With the UI side solved, all you have to do is connect your EMF models to database. You can do this the usual way, as you'd still be doing this anyway without EMF (i.e. using JPA or even your custom JDBC logic), but with EMF it's actually much easier than "plain POJO" and you can use EMF's metamodel reflection API if you want.

      If you want an easy way to link EMF to RDBMS, take a look at these projects:
      - CDO http://wiki.eclipse.org/CDO
      - Teneo http://wiki.eclipse.org/Teneo
      - Texo http://wiki.eclipse.org/Texo

      See also my CDO post: http://eclipsedriven.blogspot.com/2010/12/cdo-30-with-hibernate-experiences.html

      ReplyDelete
    3. This is a very interesting blog and so i like WOW Gold Cheap and visit your blog again and again. Keep it up.Enjoy when you can, and endure when you must. it ls a good article and love your words , so charming and make people learn a lot WOWGold, thanks !come to my site to Gold WOW for more cool games gold.

      ReplyDelete
    4. Actually impressed! Things are quite, specific, open is often a description in the dilemma. Its content has the knowledge.

      RS Gold
      Buy RS Gold
      Cheap RS Gold
      Buy Cheap RS Gold
      RSGold
      Runescape Gold for Sale

      ReplyDelete
    5. Wow Gold can be used to buy weapons and items, which are essential to finish the tasks or to conquer the enemies in game. Different items have different values, including the most common weapons. They are commonly measured and traded with certain amount of Cheap WOW Gold. So many regular gamers spend several hours every day to farm enough World Of Warcraft Gold to exchange the great weapons they seeking for. But obviously, it's time-consuming and frustrated because you could be beaten constantly.Welcome to www.zyy.com to Buy wow Gold.

      ReplyDelete
    6. While using User interfaceBuy RS Gold part fixed, all you have to perform will be hook up the EMF versions to repository. This can be achieved the typical way, since you'll be accomplishing this in any case without EMF (we.at the. using JPA as well as your current customized JDBC common sense), though EMF is in reality easier when compared with "plain POJO" and you can MapleStory Mesosutilize EMF's metamodel representation API if you need.

      ReplyDelete
    7. The Gnomes now cheap gw2 gold are tabernacle in Ironforge with the Dwarves. This member of WOW Alliance consists of four Gnome racial traits such as Escape Artist, Expansive mind, Arcane Resistance gw2 gold and Engineering Specialization.

      ReplyDelete
    8. The Personnel dread Cheap Diablo 3 Gold is incredibly underwhelming for any Forty-five second cooldown ability. Maybe own it spawn 2-3 jagged disasters as well with the dread as well as slightly improve the injury done on the mark GW2 Gems.

      ReplyDelete
    9. Microsoft Visio Standard 2010 Download offers flexibility and choice by providing tailored work-management solutions for individuals, teams, and enterprises.
      Microsoft Visio Professional 2010 Download provides real-time data connections that allow you to create dynamic, data-driven diagrams easily shared through a browser. It also provides more templates and shapes for engineering, finance, operations, sales, and human resources professionals.
      Visio 2010 Download includes Adobe LiveCycle Designer ES software for advanced form creation.

      ReplyDelete
    10. Nice article, thanks for the information. It's very complete information. I will bookmark for next reference
      jaring futsal | jaring golf | jaring pengaman proyek |
      jaring pengaman bangunan | jaring pengaman gedung
      http://www.jual-jaring.blogspot.com/
      http://www.agen-jaring.blogspot.com/
      http://www.pancasamudera-safetynet.blogspot.com/
      http://www.toko-jaring.blogspot.com/
      http://www.pusat-jaring.blogspot.com/
      http://jualjaringpengaman.blogspot.com/
      https://pancasamudera.wordpress.com/
      https://pasangjaringfutsal.wordpress.com/
      https://jualtambangmurah.wordpress.com/
      https://tokojaring.wordpress.com/
      https://jualjaringfutsal.wordpress.com/
      https://jaringfutsal.wordpress.com/


      ReplyDelete
    11. This can be achieved the typical way, since you'll be accomplishing this in any case without EMF (we.at the. using JPA as well as your current customized JDBC common sense),
      xiaomi mi 4i review
      buy Meizu Metal
      meizu mx5

      ReplyDelete