001: package net.xoetrope.builder.editor.plugin;
002:
003: import java.io.File;
004: import java.util.Collections;
005: import java.util.Vector;
006: import java.util.prefs.Preferences;
007:
008: import java.awt.AWTEvent;
009: import java.awt.Component;
010: import java.awt.Frame;
011: import java.awt.event.MouseEvent;
012: import javax.swing.JDialog;
013: import javax.swing.JFileChooser;
014: import javax.swing.JMenuItem;
015: import javax.swing.JPopupMenu;
016:
017: import net.xoetrope.builder.editor.XEditorProject;
018: import net.xoetrope.builder.editor.XEditorUtilities;
019: import net.xoetrope.builder.editor.XuiEditor;
020: import net.xoetrope.builder.editor.events.ComponentSelectListener;
021: import net.xoetrope.builder.editor.helper.AFileFilter;
022: import net.xoetrope.debug.DebugLogger;
023: import javax.swing.JFrame;
024: import java.net.URL;
025: import java.net.MalformedURLException;
026: import java.io.IOException;
027: import java.lang.reflect.InvocationTargetException;
028: import javax.swing.SwingUtilities;
029: import net.xoetrope.builder.editor.components.PropertyHelper;
030: import net.xoetrope.builder.editor.XPageResource;
031: import net.xoetrope.xui.XProjectManager;
032: import net.xoetrope.xui.XResourceManager;
033:
034: /**
035: * A class to manage XEditorPlugins.
036: * <p> Copyright (c) Xoetrope Ltd., 2002-2003</p>
037: * <p> $Revision: 1.18 $</p>
038: * <p> License: see License.txt</p>
039: */
040: public class XPluginManager implements ComponentSelectListener {
041: protected Vector plugins;
042:
043: protected XEditorProject currentProject;
044: protected Preferences prefs;
045: protected PluginListener pluginListener;
046:
047: public XPluginManager(XEditorProject project) {
048: currentProject = project;
049: plugins = new Vector();
050: prefs = Preferences.userNodeForPackage(XuiEditor.class);
051: }
052:
053: /**
054: * Notify the plugins of a shutdown
055: */
056: public void shutDown() {
057: int numPlugins = plugins.size();
058:
059: Vector menuItems = new Vector();
060: for (int i = 0; i < numPlugins; i++) {
061: XEditorPlugin plugin = currentProject.getPluginManager()
062: .getPlugin(i);
063: plugin.setState(XEditorPlugin.CLOSED);
064: }
065: }
066:
067: /**
068: * Get a list of items to add to the plugins menu
069: * @return a Vector of JMenuItems and/or plugin names.
070: */
071: public Vector getPluginMenus() {
072: int numPlugins = plugins.size();
073:
074: Vector menuItems = new Vector();
075: for (int i = 0; i < numPlugins; i++) {
076: XEditorPlugin plugin = currentProject.getPluginManager()
077: .getPlugin(i);
078: JMenuItem pluginMenuItem = plugin.getPluginMenu();
079: if (pluginMenuItem != null)
080: menuItems.add(pluginMenuItem);
081: else
082: menuItems.add(plugin.getName());
083: }
084: return menuItems;
085: }
086:
087: /**
088: * Add a plugin
089: * @param plugin
090: * @return true if the plugin can be added, or false if it is already present
091: */
092: private boolean addPlugin(JFrame applicationFrame,
093: XEditorPlugin plugin) {
094: plugin.setFrame(applicationFrame);
095: if (currentProject.getPath() != null)
096: plugin.setActiveProject(currentProject);
097:
098: // Check that the plugin is not already registered.
099: int idx = Collections.binarySearch(plugins, plugin);
100: if (idx < 0) {
101: plugins.add(plugin);
102: return true;
103: }
104:
105: return false;
106: }
107:
108: /**
109: * Remove a plugin
110: * @param plugin
111: */
112: public void removePlugin(XEditorPlugin plugin) {
113: if (plugins == null)
114: return;
115:
116: // Check that the plugin is not already registered.
117: plugins.remove(plugin);
118: savePlugins();
119: }
120:
121: /**
122: * Check if the named plugin is loaded
123: * @param pluginName the name of the plugin to find
124: * @return true if the plugin is loaded otherwise false
125: */
126: public boolean hasPlugin(String pluginName) {
127: int numPlugins = plugins.size();
128: for (int i = 0; i < numPlugins; i++) {
129: XEditorPlugin plugin = (XEditorPlugin) plugins.elementAt(i);
130: if (plugin.getName().equalsIgnoreCase(pluginName))
131: return true;
132: }
133:
134: return false;
135: }
136:
137: /**
138: * Get the number of registered plugins
139: * @return
140: */
141: public int getNumPlugins() {
142: return plugins.size();
143: }
144:
145: /**
146: * Get the i-th plugin
147: * @param i the plugin registration id
148: * @return
149: */
150: public XEditorPlugin getPlugin(int i) {
151: return (XEditorPlugin) plugins.elementAt(i);
152: }
153:
154: /**
155: * Get the named plugin if it is loaded
156: * @param pluginName the name of the plugin to find
157: * @return the plugin or null if it is not found
158: */
159: public XEditorPlugin getPlugin(String pluginName) {
160: int numPlugins = plugins.size();
161: for (int i = 0; i < numPlugins; i++) {
162: XEditorPlugin plugin = (XEditorPlugin) plugins.elementAt(i);
163: if (plugin.getName().equalsIgnoreCase(pluginName))
164: return plugin;
165: }
166:
167: return null;
168: }
169:
170: /**
171: * Set the component selection for the plugins
172: * @param selection the list of components
173: */
174: public void setSelectedComponents(Vector selection) {
175: int numPlugins = plugins.size();
176: for (int i = 0; i < numPlugins; i++) {
177: XEditorPlugin plugin = (XEditorPlugin) plugins.elementAt(i);
178: plugin.setActiveComponents(selection);
179: }
180: }
181:
182: /**
183: * Get the popup context menu for the selected components
184: * @param evt the initiating mouse event
185: */
186: public void getPluginContextMenu(MouseEvent evt,
187: JPopupMenu popupMenu) {
188: int numPlugins = plugins.size();
189: for (int i = 0; i < numPlugins; i++) {
190: XEditorPlugin plugin = (XEditorPlugin) plugins.elementAt(i);
191: JMenuItem subMenu = plugin.getContextMenu();
192: if (subMenu != null)
193: popupMenu.add(subMenu);
194: }
195:
196: if (popupMenu.getComponentCount() > 0)
197: popupMenu.show((Component) evt.getSource(), evt.getX(), evt
198: .getY());
199: }
200:
201: //--Menu support--------------------------------------------------------------
202: /**
203: * Process a menu commands for a plugin
204: * @param command the command id
205: * @param evt the original event
206: * @param selected the selected state of the toolbar or menu item or false if no state exists
207: */
208: public void processPluginCommand(int command, AWTEvent evt,
209: boolean selected) {
210: int pluginIdx = Integer.parseInt(((Component) evt.getSource())
211: .getName());
212: XEditorPlugin plugin = getPlugin(pluginIdx);
213: plugin.processCommand(command, evt, selected);
214: }
215:
216: /**
217: * Add a plugin and setup its components
218: */
219: public XEditorPlugin addPlugin(JFrame applicationFrame) {
220: String lastPluginLocation = prefs.get("LastPluginLocation", "");
221: JFileChooser chooser = new JFileChooser(lastPluginLocation);
222: XEditorUtilities.setDefaultFont(chooser);
223: chooser.setFileFilter(new AFileFilter("jar", "Plugins"));
224: int i = chooser.showOpenDialog(null);
225: if (i == 0) {
226: XEditorPlugin newPlugin = null;
227: prefs.put("LastPluginLocation", chooser.getSelectedFile()
228: .getParent());
229: try {
230: String url = chooser.getSelectedFile().toURL()
231: .toExternalForm();
232: newPlugin = loadPluginUrl(url);
233: newPlugin.setPluginUrl(url);
234: } catch (Exception ex) {
235: DebugLogger.logError("Could not load the plugin");
236: }
237:
238: if (newPlugin != null) {
239: addPlugin(applicationFrame, newPlugin);
240:
241: savePlugins();
242: }
243: return newPlugin;
244: }
245:
246: return null;
247: }
248:
249: public void loadPlugins(JFrame applicationFrame,
250: PluginListener listener) {
251: pluginListener = listener;
252: final JFrame appFrame = applicationFrame;
253:
254: new Thread(new Runnable() {
255: public void run() {
256: // Load plugins from the plugin folder
257: File pluginFolder = new File(prefs.get("PluginFolder",
258: System.getProperty("user.home")
259: + File.separatorChar + "plugins"
260: + File.separatorChar));
261: File files[] = pluginFolder.listFiles();
262: int numPlugins;
263: if (files != null) {
264: numPlugins = files.length;
265: for (int i = 0; i < numPlugins; i++) {
266: if (files[i].getName().indexOf(".jar") > 0) {
267: Object o = null;
268: String pluginUrl = null;
269: try {
270: pluginUrl = files[i].toURL().toString();
271: if (pluginUrl.indexOf(".class") > 0)
272: o = loadPluginClass(
273: getClass().getClassLoader(),
274: pluginUrl
275: .substring(
276: 0,
277: pluginUrl
278: .indexOf(".class")));
279: else
280: o = loadPluginUrl(pluginUrl);
281: } catch (Exception ex) {
282: DebugLogger
283: .logError("Could not load the plugin: "
284: + files[i].getName());
285: }
286:
287: if (o != null) {
288: XEditorPlugin newPlugin = (XEditorPlugin) o;
289: newPlugin.setPluginUrl(pluginUrl);
290: if (addPlugin(appFrame, newPlugin))
291: addPluginToolbar(newPlugin);
292: }
293: }
294: }
295: }
296:
297: // Load registered plugins
298: numPlugins = Integer.parseInt(prefs.get("NumPlugins",
299: "0"));
300: for (int i = 0; i < numPlugins; i++) {
301: String pluginUrl = prefs.get("Plugin_"
302: + Integer.toString(i), "");
303: if (pluginUrl.length() > 0) {
304: Object o = null;
305: try {
306: o = loadPluginUrl(pluginUrl);
307: } catch (Exception ex) {
308: DebugLogger
309: .logError("Could not load the plugin: "
310: + pluginUrl);
311: }
312:
313: if (o != null) {
314: XEditorPlugin newPlugin = (XEditorPlugin) o;
315: newPlugin.setPluginUrl(pluginUrl);
316: if (addPlugin(appFrame, newPlugin))
317: addPluginToolbar(newPlugin);
318: }
319: }
320: }
321:
322: // Load plugins from the classpath parameter list
323: XResourceManager rm = XProjectManager
324: .getResourceManager();
325: // Try loading plugins till no parameters are found.
326: numPlugins = 10;
327: for (int i = 0; i < numPlugins; i++) {
328: String pluginClass = rm.getStartupParam("Plugin_"
329: + Integer.toString(i));
330: if (pluginClass == null)
331: break;
332: if (pluginClass.length() > 0) {
333: Object o = null;
334: try {
335: o = loadPluginClass(getClass()
336: .getClassLoader(), pluginClass);
337: } catch (Exception ex) {
338: DebugLogger
339: .logError("Could not load the plugin: "
340: + pluginClass);
341: }
342:
343: if (o != null) {
344: XEditorPlugin newPlugin = (XEditorPlugin) o;
345: newPlugin.setPluginUrl(pluginClass
346: + ".class");
347: if (addPlugin(appFrame, newPlugin))
348: addPluginToolbar(newPlugin);
349: }
350: }
351: }
352:
353: pluginListener.pluginsLoaded();
354: }
355: }).start();
356: }
357:
358: public void setActiveProject(XEditorProject project) {
359: final XEditorProject activeProject = project;
360: new Thread(new Runnable() {
361: public void run() {
362: int numPlugins = plugins.size();
363: for (int i = 0; i < numPlugins; i++)
364: ((XEditorPlugin) plugins.elementAt(i))
365: .setActiveProject(activeProject);
366: }
367: }).start();
368: }
369:
370: protected void addPluginToolbar(XEditorPlugin newPlugin) {
371: final XEditorPlugin plugin = newPlugin;
372: SwingUtilities.invokeLater(new Runnable() {
373: public void run() {
374: currentProject.getEditor().addPluginToolbar(plugin);
375: }
376: });
377: }
378:
379: public void save() {
380: int numPlugins = plugins.size();
381: for (int i = 0; i < numPlugins; i++)
382: ((XEditorPlugin) plugins.elementAt(i)).save();
383: }
384:
385: protected void savePlugins() {
386: prefs.put("NumPlugins", Integer.toString(plugins.size()));
387: int numPlugins = plugins.size();
388: for (int i = 0; i < numPlugins; i++)
389: prefs.put("Plugin_" + Integer.toString(i),
390: ((XEditorPlugin) plugins.elementAt(i))
391: .getPluginUrl());
392: }
393:
394: protected XEditorPlugin loadPluginUrl(String pluginUrl) {
395: URL url = null;
396: try {
397: url = new URL(pluginUrl);
398: } catch (MalformedURLException e) {
399: DebugLogger.logError("Invalid URL: " + pluginUrl);
400: return null;
401: }
402:
403: // Create the class loader for the application jar file
404: JarClassLoader cl = new JarClassLoader(url);
405: // Get the application's main class name
406: String name = null;
407: try {
408: name = cl.getMainClassName();
409: } catch (IOException e) {
410: System.err.println("I/O error while loading JAR file:");
411: }
412: if (name == null) {
413: DebugLogger
414: .logError("Specified jar file does not contain a 'XuiEditorPlugin-Class' manifest attribute: "
415: + pluginUrl.toString());
416: return null;
417: }
418:
419: return loadPluginClass(cl, name);
420: }
421:
422: protected XEditorPlugin loadPluginClass(ClassLoader cl,
423: String className) {
424: // Invoke application's main class
425: try {
426: Class pluginClass = null;
427: pluginClass = cl.loadClass(className);
428: return (XEditorPlugin) pluginClass.newInstance();
429: } catch (ClassNotFoundException ex) {
430: DebugLogger
431: .logError("Plugin class not found: " + className);
432: DebugLogger.logWarning(ex.getMessage());
433: } catch (InstantiationException ex) {
434: DebugLogger.logError("Could not load the plugin class: "
435: + className);
436: DebugLogger.logWarning(ex.getMessage());
437: } catch (IllegalAccessException ex) {
438: DebugLogger.logError("Could not access the plugin class: "
439: + className);
440: DebugLogger.logWarning(ex.getMessage());
441: }
442:
443: return null;
444: }
445: }
|