001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences.plugin; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.GridBagConstraints; 007import java.awt.GridBagLayout; 008import java.awt.Insets; 009import java.awt.Rectangle; 010import java.awt.event.MouseAdapter; 011import java.awt.event.MouseEvent; 012import java.util.List; 013 014import javax.swing.JLabel; 015import javax.swing.SwingConstants; 016import javax.swing.SwingUtilities; 017 018import org.openstreetmap.josm.gui.widgets.HtmlPanel; 019import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel; 020import org.openstreetmap.josm.plugins.PluginInformation; 021 022/** 023 * A panel displaying the list of known plugins. 024 */ 025public class PluginListPanel extends VerticallyScrollablePanel { 026 static final class PluginCheckBoxMouseAdapter extends MouseAdapter { 027 private final PluginCheckBox cbPlugin; 028 029 PluginCheckBoxMouseAdapter(PluginCheckBox cbPlugin) { 030 this.cbPlugin = cbPlugin; 031 } 032 033 @Override 034 public void mouseClicked(MouseEvent e) { 035 cbPlugin.doClick(); 036 } 037 } 038 039 private transient PluginPreferencesModel model; 040 041 /** 042 * Constructs a new {@code PluginListPanel} with a default model. 043 */ 044 public PluginListPanel() { 045 this(new PluginPreferencesModel()); 046 } 047 048 /** 049 * Constructs a new {@code PluginListPanel} with a given model. 050 * @param model The plugin model 051 */ 052 public PluginListPanel(PluginPreferencesModel model) { 053 this.model = model; 054 setLayout(new GridBagLayout()); 055 } 056 057 protected static String formatPluginRemoteVersion(PluginInformation pi) { 058 StringBuilder sb = new StringBuilder(); 059 if (pi.version == null || pi.version.trim().isEmpty()) { 060 sb.append(tr("unknown")); 061 } else { 062 sb.append(pi.version); 063 if (pi.oldmode) { 064 sb.append('*'); 065 } 066 } 067 return sb.toString(); 068 } 069 070 protected static String formatPluginLocalVersion(PluginInformation pi) { 071 if (pi == null) 072 return tr("unknown"); 073 if (pi.localversion == null || pi.localversion.trim().isEmpty()) 074 return tr("unknown"); 075 return pi.localversion; 076 } 077 078 protected static String formatCheckboxTooltipText(PluginInformation pi) { 079 if (pi == null) 080 return ""; 081 if (pi.downloadlink == null) 082 return tr("Plugin bundled with JOSM"); 083 else 084 return pi.downloadlink; 085 } 086 087 /** 088 * Displays a message when the plugin list is empty. 089 */ 090 public void displayEmptyPluginListInformation() { 091 GridBagConstraints gbc = new GridBagConstraints(); 092 gbc.gridx = 0; 093 gbc.anchor = GridBagConstraints.CENTER; 094 gbc.fill = GridBagConstraints.BOTH; 095 gbc.insets = new Insets(40, 0, 40, 0); 096 gbc.weightx = 1.0; 097 gbc.weighty = 1.0; 098 099 HtmlPanel hint = new HtmlPanel(); 100 hint.setText( 101 "<html>" 102 + tr("Please click on <strong>Download list</strong> to download and display a list of available plugins.") 103 + "</html>" 104 ); 105 add(hint, gbc); 106 } 107 108 /** 109 * Refreshes the list. 110 */ 111 public void refreshView() { 112 final Rectangle visibleRect = getVisibleRect(); 113 List<PluginInformation> displayedPlugins = model.getDisplayedPlugins(); 114 removeAll(); 115 116 GridBagConstraints gbc = new GridBagConstraints(); 117 gbc.gridx = 0; 118 gbc.anchor = GridBagConstraints.NORTHWEST; 119 gbc.fill = GridBagConstraints.HORIZONTAL; 120 gbc.weightx = 1.0; 121 122 if (displayedPlugins.isEmpty()) { 123 displayEmptyPluginListInformation(); 124 return; 125 } 126 127 int row = -1; 128 for (final PluginInformation pi : displayedPlugins) { 129 boolean selected = model.isSelectedPlugin(pi.getName()); 130 String remoteversion = formatPluginRemoteVersion(pi); 131 String localversion = formatPluginLocalVersion(model.getPluginInformation(pi.getName())); 132 133 final PluginCheckBox cbPlugin = new PluginCheckBox(pi, selected, this, model); 134 String pluginText = tr("{0}: Version {1} (local: {2})", pi.getName(), remoteversion, localversion); 135 if (pi.requires != null && !pi.requires.isEmpty()) { 136 pluginText += tr(" (requires: {0})", pi.requires); 137 } 138 JLabel lblPlugin = new JLabel( 139 pluginText, 140 pi.getScaledIcon(), 141 SwingConstants.LEFT); 142 lblPlugin.addMouseListener(new PluginCheckBoxMouseAdapter(cbPlugin)); 143 144 gbc.gridx = 0; 145 gbc.gridy = ++row; 146 gbc.insets = new Insets(5, 5, 0, 5); 147 gbc.weighty = 0.0; 148 gbc.weightx = 0.0; 149 add(cbPlugin, gbc); 150 151 gbc.gridx = 1; 152 gbc.weightx = 1.0; 153 add(lblPlugin, gbc); 154 155 HtmlPanel description = new HtmlPanel(); 156 description.setText(pi.getDescriptionAsHtml()); 157 description.enableClickableHyperlinks(); 158 lblPlugin.setLabelFor(description); 159 160 gbc.gridx = 1; 161 gbc.gridy = ++row; 162 gbc.insets = new Insets(3, 25, 5, 5); 163 gbc.weighty = 1.0; 164 add(description, gbc); 165 } 166 revalidate(); 167 repaint(); 168 SwingUtilities.invokeLater(() -> scrollRectToVisible(visibleRect)); 169 } 170}