source: josm/trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java@ 2389

Last change on this file since 2389 was 2389, checked in by Gubaer, 14 years ago

see #3834: added context sensitive help

File size: 16.2 KB
Line 
1//License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.plugins;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Font;
8import java.awt.GridBagLayout;
9import java.awt.event.ActionEvent;
10import java.net.URL;
11import java.net.URLClassLoader;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.SortedMap;
19import java.util.TreeMap;
20import java.util.Map.Entry;
21
22import javax.swing.AbstractAction;
23import javax.swing.BorderFactory;
24import javax.swing.Box;
25import javax.swing.JButton;
26import javax.swing.JLabel;
27import javax.swing.JOptionPane;
28import javax.swing.JPanel;
29import javax.swing.JScrollPane;
30import javax.swing.JTextArea;
31import javax.swing.UIManager;
32
33import org.openstreetmap.josm.Main;
34import org.openstreetmap.josm.data.Version;
35import org.openstreetmap.josm.gui.ExtendedDialog;
36import org.openstreetmap.josm.gui.MapFrame;
37import org.openstreetmap.josm.gui.download.DownloadSelection;
38import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
39import org.openstreetmap.josm.tools.GBC;
40import org.openstreetmap.josm.tools.ImageProvider;
41
42public class PluginHandler {
43
44 /**
45 * All installed and loaded plugins (resp. their main classes)
46 */
47 public final static Collection<PluginProxy> pluginList = new LinkedList<PluginProxy>();
48 /**
49 * Load all plugins specified in preferences. If the parameter is
50 * <code>true</code>, all early plugins are loaded (before constructor).
51 */
52 public static void loadPlugins(boolean early) {
53 List<String> plugins = new LinkedList<String>();
54 Collection<String> cp = Main.pref.getCollection("plugins", null);
55 if (cp != null) {
56 plugins.addAll(cp);
57 }
58 if (System.getProperty("josm.plugins") != null) {
59 plugins.addAll(Arrays.asList(System.getProperty("josm.plugins").split(",")));
60 }
61
62 String [] oldplugins = new String[] {"mappaint", "unglueplugin",
63 "lang-de", "lang-en_GB", "lang-fr", "lang-it", "lang-pl", "lang-ro",
64 "lang-ru", "ewmsplugin", "ywms", "tways-0.2", "geotagged", "landsat",
65 "namefinder", "waypoints", "slippy_map_chooser", "tcx-support", "usertools"};
66 String [] unmaintained = new String[] {"gpsbabelgui", "Intersect_way"};
67
68 for (String p : oldplugins) {
69 if (plugins.contains(p)) {
70 plugins.remove(p);
71 Main.pref.removeFromCollection("plugins", p);
72 JOptionPane.showMessageDialog(
73 Main.parent,
74 tr("Loading of {0} plugin was requested. This plugin is no longer required.", p),
75 tr("Warning"),
76 JOptionPane.WARNING_MESSAGE
77 );
78 }
79 }
80 if(early)
81 {
82 for (String p : unmaintained) {
83 if (plugins.contains(p) && disablePlugin(tr("<html>Loading of {0} plugin was requested."
84 +"<br>This plugin is no longer developed and very likely will produce errors."
85 +"<br>It should be disabled.<br>Delete from preferences?</html>", p), p)) {
86 plugins.remove(p);
87 }
88 }
89 }
90
91 if (plugins.isEmpty())
92 return;
93
94 if(early)
95 {
96 String doUpdate = null;
97 String check = null;
98 int v = Version.getInstance().getVersion();
99 if(Main.pref.getInteger("pluginmanager.version", 0) < v)
100 {
101 doUpdate = tr("You updated your JOSM software.\nTo prevent problems the plugins should be updated as well.\n"
102 + "Update plugins now?");
103 check = "pluginmanger.version";
104 }
105 else
106 {
107 long tim = System.currentTimeMillis();
108 long last = Main.pref.getLong("pluginmanager.lastupdate", 0);
109 Integer maxTime = Main.pref.getInteger("pluginmanager.warntime", 60);
110 long d = (tim - last)/(24*60*60*1000l);
111 if ((last <= 0) || (maxTime <= 0)) {
112 Main.pref.put("pluginmanager.lastupdate",Long.toString(tim));
113 } else if (d > maxTime) {
114 doUpdate = tr("Last plugin update more than {0} days ago.", d);
115 check = "pluginmanager.time";
116 }
117 }
118 if(doUpdate != null)
119 {
120 ExtendedDialog dialog = new ExtendedDialog(
121 Main.parent,
122 tr("Update plugins"),
123 new String[] {tr("Update plugins"), tr("Skip update")}
124 );
125 dialog.setContent(doUpdate);
126 dialog.toggleEnable(check);
127 dialog.setButtonIcons( new String[] {"dialogs/refresh.png", "cancel.png"});
128 dialog.configureContextsensitiveHelp(ht("/Plugin/AutomaticUpdate"), true /* show help button */);
129 dialog.showDialog();
130 if(dialog.getValue() == 1) {
131 new PluginSelection().update();
132 }
133 }
134 }
135
136 SortedMap<Integer, Collection<PluginInformation>> p = new TreeMap<Integer, Collection<PluginInformation>>();
137 for (String pluginName : plugins) {
138 PluginInformation info = PluginInformation.findPlugin(pluginName);
139 if (info != null) {
140 if (info.early != early) {
141 continue;
142 }
143 int josmVersion = Version.getInstance().getVersion();
144 if (info.mainversion > josmVersion && josmVersion != Version.JOSM_UNKNOWN_VERSION) {
145 JOptionPane.showMessageDialog(
146 Main.parent,
147 tr("Plugin {0} requires JOSM update to version {1}.", pluginName,
148 info.mainversion),
149 tr("Warning"),
150 JOptionPane.WARNING_MESSAGE
151 );
152 continue;
153 }
154
155 if(info.requires != null)
156 {
157 String warn = null;
158 for(String n : info.requires.split(";"))
159 {
160 if(!plugins.contains(n))
161 { warn = n; break; }
162 }
163 if(warn != null)
164 {
165 JOptionPane.showMessageDialog(Main.parent,
166 tr("Plugin {0} is required by plugin {1} but was not found.",
167 warn, pluginName),
168 tr("Error"),
169 JOptionPane.ERROR_MESSAGE
170 );
171 continue;
172 }
173 }
174 if (!p.containsKey(info.stage)) {
175 p.put(info.stage, new LinkedList<PluginInformation>());
176 }
177 p.get(info.stage).add(info);
178 } else if(early) {
179 JOptionPane.showMessageDialog(
180 Main.parent,
181 tr("Plugin not found: {0}.", pluginName),
182 tr("Error"),
183 JOptionPane.ERROR_MESSAGE
184 );
185 }
186 }
187
188 // iterate all plugins and collect all libraries of all plugins:
189 List<URL> allPluginLibraries = new ArrayList<URL>();
190 for (Collection<PluginInformation> c : p.values()) {
191 for (PluginInformation info : c) {
192 allPluginLibraries.addAll(info.libraries);
193 }
194 }
195 // create a classloader for all plugins:
196 URL[] jarUrls = new URL[allPluginLibraries.size()];
197 jarUrls = allPluginLibraries.toArray(jarUrls);
198 URLClassLoader pluginClassLoader = new URLClassLoader(jarUrls, Main.class.getClassLoader());
199 ImageProvider.sources.add(0, pluginClassLoader);
200
201 for (Collection<PluginInformation> c : p.values()) {
202 for (PluginInformation info : c) {
203 try {
204 Class<?> klass = info.loadClass(pluginClassLoader);
205 if (klass != null) {
206 System.out.println("loading "+info.name);
207 pluginList.add(info.load(klass));
208 }
209 } catch (Throwable e) {
210 e.printStackTrace();
211 disablePlugin(tr("Could not load plugin {0}. Delete from preferences?", info.name), info.name);
212 }
213 }
214 }
215 }
216 public static boolean disablePlugin(String reason, String name)
217 {
218 ExtendedDialog dialog = new ExtendedDialog(
219 Main.parent,
220 tr("Disable plugin"),
221 new String[] {tr("Disable plugin"), tr("Keep plugin")}
222 );
223 dialog.setContent(reason);
224 dialog.setButtonIcons( new String[] {"dialogs/delete.png", "cancel.png"});
225 dialog.showDialog();
226 int result = dialog.getValue();
227
228 if(result == 1)
229 {
230 Main.pref.removeFromCollection("plugins", name);
231 return true;
232 }
233 return false;
234 }
235
236 public static void setMapFrame(MapFrame old, MapFrame map) {
237 for (PluginProxy plugin : pluginList) {
238 plugin.mapFrameInitialized(old, map);
239 }
240 }
241
242 public static Object getPlugin(String name) {
243 for (PluginProxy plugin : pluginList)
244 if(plugin.info.name.equals(name))
245 return plugin.plugin;
246 return null;
247 }
248
249 public static void addDownloadSelection(List<DownloadSelection> downloadSelections)
250 {
251 for (PluginProxy p : pluginList) {
252 p.addDownloadSelection(downloadSelections);
253 }
254 }
255 public static void getPreferenceSetting(Collection<PreferenceSettingFactory> settings)
256 {
257 for (PluginProxy plugin : pluginList) {
258 settings.add(new PluginPreferenceFactory(plugin));
259 }
260 }
261
262 public static void earlyCleanup()
263 {
264 if (!PluginDownloader.moveUpdatedPlugins()) {
265 JOptionPane.showMessageDialog(
266 Main.parent,
267 tr("Activating the updated plugins failed. Check if JOSM has the permission to overwrite the existing ones."),
268 tr("Plugins"), JOptionPane.ERROR_MESSAGE);
269 }
270 }
271 public static Boolean checkException(Throwable e)
272 {
273 PluginProxy plugin = null;
274
275 // Check for an explicit problem when calling a plugin function
276 if (e instanceof PluginException) {
277 plugin = ((PluginException)e).plugin;
278 }
279
280 if (plugin == null)
281 {
282 /**
283 * Analyze the stack of the argument and find a name of a plugin, if
284 * some known problem pattern has been found.
285 */
286 for (PluginProxy p : pluginList)
287 {
288 String baseClass = p.info.className;
289 int i = baseClass.lastIndexOf(".");
290 baseClass = baseClass.substring(0, i);
291 for (StackTraceElement element : e.getStackTrace())
292 {
293 String c = element.getClassName();
294 if(c.startsWith(baseClass))
295 {
296 plugin = p;
297 break;
298 }
299 }
300 if(plugin != null) {
301 break;
302 }
303 }
304 }
305
306 if (plugin != null) {
307 ExtendedDialog dialog = new ExtendedDialog(
308 Main.parent,
309 tr("Disable plugin"),
310 new String[] {tr("Disable plugin"), tr("Cancel")}
311 );
312 dialog.setButtonIcons(new String[] {"dialogs/delete.png", "cancel.png"});
313 dialog.setContent(
314 tr("<html>") +
315 tr("An unexpected exception occurred that may have come from the ''{0}'' plugin.", plugin.info.name)
316 + "<br>"
317 + (plugin.info.author != null
318 ? tr("According to the information within the plugin, the author is {0}.", plugin.info.author)
319 : "")
320 + "<br>"
321 + tr("Try updating to the newest version of this plugin before reporting a bug.")
322 + "<br>"
323 + tr("Should the plugin be disabled?")
324 + "</html>"
325 );
326 dialog.showDialog();
327 int answer = dialog.getValue();
328
329 if (answer == 1) {
330 List<String> plugins = new ArrayList<String>(Main.pref.getCollection("plugins", Collections.<String>emptyList()));
331 if (plugins.contains(plugin.info.name)) {
332 while (plugins.remove(plugin.info.name)) {}
333 Main.pref.putCollection("plugins", plugins);
334 JOptionPane.showMessageDialog(Main.parent,
335 tr("The plugin has been removed from the configuration. Please restart JOSM to unload the plugin."),
336 tr("Information"),
337 JOptionPane.INFORMATION_MESSAGE);
338 } else {
339 JOptionPane.showMessageDialog(
340 Main.parent,
341 tr("The plugin could not be removed. Probably it was already disabled"),
342 tr("Error"),
343 JOptionPane.ERROR_MESSAGE
344 );
345 }
346 return true;
347 }
348 }
349 return false;
350 }
351 public static String getBugReportText()
352 {
353 String text = "";
354 String pl = Main.pref.get("plugins");
355 if(pl != null && pl.length() != 0) {
356 text += "Plugins: "+pl+"\n";
357 }
358 for (final PluginProxy pp : pluginList) {
359 text += "Plugin " + pp.info.name + (pp.info.version != null && !pp.info.version.equals("") ? " Version: "+pp.info.version+"\n" : "\n");
360 }
361 return text;
362 }
363 public static JPanel getInfoPanel()
364 {
365 JPanel pluginTab = new JPanel(new GridBagLayout());
366 for (final PluginProxy p : pluginList) {
367 String name = p.info.name + (p.info.version != null && !p.info.version.equals("") ? " Version: "+p.info.version : "");
368 pluginTab.add(new JLabel(name), GBC.std());
369 pluginTab.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
370 pluginTab.add(new JButton(new AbstractAction(tr("Information")){
371 public void actionPerformed(ActionEvent event) {
372 StringBuilder b = new StringBuilder();
373 for (Entry<String,String> e : p.info.attr.entrySet()) {
374 b.append(e.getKey());
375 b.append(": ");
376 b.append(e.getValue());
377 b.append("\n");
378 }
379 JTextArea a = new JTextArea(10,40);
380 a.setEditable(false);
381 a.setText(b.toString());
382 JOptionPane.showMessageDialog(
383 Main.parent,
384 new JScrollPane(a),
385 tr("Plugin information"),
386 JOptionPane.INFORMATION_MESSAGE
387 );
388 }
389 }), GBC.eol());
390
391 JTextArea description = new JTextArea((p.info.description==null? tr("no description available"):p.info.description));
392 description.setEditable(false);
393 description.setFont(new JLabel().getFont().deriveFont(Font.ITALIC));
394 description.setLineWrap(true);
395 description.setWrapStyleWord(true);
396 description.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
397 description.setBackground(UIManager.getColor("Panel.background"));
398
399 pluginTab.add(description, GBC.eop().fill(GBC.HORIZONTAL));
400 }
401 return pluginTab;
402 }
403}
Note: See TracBrowser for help on using the repository browser.