Changes between Version 41 and Version 42 of DevelopersGuide/DevelopingPlugins
- Timestamp:
- 2010-01-13T11:42:38+01:00 (15 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
DevelopersGuide/DevelopingPlugins
v41 v42 66 66 * '''DONT''' use special characters in the plugin name, stick to alphanumeric characters. Call the plugin {{{routing4all}}} not {{{routing 4 all :-) !}}}. Note that the plugin name is used to '''create file and directory names''' on the computer where plugins are installed. If it included special characters like /, ., \, etc. these operations may fail. 67 67 68 You are recommended touse a Java package for the plugin main class and all other classes you need in the plugin, i.e. {{{org.foobar.josm.routing4all}}}. Stick to the well-established naming conventions used in the Java world (lower case package name, camel case class names, etc.).The required minimum in package naming is one individual part in the path structure of your plugin class names. The path of the base class is used to detect the source of exceptions. So when your base class is my.example.class.MyPlugin, then "my.example.class" is used to detect your plugin code. All important parts of your plugin should use that and also it should be unique for the plugin (i.e. add at least one part with the name of your plugin).68 You should use a Java package for the plugin main class and all other classes you need in the plugin, i.e. {{{org.foo.bar.routing4all}}}. Stick to the well-established naming conventions used in the Java world (lower case package name, camel case class names, etc.). Put the plugin code including the plugin main class '''in its own package'''. This allows JOSM to identify and temporarily disable a plugin which has thrown an exception. 69 69 70 == Callbacks == #Callbacks 71 Most of your plugin work will probably be tweaking the JOSM object tree at startup time, but there are a few callbacks that get automatically called on every plugin (whether you subclass Plugin or not, just the signature matters). 70 In short 71 * choose a short plugin name {{{apluginame}}} 72 * declare a unique Java package {{{foo.bar.apluginame}}} 73 * implmeent a plugin main class {{{foo.bar.apluginame.APluginName}}} 72 74 73 === mapFrameInitialized===74 Th is is called after the first data has been loaded and the mapFrame is initialized. Use this to change something on the new MapFrame (or morecommon: the MapView (THE map ;) behind the frame)- As example, you could add yourself as LayerChangeListener to newMapFrame.mapView (please don't forget to remove yourself from oldMapFrame, if newMapFrame is null). This way you can capture changes of the active layer or the addition/removal of layers.75 === The plugin interface === 76 The plugin main class neither has to be derived from a common superclass nor does it have to implement a specific Java interface. 75 77 76 === getPreferenceSetting === 77 This will be called to retrieve an creator for GUI elements for the preferences dialog. The return is an interface with two methods: one to add the GUI elements to the dialog and on that is called when the preferences dialog finishes with ok. Be sure not to write preferences in your GUI code, but remember settings and only write them in the ok() method. 78 There's nevertheless a plugin "interface" JOSM expects a plugin to provide. It consists of a collection of method signatures your plugin may implement. JOSM invokes the corresponding methods at some points in the application life cycle, provided the plugin actually implements these methods. 78 79 79 === addDownloadSelection === 80 This will be called whenever the user pops up the download dialog. The download dialog is prepared by first assembling a list of objects implementing the DownloadSelection interface, and after that giving each of them, via a call to their addGui method, the chance of adding a tab to the download dialog's tabpane. The DownloadSelection interface also has a method that is called by the download dialog if one of the other tabs changes the bounding box, and in turn the GUI elements created by addGui are expected to call boundingBoxChanged on the download dialog if they want to communicate a change to other tabs. 81 The name addDownloadSelection is not 100% accurate as a plugin is also allowed to modify the existing list of DownloadSelection objects. For example, a plugin might want to replace the existing Bookmark handler; it can do so by finding the BookmarkSelection object in the list passed to addDownloadSelection and remove it. 80 * {{{public void mapFrameInitialized(MapFrame old, MapFrame new)}}} 81 82 JOSM manages at most one [source:/trunk/src/org/openstreetmap/josm/gui/MapFrame.java MapFrame]. At startup, when JOSM displays the Message of the Day (MOTD) panel, the MapFrame is null. It is only created when the first [source:/trunk/src/org/openstreetmap/josm/layer/MapFrame.java Layer] is added and it is removed and reset to null if the last layer is removed. Plugins implementing a method {{{mapFrameInitialized}}} are notified about the change of the current map frame. 83 84 * {{{public PreferenceSetting getPreferenceSetting()}}} 85 86 The [source:/trunk/src/org/openstreetmap/josm/gui/preference/PreferenceDialog.java JOSM preference dialog] asks a plugin to supply an editor for its preferences. The editor must be a subclass of [source:/trunk/src/org/openstreetmap/josm/gui/preference/PreferenceSetting.java PreferenceSetting]. Return null from {{{getPreferenceSetting}}} or don't implement it if your plugin has no need to manage preferences. 87 88 * {{{public void addDownloadSelection(List<DownloadSelection> list)}}} 89 90 The [source:/trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java JOSM download dialog] asks a plugin to supply its own download method when the download dialog is created. The plugin must supply an object implementing [source:/trunk/src/org/openstreetmap/josm/gui/download/DownloadSelection.java DownloadSelection]. The download dialog also invokes {{{addGui(DownloadDialog gui)}}} on the supplied [source:/trunk/src/org/openstreetmap/josm/gui/download/DownloadSelection.java DownloadSelection] which gives you the chance to create an UI component (i.e. a JPanel) JOSM adds to the tabbed pane in the download dialog. Reply the unmodified {{{list}}} or don't implement the method if your plugin doesn't provide its own download method. Plugins shouldn't remove and or reorder elements in {{{list}}}. 91 82 92 83 == Some tips about the JOSMobject tree or ''What is where?''==93 === The JOSM API === 84 94 The initial JOSM author preferred public fields in Java classes over public methods, including public getters and setters. He justified this decision as follows: 85 95 86 96 ''First some words about my style of accessing public variables. Most people find this annoying and bad coding style in Java. If this would be an enterprise project, where most of the code is glue code and had to work with objects in a generic way, I would agree with them. But as JOSM is not, I like to keep the classes as simple as possible, which includes, that I don't add standard getter/setter but make the variable public. Also, there are no or very few so-called ''singleton-factories'' in JOSM that became popular in the past years. I use to reference singleton objects as global statics. This is unusual but equivalent to having stuff like Dependency Injection or Factory Methods (except you want to make complex things like auto-distributing stuff as seen in some enterprise programs).'' 87 97 88 Most of the current JOSM authors don't follow this approach and in 2008 and 2009 large parts of the JOSM code base have been refactored in order to improve the maint enability and stability of the code.In particular, this holds for the [source:/trunk/src/org/openstreetmap/josm/data/osm data classes]. In plugins, you're encouraged to follow the well-established principles of encapsulation and information hiding,too.98 Most of the current JOSM authors don't follow this approach and in 2008 and 2009 large parts of the JOSM code base have been refactored in order to improve the maintainability and stability of the code. You're encouraged to follow the well-established principles of encapsulation and information hiding in plugins too. 89 99 90 100 There are still a couple of global objects accessible through [source:/trunk/src/org/openstreetmap/josm/Main Main], though. 91 101 92 === Main.parent === 93 This is the parent of all GUI elements. Use this as first parameter to JOptionPane.show* if you want to popup a message. 102 ||Main.parent||This is the parent of all GUI elements. Use this as first parameter to JOptionPane.show* if you want to popup a message|| 103 ||Main.pref|| This is the global preferences file, loaded from {{{${josm.home}/preferences}}}. Use {{{Main.pref.get(...)}}} and {{{Main.pref.put(...)}}} to access the preferences. They will be saved immediately after a put, so don't put anything you dont want to have there. Please, prefix custom plugin preferences with your plugin name. || 104 || Main.proj|| This is the current [source:/trunk/src/org/openstreetmap/josm/data/projection/Projection.java Projection] used in JOSM. If you want to translate between Lat/Lon and East/North, use {{{Main.proj.latlon2eastnorth}}} and {{{Main.proj.eastnorth2latlon}}}.|| 105 ||Main.map.mapView||This is the main UI component in JOSM. It provides the the view with the rendered layers. You usually access this to call methods like {{{getCenter()}}}, {{{getScale()}}} or {{{zoomTo()}}}. '''Beware''': {{{Main.map}}} can be null when no layers are created yet.|| 94 106 95 === Main.pref === 96 This is the (ONLY!) access to the global preferences file, located in .josm/preferences. Use Main.pref.get(...) and Main.pref.put(...) to access the preferences. They will be saved immediately after a put, so don't put anything you dont want to have there ;). 107 JOSM plugins can '''register''' for a couple of '''events''' emitted by JOSM. 97 108 98 Please, prefix custom plugin preferences with your plugin name. 109 * '''layer change events''' 99 110 100 === Main.proj === 101 If you want to translate between Lat/Lon and East/North, use Main.proj.latlon2eastnorth and Main.proj.eastnorth2latlon. 111 Implement a [source:/trunk/src/org/openstreetmap/josm/gui/MapView.java org.openstreetmap.josm.gui.MapView.LayerChangeListener] and register is using [source:/trunk/src/org/openstreetmap/josm/gui/MapView.java addLayerChangeListener(LayerChangeListener listener)]. JOSM will then notify you about added, removed, and renamed layers. You may only or also register an [source:/trunk/src/org/openstreetmap/josm/gui/MapView.java org.openstreetmap.josm.gui.MapView.EditLayerChangeListener] in which case JOSM will notify the plugin about changes in the current edit layer, in particular whether there is or there isn't a current edit layer. 102 112 103 === Main.map.mapView === 104 This is the GUI class of the map. You usually access this to call stuff like getCenter, getScale or zoomTo. 113 * '''selection change listener''' 105 114 106 ''BEWARE'': Main.map can be null, in which case no data is loaded yet. 115 If your plugin needs to respond to changes in the currently selected set of OSM objects it can implement a [source:/trunk/src/org/openstreetmap/josm/data/SelectionChangeListener.java org.openstreetmap.josm.data.SelectionChangeListener] and add it to the global list {{{org.openstreetmap.josm.data.osm.DataSet.selListeners}}}. 107 116 108 === Main.main.editLayer() === 109 Call this to get the current OsmDataLayer. If there is no such layer, null is returned. 117 * '''data change events''' 110 118 111 === Plugin.getPluginDir() and Plugin.copy() === 112 If you subclass from the plugin class (see above), then you can call this functions to get your plugin directory or copy data into your plugin directory. This is a directory where you can freely store/read data from. It is located at ~/.josm/plugins/''youpluginname''. 119 If your plugin needs to respond to changes in the data managed by [source:/trunk/src/org/openstreetmap/josm/layer/OsmDataLayer.java org.openstreetmap.josm.layer.OsmDataLayer]s it can implement a [source:/trunk/src/org/openstreetmap/josm/data/osm/event/DataSetListener.java org.openstreetmap.josm.data.osm.event.DataSetListener] and register it on the data set of an OsmDataLayer using {{{layer.ds.addDataSetListener(yourlistener)}}}. JOSM will notify the listener about added, modified, and deleted objects in the dataset. 113 120 114 == The MANIFEST.MF == 121 Make sure your plugin also unregisters as data set listener when the respective OsmDataLayer is deleted. Listen to layer change events to and respond to layer deleted events. 122 123 * ''' preference change listener''' 124 If your plugin needs to respond to changes in the JOSM preferences it can implement a [source:/trunk/src/org/openstreetmap/josm/data/Preferences.java org.openstreetmap.josm.data.Preferences.PreferenceChangedListener]. Invoke {{{addPreferenceChangeListener(PreferenceChangedListener listener)}}} on {{{Main.pref}}}. 125 126 === Accessing the local file system === 127 JOSM plugins are currently allowed to read from and write to the local file system. Please write plugin specific files to {{{${josm.home}/preferences/${pluginname}}}}. If your plugin main class subclasses from [source:/trunk/src/org/openstreetmap/josm/plugin/Plugin.java Plugin] you can use the method {{{String getPluginDir()}}} to get the name of the plugin specific data directory. 128 129 == Packaging a plugin == 130 131 === A plugin is deployed as a single jar === 132 A JOSM plugin is deployed as a single jar file. The jar files name must be equal to the plugin name, i.e. {{{routing4all.jar}}}. 133 134 The jar file must include 135 * the required java classes, including any additional libraries the plugin requires 136 * icons, deployed data files, and other resources 137 * a manifest file with JOSM specific entries (see below) 138 139 === The manifest file for a JOSM plugin === 115 140 116 141 You have to put some information into the manifest file of your jar. If you use ant, you can set these values within the {{{build.xml}}} file. … … 132 157 For SVN managed plugins, the links to old versions and the translated descriptions are automatically added to the [http://josm.openstreetmap.de/plugin plugin information], so JOSM can use that when it displays the list of plugins in the preference dialog. 133 158 159 == Managing a plugin == 160 There is an SVN repository for JOSM plugins in the main OSM SVN repository, see [http://svn.openstreetmap.org/applications/editors/josm/plugins/ here]. Note that this repository is different from the [http://josm.openstreetmap.de/svn/ main JOSM SVN repository] which only manages the JOSM core. 161 162 You can easily get write access to the JOSM plugins repository by [http://wiki.openstreetmap.org/wiki/Accounts#SVN_access_.28OSM_software.29 following these steps]. If your plugin should be available for other users too and if you want to integrate it into the JOSM plugin update procedure you should submit it to the JOSM plugins repository. The following [http://svn.openstreetmap.org/applications/editors/josm/plugins/00_README readme file] might be helpful too. 134 163 135 164 == Updating a plugin == … … 156 185 The steps describe above can be automated, see [http://svn.openstreetmap.org/applications/editors/josm/plugins/tageditor/build.xml build.xml of the tageditor plugin]. It includes an ant target {{{publish}}}. 157 186 158 159 187 == Legal stuff (Imis opinion) == 160 188