Eclipse Search

Loading

Jun 26, 2009

Keyboard accessibility thru Command Framework

Keyboard shortcuts is usually much speedier than reaching out your mouse, moving it, pointing it to something and clicking. But there are some things which cannot be done that easily by keyboard shortcuts. For me, one of them is finding out a closed project and open it. Unfortunately, I've quite a large set of projects in my workspace and try to keep most them closed, when not used. In addition to that in the Package Explorer, I've the 'Closed Projects' filter on. So if I need to open a project, I've use the pull down menu, uncheck 'Closed Projects' navigate thru the working sets to find the right project and double click it. To enable keyboard access to this regular task, I decided to make use of Commands Framework.

The solution is to add a parameterized command, and in the values, I compute the projects which are closed. So when I press the awesome shortcut (Ctrl+3) it would display me the list of closed projects. With few keys, I can navigate to the project I want and open it. Lets see how to do it. First step is the command with the parameter:

<extension point="org.eclipse.ui.commands">
   <command
            defaultHandler="com.eclipse_tips.handlers.OpenProjectHandler"
            id="com.eclipse-tips.openProject.command"
            name="Open Project">
      <commandParameter
               id="com.eclipse-tips.openProject.projectNameParameter"
               name="Name"
               optional="false"
               values="com.eclipse_tips.handlers.ProjectNameParameterValues">
      </commandParameter>
   </command>
</extension>

And the handler:

public Object execute(ExecutionEvent event) throws ExecutionException {
 String projectName = event.getParameter("com.eclipse-tips.openProject.projectNameParameter");
 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
 IProject project = root.getProject(projectName);
 try {
  project.open(null);
 } catch (CoreException e) {
  throw new ExecutionException("Error occured while open project", e);
 }
 return null;
}

For the parameter values, I look for closed projects and return them:

public Map<String, String> getParameterValues() {

 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
 IProject[] projects = root.getProjects();
 Map<String, String> paramValues = new HashMap<String, String>();
 for (IProject project : projects) {
  if (project.exists() && !project.isOpen()) {
   paramValues.put(project.getName(), project.getName());
  }

 }
 return paramValues;
}


So finally, When I press Ctrl+3 and type OPN, I get the list:

 

This idea can be extended to provide keyboard accessibility to many functionalities. Say in an RCP mail application, you can add a command like 'Go To Mail' with parameter as the Subject/Sender:


Hmmm, if only the 'Built On Eclipse' mail app that I *have* to use, knows the existence of threads other than the UI thread :-(

Jun 3, 2009

Subtask in ProgressMonitors

Here is a trivial tip. When inspecting a bug, I found a interesting thing on Progress Monitors. We know monitor.worked() increments the progress bar, but how do we change the text to update the current subtask? The initial text is set by the beginTask() method and it should be called only once. I digged into the IProgressMonitor and found the subtask() method:

IRunnableWithProgress operation = new IRunnableWithProgress() {

 public void run(IProgressMonitor monitor) {

  monitor.beginTask("Main task running ...", 5);
  for (int i = 0; i < 5; i++) {
   monitor.subTask("Subtask # " + i + " running.");
   runSubTask(new SubProgressMonitor(monitor, 1), i);
  }
 }

};


Now the question is what happens when the runSubTask() method sets another subTask on the SubProgressMonitor?

private void runSubTask(IProgressMonitor monitor, int subTaskId) {

 monitor.beginTask("Sub task running", 10);
  for (int i = 0; i < 10; i++) {
   monitor.subTask("Inside subtask, " + i + " out of 10");
   // do something here ...
   monitor.worked(1);
   if (monitor.isCanceled())
    throw new OperationCanceledException();
 }
  monitor.done();
 }

}

Basically the SubProgressMonitor's subTask() overwrites the parent's subTask(). Thats the default behaviour. You can customize it with the style bits provided in the SubProgressMonitor:

If you want to append the SubProgressMonitor's subTask info, use the style PREPEND_MAIN_LABEL_TO_SUBTASK:
new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK), i);


Else if you want to ignore it altogher then use the SUPPRESS_SUBTASK_LABEL style:

new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL), i);