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

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

see #15229 - use Config.getPref() wherever possible

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