Archive for the ‘Eclipse 101’ Category

Accessibility and ACTF

Wednesday, September 3rd, 2008

I learned a little something about accessibility today while playing with the Accessibility Tools Framework (ACTF) project’s Java Validation Componentry (Javaco).

Actually, I learned a couple of things before I learned the interesting part. First, Javaco currently works on Windows. Try as I might, Linux just isn’t supported. Lesson learned: read the documentation before spending an hour hunting down a bug that isn’t there.

Javaco goes through your user interface and determines whether or not it is valid to call it “accessible”. It looks for all kinds of things, like whether or not tooltips have been provided for fields and buttons; it also does this clever label/text association that I haven’t quite gotten my head around (a text field has to have a corresponding label).

Using Javaco is pretty easy. I selected a class that extends SWT’s Composite class, and selected “Accessibility Tools > Perform Validation” from the context menu. The result looks something like this:

actf.png

My first error threw me for a loop: it told me that my composite was “Missing Accessible Name”. “No problem”, I thought, “I’ll just have to set that.” After a few minutes of fruitless searching, I determined that there was no method that reads anything like setAccessibleName anywhere in the SWT Text widget’s hierarchy. I was stumped. After regrouping, I came across the getAccessible() method. With a little help from the javadoc, and the SWT snippets page, I was back in business.

The Accessible Name for a widget is text that can be spoken by an accessible computer to help a user navigate through a form. You don’t actually set any value; you have to tell the widget how to respond to a request for it. Code along these lines does the job:

this.getAccessible().addAccessibleListener(new AccessibleAdapter() {
	public void getName(AccessibleEvent e) {
		e.result = "Enter personal information on this form.";
	}
});

You can (and in some cases are required to) set other values, including keyboard navigation equivalents on push buttons using the listener.

Javaco found a bunch of other problems, such as some missing tooltips (which I believe the accessibility software uses for the accessible name when available). I’m still pretty new at this, so I’m sure that there’s much more that it can (and will) expose as I play with it some more.

Javaco adds several new views to the workbench, including the “Rendered GUI” view (shown bottom left above) that manifests the composite you’re testing. The view is live and you can interact with it. It’s pretty cool: whenever you save the code, the Rendered GUI view gets updated. This is pretty handy all by itself (you can test your composite as you’re building it without have to explicitly test). The “Validation Report” view (shown bottom right above) summarizes the results of validation. The “Rulebase Viewer” view provides an overview of the rules that the validator uses and seems to have the ability to extend the set of rules.

If you’re building applications that need to be accessible, then you need to spend a little time with ACTF.

Event Service

Thursday, July 17th, 2008

I blogged a while back about the potential use of a bus for delivering property change notifications in place of the very common observer pattern. A reader commented that the exact service I need to implement that sort of thing is already available in the form of the OSGi Event Service. An implementation of this service is provided by the Equinox project.

I’ve updated part of the Eclipse Expense Expense Reporting Tool example to make use of the service.

I updated my business domain objects to post events detailing their changes through the EventAdmin service. This was made relatively easy owing to the fact that I had already implemented those objects with a common superclass. I added the postEvent(…) method to that common superclass:

	void postEvent(String propertyName, Object oldValue, Object newValue) {
		EventAdmin eventAdmin = getEventAdmin();
		if (eventAdmin == null) return;

		Properties properties = new Properties();
		properties.put(SOURCE, this);
		properties.put(SOURCE_TYPE, this.getClass().getName());
		properties.put(PROPERTY_NAME, propertyName);
		if (oldValue != null) properties.put(OLD_VALUE, oldValue);
		if (newValue != null) properties.put(NEW_VALUE, newValue);

		eventAdmin.postEvent(new Event(PROPERTY_CHANGE_TOPIC, properties));
	}

It’s pretty straightforward. The first thing it tries to do is obtain the service. The getEventAdmin() method uses the bundle activator (and a ServiceTracker) to find a service that implements EventAdmin. If no such service can be found, we bail out and pretend that nothing happened. If we do find an EventAdmin, we create and post an Event instance. The postEvent method posts the event to be delivered asynchronously; the sendEvent method delivers the event to waiting handlers before returning.

The Event instance is packed with properties. The nature of these properties are application-specific. In this case, I’m including properties that tell me what has changed and in what object. The event also has a "topic". The topic is used to determine how the event is delivered; only event handlers that are listening for this particular topic will be informed of the event (there’s a little more to it than this). It’s very much like the Java Messaging Service (JMS).

This is only part of the story. Publishing events through the event service is only interesting if there are subscribers on the other side. I’ll talk about what I’ve done on that side sometime next week…

What is Riena About?

Thursday, June 19th, 2008

Elias posted this note on the Riena Dev list. I think it’s interesting reading that deserves a broader audience. So… here it is.

From my personal point-of-view (having done a couple of RCP projects) the benefit of Riena that is important to *me* is, that Riena will provide a more “accessible” technology for writing rich clients based on RCP.

Accessible in a dual sense:

* for end-users Riena should be more accessible because of the “process oriented” UI that moves away from the ide-centric Views and Editors metaphor. To further increase acceptance by end-users Riena is also aiming to provide support for customizable look-and-feels.

This should reduce the amount of effort and customization required to create a user-friendly, nice-looking application based on RCP. Don’t get me wrong here: I really like Eclipse RCP and it’s flexibility. Hower the framework is quite complex because of that. A solution already sculpted towards a specific use case (i.e. process oriented UI) could lower the barrier of entry for that use case. My understanding is that this is the road Riena is trying to follow.

* for developers Riena should be more accessible because it is exposing existing Eclipse technologies — like Databinding and JFace Viewers — through more “high-level” APIs (for example the Ridgets). This should hopefully flatten the learning curve for adopting those technologies.

For example a ITableRidget provides a multi-column table with build-in sortability support (i.e. clicking on the table headers) and databinding in just few lines of code (i.e. create SWT table control, register table control with Riena, bind model to table ridget). This is all done using existing Eclipse technologies. Without the Ridget a developer would have to learn about TableViewers, learn about Eclipse Databinding, use a databinding enabled label and content provider, learn about selection listeners (for sorting the headers), store the sortability state of each column, manipulate the sortability state of the table ridget based on selection events and so on. Much of this stuff may seem trivial to Eclipse veterans but can be quite intimidating for Eclipse newcomers.

In short the UI-side of Riena aims to lower the barrier of entry into the world of RCP-based clients, by reducing the amount of investment and customization required to create a specific application UI (=process oriented). This should be good news for people who can buy in into that UI style. Note that Riena has more to offer, however I’m speaking for the area that I’m most familiar with.

I love the name “Ridget”. It makes me think of Scooby-Doo (“Raggy, rerate a rable ridget”…).

There’s actually more to Riena than just a higher-level RCP. But this is still pretty cool stuff.

Does anybody know how such-and-such is coded?

Wednesday, June 18th, 2008

Occasionally we get questions along these lines on the newsgroups:

Does anybody know how X is coded in Eclipse?

The simple answer is yes. Everybody can know how it’s coded. The source code is out there for all to see.

You have a couple of choices when it comes to viewing source code from Eclipse projects. If you want to do it the hard way, you can use the handy ViewCVS utility to browse through the various CVS and SVN repositories.

But nothing beats just having the source code included as part of your configuration. If you’ve downloaded the “Eclipse Classic” or “Eclipse for Plug-in/RCP Developers”, then you already have the source code for the Eclipse Platform, RCP, JDT, PDE, and more. If you need to see code from other projects, you can very often get the “source code” bundles from the project’s update site in the form of an “SDK” feature (many projects have opted to include their SDKs on the Ganymede update site).

Assuming you have the code, finding the right place in it can be challenging. This is where a handy little tool known as the “Plug-in Spy” comes in handy. When you invoke the Plug-in Spy (by hitting Alt+Shift+F1), it pops up a window showing information about the view/editor/dialog that has focus. The information includes such things as the name and package of the class that implements the view, and the bundle (plug-in) that defines it. From the pop-up window, you can even jump directly to the class definition via hyperlink. It’s pretty handy stuff when you’re trying to figure out how things are implemented.

Here’s what it looks like when you use it to find the class that implements the “Select Working Set” dialog (it can’t determine which bundle defines the dialog).

spy.png

Having that first hook into the code is pretty handy, but it’s often better to see it in motion. Drop a breakpoint somewhere in the class (the constructor or perhaps a createDialogArea method is a good place to start), create a Debug Configuration that includes all the plug-ins in the “Target Platform” (see below) and launch. The Debugger will open up when your breakpoint is encountered.

debug.png

You can merrily (or gloomily, your choice) step through the code to see how it is actually invoked.

I think this is screaming for a screencam demo. I’ll see what I can cobble together…

“20 Things”

Thursday, May 22nd, 2008

The first thing I asked about “20 Things” was for the pop culture source of the title. Apparently (according to McQ), there is none.

The first thing that I noticed about “20 Things” was that there are only 17 things on the list (at least there were only 17 when we started).

The first thing that I thought about “20 Things” was that the list provides a good path for introduction to important Eclipse topics. “20 Things” is the list of ~20 things that people building applications on the Eclipse platform need to think about. AFAIK, the fact that—at least the first few of them—are in the order that I introduce them to people.

If you’re just learning to build Eclipse plug-ins, the first thing you need to know is how to build a simple view. The PDE provides a lot of help in this regard. Once you’ve got that view that’s more-or-less independent of everything else in the workbench, probably the next thing you need to think about is the selection service. Shortly thereafter, you’ll need to look into the adapter framework ([1], [2], [3]). Not long after that, you’ll need to think about jobs, help, preferences, etc. Like I said, the list is pretty much in order. At least the first eight or so.

Of course, not every plug-in (or application) has views or a GUI of any sort. So, it’s probably more accurate to say that this list of ~20 things contains those sorts of things that developers building GUI applications based on Eclipse technology should care about. But even for that group of developers building headless plug-ins and applications, there’s still a lot of value on that list.

I’ve uploaded some pictures from the E4 Summit to Flickr.

Adapting

Monday, November 5th, 2007

Over the past week or so, I’ve been discussing how you can make your objects adaptable into different forms. This is great for getting your objects to tightly integrate with existing parts of the Eclipse infrastructure, while remaining loosely coupled with the actual implementation. Loose coupling with tight integration is pretty powerful stuff.

A while back, I created an “Image Preview” view that displays the image (if one is available) for a file selected in the workbench (it works best for image files). The best part is that the view is completely decoupled from the Resources API. That is, it doesn’t know anything about files, directories, workspaces, or anything along those lines. By implementing the image viewer using adapters, I can “teach” my view to display an image for different kinds of selected objects by providing a new adapter. A natural extension of this is that I can use my Image Preview view in an RCP application to display an image for my domain objects (assuming that this makes sense, of course).

The Image Preview view listens to the workbench selection service. When a selection occurs in a view (such as the Package Explorer, or Navigator), the selection service notifies registered listeners (see here for more information on the selection service). When the Image Preview view is notified of the selection change, it attempts to adapt the selected object to the ImageProvider interface (which is part of my implementation). The ImageProvider is then used to obtain an image. The getImageProvider method in the Image Preview view looks like this:

private ImageProvider getImageProvider(Object object) {
	// First, if the object is an ImageProvider, use it.
	if (ImageProvider.class.isInstance(object)) return (ImageProvider)object;

	// Second, if the object is adaptable, ask it to get an adapter.
	ImageProvider provider = null;
	if (object instanceof IAdaptable)
		provider = (ImageProvider)((IAdaptable)object).getAdapter(ImageProvider.class);

	// If we haven't found an adapter yet, try asking the AdapterManager.
	if (provider == null)
		provider = (ImageProvider)Platform.getAdapterManager().loadAdapter(object, ImageProvider.class.getName());

	return provider;
}

The first step, is to see if the selected object already implements our interface. If it does, we cast and return it. If we make it to the second step, we ask the object if it is adaptable (i.e. does it implement the IAdaptable interface). If it does, we use that method to attempt to find an adapter. If that method fails (returns null), the AdapterManager is used. Ultimately, this method may fail to find an appropriate adapter and return null.

The selected object doesn’t need to know anything about the Image Preview view. Conversely, my Image Preview view knows nothing about files. The adapter interface knows about both (it really only knows about the ImageProvider interface).

I’m curious about the history of this little pattern (which is repeated many times). It seems that there is an opportunity here to have a higher-level API in the AdapterManager that takes all of these steps, but I assume that there is a good (or at least historical) reason for it being the way that it is.

Note that there are two different ways to ask the AdapterManager to adapt an object: getAdapter or loadAdapter (which is highlighted in the snippet). Both methods will find programmatically- and declaratively-registered adapters, however the getAdapter method will only find declaratively-registered adapters if the bundle that contributes them has been activated. The loadAdapter will load and activate the bundle (if required) as part of the process.

Adapters, part deux

Tuesday, October 23rd, 2007

In my last post on the topic, I hinted that adapters can be used to loosen the coupling in your code and then showed how you could use adapters to add even more coupling in your code. Originally, I had a domain class, Person, that knew how to provide information to the Properties view by virtue of implementing the IPropertySource interface. Then, I “decoupled” the domain class from the interface by instead implementing a getAdapter method that returned an instance of a different class when asked for an adapter of the type IPropertySource. I put “decoupling” in quotes, because this step really does nothing to decrease coupling; all it does is move the code somewhere else, the Person class is still just as tightly coupled to the IPropertySource interface. In fact, it is now also coupled to the IAdaptable interface.

Take a few minutes to familiarize yourself with the previous steps. They’re here and here. I’ll wait…

The next step is to completely decouple the domain class from IPropertySource. To do this, I can change the getAdapter method:

public class Person implements IAdaptable {
	private String name;
	private Object street;
	private Object city;

	public Person(String name) {
		this.name = name;
		this.street = "";
		this.city = "";
	}

	public Object getAdapter(Class adapter) {
		return AdapterManager.getDefault().getAdapter(this, adapter);
	}
	…
}

Previously, the getAdapter method checked the type of the desired adapter and created an appropriate instance (if possible) itself. Now, the method makes a call to the AdapterManager, which can take care of figuring out how to adapt the instance.

For this to work, the adapter manager needs to be told how to adapt the type. This can be done declaratively through the plugin.xml file:

<plugin>
   <extension
         point="org.eclipse.core.runtime.adapters">
      <factory
            adaptableType="org.eclipse.example.Person"
            class="org.eclipse.example.adapters.PersonPropertiesSourceAdapterFactory">
         <adapter
               type="org.eclipse.ui.views.properties.IPropertySource">
         </adapter>
      </factory>
   </extension>
</plugin>

This extension defines an adapter for instances of the org.eclipse.example.Person class. When asked to adapt to the org.eclipse.ui.views.properties.IPropertySource, the PersonPropertiesSourceAdapterFactory should be used. This factory class is defined as such:

public class PersonPropertiesSourceAdapterFactory implements IAdapterFactory {
	public Object getAdapter(Object adaptableObject, Class adapterType) {
		if (adapterType == IPropertySource.class)
			return new PersonPropertySource((Person)adaptableObject);
		return null;
	}

	public Class[] getAdapterList() {
		return new Class[] {IPropertySource.class};
	}
}

The getAdapter method does the heavy lifting and creates the adapter. The getAdapterList returns a list of the types of adapters the factory can create.

Adapter factories can also be registered programmatically using APIs on the AdapterManager class.

With the adapters all safely registered, we can make one more change to our code. When adapters are used, they are usually used in three steps::

  1. If the object implements the required interface, use the object
  2. If the object implements IAdaptable, call the getAdapter method an use the returned object; if something other than null is answered, use the returned value
  3. Get the AdapterManager to try and adapt the object

The final step actually makes the current implementation of getAdapter in the Person class redundant. We can simply remove it, and remove the reference to the IAdaptable interface from the class. That is, the Person class simplifies to:

public class Person {
	private String name;
	private Object street;
	private Object city;

	public Person(String name) {
		this.name = name;
		this.street = "";
		this.city = "";
	}
	...
}

Voila! the domain class is totally decoupled from the adapter type. Instances of the person class, when selected in your favourite view will populate the Properties view.

There’s still a couple of issues to deal with. But this entry’s getting a little long, so we’ll talk about them next time (and I’ll post some example code).

Adapters

Monday, October 15th, 2007

In my last installment, I showed how—by making a domain class implement IPropertySource and (naturally) implementing the methods required by that interface—you can expose properties from a domain class that can be viewed and modified by the Properties view. In that posting, I suggested that implementing IPropertySource introduces a tight coupling between the model and view and hinted that such a tight coupling was a bad thing.

Tight coupling is bad because it tends to make things less flexible. Sure, we can look at the properties of our domain object, but what happens when we want to participate in other interactions? Do we just implement another interface? And another? Tight coupling makes reuse harder as well. Tightly coupling our domain class with the IPropertySource interface makes it so that our domain class can’t exist without that interface (and all the other types packaged along with it, plus those bits referenced by all those types, …).

Eclipse provides an adapter framework that can be used to solve this problem by decoupling the domain class from the view-specific code required to make the Properties view work.

The first step is to remove the IPropertySource behaviour from the domain class:

...
public class Person implements IAdaptable {
	private String name;
	private Object street;
	private Object city;

	public Person(String name) {
		this.name = name;
		this.street = “”;
		this.city = “”;
	}

	public Object getAdapter(Class adapter) {
		if (adapter == IPropertySource.class) return new PersonPropertySource(this);
		return null;
	}

	// Getter and setter methods follow…
	…
}

We move the IPropertySource behaviour to the PersonPropertySource class:

...
public class PersonPropertySource implements IPropertySource {
	private final Person person;

	public PersonPropertySource(Person person) {
		this.person = person;
	}

	public Object getEditableValue() {
		return this;
	}

	public IPropertyDescriptor[] getPropertyDescriptors() {
		return new IPropertyDescriptor[] {
				new TextPropertyDescriptor("name", "Name"),
				new TextPropertyDescriptor("street", "Street"),
				new TextPropertyDescriptor("city", "City")
		};
	}

	public Object getPropertyValue(Object id) {
		if ("name".equals(id)) return person.getName();
		else if ("street".equals(id)) return person.getStreet();
		else if ("city".equals(id)) return person.getCity();
		return null;
	}

	public boolean isPropertySet(Object id) {
		return false;
	}

	public void resetPropertyValue(Object id) {
	}

	public void setPropertyValue(Object id, Object value) {
		if ("name".equals(id)) person.setName((String)value);
		else if ("street".equals(id)) person.setStreet((String)value);
		else if ("city".equals(id)) person.setCity((String)value);
	}

}

The Property view goes through a few steps to sort out how it’s going to display properties. First, it determines whether or not the selected object implements the IPropertySource interface. If it does (as it did in my previous entry), it uses the selected object directly (after casting it to IPropertySource). If that check fails, the Property view then determines whether or not the selected object implements the IAdaptable interface (highlighted in the Person class). If the selected object is adaptable, it is asked—via the getAdapter method—for an adapter with the IPropertySource type. The getAdapter method either returns an object of the appropriate type or null. If the method returns an adapter, it is used by the Property view to gather properties. Our implementation of adapter fits this bill and so is used.

The astute reader will notice that this really doesn’t do very much to actually weaken the coupling between the domain class an IPropertySource. In fact, the coupling is just as strong. Even worse, we’ve actually introduced a tight coupling to another type (IAdaptable). We’ll fix this problem in the next installment…

  • You are currently browsing the archives for the Eclipse 101 category.
  • Pages

  • Archives

  • Categories