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

Last change on this file since 12841 was 12841, checked in by bastiK, 7 years ago

see #15229 - fix deprecations caused by [12840]

  • Property svn:eol-style set to native
File size: 26.2 KB
RevLine 
[8378]1// License: GPL. For details, see LICENSE file.
[6529]2package org.openstreetmap.josm.gui.preferences.plugin;
[626]3
[582]4import static org.openstreetmap.josm.tools.I18n.tr;
[2817]5import static org.openstreetmap.josm.tools.I18n.trn;
[582]6
[2817]7import java.awt.BorderLayout;
[6797]8import java.awt.Component;
[9616]9import java.awt.GraphicsEnvironment;
[2817]10import java.awt.GridBagConstraints;
[300]11import java.awt.GridBagLayout;
[3113]12import java.awt.GridLayout;
[2817]13import java.awt.Insets;
[582]14import java.awt.event.ActionEvent;
[2817]15import java.awt.event.ComponentAdapter;
16import java.awt.event.ComponentEvent;
[6623]17import java.lang.reflect.InvocationTargetException;
[3085]18import java.util.ArrayList;
[10811]19import java.util.Arrays;
[582]20import java.util.Collection;
[2864]21import java.util.Collections;
[582]22import java.util.LinkedList;
[2817]23import java.util.List;
[8846]24import java.util.Set;
[10811]25import java.util.regex.Pattern;
[582]26
[300]27import javax.swing.AbstractAction;
[2817]28import javax.swing.BorderFactory;
[300]29import javax.swing.DefaultListModel;
[582]30import javax.swing.JButton;
[10811]31import javax.swing.JCheckBox;
[582]32import javax.swing.JLabel;
[300]33import javax.swing.JList;
[582]34import javax.swing.JOptionPane;
35import javax.swing.JPanel;
36import javax.swing.JScrollPane;
[2817]37import javax.swing.JTabbedPane;
[10811]38import javax.swing.JTextArea;
[2817]39import javax.swing.SwingUtilities;
40import javax.swing.UIManager;
[2147]41import javax.swing.event.DocumentEvent;
42import javax.swing.event.DocumentListener;
[582]43
[1865]44import org.openstreetmap.josm.Main;
[10811]45import org.openstreetmap.josm.actions.ExpertToggleAction;
[5140]46import org.openstreetmap.josm.data.Version;
[2817]47import org.openstreetmap.josm.gui.HelpAwareOptionPane;
[3085]48import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
[12634]49import org.openstreetmap.josm.gui.MainApplication;
[2817]50import org.openstreetmap.josm.gui.help.HelpUtil;
[6529]51import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
52import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
53import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
54import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
[4968]55import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.PreferencePanel;
[5723]56import org.openstreetmap.josm.gui.util.GuiHelper;
[6362]57import org.openstreetmap.josm.gui.widgets.JosmTextField;
[2817]58import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
59import org.openstreetmap.josm.plugins.PluginDownloadTask;
60import org.openstreetmap.josm.plugins.PluginInformation;
61import org.openstreetmap.josm.plugins.ReadLocalPluginInformationTask;
62import org.openstreetmap.josm.plugins.ReadRemotePluginInformationTask;
[582]63import org.openstreetmap.josm.tools.GBC;
[2817]64import org.openstreetmap.josm.tools.ImageProvider;
[12620]65import org.openstreetmap.josm.tools.Logging;
[10811]66import org.openstreetmap.josm.tools.Utils;
[626]67
[6603]68/**
69 * Preference settings for plugins.
70 * @since 168
71 */
[6362]72public final class PluginPreference extends DefaultTabPreferenceSetting {
[6529]73
74 /**
75 * Factory used to create a new {@code PluginPreference}.
76 */
[1742]77 public static class Factory implements PreferenceSettingFactory {
[6084]78 @Override
[1742]79 public PreferenceSetting createPreferenceSetting() {
80 return new PluginPreference();
81 }
82 }
[5468]83
[9611]84 private JosmTextField tfFilter;
85 private PluginListPanel pnlPluginPreferences;
86 private PluginPreferencesModel model;
87 private JScrollPane spPluginPreferences;
88 private PluginUpdatePolicyPanel pnlPluginUpdatePolicy;
89
90 /**
91 * is set to true if this preference pane has been selected by the user
92 */
93 private boolean pluginPreferencesActivated;
94
[4968]95 private PluginPreference() {
[7668]96 super(/* ICON(preferences/) */ "plugin", tr("Plugins"), tr("Configure available plugins."), false, new JTabbedPane());
[4968]97 }
[1742]98
[6603]99 /**
100 * Returns the download summary string to be shown.
101 * @param task The plugin download task that has completed
102 * @return the download summary string to be shown. Contains summary of success/failed plugins.
103 */
[2817]104 public static String buildDownloadSummary(PluginDownloadTask task) {
105 Collection<PluginInformation> downloaded = task.getDownloadedPlugins();
106 Collection<PluginInformation> failed = task.getFailedPlugins();
[9621]107 Exception exception = task.getLastException();
[2817]108 StringBuilder sb = new StringBuilder();
[8390]109 if (!downloaded.isEmpty()) {
[2817]110 sb.append(trn(
111 "The following plugin has been downloaded <strong>successfully</strong>:",
[2955]112 "The following {0} plugins have been downloaded <strong>successfully</strong>:",
[2817]113 downloaded.size(),
114 downloaded.size()
[5468]115 ));
[2817]116 sb.append("<ul>");
[8510]117 for (PluginInformation pi: downloaded) {
[8390]118 sb.append("<li>").append(pi.name).append(" (").append(pi.version).append(")</li>");
[2147]119 }
[2817]120 sb.append("</ul>");
121 }
[8390]122 if (!failed.isEmpty()) {
[2817]123 sb.append(trn(
124 "Downloading the following plugin has <strong>failed</strong>:",
125 "Downloading the following {0} plugins has <strong>failed</strong>:",
126 failed.size(),
127 failed.size()
[5468]128 ));
[2817]129 sb.append("<ul>");
[8510]130 for (PluginInformation pi: failed) {
[2817]131 sb.append("<li>").append(pi.name).append("</li>");
[2147]132 }
[2817]133 sb.append("</ul>");
134 }
[9621]135 if (exception != null) {
136 // Same i18n string in ExceptionUtil.explainBadRequest()
137 sb.append(tr("<br>Error message(untranslated): {0}", exception.getMessage()));
138 }
[2817]139 return sb.toString();
140 }
[7434]141
[6797]142 /**
143 * Notifies user about result of a finished plugin download task.
144 * @param parent The parent component
145 * @param task The finished plugin download task
[8471]146 * @param restartRequired true if a restart is required
[6797]147 * @since 6797
148 */
[8018]149 public static void notifyDownloadResults(final Component parent, PluginDownloadTask task, boolean restartRequired) {
[6797]150 final Collection<PluginInformation> failed = task.getFailedPlugins();
151 final StringBuilder sb = new StringBuilder();
[8379]152 sb.append("<html>")
153 .append(buildDownloadSummary(task));
[8017]154 if (restartRequired) {
[6797]155 sb.append(tr("Please restart JOSM to activate the downloaded plugins."));
156 }
157 sb.append("</html>");
[9616]158 if (!GraphicsEnvironment.isHeadless()) {
[10611]159 GuiHelper.runInEDTAndWait(() -> HelpAwareOptionPane.showOptionDialog(
160 parent,
161 sb.toString(),
162 tr("Update plugins"),
163 !failed.isEmpty() ? JOptionPane.WARNING_MESSAGE : JOptionPane.INFORMATION_MESSAGE,
164 HelpUtil.ht("/Preferences/Plugins")
165 ));
[9616]166 }
[6797]167 }
[2147]168
[10763]169 private JPanel buildSearchFieldPanel() {
[9611]170 JPanel pnl = new JPanel(new GridBagLayout());
[8510]171 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
[2817]172 GridBagConstraints gc = new GridBagConstraints();
[2147]173
[2817]174 gc.anchor = GridBagConstraints.NORTHWEST;
175 gc.fill = GridBagConstraints.HORIZONTAL;
176 gc.weightx = 0.0;
[8510]177 gc.insets = new Insets(0, 0, 0, 3);
[2817]178 pnl.add(new JLabel(tr("Search:")), gc);
[2147]179
[2817]180 gc.gridx = 1;
181 gc.weightx = 1.0;
[6623]182 tfFilter = new JosmTextField();
183 pnl.add(tfFilter, gc);
[2817]184 tfFilter.setToolTipText(tr("Enter a search expression"));
185 SelectAllOnFocusGainedDecorator.decorate(tfFilter);
186 tfFilter.getDocument().addDocumentListener(new SearchFieldAdapter());
187 return pnl;
188 }
[299]189
[10763]190 private JPanel buildActionPanel() {
[10811]191 JPanel pnl = new JPanel(new GridLayout(1, 4));
[626]192
[2817]193 pnl.add(new JButton(new DownloadAvailablePluginsAction()));
194 pnl.add(new JButton(new UpdateSelectedPluginsAction()));
[10811]195 ExpertToggleAction.addVisibilitySwitcher(pnl.add(new JButton(new SelectByListAction())));
196 ExpertToggleAction.addVisibilitySwitcher(pnl.add(new JButton(new ConfigureSitesAction())));
[2817]197 return pnl;
198 }
[626]199
[10763]200 private JPanel buildPluginListPanel() {
[2817]201 JPanel pnl = new JPanel(new BorderLayout());
202 pnl.add(buildSearchFieldPanel(), BorderLayout.NORTH);
[10378]203 model = new PluginPreferencesModel();
[6623]204 pnlPluginPreferences = new PluginListPanel(model);
[6666]205 spPluginPreferences = GuiHelper.embedInVerticalScrollPane(pnlPluginPreferences);
[2817]206 spPluginPreferences.getVerticalScrollBar().addComponentListener(
[8510]207 new ComponentAdapter() {
[2817]208 @Override
209 public void componentShown(ComponentEvent e) {
210 spPluginPreferences.setBorder(UIManager.getBorder("ScrollPane.border"));
211 }
[8510]212
[2817]213 @Override
214 public void componentHidden(ComponentEvent e) {
215 spPluginPreferences.setBorder(null);
216 }
217 }
[5468]218 );
[2817]219
220 pnl.add(spPluginPreferences, BorderLayout.CENTER);
221 pnl.add(buildActionPanel(), BorderLayout.SOUTH);
222 return pnl;
[1169]223 }
[626]224
[10763]225 private JTabbedPane buildContentPane() {
[5631]226 JTabbedPane pane = getTabPane();
[6623]227 pnlPluginUpdatePolicy = new PluginUpdatePolicyPanel();
[5631]228 pane.addTab(tr("Plugins"), buildPluginListPanel());
[6623]229 pane.addTab(tr("Plugin update policy"), pnlPluginUpdatePolicy);
[5631]230 return pane;
[2924]231 }
232
[6084]233 @Override
[2817]234 public void addGui(final PreferenceTabbedPane gui) {
235 GridBagConstraints gc = new GridBagConstraints();
236 gc.weightx = 1.0;
237 gc.weighty = 1.0;
238 gc.anchor = GridBagConstraints.NORTHWEST;
239 gc.fill = GridBagConstraints.BOTH;
[4968]240 PreferencePanel plugins = gui.createPreferenceTab(this);
[5631]241 plugins.add(buildContentPane(), gc);
[5120]242 readLocalPluginInformation();
243 pluginPreferencesActivated = true;
[2817]244 }
245
[1169]246 private void configureSites() {
[3085]247 ButtonSpec[] options = new ButtonSpec[] {
248 new ButtonSpec(
249 tr("OK"),
250 ImageProvider.get("ok"),
251 tr("Accept the new plugin sites and close the dialog"),
252 null /* no special help topic */
[5468]253 ),
254 new ButtonSpec(
255 tr("Cancel"),
256 ImageProvider.get("cancel"),
257 tr("Close the dialog"),
258 null /* no special help topic */
259 )
[3085]260 };
261 PluginConfigurationSitesPanel pnl = new PluginConfigurationSitesPanel();
262
263 int answer = HelpAwareOptionPane.showOptionDialog(
264 pnlPluginPreferences,
265 pnl,
266 tr("Configure Plugin Sites"),
267 JOptionPane.QUESTION_MESSAGE,
268 null,
269 options,
270 options[0],
271 null /* no help topic */
[5468]272 );
[3085]273 if (answer != 0 /* OK */)
[1169]274 return;
[10137]275 Main.pref.setPluginSites(pnl.getUpdateSites());
[1169]276 }
[299]277
[2817]278 /**
[9611]279 * Replies the set of plugins waiting for update or download
[3530]280 *
[9611]281 * @return the set of plugins waiting for update or download
[2817]282 */
[8846]283 public Set<PluginInformation> getPluginsScheduledForUpdateOrDownload() {
[4970]284 return model != null ? model.getPluginsScheduledForUpdateOrDownload() : null;
[2817]285 }
286
[9611]287 /**
288 * Replies the list of plugins which have been added by the user to the set of activated plugins
289 *
290 * @return the list of newly activated plugins
291 */
[8017]292 public List<PluginInformation> getNewlyActivatedPlugins() {
293 return model != null ? model.getNewlyActivatedPlugins() : null;
294 }
295
[6084]296 @Override
[1326]297 public boolean ok() {
[8444]298 if (!pluginPreferencesActivated)
[2855]299 return false;
[2924]300 pnlPluginUpdatePolicy.rememberInPreferences();
[2817]301 if (model.isActivePluginsChanged()) {
[8338]302 List<String> l = new LinkedList<>(model.getSelectedPluginNames());
[2864]303 Collections.sort(l);
[12841]304 Main.pref.putList("plugins", l);
[9611]305 if (!model.getNewlyDeactivatedPlugins().isEmpty())
306 return true;
[8017]307 for (PluginInformation pi : model.getNewlyActivatedPlugins()) {
[9611]308 if (!pi.canloadatruntime)
309 return true;
[8017]310 }
[2817]311 }
312 return false;
[1169]313 }
[299]314
[2855]315 /**
316 * Reads locally available information about plugins from the local file system.
317 * Scans cached plugin lists from plugin download sites and locally available
318 * plugin jar files.
[3530]319 *
[2855]320 */
[2817]321 public void readLocalPluginInformation() {
322 final ReadLocalPluginInformationTask task = new ReadLocalPluginInformationTask();
[10611]323 Runnable r = () -> {
324 if (!task.isCanceled()) {
325 SwingUtilities.invokeLater(() -> {
326 model.setAvailablePlugins(task.getAvailablePlugins());
327 pnlPluginPreferences.refreshView();
328 });
[2990]329 }
[2817]330 };
[12634]331 MainApplication.worker.submit(task);
332 MainApplication.worker.submit(r);
[2817]333 }
334
335 /**
336 * The action for downloading the list of available plugins
337 */
338 class DownloadAvailablePluginsAction extends AbstractAction {
339
[8471]340 /**
341 * Constructs a new {@code DownloadAvailablePluginsAction}.
342 */
[8836]343 DownloadAvailablePluginsAction() {
[8510]344 putValue(NAME, tr("Download list"));
[2817]345 putValue(SHORT_DESCRIPTION, tr("Download the list of available plugins"));
[10482]346 new ImageProvider("download").getResource().attachImageIcon(this);
[1191]347 }
348
[6084]349 @Override
[2817]350 public void actionPerformed(ActionEvent e) {
[8471]351 Collection<String> pluginSites = Main.pref.getOnlinePluginSites();
[7434]352 if (pluginSites.isEmpty()) {
353 return;
354 }
355 final ReadRemotePluginInformationTask task = new ReadRemotePluginInformationTask(pluginSites);
[10611]356 Runnable continuation = () -> {
357 if (!task.isCanceled()) {
358 SwingUtilities.invokeLater(() -> {
359 model.updateAvailablePlugins(task.getAvailablePlugins());
360 pnlPluginPreferences.refreshView();
[12841]361 Main.pref.putInt("pluginmanager.version", Version.getInstance().getVersion()); // fix #7030
[10611]362 });
[2817]363 }
364 };
[12634]365 MainApplication.worker.submit(task);
366 MainApplication.worker.submit(continuation);
[1191]367 }
[2817]368 }
[1191]369
[2817]370 /**
[7434]371 * The action for updating the list of selected plugins
[2817]372 */
373 class UpdateSelectedPluginsAction extends AbstractAction {
[8836]374 UpdateSelectedPluginsAction() {
[8510]375 putValue(NAME, tr("Update plugins"));
[2817]376 putValue(SHORT_DESCRIPTION, tr("Update the selected plugins"));
[10482]377 new ImageProvider("dialogs", "refresh").getResource().attachImageIcon(this);
[1191]378 }
379
[3090]380 protected void alertNothingToUpdate() {
[5468]381 try {
[10611]382 SwingUtilities.invokeAndWait(() -> HelpAwareOptionPane.showOptionDialog(
383 pnlPluginPreferences,
384 tr("All installed plugins are up to date. JOSM does not have to download newer versions."),
385 tr("Plugins up to date"),
386 JOptionPane.INFORMATION_MESSAGE,
387 null // FIXME: provide help context
388 ));
[7004]389 } catch (InterruptedException | InvocationTargetException e) {
[12620]390 Logging.error(e);
[5468]391 }
[3090]392 }
393
[6084]394 @Override
[2817]395 public void actionPerformed(ActionEvent e) {
[3090]396 final List<PluginInformation> toUpdate = model.getSelectedPlugins();
[3088]397 // the async task for downloading plugins
398 final PluginDownloadTask pluginDownloadTask = new PluginDownloadTask(
[2817]399 pnlPluginPreferences,
400 toUpdate,
401 tr("Update plugins")
[5468]402 );
[3088]403 // the async task for downloading plugin information
[8471]404 final ReadRemotePluginInformationTask pluginInfoDownloadTask = new ReadRemotePluginInformationTask(
405 Main.pref.getOnlinePluginSites());
[3086]406
[3088]407 // to be run asynchronously after the plugin download
408 //
[10611]409 final Runnable pluginDownloadContinuation = () -> {
410 if (pluginDownloadTask.isCanceled())
411 return;
412 boolean restartRequired = false;
413 for (PluginInformation pi : pluginDownloadTask.getDownloadedPlugins()) {
414 if (!model.getNewlyActivatedPlugins().contains(pi) || !pi.canloadatruntime) {
415 restartRequired = true;
416 break;
[8018]417 }
[2817]418 }
[10611]419 notifyDownloadResults(pnlPluginPreferences, pluginDownloadTask, restartRequired);
420 model.refreshLocalPluginVersion(pluginDownloadTask.getDownloadedPlugins());
421 model.clearPendingPlugins(pluginDownloadTask.getDownloadedPlugins());
422 GuiHelper.runInEDT(pnlPluginPreferences::refreshView);
[2817]423 };
[3086]424
[3088]425 // to be run asynchronously after the plugin list download
426 //
[10611]427 final Runnable pluginInfoDownloadContinuation = () -> {
428 if (pluginInfoDownloadTask.isCanceled())
429 return;
430 model.updateAvailablePlugins(pluginInfoDownloadTask.getAvailablePlugins());
431 // select plugins which actually have to be updated
432 //
[11339]433 toUpdate.removeIf(pi -> !pi.isUpdateRequired());
[10611]434 if (toUpdate.isEmpty()) {
435 alertNothingToUpdate();
436 return;
437 }
438 pluginDownloadTask.setPluginsToDownload(toUpdate);
[12634]439 MainApplication.worker.submit(pluginDownloadTask);
440 MainApplication.worker.submit(pluginDownloadContinuation);
[3086]441 };
442
[12634]443 MainApplication.worker.submit(pluginInfoDownloadTask);
444 MainApplication.worker.submit(pluginInfoDownloadContinuation);
[1191]445 }
[2817]446 }
[1191]447
[2817]448 /**
449 * The action for configuring the plugin download sites
450 *
451 */
452 class ConfigureSitesAction extends AbstractAction {
[8836]453 ConfigureSitesAction() {
[8510]454 putValue(NAME, tr("Configure sites..."));
[2817]455 putValue(SHORT_DESCRIPTION, tr("Configure the list of sites where plugins are downloaded from"));
[10482]456 new ImageProvider("dialogs", "settings").getResource().attachImageIcon(this);
[1191]457 }
[2817]458
[6084]459 @Override
[2817]460 public void actionPerformed(ActionEvent e) {
461 configureSites();
462 }
[1191]463 }
[2817]464
465 /**
[10811]466 * The action for selecting the plugins given by a text file compatible to JOSM bug report.
467 * @author Michael Zangl
468 */
469 class SelectByListAction extends AbstractAction {
470 SelectByListAction() {
471 putValue(NAME, tr("Load from list..."));
472 putValue(SHORT_DESCRIPTION, tr("Load plugins from a list of plugins"));
473 }
474
475 @Override
476 public void actionPerformed(ActionEvent e) {
477 JTextArea textField = new JTextArea(10, 0);
478 JCheckBox deleteNotInList = new JCheckBox(tr("Disable all other plugins"));
479
480 JLabel helpLabel = new JLabel("<html>" + Utils.join("<br/>", Arrays.asList(
481 tr("Enter a list of plugins you want to download."),
482 tr("You should add one plugin id per line, version information is ignored."),
483 tr("You can copy+paste the list of a status report here."))) + "</html>");
484
485 if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(GuiHelper.getFrameForComponent(getTabPane()),
486 new Object[] {helpLabel, new JScrollPane(textField), deleteNotInList},
487 tr("Load plugins from list"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE)) {
488 activatePlugins(textField, deleteNotInList.isSelected());
489 }
490 }
491
492 private void activatePlugins(JTextArea textField, boolean deleteNotInList) {
493 String[] lines = textField.getText().split("\n");
494 List<String> toActivate = new ArrayList<>();
495 List<String> notFound = new ArrayList<>();
[11565]496 // This pattern matches the default list format JOSM uses for bug reports.
497 // It removes a list item mark at the beginning of the line: +, -, *
[11636]498 // It removes the version number after the plugin, like: 123, (123), (v5.7alpha3), (1b3), (v1-SNAPSHOT-1)...
499 Pattern regex = Pattern.compile("^[-+\\*\\s]*|\\s[\\d\\s]*(\\([^\\(\\)\\[\\]]*\\))?[\\d\\s]*$");
[10811]500 for (String line : lines) {
501 String name = regex.matcher(line).replaceAll("");
502 if (name.isEmpty()) {
503 continue;
504 }
505 PluginInformation plugin = model.getPluginInformation(name);
506 if (plugin == null) {
507 notFound.add(name);
508 } else {
509 toActivate.add(name);
510 }
511 }
512
513 if (notFound.isEmpty() || confirmIgnoreNotFound(notFound)) {
514 activatePlugins(toActivate, deleteNotInList);
515 }
516 }
517
518 private void activatePlugins(List<String> toActivate, boolean deleteNotInList) {
519 if (deleteNotInList) {
520 for (String name : model.getSelectedPluginNames()) {
521 if (!toActivate.contains(name)) {
522 model.setPluginSelected(name, false);
523 }
524 }
525 }
526 for (String name : toActivate) {
527 model.setPluginSelected(name, true);
528 }
529 pnlPluginPreferences.refreshView();
530 }
531
532 private boolean confirmIgnoreNotFound(List<String> notFound) {
533 String list = "<ul><li>" + Utils.join("</li><li>", notFound) + "</li></ul>";
534 String message = "<html>" + tr("The following plugins were not found. Continue anyway?") + list + "</html>";
535 return JOptionPane.showConfirmDialog(GuiHelper.getFrameForComponent(getTabPane()),
536 message) == JOptionPane.OK_OPTION;
537 }
538 }
539
540 /**
[10137]541 * Applies the current filter condition in the filter text field to the model.
[2817]542 */
543 class SearchFieldAdapter implements DocumentListener {
[10137]544 private void filter() {
[2817]545 String expr = tfFilter.getText().trim();
[6087]546 if (expr.isEmpty()) {
[2817]547 expr = null;
548 }
549 model.filterDisplayedPlugins(expr);
550 pnlPluginPreferences.refreshView();
551 }
552
[6084]553 @Override
[10611]554 public void changedUpdate(DocumentEvent evt) {
[2817]555 filter();
556 }
557
[6084]558 @Override
[10611]559 public void insertUpdate(DocumentEvent evt) {
[2817]560 filter();
561 }
562
[6084]563 @Override
[10611]564 public void removeUpdate(DocumentEvent evt) {
[2817]565 filter();
566 }
567 }
[3085]568
[6603]569 private static class PluginConfigurationSitesPanel extends JPanel {
[3085]570
[9611]571 private final DefaultListModel<String> model = new DefaultListModel<>();
[3085]572
[9611]573 PluginConfigurationSitesPanel() {
574 super(new GridBagLayout());
[3085]575 add(new JLabel(tr("Add JOSM Plugin description URL.")), GBC.eol());
576 for (String s : Main.pref.getPluginSites()) {
577 model.addElement(s);
578 }
[7005]579 final JList<String> list = new JList<>(model);
[3085]580 add(new JScrollPane(list), GBC.std().fill());
581 JPanel buttons = new JPanel(new GridBagLayout());
[8510]582 buttons.add(new JButton(new AbstractAction(tr("Add")) {
[6084]583 @Override
[3085]584 public void actionPerformed(ActionEvent e) {
585 String s = JOptionPane.showInputDialog(
[10035]586 GuiHelper.getFrameForComponent(PluginConfigurationSitesPanel.this),
[3085]587 tr("Add JOSM Plugin description URL."),
588 tr("Enter URL"),
589 JOptionPane.QUESTION_MESSAGE
[5468]590 );
[11198]591 if (s != null && !s.isEmpty()) {
[3085]592 model.addElement(s);
593 }
594 }
595 }), GBC.eol().fill(GBC.HORIZONTAL));
[8510]596 buttons.add(new JButton(new AbstractAction(tr("Edit")) {
[6084]597 @Override
[3085]598 public void actionPerformed(ActionEvent e) {
599 if (list.getSelectedValue() == null) {
600 JOptionPane.showMessageDialog(
[10035]601 GuiHelper.getFrameForComponent(PluginConfigurationSitesPanel.this),
[3085]602 tr("Please select an entry."),
603 tr("Warning"),
604 JOptionPane.WARNING_MESSAGE
[5468]605 );
[3085]606 return;
607 }
[8510]608 String s = (String) JOptionPane.showInputDialog(
[3085]609 Main.parent,
610 tr("Edit JOSM Plugin description URL."),
611 tr("JOSM Plugin description URL"),
612 JOptionPane.QUESTION_MESSAGE,
613 null,
614 null,
615 list.getSelectedValue()
[5468]616 );
[11198]617 if (s != null && !s.isEmpty()) {
[3585]618 model.setElementAt(s, list.getSelectedIndex());
619 }
[3085]620 }
621 }), GBC.eol().fill(GBC.HORIZONTAL));
[8510]622 buttons.add(new JButton(new AbstractAction(tr("Delete")) {
[6084]623 @Override
[3085]624 public void actionPerformed(ActionEvent event) {
625 if (list.getSelectedValue() == null) {
626 JOptionPane.showMessageDialog(
[10035]627 GuiHelper.getFrameForComponent(PluginConfigurationSitesPanel.this),
[3085]628 tr("Please select an entry."),
629 tr("Warning"),
630 JOptionPane.WARNING_MESSAGE
[5468]631 );
[3085]632 return;
633 }
634 model.removeElement(list.getSelectedValue());
635 }
636 }), GBC.eol().fill(GBC.HORIZONTAL));
637 add(buttons, GBC.eol());
638 }
639
[10137]640 protected List<String> getUpdateSites() {
[9611]641 if (model.getSize() == 0)
642 return Collections.emptyList();
[7005]643 List<String> ret = new ArrayList<>(model.getSize());
[8510]644 for (int i = 0; i < model.getSize(); i++) {
[7021]645 ret.add(model.get(i));
[3085]646 }
647 return ret;
648 }
649 }
[626]650}
Note: See TracBrowser for help on using the repository browser.