Reader small image

You're reading from  Eclipse Plug-in Development Beginner's Guide - Second Edition

Product typeBook
Published inAug 2016
Reading LevelExpert
Publisher
ISBN-139781783980697
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Alex Blewitt
Alex Blewitt
author image
Alex Blewitt

contacted on 30 aug 16 _____________ Dr Alex Blewitt has over 20 years of experience in Objective-C and has been using Apple frameworks since NeXTstep 3.0. He upgraded his NeXTstation for a TiBook when Apple released Mac OS X in 2001 and has been developing on it ever since. Alex currently works for an investment bank in London, writes for the on-line technology news site InfoQ and has published two other books for Packt publishing. He also has a number of apps on the Apple AppStore through Bandlem Limited. When he's not working on technology, and if the weather is nice, he likes to go flying from the nearby Cranfield airport. Alex writes regularly at his blog, http://alblue.bandlem.com, as well tweeting regularly from Twitter as @alblue. Acknowledgements This book would not have been possible without the ongoing love and support of my wife Amy, who has helped me through both the highs and lows of life. She gave me the freedom to work during the many late nights and weekends that it takes to produce a book and its associated code repository. She truly is the Lem of my life. I'd also like to thank my parents, Ann and Derek, for their encouragement and support during my formative years. It was this work ethic that allowed me to start my technology career as a teenager and to incorporate my first company before I was 25. I'd also like to congratulate them on their 50th wedding anniversary in 2015, and I look forward to reaching that goal with Amy. Thanks are due especially to the reviewer of this version of the book: Antonio Bello, as well as the previous version of this book: Nate Cook, James Robert and Arvid Gerstmann, who provided excellent feedback on the contents of this book during development and caught many errors in both the text and code. Any remaining errors are my own. I'd also like to thank my children Sam and Holly for inspiring me and hope that they too can achieve anything that they set their minds to. Finally, I'd like to thank Ben Moseley and Eren Kotan, both of whom introduced me to NeXT in the first place and set my career going on a twenty year journey to this book.
Read more about Alex Blewitt

Right arrow

Chapter 4. Interacting with the User

In the last chapter, we looked at some of the basic JFace viewers that provide a representation of data. However, we need to interact with the user and we can do this in multiple ways, from responding to mouse clicks to processing data-intensive operations in the background.

In this chapter we will:

  • Create a menu in response to a user popup

  • Add a command and a handler in a menu

  • Use progress managers to report work

  • Add commands to the progress manager

  • Show errors and deal with failure

Creating menus, commands, and handlers


In Eclipse, menus can be used to trigger user actions. These menus can be displayed at the top of the application window (or top of the screen on macOS). Menus can also be associated with a view through a contextual popup using the right mouse button.

A menu can be associated with a command, which represents a generic operation. The command is then dynamically associated with a handler, which is the code that executes the operation. This allows a generic operation (such as copy) to be executed by different handlers depending on the context.

Time for action – installing the E4 tools


A model fragment needs to be created to add commands and handlers into an E4 plug-in or application. This can be created with the E4 tools that are part of the default Eclipse repository for Eclipse Mars and Eclipse Neon, or can be installed from the E4 page for Luna and below versions.

  1. Go to the Help | Install New Software… menu. For Eclipse Mars, Eclipse Neon and later, choose the http://download.eclipse.org/releases/neon/ site, substituting the platform name if necessary. For Eclipse Luna and below, choose the corresponding update site from the http://download.eclipse.org/e4/downloads/ page instead.

  2. Type e4 tools into the search box and select the Eclipse e4 Tools feature:

  3. Click on Finish to continue installing the tools and restart Eclipse when prompted.

  4. To verify that the tools have been installed correctly, select the com.packtpub.e4.clock.ui project, go to the File | New menu, and search for new model fragment. This should show an entry under...

Time for action – creating commands and handlers


Commands and handlers are common to both Eclipse 3.x and the Eclipse 4 model. In Eclipse 3.x, they are represented as extension points in the plugin.xml file under org.eclipse.ui.commands. In Eclipse 4, they are stored in the E4 fragment file.

A command will be created to represent saying "hello world," and a handler will be created to display the message. These will then be used to add a menu item to execute the operation.

  1. Open the fragment for the project, or double-click on the fragment.e4xmi file.

    Tip

    This should open a model editor; if it opens plain XML content, then verify that the E4 tools have been installed correctly.

  2. Select the Model Fragment Definition element and click on Add to create a new fragment. Fill in the fields as follows:

    1. Extended Element ID: org.eclipse.e4.legacy.ide.application (this can be found under the Container-Type: Application from the search field)

    2. Feature Name: commands

  3. Select the newly created Model Fragment if...

Time for action – binding commands to keys


Hooking up the command to a keystroke requires a KeyBinding. This allows a key (or series of keys) to be used to invoke the command instead of only via the menu. KeyBindings are set up inside a Binding Table and associated with a Binding Context.

  1. Open the fragment.e4xmi in the clock.ui project.

  2. In the imports, select the Binding Context from the dropdown and click on Add. In the Reference-ID, click on Find… and a dialog will be shown with the contexts. Choose the org.eclipse.ui.contexts.dialogAndWindow context:

  3. Once the binding context has been imported, it can be used within a binding table. Click on Model Fragments and select Add to create a new fragment. Fill in the details as follows:

    1. Extended Element ID: org.eclipse.e4.legacy.ide.application

    2. Feature Name: bindingTables

  4. In the BindingTable element, choose the org.eclipse.ui.contexts.dialogAndWindow context. This will ensure that the key binding is available in all windows and dialogs:

  5. Click on...

Time for action – changing contexts


The context is the location in which this binding is valid. For commands that are visible everywhere—typically the kind of options in the default menu—they can be associated with the org.eclipse.ui.contexts.dialogAndWindow context. If the command should only be invoked from dialogs, then the org.eclipse.ui.contexts.dialog context would be used instead.

  1. Open the fragment.e4xmi of the com.packtpub.e4.clock.ui project.

  2. To enable the command only for dialogs, go to the Binding Context, and modify the Reference-ID to point to org.eclipse.ui.contexts.dialog.

  3. Run the Eclipse instance, and try the command with Cmd + 9 or Ctrl + 9 depending on platform. The command should not work unless a dialog is being shown. Open a dialog by navigating to the File | New | Other menu and then try Cmd + 9 or Ctrl + 9 again.

Note

If there is no change in the behavior, try cleaning the workspace of the target instance at launch, by going to the Run | Run… menu and choosing Clear on...

Time for action – enabling and disabling menus items


The previous section showed how to hide or show a specific KeyBinding depending on the open editor type. However, it doesn't stop the command from being called via the menu, or from it showing up in the menu itself. Instead of just hiding the KeyBinding, the menu can be hidden as well by adding a visibleWhen block to the command.

The expressions framework provides a number of variables, including activeContexts, which contains a list of the active contexts at the time. Since many contexts can be active simultaneously, the active contexts is a list (for example, [dialogAndWindow,window,textEditor,javaEditor])—so to find an entry (in effect, a contains operation), an iterate with equals expression is used. Although it's possible to copy and paste expressions between places where they are used, it is preferable to reuse an identical expression.

  1. Open the plugin.xml file, and add declare an expression using the expressions extension point as...

Time for action – contributing commands to pop-up menus


It's useful to be able to add contributions to pop-up menus so that they can be used by different places. Fortunately this can be done fairly easily with the menuContribution fragment and a combination of enablement tests. However, to implement this in E4, the view must be moved into the fragment.e4xmi file in order to attach a PopupMenu.

  1. Add the org.eclipse.ui.services package as a dependency to the plugin.xml in the Dependencies tab, if it's not already added.

  2. Open the TimeZoneTableView class and add the following to the end of the createPartControl method:

    private void createPartControl(Composite parent, EMenuService menuService) {
      menuService.registerContextMenu(tableViewer.getControl(), "com.packtpub.e4.clock.ui.popup");
      tableViewer.addSelectionChangedListener(event -> {
        // forward selection
        Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
        if (selection != null && selectionService...

Jobs and progress


Since the user interface is single-threaded, if a command takes a long amount of time, it will block the user interface from being redrawn or processed. As a result, it is necessary to run long-running operations in a background thread to prevent the UI from hanging.

Although the core Java library contains java.util.Timer, the Eclipse Jobs API provides a mechanism to both run jobs and report progress. It also allows jobs to be grouped together and paused or joined as a whole.

Time for action – running operations in the background


If the command takes a long time to execute, the user interface will be blocked. This happens because there is only one user interface thread, and because the command is launched from the UI, it will run in the UI thread. Instead, long-running operations should run in a background thread, and then once finished, be able to display the results. Clearly creating a new Thread (like the clock updates initially) or other techniques such as a Timer would work. However, the Eclipse system has a mechanism to provide a Job to do the work instead, or UIJob to run in the context of the UI thread.

  1. Open the HelloHandler and go to the execute method. Replace its contents with the following:

    public void execute() {
      Job job = new Job("About to say hello") {
        protected IStatus run(IProgressMonitor monitor) {
          try {
            Thread.sleep(5000);
          } catch (InterruptedException e) {
          }
          MessageDialog.openInformation(null, "Hello", ...

Time for action – reporting progress


Normally when a Job is running, it is necessary to periodically update the user to let them know the state of the progress. By default, if a Job provides no information, a generic busy indicator is shown. When a Job is executed, it is passed an IProgressMonitor, which can be used to notify the user of the progress (and provide a way to cancel the operation). A progress monitor has a number of tasks, each of which has a total unit of work that it can do. For jobs that don't have a known amount of work, UNKNOWN can be specified and it will display in a generic busy indicator.

  1. Open the HelloHandler and go to the execute method. In the inner run method, add a beginTask at the beginning, and a worked in the loop after each second's sleep, for five iterations. The code will look like:

    protected IStatus run(IProgressMonitor monitor) {
      try {
        monitor.beginTask("Preparing", 5000);
        for (int i = 0; i < 5; i++) {
          Thread.sleep(1000);
          monitor...

Time for action – dealing with cancellation


Sometimes the user will change their mind; they may have selected the wrong option, or something more important may have come up. The progress monitor allows for two-way communication; the user can signify when they want to cancel as well. There is a method, isCancelled, which returns true if the user has signified in some way that they want the job to finish early.

Periodically checking this during the operation of the Job allows the user to cancel a long-running job before it reaches the end.

  1. Modify the for loop in the HelloHandler to check on each iteration whether the monitor is cancelled:

    for (int i = 0; i < 50 && !monitor.isCanceled(); i++) {
      ...
    }
    if (!monitor.isCancelled()) {
      display.asyncExec(() -> {...});
    }
  2. Run the Eclipse instance and click on the Hello command. This time, go into the Progress view and click on the red stop square next to the job; the job should cancel and the dialog showing the message shouldn't be shown...

Time for action – using subtasks and sub-progress monitors


When performing a set of operations, subtasks can give the user additional details about the state of the operation. A subtask is merely a named message that is displayed along with the task name in the Progress view.

  1. Add a monitor.subTask during the operation to give feedback:

    for (int i=0; i<50 && !monitor.isCanceled(); i++) {
      if (i == 10) {
        monitor.subTask("Doing something");
      } else if (i == 25) {
        monitor.subTask("Doing something else");
      } else if (i == 40) {
        monitor.subTask("Nearly there");
      }
      Thread.sleep(100);
      monitor.worked(100);
    }
  2. Run the Eclipse instance, and look at the Progress view. The subtask should be shown underneath the status bar:

  3. When calling another method with a progress monitor, if the monitor is passed as is, it can have undesirable effects. Add a new method, checkDozen, to the anonymous Job class inside the HelloHandler class, and add a condition in the for loop that breaks out...

Time for action – using null progress monitors and sub monitors


When a method uses progress monitors extensively, it is inelegant to keep checking whether the monitor is null or not. Instead, the progress monitor can be replaced with a NullProgressMonitor, which acts as a no-op for all monitor calls.

  1. Update the checkDozen to use a NullProgressMonitor if null is passed:

    private void checkDozen(IProgressMonitor monitor) {
      if (monitor == null)
        monitor = new NullProgressMonitor();

    This allows the remainder of the method to run without modification and saves any NullPointerException errors that may result.

  2. A similar result to both the NullProgressMonitor and a SubProgressMonitor with a wrapper/factory class called SubMonitor. This provides factory methods to wrap the monitor and create child progress monitors:

    protected IStatus run(IProgressMonitor monitor) {
      try {
        SubMonitor subMonitor = 
          SubMonitor.convert(monitor,"Preparing", 5000);
        for (int i = 0; i < 50 && !subMonitor...

Time for action – setting job properties


It is possible to associate arbitrary properties with a Job, which can be used to present its progress in different ways. For example, by specifying a command, it's possible to click on a running job and then execute something in the user interface, such as a detailed job description. Job properties are set with setProperty and can include any key/value combination. The keys use a QualifiedName, which is like a pair of strings for namespace/value. In the case of the progress view, there is an IProgressConstants2 interface that defines what values can be set, including COMMAND_PROPERTY, which can be used to associate a command with a Job.

  1. Open the HelloHandler and go to the execute method. Just before the Job is scheduled, acquire the Command from the ICommandService and then stamp it on the job as a property. This will require adding an argument into the method signature and adding org.eclipse.core.commands as a dependent bundle:

    public void execute...

Reporting errors


As long as everything works as expected, the IDE won't need to tell the user that something has gone wrong. Unfortunately, even the most optimistic programmer won't believe that the code will work in every situation. Bad data, threading issues, simple bugs, and environmental issues can result in operations failing, and when they fail, the user needs to be notified.

Eclipse has built-in mechanisms to report problems, and these should be used in response to a user interaction that has failed.

Time for action – showing errors


So far, the code has been using an information dialog as the demonstration of the handler. There's an equivalent method that can be used to create an Error message instead. Instead of calling MessageDialog.openInformation(), there's an openError() that presents the same kind of dialog, but with an error message.

Using dialogs to report errors may be useful for certain environments, but unless the user has just invoked something (and the UI is blocked whilst doing it), reporting errors via a dialog is not a very useful thing to do. Instead, Eclipse offers a standard way to encapsulate both success and failure, in the Status object and the interface IStatus that it implements. When a Job completes, it returns an IStatus object to denote success or failure of executing the Job.

  1. Introduce an error into the HelloHandler method run that will generate a NullPointerException. Add a catch to the existing try block and use that to return an error status. Since the OK_STATUS...

Summary


This chapter covered how user interfaces respond to user input, by defining menus associated with abstract commands that are associated with handlers to execute code. It also covered how to run code in the background with jobs, and report the errors via the standard error reporting mechanism.

The next chapter will look at how to store preferences so that configuration items can be kept between restarts of the Eclipse platform.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Eclipse Plug-in Development Beginner's Guide - Second Edition
Published in: Aug 2016Publisher: ISBN-13: 9781783980697
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Alex Blewitt

contacted on 30 aug 16 _____________ Dr Alex Blewitt has over 20 years of experience in Objective-C and has been using Apple frameworks since NeXTstep 3.0. He upgraded his NeXTstation for a TiBook when Apple released Mac OS X in 2001 and has been developing on it ever since. Alex currently works for an investment bank in London, writes for the on-line technology news site InfoQ and has published two other books for Packt publishing. He also has a number of apps on the Apple AppStore through Bandlem Limited. When he's not working on technology, and if the weather is nice, he likes to go flying from the nearby Cranfield airport. Alex writes regularly at his blog, http://alblue.bandlem.com, as well tweeting regularly from Twitter as @alblue. Acknowledgements This book would not have been possible without the ongoing love and support of my wife Amy, who has helped me through both the highs and lows of life. She gave me the freedom to work during the many late nights and weekends that it takes to produce a book and its associated code repository. She truly is the Lem of my life. I'd also like to thank my parents, Ann and Derek, for their encouragement and support during my formative years. It was this work ethic that allowed me to start my technology career as a teenager and to incorporate my first company before I was 25. I'd also like to congratulate them on their 50th wedding anniversary in 2015, and I look forward to reaching that goal with Amy. Thanks are due especially to the reviewer of this version of the book: Antonio Bello, as well as the previous version of this book: Nate Cook, James Robert and Arvid Gerstmann, who provided excellent feedback on the contents of this book during development and caught many errors in both the text and code. Any remaining errors are my own. I'd also like to thank my children Sam and Holly for inspiring me and hope that they too can achieve anything that they set their minds to. Finally, I'd like to thank Ben Moseley and Eren Kotan, both of whom introduced me to NeXT in the first place and set my career going on a twenty year journey to this book.
Read more about Alex Blewitt