source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginListPanel.java

Last change on this file was 19080, checked in by taylor.smock, 4 months ago

See #23671: Deprecate Utils#isBlank and replace instances of it with Utils#isStripEmpty

As noted in r19079, the two functions were identical in behavior.

  • Property svn:eol-style set to native
File size: 8.1 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;
5
6import java.awt.GridBagConstraints;
7import java.awt.GridBagLayout;
8import java.awt.Insets;
9import java.awt.Rectangle;
10import java.awt.event.MouseAdapter;
11import java.awt.event.MouseEvent;
12import java.util.HashSet;
13import java.util.List;
14import java.util.Set;
15
16import javax.swing.JComponent;
17import javax.swing.JLabel;
18import javax.swing.SwingConstants;
19import javax.swing.SwingUtilities;
20
21import org.openstreetmap.josm.gui.widgets.HtmlPanel;
22import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
23import org.openstreetmap.josm.plugins.PluginInformation;
24import org.openstreetmap.josm.tools.Utils;
25
26/**
27 * A panel displaying the list of known plugins.
28 */
29public class PluginListPanel extends VerticallyScrollablePanel {
30 static final class PluginCheckBoxMouseAdapter extends MouseAdapter {
31 private final PluginCheckBox cbPlugin;
32
33 PluginCheckBoxMouseAdapter(PluginCheckBox cbPlugin) {
34 this.cbPlugin = cbPlugin;
35 }
36
37 @Override
38 public void mouseClicked(MouseEvent e) {
39 cbPlugin.doClick();
40 }
41 }
42
43 private final transient PluginPreferencesModel model;
44
45 /** Whether the plugin list has been built up already in the UI. */
46 private boolean pluginListInitialized;
47
48 /**
49 * Constructs a new {@code PluginListPanel} with a default model.
50 */
51 public PluginListPanel() {
52 this(new PluginPreferencesModel());
53 }
54
55 /**
56 * Constructs a new {@code PluginListPanel} with a given model.
57 * @param model The plugin model
58 */
59 public PluginListPanel(PluginPreferencesModel model) {
60 this.model = model;
61 setLayout(new GridBagLayout());
62 }
63
64 protected static String formatPluginRemoteVersion(PluginInformation pi) {
65 StringBuilder sb = new StringBuilder();
66 if (Utils.isStripEmpty(pi.version)) {
67 sb.append(tr("unknown"));
68 } else {
69 sb.append(pi.version);
70 if (pi.oldmode) {
71 sb.append('*');
72 }
73 }
74 return sb.toString();
75 }
76
77 protected static String formatPluginLocalVersion(PluginInformation pi) {
78 if (pi == null)
79 return tr("unknown");
80 if (Utils.isStripEmpty(pi.localversion))
81 return tr("unknown");
82 return pi.localversion;
83 }
84
85 protected static String formatCheckboxTooltipText(PluginInformation pi) {
86 if (pi == null)
87 return "";
88 if (pi.downloadlink == null)
89 return tr("Plugin bundled with JOSM");
90 else
91 return pi.downloadlink;
92 }
93
94 /**
95 * Displays a message when the plugin list is empty.
96 */
97 public void displayEmptyPluginListInformation() {
98 GridBagConstraints gbc = new GridBagConstraints();
99 gbc.gridx = 0;
100 gbc.anchor = GridBagConstraints.CENTER;
101 gbc.fill = GridBagConstraints.BOTH;
102 gbc.insets = new Insets(40, 0, 40, 0);
103 gbc.weightx = 1.0;
104 gbc.weighty = 1.0;
105
106 HtmlPanel hint = new HtmlPanel();
107 hint.setText(
108 "<html>"
109 + (model.getAvailablePlugins().isEmpty() ?
110 tr("Please click on <strong>Download list</strong> to download and display a list of available plugins.") :
111 tr("The filter returned no results."))
112 + "</html>"
113 );
114 hint.putClientProperty("plugin", "empty");
115 hint.setVisible(false);
116 add(hint, gbc);
117 }
118
119 /**
120 * Displays a list of plugins.
121 * @param displayedPlugins list of plugins
122 * @since 13799
123 */
124 public void displayPluginList(List<PluginInformation> displayedPlugins) {
125 GridBagConstraints gbc = new GridBagConstraints();
126 gbc.gridx = 0;
127 gbc.anchor = GridBagConstraints.NORTHWEST;
128 gbc.fill = GridBagConstraints.HORIZONTAL;
129 gbc.weightx = 1.0;
130
131 int row = -1;
132 for (final PluginInformation pi : displayedPlugins) {
133 boolean selected = model.isSelectedPlugin(pi.getName());
134 String remoteversion = formatPluginRemoteVersion(pi);
135 String localversion = formatPluginLocalVersion(model.getPluginInformation(pi.getName()));
136
137 final PluginCheckBox cbPlugin = new PluginCheckBox(pi, selected, this, model);
138 String pluginText = tr("{0}: Version {1} (local: {2})", pi.getName(), remoteversion, localversion);
139 if (!Utils.isEmpty(pi.requires)) {
140 pluginText += tr(" (requires: {0})", pi.requires);
141 }
142 JLabel lblPlugin = new JLabel(
143 pluginText,
144 pi.getScaledIcon(),
145 SwingConstants.LEADING);
146 lblPlugin.addMouseListener(new PluginCheckBoxMouseAdapter(cbPlugin));
147
148 gbc.gridx = 0;
149 gbc.gridy = ++row;
150 gbc.insets = new Insets(5, 5, 0, 5);
151 gbc.weighty = 0.0;
152 gbc.weightx = 0.0;
153 cbPlugin.putClientProperty("plugin", pi);
154 add(cbPlugin, gbc);
155
156 gbc.gridx = 1;
157 gbc.weightx = 1.0;
158 lblPlugin.putClientProperty("plugin", pi);
159 add(lblPlugin, gbc);
160
161 HtmlPanel description = new HtmlPanel();
162 description.setText(pi.getDescriptionAsHtml());
163 description.enableClickableHyperlinks();
164 lblPlugin.setLabelFor(description);
165
166 gbc.gridx = 1;
167 gbc.gridy = ++row;
168 gbc.insets = new Insets(3, 25, 5, 5);
169 gbc.weighty = 1.0;
170 description.putClientProperty("plugin", pi);
171 add(description, gbc);
172 }
173 pluginListInitialized = true;
174 }
175
176 /**
177 * Refreshes the list.
178 *
179 * If the list has been changed completely (i.e. not just filtered),
180 * call {@link #resetDisplayedComponents()} prior to calling this method.
181 */
182 public void refreshView() {
183 final Rectangle visibleRect = getVisibleRect();
184 if (!pluginListInitialized) {
185 removeAll();
186 displayEmptyPluginListInformation();
187 displayPluginList(model.getAvailablePlugins());
188 } else {
189 hidePluginsNotInList(new HashSet<>(model.getDisplayedPlugins()));
190 }
191 revalidate();
192 repaint();
193 SwingUtilities.invokeLater(() -> scrollRectToVisible(visibleRect));
194 }
195
196 /**
197 * Hides components in the list for plugins that are currently filtered away.
198 *
199 * Since those components are relatively heavyweight rebuilding them every time
200 * when the filter changes is fairly slow, so we build them once and just hide
201 * those that shouldn't be visible.
202 *
203 * @param displayedPlugins A set of plugins that are currently visible.
204 */
205 private void hidePluginsNotInList(Set<PluginInformation> displayedPlugins) {
206 synchronized (getTreeLock()) {
207 for (int i = 0; i < getComponentCount(); i++) {
208 JComponent component = (JComponent) getComponent(i);
209 Object plugin = component.getClientProperty("plugin");
210 if ("empty".equals(plugin)) {
211 // Hide the empty plugin list warning if it's there
212 component.setVisible(displayedPlugins.isEmpty());
213 } else {
214 component.setVisible(displayedPlugins.contains(plugin));
215 }
216 }
217 }
218 }
219
220 /**
221 * Causes the components for the list items to be rebuilt from scratch.
222 *
223 * Should be called before calling {@link #refreshView()} whenever the
224 * underlying list changes to display a completely different set of
225 * plugins instead of merely hiding plugins by a filter.
226 */
227 public void resetDisplayedComponents() {
228 pluginListInitialized = false;
229 }
230
231 @Override
232 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
233 return visibleRect.height / 4;
234 }
235
236 @Override
237 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
238 return visibleRect.height;
239 }
240}
Note: See TracBrowser for help on using the repository browser.