Time for action – creating a nature

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

  1. Create a class called MinimarkNature in the com.packtpub.e4.minimark.ui package as follows:
    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 class, 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 whether it is present, and then add or remove it. Using the Arrays class takes away some of the pain. Implement the configure method in the MinimarkNature class 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);
    }

    Note

    The project description's build spec is an array, and should be kept in the same order if it is updated. As a result, non-order-preserving data structures such as a Set or Map cannot be used here.

  4. To de-configure 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 file in the com.packtpub.e4.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.

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—however, 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 popup:org.eclipse.ui.projectConfigure?after=additions menu, 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 menu items. The advantage of the separate add or 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, although 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 – enable for selected object type

It is conventional to only show the Configure option if it is strictly necessary. In the case where projects already have a MinimarkNature, the command should not be shown. Use the visibleWhen property to target the selection and only enable it if the projectNature of the selected object is that of the MinimarkNature. Alternatively, implement another handler that performs the removal of the nature, and then use an expression to determine whether the handler should be shown based on whether the project already has the nature or not.

The handler here was implemented using Eclipse 3.x classes. Convert these to a handler using the E4 model, as shown in Chapter 4, Interacting with the User.

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

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