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

Last change on this file since 873 was 873, checked in by stoecker, 16 years ago

cleanups in plugin handling

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