PageRenderTime 115ms CodeModel.GetById 65ms app.highlight 12ms RepoModel.GetById 18ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/EditPlugin.java

#
Java | 448 lines | 107 code | 29 blank | 312 comment | 12 complexity | fb7cdd652dd7c16216fefbb4a891955f MD5 | raw file
  1/*
  2 * EditPlugin.java - Abstract class all plugins must implement
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 1999, 2003 Slava Pestov
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22
 23package org.gjt.sp.jedit;
 24
 25import javax.swing.JMenuItem;
 26import java.util.*;
 27import org.gjt.sp.jedit.browser.VFSBrowser;
 28import org.gjt.sp.jedit.gui.OptionsDialog;
 29import org.gjt.sp.jedit.menu.EnhancedMenu;
 30
 31/**
 32 * The abstract base class that every plugin must implement.
 33 * Alternatively, instead of extending this class, a plugin core class can
 34 * extend {@link EBPlugin} to automatically receive EditBus messages.
 35 *
 36 * <h3>Basic plugin information properties</h3>
 37 *
 38 * Note that in all cases above where a class name is needed, the fully
 39 * qualified class name, including the package name, if any, must be used.<p>
 40 *
 41 * The following properties are required for jEdit to load the plugin:
 42 *
 43 * <ul>
 44 * <li><code>plugin.<i>class name</i>.activate</code> - set this to
 45 * <code>defer</code> if your plugin only needs to be loaded when it is first
 46 * invoked; set it to <code>startup</code> if your plugin must be loaded at
 47 * startup regardless; set it to a whitespace-separated list of property names
 48 * if your plugin should be loaded if at least one of these properties is set.
 49 * Note that if this property is <b>not</b> set, the plugin is loaded like an
 50 * old-style jEdit 4.1 plugin.
 51 * </li>
 52 * <li><code>plugin.<i>class name</i>.name</code></li>
 53 * <li><code>plugin.<i>class name</i>.version</code></li>
 54 * <li><code>plugin.<i>class name</i>.jars</code> - only needed if your plugin
 55 * bundles external JAR files. Contains a whitespace-separated list of JAR
 56 * file names. Without this property, the plugin manager will leave behind the
 57 * external JAR files when removing the plugin.</li>
 58 * </ul>
 59 *
 60 * The following properties are optional but recommended:
 61 *
 62 * <ul>
 63 * <li><code>plugin.<i>class name</i>.author</code></li>
 64 * <li><code>plugin.<i>class name</i>.docs</code> - the path to plugin
 65 * documentation in HTML format within the JAR file.</li>
 66 * </ul>
 67 *
 68 * <h3>Plugin dependency properties</h3>
 69 *
 70 * Plugin dependencies are also specified using properties.
 71 * Each dependency is defined in a property named with
 72 * <code>plugin.<i>class name</i>.depend.</code> followed by a number.
 73 * Dependencies must be numbered in order, starting from zero.<p>
 74 *
 75 * The value of a dependency property has one of the following forms:
 76 *
 77 * <ul>
 78 * <li><code>jdk <i>minimum Java version</i></code></li>
 79 * <li><code>jedit <i>minimum jEdit version</i></code> - note that this must be
 80 * a version number in the form returned by {@link jEdit#getBuild()},
 81 * not {@link jEdit#getVersion()}. Note that the documentation here describes
 82 * the jEdit 4.2 plugin API, so this dependency must be set to at least
 83 * <code>04.02.01.00</code>.</li>
 84 * <li><code>plugin <i>plugin</i> <i>version</i></code> - the fully quailified
 85 * plugin class name must be specified.</li>
 86 * </ul>
 87 *
 88 * <h3>Plugin menu item properties</h3>
 89 *
 90 * To add your plugin to the view's <b>Plugins</b> menu, define one of these two
 91 * properties:
 92 *
 93 * <ul>
 94 * <li><code>plugin.<i>class name</i>.menu-item</code> - if this is defined,
 95 * the action named by this property is added to the <b>Plugins</b> menu.</li>
 96 * <li><code>plugin.<i>class name</i>.menu</code> - if this is defined,
 97 * a sub-menu is added to the <b>Plugins</b> menu whose content is the
 98 * whitespace-separated list of action names in this property. A separator may
 99 * be added to the sub-menu by listing <code>-</code> in the property.</li>
100 * </ul>
101 *
102 * If you want the plugin's menu items to be determined at runtime, define a
103 * property <code>plugin.<i>class name</i>.menu.code</code> to be BeanShell
104 * code that evaluates to an implementation of
105 * {@link org.gjt.sp.jedit.menu.DynamicMenuProvider}.<p>
106 *
107 * To add your plugin to the file system browser's <b>Plugins</b> menu, define
108 * one of these two properties:
109 *
110 * <ul>
111 * <li><code>plugin.<i>class name</i>.browser-menu-item</code> - if this is
112 * defined, the action named by this property is added to the <b>Plugins</b>
113 * menu.</li>
114 * <li><code>plugin.<i>class name</i>.browser-menu</code> - if this is defined,
115 * a sub-menu is added to the <b>Plugins</b> menu whose content is the
116 * whitespace-separated list of action names in this property. A separator may
117 * be added to the sub-menu by listing <code>-</code> in the property.</li>
118 * </ul>
119 *
120 * In all cases, each action's
121 * menu item label is taken from the <code><i>action name</i>.label</code>
122 * property. View actions are defined in an <code>actions.xml</code>
123 * file, file system browser actions are defined in a
124 * <code>browser.actions.xml</code> file; see {@link ActionSet}.
125 *
126 * <h3>Plugin option pane properties</h3>
127 *
128 * To add your plugin to the <b>Plugin Options</b> dialog box, define one of
129 * these two properties:
130 *
131 * <ul>
132 * <li><code>plugin.<i>class name</i>.option-pane</code> - if this is defined,
133 * the option pane named by this property is added to the <b>Plugin Options</b>
134 * menu.</li>
135 * <li><code>plugin.<i>class name</i>.option-group</code> - if this is defined,
136 * a branch node is added to the <b>Plugin Options</b> dialog box whose content
137 * is the whitespace-separated list of option pane names in this property.</li>
138 * </ul>
139 *
140 * Then for each option pane name, define these two properties:
141 *
142 * <ul>
143 * <li><code>options.<i>option pane name</i>.label</code> - the label to show
144 * for the pane in the dialog box.</li>
145 * <li><code>options.<i>option pane name</i>.code</code> - BeanShell code that
146 * evaluates to an instance of the {@link OptionPane} class.</li>
147 *
148 * <h3>Example</h3>
149 *
150 * Here is an example set of plugin properties:
151 *
152 * <pre>plugin.QuickNotepadPlugin.activate=defer
153 *plugin.QuickNotepadPlugin.name=QuickNotepad
154 *plugin.QuickNotepadPlugin.author=John Gellene
155 *plugin.QuickNotepadPlugin.version=4.2
156 *plugin.QuickNotepadPlugin.docs=QuickNotepad.html
157 *plugin.QuickNotepadPlugin.depend.0=jedit 04.02.01.00
158 *plugin.QuickNotepadPlugin.menu=quicknotepad \
159 *    - \
160 *    quicknotepad.choose-file \
161 *    quicknotepad.save-file \
162 *    quicknotepad.copy-to-buffer
163 *plugin.QuickNotepadPlugin.option-pane=quicknotepad</pre>
164 *
165 * Note that action and option pane labels are not shown in the above example.
166 *
167 * @see org.gjt.sp.jedit.jEdit#getProperty(String)
168 * @see org.gjt.sp.jedit.jEdit#getPlugin(String)
169 * @see org.gjt.sp.jedit.jEdit#getPlugins()
170 * @see org.gjt.sp.jedit.jEdit#getPluginJAR(String)
171 * @see org.gjt.sp.jedit.jEdit#getPluginJARs()
172 * @see org.gjt.sp.jedit.jEdit#addPluginJAR(String)
173 * @see org.gjt.sp.jedit.jEdit#removePluginJAR(PluginJAR,boolean)
174 * @see org.gjt.sp.jedit.ActionSet
175 * @see org.gjt.sp.jedit.gui.DockableWindowManager
176 * @see org.gjt.sp.jedit.OptionPane
177 * @see org.gjt.sp.jedit.PluginJAR
178 * @see org.gjt.sp.jedit.ServiceManager
179 *
180 * @author Slava Pestov
181 * @author John Gellene (API documentation)
182 * @version $Id: EditPlugin.java 4681 2003-05-03 20:34:26Z spestov $
183 * @since jEdit 2.1pre1
184 */
185public abstract class EditPlugin
186{
187	//{{{ start() method
188	/**
189	 * jEdit calls this method when the plugin is being activated, either
190	 * during startup or at any other time. A plugin can get activated for
191	 * a number of reasons:
192	 *
193	 * <ul>
194	 * <li>The plugin is written for jEdit 4.1 or older, in which case it
195	 * will always be loaded at startup.</li>
196	 * <li>The plugin has its <code>activate</code> property set to
197	 * <code>startup</code>, in which case it will always be loaded at
198	 * startup.</li>
199	 * <li>One of the properties listed in the plugin's
200	 * <code>activate</code> property is set to <code>true</code>,
201	 * in which case it will always be loaded at startup.</li>
202	 * <li>One of the plugin's classes is being accessed by another plugin,
203	 * a macro, or a BeanShell snippet in a plugin API XML file.</li>
204	 * </ul>
205	 *
206	 * Note that this method is always called from the event dispatch
207	 * thread, even if the activation resulted from a class being loaded
208	 * from another thread. A side effect of this is that some of your
209	 * plugin's code might get executed before this method finishes
210	 * running.<p>
211	 *
212	 * When this method is being called for plugins written for jEdit 4.1
213	 * and below, no views or buffers are open. However, this is not the
214	 * case for plugins using the new API. For example, if your plugin adds
215	 * tool bars to views, make sure you correctly handle the case where
216	 * views are already open when the plugin is loaded.<p>
217	 *
218	 * If your plugin must be loaded on startup, take care to have this
219	 * method return as quickly as possible.<p>
220	 *
221	 * The default implementation of this method does nothing.
222	 *
223	 * @since jEdit 2.1pre1
224	 */
225	public void start() {}
226	//}}}
227
228	//{{{ stop() method
229	/**
230	 * jEdit calls this method when the plugin is being unloaded. This can
231	 * be when the program is exiting, or at any other time.<p>
232	 *
233	 * If a plugin uses state information or other persistent data
234	 * that should be stored in a special format, this would be a good place
235	 * to write the data to storage.  If the plugin uses jEdit's properties
236	 * API to hold settings, no special processing is needed for them on
237	 * exit, since they will be saved automatically.<p>
238	 *
239	 * With plugins written for jEdit 4.1 and below, this method is only
240	 * called when the program is exiting. However, this is not the case
241	 * for plugins using the new API. For example, if your plugin adds
242	 * tool bars to views, make sure you correctly handle the case where
243	 * views are still open when the plugin is unloaded.<p>
244	 *
245	 * To avoid memory leaks, this method should ensure that no references
246	 * to any objects created by this plugin remain in the heap. In the
247	 * case of actions, dockable windows and services, jEdit ensures this
248	 * automatically. For other objects, your plugin must clean up maually.
249	 * <p>
250	 *
251	 * The default implementation of this method does nothing.
252	 *
253	 * @since jEdit 2.1pre1
254	 */
255	public void stop() {} //}}}
256
257	//{{{ getClassName() method
258	/**
259	 * Returns the plugin's class name. This might not be the same as
260	 * the class of the actual <code>EditPlugin</code> instance, for
261	 * example if the plugin is not loaded yet.
262	 *
263	 * @since jEdit 2.5pre3
264	 */
265	public String getClassName()
266	{
267		return getClass().getName();
268	} //}}}
269
270	//{{{ getPluginJAR() method
271	/**
272	 * Returns the JAR file containing this plugin.
273	 * @since jEdit 4.2pre1
274	 */
275	public PluginJAR getPluginJAR()
276	{
277		return jar;
278	} //}}}
279
280	//{{{ createMenuItems() method
281	/**
282	 * Called by the view when constructing its <b>Plugins</b> menu.
283	 * See the description of this class for details about how the
284	 * menu items are constructed from plugin properties.
285	 *
286	 * @since jEdit 4.2pre1
287	 */
288	public final JMenuItem createMenuItems()
289	{
290		if(this instanceof Broken)
291			return null;
292
293		String menuItemName = jEdit.getProperty("plugin." +
294			getClassName() + ".menu-item");
295		if(menuItemName != null)
296			return GUIUtilities.loadMenuItem(menuItemName);
297
298		String menuProperty = "plugin." + getClassName() + ".menu";
299		String codeProperty = "plugin." + getClassName() + ".menu.code";
300		if(jEdit.getProperty(menuProperty) != null
301			|| jEdit.getProperty(codeProperty) != null)
302		{
303			String pluginName = jEdit.getProperty("plugin." +
304				getClassName() + ".name");
305			return new EnhancedMenu(menuProperty,pluginName);
306		}
307
308		return null;
309	} //}}}
310
311	//{{{ createBrowserMenuItems() method
312	/**
313	 * Called by the filesystem browser when constructing its
314	 * <b>Plugins</b> menu.
315	 * See the description of this class for details about how the
316	 * menu items are constructed from plugin properties.
317	 *
318	 * @since jEdit 4.2pre1
319	 */
320	public final JMenuItem createBrowserMenuItems()
321	{
322		if(this instanceof Broken)
323			return null;
324
325		String menuItemName = jEdit.getProperty("plugin." +
326			getClassName() + ".browser-menu-item");
327		if(menuItemName != null)
328		{
329			return GUIUtilities.loadMenuItem(
330				VFSBrowser.getActionContext(),
331				menuItemName,
332				false);
333		}
334
335		String menuProperty = "plugin." + getClassName() + ".browser-menu";
336		if(jEdit.getProperty(menuProperty) != null)
337		{
338			String pluginName = jEdit.getProperty("plugin." +
339				getClassName() + ".name");
340			return new EnhancedMenu(menuProperty,pluginName,
341				VFSBrowser.getActionContext());
342		}
343
344		return null;
345	} //}}}
346
347	//{{{ Deprecated methods
348
349	//{{{ createMenuItems() method
350	/**
351	 * @deprecated Instead of overriding this method, define properties
352	 * as specified in the description of this class.
353	 */
354	public void createMenuItems(Vector menuItems) {} //}}}
355
356	//{{{ createOptionPanes() method
357	/**
358	 * @deprecated Instead of overriding this method, define properties
359	 * as specified in the description of this class.
360	 */
361	public void createOptionPanes(OptionsDialog optionsDialog) {} //}}}
362
363	//{{{ getJAR() method
364	/**
365	 * @deprecated Call <code>getPluginJAR()</code> instead.
366	 */
367	public EditPlugin.JAR getJAR()
368	{
369		return jar;
370	} //}}}
371
372	//}}}
373
374	//{{{ Package-private members
375	EditPlugin.JAR jar;
376	//}}}
377
378	//{{{ Broken class
379	/**
380	 * A placeholder for a plugin that didn't load.
381	 * @see jEdit#getPlugin(String)
382	 * @see PluginJAR#getPlugin()
383	 * @see PluginJAR#activatePlugin()
384	 */
385	public static class Broken extends EditPlugin
386	{
387		public String getClassName()
388		{
389			return clazz;
390		}
391
392		// package-private members
393		Broken(String clazz)
394		{
395			this.clazz = clazz;
396		}
397
398		// private members
399		private String clazz;
400	} //}}}
401
402	//{{{ Deferred class
403	/**
404	 * A placeholder for a plugin that hasn't been loaded yet.
405	 * @see jEdit#getPlugin(String)
406	 * @see PluginJAR#getPlugin()
407	 * @see PluginJAR#activatePlugin()
408	 */
409	public static class Deferred extends EditPlugin
410	{
411		public String getClassName()
412		{
413			return clazz;
414		}
415
416		// package-private members
417		Deferred(String clazz)
418		{
419			this.clazz = clazz;
420		}
421
422		EditPlugin loadPluginClass()
423		{
424			return null;
425		}
426
427		public String toString()
428		{
429			return "Deferred[" + clazz + "]";
430		}
431
432		// private members
433		private String clazz;
434	} //}}}
435
436	//{{{ JAR class
437	/**
438	 * @deprecated Use <code>PluginJAR</code> instead.
439	 */
440	public static class JAR extends PluginJAR
441	{
442		JAR(java.io.File file)
443		{
444			super(file);
445		}
446	}
447	//}}}
448}