Andami and the management of windows
The application or framework that serves as skeleton for gvSIG is _fwAndami (framework Andami). It has several functions:
- To send the application.
- To load plugins and its extensions.
- To manage the translations.
It offers services to the pluggins for the management and load of dependencies, handling of windows, for some utilities to send tasks into the background, etc.
The common libraries for the entire application is in the directory lib. Of special interest is log4j (registry of incidences), xerces (management of xml), castor (it is used to read xml of the project), gvsig-i18n (translations), beans (common graphic components), iver-utiles (generic useful classes).
Within Andami we find a series of classes that can be of utility for extensions. For example:
The class com.iver.andami. Launcher.java is the entry point to the application. In spite of being quite complex, when an extension sends an unexpected exception, it can sometimes easily be solved by adding a breakpoint to watch the class.
While working with our own extensions, we often needed to use the class com.iver.andami.PluginServices. As its name indicates, it is a class that yields service plugins, offering static methods like:
- getMainFrame () => the main application window
- getMDIManager () => through this class, we access the active window (PluginServices.getMDIManager () .getActiveWindow ()), something that we will continously use in the methods isEnabled and isVisible of all the extensions. It is also used to add a new window, and a few other minor things.
- getDlgPreferences () => obtain the common dialogue of preferences, where all plugin configurations are registered.
- getArguments () => recover arguments by command lines. For example, it is very useful for opening a project by line commands.
- getExtension (Class) => with this call, you can obtain an instance of the extension that executes that class. If the call is made in the initialize () method, you must be sure the extension has already been initialized (careful with the dependencies).
- getText (Object, String) => is used to work with translated text. From the plugin and a key, you obtain the string in the current language.
- registerKeyStroke (KeyStroke) => serves to determine the fast access global keys.
Additional methods exist, but the most frequently used are those we have described.
Andami is also responsible to manage a theme by default with the controls and the generic aspects of the application, to launch the welcoming image of the application (Splash Window) and other tasks we will not go into detail since you normally will not need to manipulate the code there.
The windows in Andami behave like generic units. That is, from the start, they do not depend on a Swing class. The reason is someday it may be decided to change this aspect of the application completely.
The plugin that instantiates the windows is the project libCorePlugin. In this plugin, the extensions are defined which connect the menu, control and window definitions with actual Swing objects. In our case, we chose to use the JInternalFrame class as the basis for gvSIG windows. Being this is an MDI (Multiple Document Interface) application, it seems most suitable.
The windows in Andami are defined thanks to the IWindow interface. This interface is very simple, it only requires to implement the getWindowInfo () method. This returns for a WindowInfo class where it is specified the size of the window, the title, and several constants indicating if the window is modal or not, resizable, or a pallette (very useful for showing information, a group of controls, or tools for example - it is always drawn over all other windows).
In order to show how to add a window in Andami, it is best to see an example:
PluginServices.getMDIManager().addWindow(symbolPanel);
where symbolPanel is
public class PanelEditSymbol extends JPanel implements IWindow {
We see that windows in gvSIG are in fact subclasses of JPanel implemented by the IWindow interface.
When we do not want to re-create a window again, but would rather reuse an already created window, we use the ISingletonWindow interface. This interface add a method (getWindowModel ()) that it is used for avoiding the creation of new windows if they have been previously created. That way it is avoided the creation of multiple windows with each requesting information click.
dlg = (DlgProvin) PluginServices.getMDIManager().addWindow(dlg);
for (int i=bs.nextSetBit(0); i >=0; i=bs.nextSetBit(i+1))
{
long idRec = i;
String nom = ds.getFieldValue(idRec, idField).toString();
dlg.setProvinName(name));
}
where DlgProvin is defined as:
public class DlgProvin extends JPanel implements IWindow, SingletonWindow {
and the methods getWindowInfo
public WindowInfo getWindowInfo() {
if (wi==null)
{
wi = new WindowInfo(WindowInfo.PALETTE);
wi.setWidth(this.getPreferredSize().width);
wi.setHeight(this.getPreferredSize().height);
wi.setTitle("Provin Info");
}
return wi;
and getWindowModel:
public Object getWindowModel() {
return "MyProvinDialog";
}
The windows currently in gvSIG are defined in libCorePlugin (the WindowInfo definition is used to create JinternalFrame windows). Sometimes it is useful to know in more detail how a window was created (to distinguish between SingletonWindow and other types, etc…). You can put a breakpoint in the class com.iver.core.mdiManager.NewSkin.java, in the function addWindow. rabajas which is a JinternalFrame. Be careful with this, future versions libCorePlugin might be changed to create a different type of window (this has not been planned, but is a possibility).