Map Editor - Plugins
Installation Feature LayerStyles Effects Drop Shadow |
Many of the features of the editor can be extended using the plugin mechanism. This allows new tools, menu items, projections, units, coordinate systems, file formats and many other features to be added. If, for example, you want to import map data in a file format which the editor doesn't handle, you can write a plugin to handle the new format. A map viewer plugin Plugins are easy to use: all plugins are stored in a directory called "plugins". When the editor starts up, all plugins found will be loaded and added to the appropriate place. Menu items are added to the menu bar, coordinate systems will be available in all appropriate dialogs, file exporters will appear in the File menu and so on. To write a plugin you need to write a Java bean of the appropriate class (see below) and then package it. The plugin classes must be placed into a JAR file which is then placed into the plugins directory. A plugin can have as many classes as it needs and multiple plugins may be placed into the JAR file. In addition, it is possible to write a plugin which generates new plugins when loaded. Plugins can be organised into plugin suites, which are groups of plugins which belong together. A plugin suite has a version number and it is possible to express dependencies between suites to state that a particular plugin requires a particular version of some other plugin to be loaded. In order for the editor to know which classes are plugins you must add a file to the JAR describing the plugins. This is an XML file which must be in a directory named "config" in the JAR file. There should only be one such file in the JAR. A typical config file might look like this: <plugins> <plugin-suite id="com.jhlabs.map.myplugins" name="Sample Plugins" version="1.0"> <plugin bean="com.jhlabs.map.ImportMyFileFormat"/> <plugin bean="com.jhlabs.map.MyCoordinateSystem"/> </plugin-suite> </plugins> This declares two plugins in the JAR file, a coordinate system and a file importer. These are contained in a suite called "Sample Plugins". The id is the internal name of of the suite and should be unique. For this reason, it should follow the Java convention of placing a domain name at the start. The editor can also load serialized Java Beans as plugins. To do this, just place the serialized bean file into the plugins folder.
Writing a File ImporterFile importers are one of the most important plugins for the viewer, allowing the import of map data from variaous file formats. Typically a file importer will read in a file or stream and create one layer to hold the map data, although importers can perform other tasks such as creating styles or symbols. A user can ask for a layer to be reloaded from its original source in which case the importer will be called again, but be passed the layer into which to import. For an importer which supports this type of working, it is important that it checks the given layer. If it's null, it should create a new layer, if not it should reuse the layer, provided it is of an appropriate type - you can't import images into a Shapefile layer for example. A file importer must implement the MapImport interface. This has a method for allowing the viewer to recognise which files can be imported by the importer and a method for actually importing the data. Like all plugins, the importer should have a toString() method which returns a human-readable name for the plugin. public interface MapImport { public String[] getMimeTypes(); public void importData(ImportExportParams data) throws IOException; }
The importData() method is the most important part of an importer. It takes one parameter of type ImportExportParams which containes details of the file to be imported. The ImportExportParams class has a number of methods which return objects likely to be useful to an importer, such as the file or URL, an input stream onto the data, the map and layer to import into, and the viewer application itself. Here's a sample file importer for importing AWT images: It's fairly simple, the main complications being the logic to load the image and to decide whether to create a new layer or not. This importer creates a RasterLayer for its images. It could have decided to create a FeatureLayer containing an ImageFeature, or it could ask the user at import time what to do with the data. [Note: at present, if two importers exists for the same file type the last one loaded will take precedence. In the future, the viewer will ask the user which to use]. /* * Copyright (C) Jerry Huxtable 1998-2001. All rights reserved. */ package com.jhlabs.map.io; import java.io.*; import java.net.*; import java.awt.*; import java.awt.geom.*; import java.awt.image.*; import com.jhlabs.app.*; import com.jhlabs.map.*; import com.jhlabs.map.layer.*; public class ImportImage implements MapImport { public String[] getMimeTypes() { return new String[] { "image/gif", "image/jpeg", ".gif", ".jpg" }; } public void importData(ImportExportParams iep) throws IOException { Map map = iep.getMap(); StatusDisplay status = iep.getStatusDisplay(); Image image; URL url = null; if (iep.getFile() != null) { url = iep.getFile().toURL(); image = iep.getFrame().getToolkit().getImage(iep.getFile().getPath()); } else { url = iep.getURL(); image = iep.getFrame().getToolkit().getImage(iep.getURL()); } MediaTracker tracker = new MediaTracker(iep.getFrame()); tracker.addImage(image, 0); try { status.showMessage("Loading image..."); tracker.waitForID(0); } catch (InterruptedException e) { } Layer layer = iep.getLayer(); RasterLayer rasterLayer; if (layer != null) { if (!(layer instanceof RasterLayer)) throw new IllegalArgumentException("Images cannot be imported into this layer"); rasterLayer = (RasterLayer)layer; } else rasterLayer = new RasterLayer(iep.getName()); rasterLayer.setDataURL(url); ImageObserver io = iep.getApplication().getFrame(); BufferedImage bufferedImage = new BufferedImage(image.getWidth(io), image.getHeight(io), BufferedImage.TYPE_INT_ARGB); Graphics2D g = bufferedImage.createGraphics(); g.drawImage(image, 0, 0, io); g.dispose(); rasterLayer.setLayerImage(bufferedImage); if (layer == null) map.addLayer(rasterLayer); } public String toString() { return "GIF/JPEG Image"; } }
|