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

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

added generic mirroring Input stream, replace validator specific one soon

  • Property svn:eol-style set to native
File size: 12.0 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 refreshPluginPanel(gui);
174
175 Set<PluginDescription> toUpdate = new HashSet<PluginDescription>();
176 StringBuilder toUpdateStr = new StringBuilder();
177 for (PluginProxy proxy : Main.plugins) {
178 PluginDescription description = findDescription(proxy.info.name);
179 if (description != null && (description.version == null || description.version.equals("")) ? (proxy.info.version != null && proxy.info.version.equals("")) : !description.version.equals(proxy.info.version)) {
180 toUpdate.add(description);
181 toUpdateStr.append(description.name+"\n");
182 }
183 }
184 if (toUpdate.isEmpty()) {
185 JOptionPane.showMessageDialog(Main.parent, tr("All installed plugins are up to date."));
186 return;
187 }
188 int answer = JOptionPane.showConfirmDialog(Main.parent, tr("Update the following plugins:\n\n{0}", toUpdateStr.toString()), tr("Update"), JOptionPane.OK_CANCEL_OPTION);
189 if (answer != JOptionPane.OK_OPTION)
190 return;
191 PluginDownloader.update(toUpdate);
192 }
193
194 private PluginDescription findDescription(String name) {
195 for (PluginDescription d : pluginMap.keySet())
196 if (d.name.equals(name))
197 return d;
198 return null;
199 }
200
201 private void refreshPluginPanel(final PreferenceDialog gui) {
202 Collection<PluginDescription> availablePlugins = getAvailablePlugins();
203 pluginMap = new HashMap<PluginDescription, Boolean>();
204 pluginPanel.removeAll();
205
206 // the following could probably be done more elegantly?
207 Collection<String> enabledPlugins = null;
208 String enabledProp = Main.pref.get("plugins");
209 if ((enabledProp == null) || ("".equals(enabledProp))) {
210 enabledPlugins = Collections.emptySet();
211 }
212 else
213 {
214 enabledPlugins = Arrays.asList(enabledProp.split(","));
215 }
216
217 for (final PluginDescription plugin : availablePlugins) {
218 boolean enabled = enabledPlugins.contains(plugin.name);
219 String remoteversion = plugin.version;
220 if(remoteversion == null || remoteversion.equals(""))
221 remoteversion = tr("unknown");
222
223 String localversion;
224 PluginInformation p = PluginInformation.findPlugin(plugin.name);
225 if(p != null)
226 {
227 if(p.version != null && !p.version.equals(""))
228 localversion = p.version;
229 else
230 localversion = tr("unknown");
231 localversion = " (" + localversion + ")";
232 }
233 else
234 localversion = "";
235
236 final JCheckBox pluginCheck = new JCheckBox(tr("{0}: Version {1}{2}", plugin.name, remoteversion, localversion), enabled);
237 pluginPanel.add(pluginCheck);
238
239 pluginCheck.setToolTipText(plugin.resource != null ? ""+plugin.resource : tr("Plugin bundled with JOSM"));
240 JLabel label = new JLabel("<html><i>"+(plugin.description==null?tr("no description available"):plugin.description)+"</i></html>");
241 label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
242 label.setMaximumSize(new Dimension(450,1000));
243 pluginPanel.add(label);
244 pluginPanel.add(Box.createVerticalStrut(5));
245
246 pluginMap.put(plugin, enabled);
247 pluginCheck.addActionListener(new ActionListener(){
248 public void actionPerformed(ActionEvent e) {
249 pluginMap.put(plugin, pluginCheck.isSelected());
250 }
251 });
252 }
253 plugin.updateUI();
254 }
255
256 private Collection<PluginDescription> getAvailablePlugins() {
257 SortedMap<String, PluginDescription> availablePlugins = new TreeMap<String, PluginDescription>(new Comparator<String>(){
258 public int compare(String o1, String o2) {
259 return o1.compareToIgnoreCase(o2);
260 }
261 });
262 for (String location : PluginInformation.getPluginLocations()) {
263 File[] pluginFiles = new File(location).listFiles();
264 if (pluginFiles != null) {
265 Arrays.sort(pluginFiles);
266 for (File f : pluginFiles) {
267 if (!f.isFile())
268 continue;
269 if (f.getName().endsWith(".jar")) {
270 try {
271 PluginInformation info = new PluginInformation(f);
272 if (!availablePlugins.containsKey(info.name))
273 availablePlugins.put(info.name, new PluginDescription(
274 info.name,
275 info.description,
276 PluginInformation.fileToURL(f).toString(),
277 info.version));
278 } catch (PluginException x) {
279 }
280 } else if (f.getName().matches("^[0-9]+-site.*\\.xml$")) {
281 try {
282 Uniform<PluginDescription> parser = new Uniform<PluginDescription>(new FileReader(f), "plugin", PluginDescription.class);
283 for (PluginDescription pd : parser)
284 if (!availablePlugins.containsKey(pd.name))
285 availablePlugins.put(pd.name, pd);
286 } catch (Exception e) {
287 e.printStackTrace();
288 JOptionPane.showMessageDialog(Main.parent, tr("Error reading plugin information file: {0}", f.getName()));
289 }
290 }
291 }
292 }
293 }
294 for (PluginProxy proxy : Main.plugins)
295 if (!availablePlugins.containsKey(proxy.info.name))
296 availablePlugins.put(proxy.info.name, new PluginDescription(
297 proxy.info.name,
298 proxy.info.description,
299 proxy.info.file == null ? null :
300 PluginInformation.fileToURL(proxy.info.file).toString(),
301 proxy.info.version));
302 return availablePlugins.values();
303 }
304
305 public void ok() {
306 Collection<PluginDescription> toDownload = new LinkedList<PluginDescription>();
307 String msg = "";
308 for (Entry<PluginDescription, Boolean> entry : pluginMap.entrySet()) {
309 if (entry.getValue() && PluginInformation.findPlugin(entry.getKey().name) == null) {
310 toDownload.add(entry.getKey());
311 msg += entry.getKey().name+"\n";
312 }
313 }
314 if (!toDownload.isEmpty()) {
315 int answer = JOptionPane.showConfirmDialog(Main.parent,
316 tr("Download the following plugins?\n\n{0}", msg),
317 tr("Download missing plugins"),
318 JOptionPane.YES_NO_OPTION);
319 if (answer != JOptionPane.OK_OPTION)
320 for (PluginDescription pd : toDownload)
321 pluginMap.put(pd, false);
322 else
323 for (PluginDescription pd : toDownload)
324 if (!PluginDownloader.downloadPlugin(pd))
325 pluginMap.put(pd, false);
326
327 }
328
329 String plugins = "";
330 for (Entry<PluginDescription, Boolean> entry : pluginMap.entrySet())
331 if (entry.getValue())
332 plugins += entry.getKey().name + ",";
333 if (plugins.endsWith(","))
334 plugins = plugins.substring(0, plugins.length()-1);
335
336 String oldPlugins = Main.pref.get("plugins");
337 if (!plugins.equals(oldPlugins)) {
338 Main.pref.put("plugins", plugins);
339 gui.requiresRestart = true;
340 }
341 }
342}
Note: See TracBrowser for help on using the repository browser.