Console: Sort summary bar services section

Simplify data structures in NavHelper
Index NavHelper map by untranslated app name
NavHelper cleanups
This commit is contained in:
zzz
2019-12-04 17:01:29 +00:00
parent 00667151da
commit 3a3416d2a5
2 changed files with 94 additions and 74 deletions

View File

@ -2,24 +2,24 @@ package net.i2p.router.web;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.router.web.App;
public class NavHelper { public class NavHelper {
private static final Map<String, String> _apps = new ConcurrentHashMap<String, String>(4); // both indexed by standard (untranslated) app name
private static final Map<String, String> _tooltips = new ConcurrentHashMap<String, String>(4); private static final Map<String, App> _apps = new ConcurrentHashMap<String, App>(4);
private static final Map<String, String> _icons = new ConcurrentHashMap<String, String>(4);
private static final Map<String, byte[]> _binary = new ConcurrentHashMap<String, byte[]>(4); private static final Map<String, byte[]> _binary = new ConcurrentHashMap<String, byte[]>(4);
/** /**
* To register a new client application so that it shows up on the router * To register a new client application so that it shows up on the router
* console's nav bar, it should be registered with this singleton. * console's nav bar, it should be registered with this singleton.
* *
* @param name pretty name the app will be called in the link * @param name standard name for the app (plugin)
* @param displayName translated name the app will be called in the link
* warning, this is the display name aka ConsoleLinkName, not the plugin name * warning, this is the display name aka ConsoleLinkName, not the plugin name
* @param path full path pointing to the application's root * @param path full path pointing to the application's root
* (e.g. /i2ptunnel/index.jsp), non-null * (e.g. /i2ptunnel/index.jsp), non-null
@ -27,19 +27,17 @@ public class NavHelper {
* @param iconpath path-only URL starting with /, HTML escaped, or null * @param iconpath path-only URL starting with /, HTML escaped, or null
* @since 0.9.20 added iconpath parameter * @since 0.9.20 added iconpath parameter
*/ */
public static void registerApp(String name, String path, String tooltip, String iconpath) { public static void registerApp(String appName, String displayName, String path, String tooltip, String iconpath) {
_apps.put(name, path); if (iconpath != null && !iconpath.startsWith("/"))
if (tooltip != null) iconpath = null;
_tooltips.put(name, tooltip); _apps.put(appName, new App(displayName, tooltip, path, iconpath));
if (iconpath != null && iconpath.startsWith("/"))
_icons.put(name, iconpath);
} }
/**
* @param name standard name for the app
*/
public static void unregisterApp(String name) { public static void unregisterApp(String name) {
_apps.remove(name); _apps.remove(name);
_tooltips.remove(name);
_icons.remove(name);
} }
/** /**
@ -67,40 +65,42 @@ public class NavHelper {
/** /**
* Translated string is loaded by PluginStarter * Translated string is loaded by PluginStarter
* @param buf appended to * @return map of translated name to HTML string, or null if none
*/ */
public static void getClientAppLinks(StringBuilder buf) { public static Map<String, String> getClientAppLinks() {
if (_apps.isEmpty()) if (_apps.isEmpty())
return; return null;
List<String> l = new ArrayList<String>(_apps.keySet()); Map<String, String> rv = new HashMap<String, String>(_apps.size());
Collections.sort(l); StringBuilder buf = new StringBuilder(128);
for (String name : l) { for (Map.Entry<String, App> e : _apps.entrySet()) {
String path = _apps.get(name); String appName = e.getKey();
App app = e.getValue();
String path = app.url;
if (path == null) if (path == null)
continue; continue;
String name = app.name;
buf.setLength(0);
buf.append("<tr><td>"); buf.append("<tr><td>");
getClientAppImg(buf, name); getClientAppImg(buf, appName, app.icon);
buf.append("</td><td align=\"left\"><a target=\"_blank\" href=\"").append(path).append("\" "); buf.append("</td><td align=\"left\"><a target=\"_blank\" href=\"").append(path).append("\" ");
String tip = _tooltips.get(name); String tip = app.desc;
if (tip != null) if (tip != null)
buf.append("title=\"").append(tip).append("\" "); buf.append("title=\"").append(tip).append("\" ");
buf.append('>').append(name.replace(" ", "&nbsp;")).append("</a></td></tr>\n"); buf.append('>').append(name.replace(" ", "&nbsp;")).append("</a></td></tr>\n");
rv.put(name, buf.toString());
} }
return rv;
} }
/** /**
* Get icon img and append to buf * Get 16x16 icon img and append to buf
* @param name warning this is the display name aka ConsoleLinkName, not the plugin name * @param name standard app name
* @since 0.9.45 * @since 0.9.45
*/ */
static void getClientAppImg(StringBuilder buf, String name) { private static void getClientAppImg(StringBuilder buf, String name, String iconpath) {
if (_binary.containsKey(name)) {
buf.append("<img src=\"/Plugins/pluginicon?plugin=").append(name).append("\" height=\"16\" width=\"16\" alt=\"\">");
} else {
String iconpath = _icons.get(name);
if (iconpath != null) { if (iconpath != null) {
buf.append("<img src=\"").append(iconpath).append("\" height=\"16\" width=\"16\" alt=\"\">"); buf.append("<img src=\"").append(iconpath).append("\" height=\"16\" width=\"16\" alt=\"\">");
} else if (name.equals("Orchid")) { } else if (name.equals("orchid")) {
buf.append("<img src=\"/themes/console/light/images/flower.png\" alt=\"\">"); buf.append("<img src=\"/themes/console/light/images/flower.png\" alt=\"\">");
} else if (name.equals("i2pbote")) { } else if (name.equals("i2pbote")) {
buf.append("<img src=\"/themes/console/light/images/mail_black.png\" alt=\"\">"); buf.append("<img src=\"/themes/console/light/images/mail_black.png\" alt=\"\">");
@ -108,35 +108,34 @@ public class NavHelper {
buf.append("<img src=\"/themes/console/images/plugin.png\" height=\"16\" width=\"16\" alt=\"\">"); buf.append("<img src=\"/themes/console/images/plugin.png\" height=\"16\" width=\"16\" alt=\"\">");
} }
} }
}
/** /**
* For HomeHelper * For HomeHelper. 32x32 icon paths.
* @param ctx unused * @param ctx unused
* @return non-null, possibly empty * @return non-null, possibly empty, unsorted
* @since 0.9, public since 0.9.33, was package private * @since 0.9, public since 0.9.33, was package private
*/ */
public static List<App> getClientApps(I2PAppContext ctx) { public static List<App> getClientApps(I2PAppContext ctx) {
if (_apps.isEmpty()) if (_apps.isEmpty())
return Collections.emptyList(); return Collections.emptyList();
List<App> rv = new ArrayList<App>(_apps.size()); List<App> rv = new ArrayList<App>(_apps.size());
for (Map.Entry<String, String> e : _apps.entrySet()) { for (Map.Entry<String, App> e : _apps.entrySet()) {
String name = e.getKey(); String name = e.getKey();
String path = e.getValue(); App mapp = e.getValue();
if (path == null) if (mapp.url == null)
continue; continue;
String tip = _tooltips.get(name); String tip = mapp.desc;
if (tip == null) if (tip == null)
tip = ""; tip = "";
String icon; String icon = mapp.icon;
if (_icons.containsKey(name)) if (icon == null) {
icon = _icons.get(name);
// hardcoded hack // hardcoded hack
else if (path.equals("/i2pbote/index.jsp")) if (name.equals("i2pbote"))
icon = "/themes/console/images/email.png"; icon = "/themes/console/images/email.png";
else else
icon = "/themes/console/images/plugin.png"; icon = "/themes/console/images/plugin.png";
App app = new App(name, tip, path, icon); }
App app = new App(mapp.name, tip, mapp.url, icon);
rv.add(app); rv.add(app);
} }
return rv; return rv;

View File

@ -3,8 +3,10 @@ package net.i2p.router.web.helpers;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.text.Collator;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.TreeMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -201,47 +203,66 @@ class SummaryBarRenderer {
.append("</a></h3>\n" + .append("</a></h3>\n" +
"<hr class=\"b\"><table id=\"sb_services\">"); "<hr class=\"b\"><table id=\"sb_services\">");
// Store all items in map so they are sorted by translated name, add the plugins, then output
Map<String, String> svcs = new TreeMap<String, String>(Collator.getInstance());
StringBuilder rbuf = new StringBuilder(128);
PortMapper pm = _context.portMapper(); PortMapper pm = _context.portMapper();
if (pm.isRegistered(PortMapper.SVC_SUSIMAIL)) { if (pm.isRegistered(PortMapper.SVC_SUSIMAIL)) {
buf.append("<tr><td><img src=\"/themes/console/light/images/inbox.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">"); String tx = _t("Email");
buf.append("<a href=\"/webmail\" target=\"_top\" title=\"") rbuf.append("<tr><td><img src=\"/themes/console/light/images/inbox.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">" +
"<a href=\"/webmail\" target=\"_top\" title=\"")
.append(_t("Anonymous webmail client")) .append(_t("Anonymous webmail client"))
.append("\">") .append("\">")
.append(nbsp(_t("Email"))) .append(nbsp(tx))
.append("</a></td></tr>\n"); .append("</a></td></tr>\n");
svcs.put(tx, rbuf.toString());
} }
if (pm.isRegistered(PortMapper.SVC_JSONRPC)) { if (pm.isRegistered(PortMapper.SVC_JSONRPC)) {
buf.append("<tr><td><img src=\"/themes/console/images/plugin.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">"); String tx = _t("I2PControl");
buf.append("<a href=\"/jsonrpc/\" target=\"_top\" title=\"") rbuf.setLength(0);
rbuf.append("<tr><td><img src=\"/themes/console/images/plugin.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">" +
"<a href=\"/jsonrpc/\" target=\"_top\" title=\"")
.append(_t("RPC Service")) .append(_t("RPC Service"))
.append("\">") .append("\">")
.append(nbsp(_t("I2PControl"))) .append(nbsp(tx))
.append("</a></td></tr>\n"); .append("</a></td></tr>\n");
svcs.put(tx, rbuf.toString());
} }
if (pm.isRegistered(PortMapper.SVC_I2PSNARK)) { if (pm.isRegistered(PortMapper.SVC_I2PSNARK)) {
buf.append("<tr><td><img src=\"/themes/console/images/i2psnark.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">"); String tx = _t("Torrents");
buf.append("<a href=\"/torrents\" target=\"_top\" title=\"") rbuf.setLength(0);
rbuf.append("<tr><td><img src=\"/themes/console/images/i2psnark.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">" +
"<a href=\"/torrents\" target=\"_top\" title=\"")
.append(_t("Built-in anonymous BitTorrent Client")) .append(_t("Built-in anonymous BitTorrent Client"))
.append("\">") .append("\">")
.append(nbsp(_t("Torrents"))) .append(nbsp(tx))
.append("</a></td></tr>\n"); .append("</a></td></tr>\n");
svcs.put(tx, rbuf.toString());
} }
String url = getEepsiteURL(pm); String url = getEepsiteURL(pm);
if (url != null) { if (url != null) {
buf.append("<tr><td><img src=\"/themes/console/images/server.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">"); String tx = _t("Web Server");
buf.append("<a href=\"") rbuf.setLength(0);
rbuf.append("<tr><td><img src=\"/themes/console/images/server.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">" +
"<a href=\"")
.append(url) .append(url)
.append("\" target=\"_blank\" title=\"") .append("\" target=\"_blank\" title=\"")
.append(_t("Local web server")) .append(_t("Local web server"))
. append("\">") . append("\">")
.append(nbsp(_t("Web Server"))) .append(nbsp(tx))
.append("</a></td></tr>\n"); .append("</a></td></tr>\n");
svcs.put(tx, rbuf.toString());
} }
NavHelper.getClientAppLinks(buf); Map<String, String> apps = NavHelper.getClientAppLinks();
if (apps != null)
svcs.putAll(apps);
for (String row : svcs.values()) {
buf.append(row);
}
buf.append("</table>\n"); buf.append("</table>\n");
return buf.toString(); return buf.toString();
} }