Informing the User
One of the key elements of the new prototype is something called an event listener. An event listener is a separate class that implements IStatusListener, that is instantiated within a server monitor and does just that – listens for events. When it hears an event that it is interested in, then it can do whatever it likes!
This is important because in the current CCTray, this type of functionality was hard-coded into the application. Even if the user doesn’t want speech or X10, the functionality is still there (yes, they can disable it, but they can’t remove it). In contrast, event listeners can sit in their own libraries and so are independant of the main application.
There are two parts to an event listener, first I need to develop the event listener and add it to the bin folder. Second the listener needs to be configured. In the long term a developer will only need to worry about the first point, but since I’m still working on the prototype I need to do both parts
How To Listen
The first part is building an actual listener. I’m going to build a listener that adds a little pop-up window, similar to the MSN notification window. Therefore I’m going to call my event listener PopUpNotification (yeah, not very original!)
The only interface that I need to implement is IStatusListener – this has two methods: Register() and Unregister(). Register() is called when the server monitor starts up and it allows the event listeners to add handlers to any of the events (ServerChanged, QueueChanged, ProjectChanged – I’ll add some more later). Unregister() is called when the server monitor is stopping and it allows the event listener to gracefully remove any handlers.
For my pop-up notification I am only interested when a project changes, so I added an event handler for the ProjectChanged event.
Next, I built a small pop-up window that has an icon, the name of the project and a message:
When a ProjectChanged event is received I display this window, and populate the project name and status. I added a method to the window to do this automatically (including a pop-up effect). And that’s all there is to it.
Configuring the Listener
Configuring the listener should just be an easy process of the user selecting the listener and then setting any configuration options, so my task is to make it that easy.
On the project configuration tab there is a button labelled “Event Listeners”. All I need to do is wire up some functionality. So, the first thing to do is add a new form, called ListenersWindow:
This window displays the name of the server monitor (just so the user can always see where they are) and a list of event listeners. To add a listener to the monitor the user checks the event listener.
Since event listeners can have additional configuration settings there is a nice empty pane next to the list. When the user selects a checked listener it will check to see if there are any configuration options for the listener. If there are no options then it will tell the user, otherwise it will show a PropertyGrid with the options in it:
These settings come from an IConfigurable instance – if the event listener implements this interface then it has configuration options.
The code behind this form is very simple – it just lists all the possible event listeners it can find, then it goes through the list and instantiates each instance that is already in the configuration. When the user selects an event listener it checks to see if it has configuration and if so displays it, otherwise it displays a message saying there is no configuration. When the user clicks on “Save” it goes through and generates a list of PluginConfiguration instances that contains the type name and any custom configuration.
What’s in a Name
One item I didn’t mention earlier is the name of the plug-in. The full type name is something like ThoughtWorks.Leo.PopUpNotification.EventListener,…, but in the screenshots above it has the name “Pop-up Notifications”.
This is handled by adding a custom attribute to the class called PlugInName. This allows a developer to associate a friendly-name with any classes that appear in lists (e.g. event listeners, transport protocols and display tabs). When the application loads the classes for these lists it checks to see if this attribute exists, if so then the friendly-name is displayed, otherwise the full type name is displayed.
Another Item Down
That’s yet another item on my to-do list completed. Next I’m planning on doing some tidying up, which will include an HTTP transport protocol, some general settings and maybe even security.