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

Last change on this file since 2667 was 2584, checked in by stoecker, 14 years ago

fixed #4107 - obsolete plugin message improvement

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