Time for action – creating a nature

A nature is created by implementing the IProjectNature interface. This will be used to create a MinimarkNature, which will allow projects to be associated with the MinimarkBuilder. Perform the following steps:

  1. Create a class called MinimarkNature in the com.packtpub.e4.minimark.ui package:
    public class MinimarkNature implements IProjectNature {
      public static final String ID ="com.packtpub.e4.minimark.ui.MinimarkNature";
      private IProject project;
      public IProject getProject() {
        return project;
      }
      public void setProject(IProject project) {
        this.project = project;
      }
      public void configure() throws CoreException {
      }
      public void deconfigure() throws CoreException {
      }
    }
  2. The purpose of a nature is to assist by adding (or configuring) the builders, which are associated by an ID. To make cross-referencing possible, define a constant in the MinimarkBuilder which can be used to refer to it by the nature:
    public class MinimarkBuilder extends IncrementalProjectBuilder {
      public static final String ID ="com.packtpub.e4.minimark.ui.MinimarkBuilder";
  3. The way a builder is added to the project is by accessing the project descriptor and adding a build command. There is no easy way of adding or removing a builder, so acquire the set of commands, search to see if it is present, and then add or remove it. Using the Arrays class takes away some of the pain. Implement the configure() method as follows:
    public void configure() throws CoreException {
      IProjectDescription desc = project.getDescription();
      List<ICommand> commands = new ArrayList<ICommand>(
        Arrays.asList(desc.getBuildSpec()));
      Iterator<ICommand> iterator = commands.iterator();
      while (iterator.hasNext()) {
        ICommand command = iterator.next();
        if (MinimarkBuilder.ID.equals(command.getBuilderName())) {
          return;
        }
      }
      ICommand newCommand = desc.newCommand();
      newCommand.setBuilderName(MinimarkBuilder.ID);
      commands.add(newCommand);
      desc.setBuildSpec(commands.toArray(new ICommand[0]));
      project.setDescription(desc,null);
    }
  4. To deconfigure a project, the reverse is done. Implement the deconfigure() method as follows:
    public void deconfigure() throws CoreException {
      IProjectDescription desc = project.getDescription();
      List<ICommand> commands = new ArrayList<ICommand>(Arrays.asList(desc.getBuildSpec()));
      Iterator<ICommand> iterator = commands.iterator();
      while (iterator.hasNext()) {
        ICommand command = iterator.next();
        if (MinimarkBuilder.ID.equals(command.getBuilderName())) {
          iterator.remove();
        }
      }
      desc.setBuildSpec(commands.toArray(new ICommand[0]));
      project.setDescription(desc,null);
     }
  5. Having implemented the nature, it needs to be defined as an extension point within the plugin.xml of the minimark.ui project:
    <extension id="MinimarkNature"point="org.eclipse.core.resources.natures">
      <runtime>
        <run class="com.packtpub.e4.minimark.ui.MinimarkNature"/>
      </runtime>
    </extension>
  6. To associate the nature with a project, a menu needs to be added to the Configure menu associated with projects. Create an entry in the plugin.xml file for the Add Minimark Nature command, and put it in the projectConfigure menu:
    <extension point="org.eclipse.ui.commands">
      <command name="Add Minimark Nature"defaultHandler="com.packtpub.e4.minimark.ui.AddMinimarkHandler"id="com.packtpub.e4.minimark.ui.AddMinimarkNature"/>
    </extension>
    <extension point="org.eclipse.ui.menus">
      <menuContribution allPopups="false" locationURI="popup:org.eclipse.ui.projectConfigure?after=additions">
        <command label="Add Minimark Nature" style="push"commandId="com.packtpub.e4.minimark.ui.AddMinimarkNature"/>
      </menuContribution>
    </extension>
  7. Create a new class in the com.packtpub.e4.minimark.ui package called AddMinimarkNature, as follows:
    public class AddMinimarkHandler extends AbstractHandler {
      public Object execute(ExecutionEvent event)throws ExecutionException {ISelection sel = HandlerUtil.getCurrentSelection(event);
        if (sel instanceof IStructuredSelection) {
          Iterator<?> it = ((IStructuredSelection)sel).iterator();
          while (it.hasNext()) {
            Object object = (Object) it.next();
            if(object instanceof IProject) {
              try {
                addProjectNature((IProject) object,MinimarkNature.ID);
              } catch (CoreException e) {
                throw new ExecutionException("Failed to set nature on"+ object,e);
              }
            }
          }
        }
        return null;
      }
      private void addProjectNature(IProject project, String nature)throws CoreException {
        IProjectDescription description = project.getDescription();
        List<String> natures = new ArrayList<String>(
          Arrays.asList(description.getNatureIds()));
        if(!natures.contains(nature)) {
          natures.add(nature);
          description.setNatureIds(natures.toArray(new String[0]));
          project.setDescription(description, null);
        }
      }
    }
  8. Run the Eclipse instance, create a new General project, and open the .project file using the Navigator view. Now right-click on the project, and select Configure | Add Minimark Nature to add the nature. When the nature is added, it will add the commands automatically and the changes will be visible in the .project file.

What just happened?

The MinimarkNature class was created to inject a builder into the project description when added. Changing the .project file manually does not add the builder, so an action to programmatically add the nature was created and added to the standard Configure menu.

Both the Nature and the Builder are referred to via IDs; these are stored in the .project and .classpath files. Since these may be checked into a version control system, the names of these IDs should be consistent between releases. (It's best practice to add these to version control.)

The project descriptor contains the content from the .project file and stores an array of nature IDs and commands. To add a nature to a project, its identifier is appended to this list. Note that the change only takes effect when the updated project descriptor is set on the project.

Since the nature's modifications only take effect when set programmatically, the Add Minimark Nature command was created to add the nature. The command was put into the menu popup org.eclipse.ui.projectConfigure?after=additions, which is the standard location for adding and configuring natures. Conventionally, either a separate command to Add Minimark Nature and Remove Minimark Nature is used, or a Toggle Minimark Nature could be used for both actions. The advantage of the separate Add/Remove menu items is that their visibility can be controlled based on whether the project already has the nature or not.

The handler class used HandlerUtil to extract the current selection; though this just extracts the object from the parameter map via the variable name selection.

To avoid spelling errors, it makes sense to define constants as static final variables. If they are related with class names, it can be better to use class.getName() as the identifier so that if they are renamed then the identifiers are automatically updated as well. Alternatively, they can be created from a concatenation with the plug-in's ID (in this case, via Activator.ID).

Have a go hero – enabling for a selected object type

It is conventional to only show the configure option if it is strictly necessary. In the case where projects already have MinimarkNature, we should not show the command. Use the visibleWhen property to target the selection and only enable it if the projectNature of the selected object is that of the minimark builder.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset