001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences.plugin; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005import static org.openstreetmap.josm.tools.I18n.trn; 006 007import java.awt.Component; 008import java.awt.event.ActionEvent; 009import java.awt.event.ActionListener; 010import java.util.HashSet; 011import java.util.Set; 012 013import javax.swing.JCheckBox; 014import javax.swing.JOptionPane; 015 016import org.openstreetmap.josm.plugins.PluginHandler; 017import org.openstreetmap.josm.plugins.PluginInformation; 018import org.openstreetmap.josm.tools.Utils; 019 020/** 021 * A plugin checkbox. 022 * @since 10228 023 */ 024public class PluginCheckBox extends JCheckBox implements ActionListener { 025 private final transient PluginInformation pi; 026 private final PluginListPanel panel; 027 private final transient PluginPreferencesModel ppModel; 028 029 PluginCheckBox(PluginInformation pi, boolean selected, PluginListPanel panel, PluginPreferencesModel ppModel) { 030 this.pi = pi; 031 this.panel = panel; 032 this.ppModel = ppModel; 033 setSelected(selected); 034 setToolTipText(PluginListPanel.formatCheckboxTooltipText(pi)); 035 addActionListener(this); 036 } 037 038 protected void selectRequiredPlugins(PluginInformation info) { 039 if (info != null && info.requires != null) { 040 for (String s : info.getRequiredPlugins()) { 041 if (!ppModel.isSelectedPlugin(s)) { 042 ppModel.setPluginSelected(s, true); 043 selectRequiredPlugins(ppModel.getPluginInformation(s)); 044 } 045 } 046 } 047 } 048 049 @Override 050 public void actionPerformed(ActionEvent e) { 051 // Select/unselect corresponding plugin in the model 052 ppModel.setPluginSelected(pi.getName(), isSelected()); 053 // Does the newly selected plugin require other plugins ? 054 if (isSelected() && pi.requires != null) { 055 // Select required plugins 056 selectRequiredPlugins(pi); 057 // Alert user if plugin requirements are not met 058 PluginHandler.checkRequiredPluginsPreconditions(panel, ppModel.getAvailablePlugins(), pi, false); 059 } else if (!isSelected()) { 060 // If the plugin has been unselected, was it required by other plugins still selected ? 061 Set<String> otherPlugins = new HashSet<>(); 062 for (PluginInformation p : ppModel.getAvailablePlugins()) { 063 if (!p.equals(pi) && p.requires != null && ppModel.isSelectedPlugin(p.getName())) { 064 for (String s : p.getRequiredPlugins()) { 065 if (s.equals(pi.getName())) { 066 otherPlugins.add(p.getName()); 067 break; 068 } 069 } 070 } 071 } 072 if (!otherPlugins.isEmpty()) { 073 alertPluginStillRequired(panel, pi.getName(), otherPlugins); 074 } 075 } 076 } 077 078 /** 079 * Alerts the user if an unselected plugin is still required by another plugins 080 * 081 * @param parent The parent Component used to display error popup 082 * @param plugin the plugin 083 * @param otherPlugins the other plugins 084 */ 085 private static void alertPluginStillRequired(Component parent, String plugin, Set<String> otherPlugins) { 086 StringBuilder sb = new StringBuilder("<html>") 087 .append(trn("Plugin {0} is still required by this plugin:", 088 "Plugin {0} is still required by these {1} plugins:", 089 otherPlugins.size(), 090 Utils.escapeReservedCharactersHTML(plugin), 091 otherPlugins.size())) 092 .append(Utils.joinAsHtmlUnorderedList(otherPlugins)) 093 .append("</html>"); 094 JOptionPane.showMessageDialog( 095 parent, 096 sb.toString(), 097 tr("Warning"), 098 JOptionPane.WARNING_MESSAGE 099 ); 100 } 101}