Archive for January, 2008

BoF BoF bo BoF, banane manane a fo FoF, …

Thursday, January 31st, 2008

The BoF submissions for EclipseCon 2008 are starting to pile up. You can view them here. Sadly, none of them have descriptions that rival the Mylyn one in comedic value, but there’s still time.

In terms of popularity, it seems that the Mega Modeling Mania BoF is the current front runner. While I probably wouldn’t have listed quite so many presenters, the effect is the same. As I said in a previous post, I intend to accept and schedule the most popular BoF entries into the first 10% of available space. After that, they’ll be scheduled in a first-come, first-served fashion. If you want to be sure that a particular BoF will happen, add your comments to the entry!

Submitters: I’m not sure what resources will be available in the rooms. If you need a projector, for example, please add a comment to the proposal letting me know. I’ll do my best, but I cannot guarantee anything at this point. Please also let me know (via comments) if there are any constraints on timing; again, I’ll do my best.

Klingon? Why not?

Wednesday, January 30th, 2008

I think that I may have had something to do with this… A few months back, I made a crack to Denis that it’d only be a matter of time before somebody submitted Klingon translations for Eclipse. Imagine that, Eclipse in Klingon…

Anyway, Klingon is a featured language on Babel. Check it out. You can even provide translations in more common languages if you’d like…

As a side note, I’m a little distressed that this editor isn’t flagging “Klingon” as a spelling error…

On again, BoF again

Tuesday, January 29th, 2008

I’ve started to go through some of the BoF submissions for EclipseCon, and came across this gem:

Mylyn Bashing, Brainstorming and Beer BOF

On Mylyn we typically perform UI reviews on conference calls and bug reports. This one will be a little different. As the Mylyn committers present the key parts of the UI, everyone attending will have a chance to complain and throw tomatoes at the screen. We will then brainstorm designs that address the most interesting usability problems that we face for Mylyn 3.0. If the design discussions do not converge we will give up, go for beer, lament about how hard UI design is, and search the hallways for Platform people to blame things on.

I love amusing abstracts. Mylyn just keeps on giving and giving.

I’m in charge of scheduling the BoFs again this year. Once again, I’m trying to determine how to best schedule them. Ideally, I’d like to schedule them based on feedback in the comments. It seems very natural to me to schedule the BoFs that people most what to see, and one way to gauge interest is by feedback on the proposal. In the past, however, relatively little feedback has been provided.

That said, I am an extremely positive person, and I feel that there may be a change this year. In this spirit, I am going to hold off accepting any BoFs until February 14th. On that day, I’ll go through the proposals and will first schedule the most popular ones (I’ll judge popularity based on the number of commenters expressing interest in attending). I’ll reserve the first 10% of the available BoF slots for this. After that, I’ll schedule the rest on a first-come, first-served basis.

We run short of BoF slots every year, so get your proposal in sooner rather than later. Add a comment to your proposal that indicates when you’d like it scheduled (i.e. what slot) and I’ll do my best (no promises). Don’t put it in the abstract, make a separate comment for it. Make sure that you let your audience know about the BoF and encourage them to add their comments acknowledging their interest.

Submit your proposals here.

See you at EclipseCon!

Using the Eclipse Workbench

Monday, January 28th, 2008

Mark Dexter’s done it again. If you’re new to the Eclipse Workbench and need a tour, take a look here. For the uninitiated, the workbench is the focal point of an IDE built on Eclipse.

If you’re thinking, for example, of using the Eclipse IDE for Java Developers download from the eclipse.org downloads page, another Eclipse distribution, or a product built on Eclipse technology, this tutorial is a good starting point.

Eclipse on Four Operating Systems

Wednesday, January 23rd, 2008

Last week, I successfully fixed the Ubuntu 7.10 installation my laptop (a Dell D820). I had been experiencing several bizarre problems; most of them unquantifiable. It just didn’t work “right”. One of the more quantifiable problems was some Java instability. Java applications (at least while running the Sun JVM) just weren’t able to run without crashing (normally, I will leave Eclipse, for example, running for weeks at a time). I assume that there was something funky in the upgrade from Ubuntu 7.04 to 7.10. I don’t begrudge the good folks at Ubuntu for the upgrade problems, since I’d been screwing around with the plumbing pre-upgrade. Besides, it’s gone now and—other than some funkiness with sound capture—everything seems to be working just fine. Great even.

While I was having stability issues, I started doing more development on some of the other workstations I have around. Specifically, I have a very nice HP workstation running Fedora 8. Fedora 8 has several Eclipse Europa-based packages, so you can get up to speed quickly by either selecting the packages you want when you install, or add later. In both cases, it installs all the necessary software and sets up handy menu entries. Very nice. I’ve been using these prepared packages and they work great. I’ve also been using Ganymede I-builds of the Eclipse IDE for RCP Developers from the Eclipse Packaging Project (EPP) which work great as expected (are you starting to notice the “great” trend?). I’ve been switching between the Fedora 8 machine and another box with similar hardware running Windows Vista with a recent Ganymede EPP I-build. At home, I have an older bit of hardware running Windows XP. I’ve got a couple of versions of Eclipse running there, including a recent Ganymede EPP I-build of the Eclipse IDE for RCP Developers which (in keeping with my established theme) works great.

The part that makes giggle is that I’ve been using these four machines to develop the same bit of software. Everything is in CVS, so keeping things synchronized is pretty easy. Eclipse Mylyn, which is included in the EPP packages, makes it really easy to flip between workstations. I have the same task query (against Eclipse Bugzilla) on all four machines. When I complete some part of a task on one machine, I store the task context on the bug. When I switch to another machine, I recall that task context (after synchronizing from CVS) from the bug and Mylyn configures my workspace to show me what I need to see for that task. CVS keeps everything in its place, and Mylyn makes sure that I can find everything. A wonderful combination (or should I say great combination?)

The bottom line for me is that Eclipse runs great on all four of these platforms. Now Mike… about that requisition for a Mac…

PEBKAC

Saturday, January 19th, 2008

Here’s a great time way to kill an hour… Add a table to your view and neglect to set widths on the columns. Hilarity ensues. Pebkac.

DeferredContentProvider: My new favourite thing

Wednesday, January 16th, 2008

I’ve built two tables over the past two days and both of them are pretty expensive to populate. Leaving the user waiting while you run off and fetch all the data before you can display the table is bad form. To keep in your users’ good graces, consider using the DeferredContentProvider.

DeferredContentProvider is part of JFace, and works well with the JFace TableViewer (I assume that it can also work with a TreeViewer, but haven’t tried it yet). Rather than try and do a bad job at explaining how it works, here’s an example of an Eclipse view that employs one:

...
public class SampleView extends ViewPart {
  private TableViewer viewer;
  private SetModel files = new SetModel();
  private Job findFilesJob;
  ...
  public void createPartControl(Composite parent) {
    viewer = new TableViewer(parent, SWT.VIRTUAL | SWT.H_SCROLL | SWT.V_SCROLL);
    viewer.setContentProvider(new DeferredContentProvider(new Comparator() {
      public int compare(File file1, File file2) {
        return file1.getName().compareTo(file2.getName());
      }
    }));
    viewer.setLabelProvider(new ViewLabelProvider());
    viewer.setInput(files);

    startFindFilesJob();
  }
  ...
}

This view lists—in a table—all the files in your file system. As you might expect, this can take a while. Starting from the top of the createPartControl method, you’ll notice that I’ve created the TableViewer using the SWT.VIRTUAL style: this is a requirement of use for the DeferredContentProvider (it configures the table to ask for the bits it needs to display as it needs them, rather than getting them all up front; more information here).

The content provider for the TableViewer is set to a new instance of DeferredContentProvider. The solitary constructor requires that a Comparator be provided: this Comparator, which must be provided, tells the content provider how to sort the items in the table. If you want to change how items are sorted, you need to tell the content provider, not the TableViewer.

The next bit is the input. The input tells the table what to display. The input has to be something that implements IConcurrentModel. For our purposes, an instance of the SetModel class (which has been created in the field named “files”) does what we need.

The last thing the method does is start a Job to populate the table via the startFindFilesJob method:

private void startFindFilesJob() {
  findFilesJob = new Job("Find Files") {
    @Override
    protected IStatus run(IProgressMonitor monitor) {
      monitor.beginTask("Find files", IProgressMonitor.UNKNOWN);
      for (File root : File.listRoots()) {
        findFiles(monitor, root);
      }
      if (monitor.isCanceled()) return Status.CANCEL_STATUS;
      return Status.OK_STATUS;
    }
  };
  findFilesJob.setPriority(Job.DECORATE);
  findFilesJob.schedule();
}

Note that this very simple example starts populating itself when it is opened, and I haven’t provided any means of restarting the population process other than to close and reopen the window.

Creating the job is pretty straightforward. I’ve decided to set the priority of the job to the lowest setting (Job.DECORATE) because experience has shown that it takes a very long time and I want the rest of the workbench to be as responsive as possible. The job, as defined above, will appear in the Progress view where is can easily be canceled. There’s more information about the Jobs API here.

The findFiles method recursively discovers the files and adds them to the SetModel (highlighted):

void findFiles(IProgressMonitor monitor, File root) {
  if (monitor.isCanceled()) return;
  File[] children = root.listFiles();
  if (children == null) return;
  files.addAll(children);
  for (File file : children) {
    findFiles(monitor, file);
  }
}

When the addAll method is called, the magic happens and the table is updated. It’s pretty neat to watch. Hypnotic even.

For completeness, the dispose method stops the job (no need to keep doing the work if the user closes the view):

@Override
public void dispose() {
  findFilesJob.cancel();
}

For what I’m doing, the SetModel seems to work well. I believe that this is true only because I’m updating it in a single thread. A quick browse through the code leads me to believe that it would break if multiple threads tried updating it at the same time. So keep that in mind.

I’m using the DeferredContentProvider on a plug-in that scans an IFileStore for image files and displays them (right now, I have it scanning eclipse.org’s CVS server). The deferred loading of the images is darned cool to watch. Once this reaches a reasonable level of maturity, I’ll let you know.

Listenin’ to Parts

Tuesday, January 15th, 2008

The Eclipse workbench contains a collection of stacked views and editors. Some views change their appearance based on the active editor. The Outline view is a good example of this: it changes its appearance (sometimes quite dramatically) when a different editor is activated. The workbench provides a handy mechanism that you can use to make your view do the same thing. All you have to do is provide an IPartListener (or an IPartListener2. Here’s the createPartControl method from a view that does just this:

public void createPartControl(Composite parent) {
	viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
	viewer.setContentProvider(new ViewContentProvider());
	viewer.setLabelProvider(new ViewLabelProvider());
	viewer.setInput(getActivePage().getActiveEditor()); /* 1 */

	partListener = new IPartListener() {
		private IWorkbenchPart activePart;
		public void partActivated(IWorkbenchPart part) {
			if (part instanceof IEditorPart) {
				activePart = part;
				viewer.setInput(part); /* 2 */
			}
		}

		public void partClosed(IWorkbenchPart part) {
			if (part == activePart) {
				activePart = null;
				viewer.setInput(null);
			}
		}
		…
	};
	getActivePage().addPartListener(partListener); /* 3 */
}

I’ve highlighted three lines in the code. The first highlight is were we set the input for the TableViewer to the currently active editor (if any). The input is passed to the content provider which is responsible for deciding what to display. This leads us to the second highlight. Here, we respond to a part being activated in the workbench. The part could be a view (instance of IViewPart) or an editor (instance of IEditorPart). If the activated part is an editor, it is given as input to the viewer which then uses the content provider to refresh itself with new information. You may also notice a that the partClosed method does something similar to make the view refresh to a “blank” state (as defined by the content provider).

The third bit of highlighted code shows how the part listener is added to the active page. Note that a corresponding dispose method is required to remove the listener when the view is closed.

The content provider for this example is pretty simple: it provides some rows containing pretty basic information about the active editor (or empty rows if the input is something other than an editor):

class ViewContentProvider implements IStructuredContentProvider {
	...
	public Object[] getElements(Object input) {
		if (input instanceof IEditorPart) {
			IEditorPart activeEditor = (IEditorPart)input;
			return new String[] {activeEditor.getTitle(), activeEditor.getTitleToolTip()};
		} else {
			return new String[] { };
		}
	}
}

The getActivePage method is a simple helper-method that just digs out the active workbench page from the site (the site is the glue between your view and the workbench):

private IWorkbenchPage getActivePage() {
	return getSite().getWorkbenchWindow().getActivePage();
}

I haven’t shown all the methods on IPartListener. There are other methods that are invoked when other types of things happen. There’s also a newer IPartListener2 that works the same way but can respond to more kinds of change.

Curiously, there is no “adapter” class for either of these listener interfaces. I’ve wondered why for a while, but haven’t bothered to ask. Any ideas?

Last Chance To Be Heard at OSCON 2008!

Monday, January 14th, 2008

Hey all you folks out there doing Eclipse stuff… The call for participation for OSCON, the O’Reilly Open Source Convention, to be held July 21-25 in Portland, Oregon ends on February 4th. Last year’s conference was a lot of fun and they love the Eclipse content!

Submit your proposals today. There’s more information here.

The Selection Service

Monday, January 14th, 2008

If you’re building plug-ins for the Eclipse platform, you’re more than likely going to need the selection service. The selection service, as you might have guess from the name, takes care of selections in the workbench. Selections happen all over the place. Selecting a file in the navigator results in a selection. Similarly, selecting a Java class or method in the Package Explorer also results in a selection. Selections can also come from other places, including text editors.

Making a view that updates itself based on the selection is relatively easy. The selection service implements the observer pattern; to be notified of selections, create an register a listener. Below, the createPartControl method for a workbench view registers a selection listener:

...
ISelectionListener selectionListener;
...
public void createPartControl(Composite parent) {
	listener = new ISelectionListener() {
		public void selectionChanged(IWorkbenchPart part, ISelection selection) {
			handleSelection(selection);
		}
	};
	getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(selectionListener);
	// build the view
	...
}

The site provides an interface between the view and the workbench. Here, we’re asking the site to get the workbench window; from the workbench window, we get the selection service and ask it to add our listener. The corresponding removeSelectionListener should be invoked when the view is closed:

public void dispose() {
	getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(selectionListener);
}

Note that there can be multiple open workbench windows; the safest way to find the right one is through the part’s site. If you obtain a workbench window through PlatformUI, you could end up with a situation where a selection in one workbench window affects the state of a view in another. This results in weirdness for the user and a less than seamless experience.

The selection object that is delivered to the listener can be a few different kinds of things so you probably will need to inspect it and, based on the type of selection, decide what to do. The listener that I created passes responsibility for this on the handleSelection method:

void handleSelection(ISelection selection) {
	if (selection instanceof IStructuredSelection) {
		handleStructuredSelection((IStructuredSelection)selection);
	}
}

void handleStructuredSelection(IStructuredSelection selection) {
	Object first = selection.getFirstElement();
	if (first instanceof ThingThatICareAbout) {
		...
	}
}

In this case, the handleSelection method checks the type of selection. The type IStructuredSelection—which indicates that the selection comes from a tree, table, list, or the like—contains one more more selected objects. The handleStructuredSelection method demonstrates how the first selected element is extracted from the selection; what happens next is up to the application. I can update the view based on that selection, or choose to just ignore the selection event (which I tend to do this for selections that I don’t care about). There are several different types of selection, including ITextSelection, ITreeSelection (which specializes IStructuredSelection), IMarkSelection.

The final bit of the equation is the selection provider. You may need your view to provide selections for the workbench window. If you have, for example, a table viewer in your view, you can pretty easily get that table viewer to set the selection and invoke the listeners via the setSelectionProvider method (shown here in the createPartControl method for the view):

public void createPartControl(Composite parent) {
	...
	viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
	...
	getSite().setSelectionProvider(viewer);
}

Note that your view will be its own consumer if you make it both a producer and consumer of events.

A more comprehensive treatment of the selection service is available as an Eclipse Corner article by Marc Hoffman. You can view the article here.

You are currently browsing the Eclipse hints, tips, and random musings weblog archives for January, 2008.

  • Pages

  • Archives

  • Categories