This chapter details features of JMatter applications' user interfaces,
including many subtle features that aim to improve usability and users'
productivity.
21.1 Visual Command Interface
JMatter sports a feature inspired by blacktree software's QuickSilver,
and more recently, Gnome Do. Briefly, these applications provide
a visual command interface for desktops. For a desktop management
application, most commands involve launching applications or bringing
them up in the terminal or the file manager. The end user composes
an instruction by first specifying the target application and second
the specific command to invoke on that application. Its primary use
is for launching applications. Applications are specified by typing,
and identified via a text matching algorithm.
It turns out that these applications adhere to the noun-verb metaphor
which is a strong part of JMatter's general philosophy. Every operation
in JMatter boils down to the invocation of a command on a target object
(and optionally specifying command arguments). JMatter's implementation
of a visual command interface now provides an additional, alternative
visual mechanism to invoke commands.
I will illustrate how this interface works with an example. Let's
take the Sympster demonstration application. Let's say we wish to
create a new speaker. We typically do this by right-clicking on the
Speaker icon in the class bar (the visual representation of its type)
and selecting the command New from its context menu. Now, you
can also:
- Press Ctrl-I (Cmd-I on the mac) to invoke the visual
command interface,
- Type Spe, press the tab key, and type New
- Press the Enter key
In step 2, we first search for the type Speakers by name, and
then we search for the command named New. We don't have to
type the full name, just enough characters to match the item (the
object) we're looking for. Optionally, you can press the down-arrow
key to see other matches and select the appropriate one. The escape
key dismisses the visual command interface. In the above case, invoking
the command causes the visual command interface to auto-dismiss.
Figure 21.1 shows JMatter's visual command interface
in action.
Figure 21.1: JMatter's visual command interface in action
Many desktop users have become habituated to this type of command
interface and prefer it. First, this is a testament that noun-verb
types of user interfaces are a good match for the way we tend to go
about doing things. Second, it provides a uniform way of invoking
any command. Finally, you don't have to take your fingers off of the
keyboard.
This feature is built-in to JMatter. No work is necessary to enable
it. You might however be interested in extending its capabilities
further by extending its index, which we discuss next.
21.1.1 Extending the Index
The visual command interface by default matches types. Match a target
type, and then invoke a specific command on it, for example: Person
Contacts -> Browse.
It would be nice however if we could interact with instances of a
given type in addition. For example, with the contact manager, it'd
be nice to match a contact by name directly from the visual command
interface. Likewise, in MyTunes, it'd be nice to direclty match a
song by title. In Sympster, Speakers and Talks are also
good candidates.
The visual command interface provides a mechanism for you to add items
to its index. The ContactMgr application has recently been enhanced
to show you how. Here's how this is done..
First, we subclass com.u2d.app.Application and override the
postInitialize() method:
-
public class Application extends com.u2d.app.Application
{
public void postInitialize()
{
super.postInitialize();
contributeToIndex(PersonContact.class);
}
}
The above call to contributeToIndex() instructs the visual
interface to include contact instances in its index.
Next we need to revise our spring configuration file to specify our
subclass as the application's Application bean. We edit the
file src/applicationContext.xml as follows:
-
<bean id="application" class="com.u2d.contactmgr.Application">
<property name="name" value="Contact Manager" />
<property name="version" value="1.0" />
<property name="description"
value="A simple contact manager" />
<property name="helpContentsUrl"
value="http://jmatter.org/documentation/html/index.html" />
<property name="pagesize" value="15" />
<property name="persistenceMechanism" ref="persistor" />
</bean>
Notice how the bean's class above references our subclass. That's
it. Now when we launch the contact manager, assuming we have a contact
named John Doe, we can invoke the visual command interface,
start typing John and the instance will be matched. We can
then invoke any of a number of commands, for example Open or
Edit.
21.2 Associations Made Easy
NakedObjects originally introduced a terrific way to establish associations
between objects in a user interface. It automatically enabled this
via drag and drop.
For some reason, dnd in many ways is not used as much as it used to
be. Having to take the hand off the keyboard is admittedly a "productivity
mark deduction."
So, in JMatter, I set out to enable associations in more than one
way. For starters, dnd works out of the box. But one can also click
a "pick" button that will display a listing of entries
of the type for a given association, that the user simply picks from.
Let's look at a concrete example: let's say we're working with the
Symposium manager demo application in JMatter. And let's further say
that we're defining a new talk to be given. Talks have a many-to-one
association to the speaker (or presenter) giving the talk.
My favorite way of establishing that association is with the in-place
associator widget that's built-in to JMatter. Here's how it works.
When editing the talk, click (or tab into) the association field in
question, which in this case is Speaker. Simply start typing
and a matching list of entries automatically appears. This component
dynamically fetches matching entries from the database as you type.
The matched items listing also pages by default, so for a scenario
with too many matching entires, only the first page will be fetched.
In my experience with this component, this is one of the fastest ways
of making an association between two objects.
Here's a snapshot of me trying to define a new talk, *In Action*,
as it were24:
Figure 21.2: Associating a Speaker to a talk
The only detail to tend to is to specify which field of Speaker are
we searching by. That's what that little magnifying glass icon to
the left of the text field is for. It's a drop-down combobox that
dynamically lists the various fields you might want to search by.
The default field that JMatter should use for searching in the context
of in-place associations is controlled by the defaultSearchPath
metadata, as shown by this example:
-
public static String defaultSearchPath = "name.first";
See section 8.4.9.
We've all had to implement this feature as developers. Today, many
frameworks such as Tapestry for example, will provide components out
of the box that will automatically take care of paging a listing on
your behalf.
JMatter also provides paging out of the box. When I sat down and started
to think about this feature, I saw a certain pattern. One's first,
naive implementation of paging might consist of a simple forward and
back navigation buttons:
-
< >
Shortly afterwards comes the request for the ability to navigate to
the first and last page in a listing, and so the above evolves to:
-
<< < > >>
Then embellished, like so:
-
<< < [Page 3] > >>
Over time, paging has evolved to let you navigate to a number of pages
in the vicinity of the current page:
-
1 2 .. 7 [Page 8] 9 .. 13 14
This is what most web-based applications do today.
What I realized is that paging, taken to its eventual limit, is essentially
embodied in the behaviour of a scrollbar. Most scrollbars provide
continous scrolling. Whereas in the case of paging, the scrolling
is discrete. The more pages there are, the less this discrete behaviour
is apparent. What's nice about today's scrollbars is that their size
is inversely proportional to the length of the list. The larger the
list, the smaller they are. Scrollbars have the advantage of giving
you more of a visual perspective of where you are in the list. And
you can simply drag the scrollbutton to any location along its dimension.
JMatter's Swing-based view mechanism defines a view implementation:
a component named PageScrollBar which extends Swing's JScrollBar,
shown at the bottom of the following two-page listing:
Figure 21.3: Paging a Conference's Sessions
As usual, developers of JMatter applications need not concern themselves
with this at all. It's bundled into the framework and it just works.
If however you feel the need to customize the way this scrollbar looks
or behaves, it's easy enough with a little Swing experience to make
whatever enhancements or decorations one might have in mind.
JMatter GUIs are inherently Object Oriented UIs. I like to make the
analogy to our operating systems' desktops. There are a number of
ways to make such UIs more effective. Sometimes I look to these desktop
systems for ideas and features.
One such feature is Apple's Exposé which has since also been
copied by the Compiz Fusion project on Linux: the idea of scaling
down and fanning out one's windows temporarily for the purpose of
easily switching focus to a window that is otherwise hidden by other
windows with a higher z-index. JMatter incorporates such a feature.
Pressing the F12 key invokes the JExplose 25 feature which does precisely this. This option is also available
form the desktop pane's context menu.
21.5 Navigation
21.5.1 Window Placement
JMatter takes a certain strategy relating to the placement of new
windows (internal frames) in its Graphical User Interface.
I recall trying various window placement strategies and then realizing
something I was doing as a user of my applications: after creating
a new view, I'd quickly reach for the window's title bar and place
the window where I really wanted it. I don't think there's an algorithm
for guessing the user's intent. So I started thinking about what might
the next best thing be.
The strategy was to minimize the amount of work one has to do in moving
the resulting window. What I do is place new windows such that their
title bars are near the current mouse cursor location, thus minimizing
the distance one would have to move their mouse to reach for it.
There's a somewhat hidden feature in JMatter which I very much like
and that I'd like to share. This feature takes things one step further:
it automatically puts the newly created window in placement mode.
Allow me to explain..
This feature requires pressing a metakey to communicate your intent
to use it: when you're about to invoke a command that creates a new
view (e.g. the Open command) , hold down the Control
key (on the mac, use the Command key).
The resulting window automatically "binds" to your
mouse location. That is, it will follow your mouse. So, the way it
works is you invoke the command with the Control key pressed
and the new view is created, but it starts following your mouse around.
Once you've found that ideal spot, a single left-click is all you
need to do to pin it back down onto the desktop.
21.5.2 New View Placement Options
Another feature of desktop systems, one that has been around for some
time, and is specifically related to the file manager, is the idea
of giving users options in terms of how to place newly-created views.
When navigating a folder hierarchy, one can double-click on a folder,
which typically opens a new window with the contents of that folder.
Long ago, on ms-windows I recall always turning on the option "re-use
existing window"; that is, replacing the existing view with
the new one. This can really help with an otherwise rapid proliferation
of windows on one's desktop.
Separately, the mozilla project introduced us to another navigation
option: tabbed browsing, which is a sort of "middle of the
road" approach: don't create a new window, but don't replace
the existing view either. Since then, we've seen other applications,
such as shell terminals, copy this handy feature.
JMatter now supports both modes of navitgation. A User's default browsing
preferences can be specified through the User model object,
which has an aggregate property named Preferences. Its first
and only option at the moment captures how a user generally prefers
to navigate in JMatter: should new views be created by default:
- in a new window?
- in a new tab?
- in-place, replacing the existing view?
Setting your preference is all it takes to change JMatter's default
navigation behavior.
In many situations there may be exceptions to the default rule. Say,
for example, that we wish to open a new view in a new tab even though
the default setting is in-place navigation. To accommodate this, a
new gesture has been introduced in JMatter: holding down the Shift
key while invoking a command that produces a new view will cause a
context menu to appear at the mouse location, for selecting how to
create the new view. The choices again are the above three: in a new
window, tab, or in-place.
Figure 21.4 captures the invocation of the Open
command while holding down the Shift key.
Figure 21.4: Invoking the Open command, holding down the Shift key
Figure 21.5 shows the navigation option pop up. I selected
the in new tab option.
Figure 21.5: "Open in new tab" Option
The next figure shows the result of the view created in a new tab.
Figure 21.6: Resulting View
Finally, this last screenshot shows that, with tabs, you have the
option of detaching the view onto its own window or closing the tab
(Ctrl+w is the corresponding key binding).
Figure 21.7: Tab Detach Option
I believe this to be an important feature, finally producing a desktop
with a number of effective navigation instruments:
- Fundamentally an OOUI
- DnD support
- An exposé-like feature
- Tabbed, In-Place, or New-window view placement
Another complementary feature that is contemplated for JMatter is
support for docking views. I have looked at flexdock, which is a terrific
effort. But I'm looking for something that is more transparent: effectively
a layout manager designed for JDesktopPane that transparently provides
docking support. Let me know what you recommend.
21.6 Copy and Paste
Every Swing application gets for free the ability to use the underlying
platform's copy and paste capabilities when working with JTextFields
and JTextAreas.
In JMatter you might have noticed that instances also sport their
own Copy/Paste commands. You'll find this feature to be a little more
powerful and interesting compared to the basic clipboard copy/paste
feature.
The main difference is that unlike the clipboard, where you get one
temporary area to copy to, JMatter provides a temporary "buffer"
area for every distinct type.
So, for example in the Contact Manager demo application, I can go
about and copy an Address here, a Contact object there, or an entire
Person instance and all three copies exist in memory simultaneously,
each in its own buffer. I can then, say, create a new Person instance
and right-click "Paste" on the title view for the
new instance. All of the information is copied over. This use case
may not be very interesting or real.
But there are other situations. Take for example how a Person has
a Contact property modeled using composition (or aggregation). Each
instance has its own copy. Yet it's very possible for two persons
to have the same contact information, or perhaps the same address,
with the very real possibility that the two copies will change/diverge
over time.
The copy/paste commands on instances are automatically placed by JMatter
in a number of context menus for a number of views. You'll find these
commands in the title view's context menu, as shown below.
Figure 21.8: Copy on Instance Title View
You'll also find it on aggregate objects' nodes as shown in figure
21.9.
Figure 21.9: Copy on Aggregate Node View
Finally, you'll find it on the context menus for individual tab title
views, as shown here:
Figure 21.10: Copy on Tab Title View
This feature can come in handy and save repetitive data entry tasks,
where one might otherwise be forced to invoke copy/paste individually
on atomic fields.
21.7 The Restore Desktop Feature
One last feature, though not completely polished, is worth mentioning.
JMatter saves and restores end users' desktops between sessions.
That is, the size and positions and other information about open windows
is recorded and stored to the database when one logs out or quits
the application. Conversely an attempt is made to restore these views
on login. What's nice about saving this information to database is
that one's desktop configuration is independent of the workstation
you log in to. Instead it's tied to your user information in the database.
This feature is at the moment fairly simple. Other than restoring
the main window bounds and simple child windows (lists and instances),
it does not yet properly restore other types of views at the moment.