Chapter 19. Implementing a Simple Plugin

Table of Contents

19.1. How Plugins are Loaded
19.2. The QuickNotepadPlugin Class
19.3. The Property Files
19.3.1. Localization Files
19.4. The EditBus
19.5. The Actions.xml Catalog
19.6. The dockables.xml Window Catalog
19.7. The services.xml file
19.8. The QuickNotepad Class
19.9. The QuickNotepadToolBar Class
19.10. The QuickNotepadOptionPane Class
19.11. Plugin Documentation
19.12. The build.xml Ant build file
19.13. Reloading the Plugin
19.14. Tips for debugging plugins

There are many applications for the leading operating systems that provide a scratch-pad or sticky note facility for the desktop display. A similar type of facility operating within the jEdit display would be a convenience. The use of dockable windows would allow the notepad to be displayed or hidden with a single mouse click or keypress (if a keyboard shortcut were defined). The contents of the notepad could be saved at program exit (or, if earlier, deactivation of the plugin) and retrieved at program startup or plugin activation.

We will keep the capabilities of this plugin modest, but a few other features would be worthwhile. The user should be able to write the contents of the notepad to storage on demand. It should also be possible to choose the name and location of the file that will be used to hold the notepad text. This would allow the user to load other files into the notepad display. The path of the notepad file should be displayed in the plugin window, but will give the user the option to hide the file name. Finally, there should be an action by which a single click or keypress would cause the contents of the notepad to be written to the new text buffer for further processing.

The full source code for QuickNotepad is contained in jEdit's source code distribution. We will provide excerpts in this discussion where it is helpful to illustrate specific points. You are invited to obtain the source code for further study or to use as a starting point for your own plugin.

19.1.  How Plugins are Loaded

We will discuss the implementation of the QuickNotepad plugin, along with the jEdit APIs it makes use of. But first, we describe how plugins are loaded.

As part of its startup routine, jEdit's main method calls various methods to load and initialize plugins.

Additionally, plugins using the jEdit 4.2 plugin API can be loaded and unloaded at any time. This is a great help when developing your own plugins -- there is no need to restart the editor after making changes (see Section 19.13, “Reloading the Plugin” ).

Plugins are loaded from files with the .jar filename extension located in the jars subdirectories of the jEdit installation and user settings directories (see Section 8.4, “The jEdit Settings Directory”).

For each JAR archive file it finds, jEdit scans its entries and performs the following tasks:

  • Adds to a collection maintained by jEdit a new object of type PluginJAR. This is a data structure holding the name of the JAR archive file, a reference to the JARClassLoader, and a collection of plugins found in the archive file.

  • Loads any properties defined in files ending with the extension .props that are contained in the archive. See Section 19.3, “The Property Files”.

  • Reads action definitions from any file named actions.xml in the archive (the file need not be at the top level). See Section 19.5, “The Actions.xml Catalog”.

  • Parses and loads the contents of any file named dockables.xml in the archive (the file need not be at the top level). This file contains BeanShell code for creating docking or floating windows that will contain the visible components of the plugin. Not all plugins define dockable windows, but those that do need a dockables.xml file. See Section 19.6, “The dockables.xml Window Catalog”.

  • Checks for a class name with a name ending with Plugin.class.

    Such a class is known as a plugin core class and must extend jEdit's abstract EditPlugin class.

    The initialization routine checks the plugin's properties to see if it is subject to any dependencies. For example, a plugin may require that the version of the Java runtime environment or of jEdit itself be equal to or above some threshold version. A plugin can also require the presence of another plugin.

    If any dependency is not satisfied, the loader marks the plugin as broken and logs an error message.

After scanning the plugin JAR file and loading any resources, a new instance of the plugin core class is created and added to the collection maintained by the appropriate PluginJAR. jEdit then calls the start() method of the plugin core class. The start() method can perform initialization of the object's data members. Because this method is defined as an empty no-op in the EditPlugin abstract class, a plugin need not provide an implementation if no unique initialization is required.