source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java@ 1053

Last change on this file since 1053 was 1053, checked in by stoecker, 15 years ago

added preferences patch to get correct window sizes again. Fixes #1671 and #1672. Patch by Jan Peter Stotz

  • Property svn:eol-style set to native
File size: 12.8 KB
Line 
1//License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui.preferences;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.Dimension;
8import java.awt.Graphics;
9import java.awt.GridBagLayout;
10import java.awt.event.ActionEvent;
11import java.awt.event.ActionListener;
12import java.io.File;
13import java.io.FileReader;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.Comparator;
18import java.util.HashMap;
19import java.util.HashSet;
20import java.util.LinkedList;
21import java.util.Map;
22import java.util.Set;
23import java.util.SortedMap;
24import java.util.TreeMap;
25import java.util.Map.Entry;
26
27import javax.swing.AbstractAction;
28import javax.swing.BorderFactory;
29import javax.swing.Box;
30import javax.swing.BoxLayout;
31import javax.swing.DefaultListModel;
32import javax.swing.JButton;
33import javax.swing.JCheckBox;
34import javax.swing.JLabel;
35import javax.swing.JList;
36import javax.swing.JOptionPane;
37import javax.swing.JPanel;
38import javax.swing.JScrollPane;
39
40import org.openstreetmap.josm.Main;
41import org.openstreetmap.josm.plugins.PluginDownloader;
42import org.openstreetmap.josm.plugins.PluginException;
43import org.openstreetmap.josm.plugins.PluginInformation;
44import org.openstreetmap.josm.plugins.PluginProxy;
45import org.openstreetmap.josm.tools.GBC;
46import org.openstreetmap.josm.tools.XmlObjectParser.Uniform;
47
48public class PluginPreference implements PreferenceSetting {
49
50 /**
51 * Only the plugin name, its jar location and the description.
52 * In other words, this is the minimal requirement the plugin preference page
53 * needs to show the plugin as available
54 *
55 * @author imi
56 */
57 public static class PluginDescription implements Comparable<Object> {
58 // Note: All the following need to be public instance variables of
59 // type String. (Plugin description XMLs from the server are parsed
60 // with tools.XmlObjectParser, which uses reflection to access them.)
61 public String name;
62 public String description;
63 public String resource;
64 public String version;
65 public PluginDescription(String name, String description, String resource, String version) {
66 this.name = name;
67 this.description = description;
68 this.resource = resource;
69 this.version = version;
70 }
71 public PluginDescription() {
72 }
73 public int compareTo(Object n) {
74 if(n instanceof PluginDescription)
75 return name.compareToIgnoreCase(((PluginDescription)n).name);
76 return -1;
77 }
78 }
79
80 private Map<PluginDescription, Boolean> pluginMap;
81 private JPanel plugin;
82 private class MyBox extends Box {
83 int lastwidth;
84 int offset = 40;
85 public MyBox()
86 {
87 super(BoxLayout.Y_AXIS);
88 }
89 public int myGetWidth()
90 {
91 int w = plugin.getWidth()-offset;
92 if(w <= 0) w = 450;
93 lastwidth = w;
94 return w;
95 }
96 public void paint(Graphics g)
97 {
98 if(lastwidth != plugin.getWidth()-offset)
99 refreshPluginPanel(gui);
100 super.paint(g);
101 }
102 }
103 private MyBox pluginPanel = new MyBox();
104 private PreferenceDialog gui;
105
106 public void addGui(final PreferenceDialog gui) {
107 this.gui = gui;
108 plugin = gui.createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
109 JScrollPane pluginPane = new JScrollPane(pluginPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
110 pluginPane.setBorder(null);
111 plugin.add(pluginPane, GBC.eol().fill(GBC.BOTH));
112 plugin.add(GBC.glue(0,10), GBC.eol());
113 JButton morePlugins = new JButton(tr("Download List"));
114 morePlugins.addActionListener(new ActionListener(){
115 public void actionPerformed(ActionEvent e) {
116 int count = PluginDownloader.downloadDescription();
117 if (count > 0)
118 JOptionPane.showMessageDialog(Main.parent,
119 trn("Downloaded plugin information from {0} site",
120 "Downloaded plugin information from {0} sites", count, count));
121 else
122 JOptionPane.showMessageDialog(Main.parent, tr("No plugin information found."));
123 refreshPluginPanel(gui);
124 }
125 });
126 plugin.add(morePlugins, GBC.std().insets(0,0,10,0));
127
128 JButton update = new JButton(tr("Update"));
129 update.addActionListener(new ActionListener(){
130 public void actionPerformed(ActionEvent e) {
131 update();
132 refreshPluginPanel(gui);
133 }
134
135 });
136 plugin.add(update, GBC.std().insets(0,0,10,0));
137
138 JButton configureSites = new JButton(tr("Configure Sites ..."));
139 configureSites.addActionListener(new ActionListener(){
140 public void actionPerformed(ActionEvent e) {
141 configureSites();
142 }
143
144 });
145 plugin.add(configureSites, GBC.std());
146
147 refreshPluginPanel(gui);
148 }
149
150 private void configureSites() {
151 JPanel p = new JPanel(new GridBagLayout());
152 p.add(new JLabel(tr("Add either site-josm.xml or Wiki Pages.")), GBC.eol());
153 final DefaultListModel model = new DefaultListModel();
154 for (String s : PluginDownloader.getSites())
155 model.addElement(s);
156 final JList list = new JList(model);
157 p.add(new JScrollPane(list), GBC.std().fill());
158 JPanel buttons = new JPanel(new GridBagLayout());
159 buttons.add(new JButton(new AbstractAction(tr("Add")){
160 public void actionPerformed(ActionEvent e) {
161 String s = JOptionPane.showInputDialog(gui, tr("Add either site-josm.xml or Wiki Pages."));
162 if (s != null)
163 model.addElement(s);
164 }
165 }), GBC.eol().fill(GBC.HORIZONTAL));
166 buttons.add(new JButton(new AbstractAction(tr("Edit")){
167 public void actionPerformed(ActionEvent e) {
168 if (list.getSelectedValue() == null) {
169 JOptionPane.showMessageDialog(gui, tr("Please select an entry."));
170 return;
171 }
172 String s = JOptionPane.showInputDialog(gui, tr("Add either site-josm.xml or Wiki Pages."), list.getSelectedValue());
173 model.setElementAt(s, list.getSelectedIndex());
174 }
175 }), GBC.eol().fill(GBC.HORIZONTAL));
176 buttons.add(new JButton(new AbstractAction(tr("Delete")){
177 public void actionPerformed(ActionEvent event) {
178 if (list.getSelectedValue() == null) {
179 JOptionPane.showMessageDialog(gui, tr("Please select an entry."));
180 return;
181 }
182 model.removeElement(list.getSelectedValue());
183 }
184 }), GBC.eol().fill(GBC.HORIZONTAL));
185 p.add(buttons, GBC.eol());
186 int answer = JOptionPane.showConfirmDialog(gui, p, tr("Configure Plugin Sites"), JOptionPane.OK_CANCEL_OPTION);
187 if (answer != JOptionPane.OK_OPTION)
188 return;
189 StringBuilder b = new StringBuilder();
190 for (int i = 0; i < model.getSize(); ++i) {
191 b.append(model.getElementAt(i));
192 if (i < model.getSize()-1)
193 b.append(" ");
194 }
195 Main.pref.put("pluginmanager.sites", b.toString());
196 }
197
198 private void update() {
199 // refresh description
200 PluginDownloader.downloadDescription();
201 refreshPluginPanel(gui);
202
203 Set<PluginDescription> toUpdate = new HashSet<PluginDescription>();
204 StringBuilder toUpdateStr = new StringBuilder();
205 for (PluginProxy proxy : Main.plugins) {
206 PluginDescription description = findDescription(proxy.info.name);
207 if (description != null && (description.version == null || description.version.equals("")) ? (proxy.info.version != null && proxy.info.version.equals("")) : !description.version.equals(proxy.info.version)) {
208 toUpdate.add(description);
209 toUpdateStr.append(description.name+"\n");
210 }
211 }
212 if (toUpdate.isEmpty()) {
213 JOptionPane.showMessageDialog(Main.parent, tr("All installed plugins are up to date."));
214 return;
215 }
216 int answer = JOptionPane.showConfirmDialog(Main.parent, tr("Update the following plugins:\n\n{0}", toUpdateStr.toString()), tr("Update"), JOptionPane.OK_CANCEL_OPTION);
217 if (answer != JOptionPane.OK_OPTION)
218 return;
219 PluginDownloader.update(toUpdate);
220 }
221
222 private PluginDescription findDescription(String name) {
223 for (PluginDescription d : pluginMap.keySet())
224 if (d.name.equals(name))
225 return d;
226 return null;
227 }
228
229 private void refreshPluginPanel(final PreferenceDialog gui) {
230 Collection<PluginDescription> availablePlugins = getAvailablePlugins();
231 pluginMap = new HashMap<PluginDescription, Boolean>();
232 pluginPanel.removeAll();
233 int width = pluginPanel.myGetWidth();
234
235 // the following could probably be done more elegantly?
236 Collection<String> enabledPlugins = null;
237 String enabledProp = Main.pref.get("plugins");
238 if ((enabledProp == null) || ("".equals(enabledProp))) {
239 enabledPlugins = Collections.emptySet();
240 }
241 else
242 {
243 enabledPlugins = Arrays.asList(enabledProp.split(","));
244 }
245
246 for (final PluginDescription plugin : availablePlugins) {
247 boolean enabled = enabledPlugins.contains(plugin.name);
248 String remoteversion = plugin.version;
249 if(remoteversion == null || remoteversion.equals(""))
250 remoteversion = tr("unknown");
251
252 String localversion;
253 PluginInformation p = PluginInformation.findPlugin(plugin.name);
254 if(p != null)
255 {
256 if(p.version != null && !p.version.equals(""))
257 localversion = p.version;
258 else
259 localversion = tr("unknown");
260 localversion = " (" + localversion + ")";
261 }
262 else
263 localversion = "";
264
265 final JCheckBox pluginCheck = new JCheckBox(tr("{0}: Version {1}{2}", plugin.name, remoteversion, localversion), enabled);
266 pluginPanel.add(pluginCheck);
267
268 pluginCheck.setToolTipText(plugin.resource != null ? ""+plugin.resource : tr("Plugin bundled with JOSM"));
269 JLabel label = new JLabel("<html><i>"+(plugin.description==null?tr("no description available"):plugin.description)+"</i></html>");
270 label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
271 label.setMaximumSize(new Dimension(width,1000));
272 pluginPanel.add(label);
273 pluginPanel.add(Box.createVerticalStrut(5));
274
275 pluginMap.put(plugin, enabled);
276 pluginCheck.addActionListener(new ActionListener(){
277 public void actionPerformed(ActionEvent e) {
278 pluginMap.put(plugin, pluginCheck.isSelected());
279 }
280 });
281 }
282 plugin.updateUI();
283 }
284
285 private Collection<PluginDescription> getAvailablePlugins() {
286 SortedMap<String, PluginDescription> availablePlugins = new TreeMap<String, PluginDescription>(new Comparator<String>(){
287 public int compare(String o1, String o2) {
288 return o1.compareToIgnoreCase(o2);
289 }
290 });
291 for (String location : PluginInformation.getPluginLocations()) {
292 File[] pluginFiles = new File(location).listFiles();
293 if (pluginFiles != null) {
294 Arrays.sort(pluginFiles);
295 for (File f : pluginFiles) {
296 if (!f.isFile())
297 continue;
298 if (f.getName().endsWith(".jar")) {
299 try {
300 PluginInformation info = new PluginInformation(f);
301 if (!availablePlugins.containsKey(info.name))
302 availablePlugins.put(info.name, new PluginDescription(
303 info.name,
304 info.description,
305 PluginInformation.fileToURL(f).toString(),
306 info.version));
307 } catch (PluginException x) {
308 }
309 } else if (f.getName().matches("^[0-9]+-site.*\\.xml$")) {
310 try {
311 Uniform<PluginDescription> parser = new Uniform<PluginDescription>(new FileReader(f), "plugin", PluginDescription.class);
312 for (PluginDescription pd : parser)
313 if (!availablePlugins.containsKey(pd.name))
314 availablePlugins.put(pd.name, pd);
315 } catch (Exception e) {
316 e.printStackTrace();
317 JOptionPane.showMessageDialog(Main.parent, tr("Error reading plugin information file: {0}", f.getName()));
318 }
319 }
320 }
321 }
322 }
323 for (PluginProxy proxy : Main.plugins)
324 if (!availablePlugins.containsKey(proxy.info.name))
325 availablePlugins.put(proxy.info.name, new PluginDescription(
326 proxy.info.name,
327 proxy.info.description,
328 proxy.info.file == null ? null :
329 PluginInformation.fileToURL(proxy.info.file).toString(),
330 proxy.info.version));
331 return availablePlugins.values();
332 }
333
334 public void ok() {
335 Collection<PluginDescription> toDownload = new LinkedList<PluginDescription>();
336 String msg = "";
337 for (Entry<PluginDescription, Boolean> entry : pluginMap.entrySet()) {
338 if (entry.getValue() && PluginInformation.findPlugin(entry.getKey().name) == null) {
339 toDownload.add(entry.getKey());
340 msg += entry.getKey().name+"\n";
341 }
342 }
343 if (!toDownload.isEmpty()) {
344 int answer = JOptionPane.showConfirmDialog(Main.parent,
345 tr("Download the following plugins?\n\n{0}", msg),
346 tr("Download missing plugins"),
347 JOptionPane.YES_NO_OPTION);
348 if (answer != JOptionPane.OK_OPTION)
349 for (PluginDescription pd : toDownload)
350 pluginMap.put(pd, false);
351 else
352 for (PluginDescription pd : toDownload)
353 if (!PluginDownloader.downloadPlugin(pd))
354 pluginMap.put(pd, false);
355
356 }
357
358 String plugins = "";
359 Object pd[] = pluginMap.keySet().toArray();
360 Arrays.sort(pd);
361 for (Object d : pd) {
362 if (pluginMap.get(d))
363 plugins += ((PluginDescription)d).name + ",";
364 }
365 if (plugins.endsWith(","))
366 plugins = plugins.substring(0, plugins.length()-1);
367 if (plugins.length() == 0)
368 plugins = null;
369
370 String oldPlugins = Main.pref.get("plugins");
371 if(oldPlugins == null && plugins == null)
372 return;
373 if(plugins == null || oldPlugins == null || !plugins.equals(oldPlugins))
374 {
375 Main.pref.put("plugins", plugins);
376 gui.requiresRestart = true;
377 }
378 }
379}
Note: See TracBrowser for help on using the repository browser.