From 3a3416d2a51f873b27f1eb5c5f100183f3e3b475 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Wed, 4 Dec 2019 17:01:29 +0000
Subject: [PATCH] Console: Sort summary bar services section Simplify data
 structures in NavHelper Index NavHelper map by untranslated app name
 NavHelper cleanups

---
 .../src/net/i2p/router/web/NavHelper.java     | 93 +++++++++----------
 .../web/helpers/SummaryBarRenderer.java       | 75 +++++++++------
 2 files changed, 94 insertions(+), 74 deletions(-)

diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java
index 9155d6808d..0b89b6685e 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java
@@ -2,24 +2,24 @@ package net.i2p.router.web;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import net.i2p.I2PAppContext;
-import net.i2p.router.web.App;
 
 public class NavHelper {
-    private static final Map<String, String> _apps = new ConcurrentHashMap<String, String>(4);
-    private static final Map<String, String> _tooltips = new ConcurrentHashMap<String, String>(4);
-    private static final Map<String, String> _icons = new ConcurrentHashMap<String, String>(4);
+    // both indexed by standard (untranslated) app name
+    private static final Map<String, App> _apps = new ConcurrentHashMap<String, App>(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
      * 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
      * @param path full path pointing to the application's root 
      *             (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
      * @since 0.9.20 added iconpath parameter
      */
-    public static void registerApp(String name, String path, String tooltip, String iconpath) {
-        _apps.put(name, path);
-        if (tooltip != null)
-            _tooltips.put(name, tooltip);
-        if (iconpath != null && iconpath.startsWith("/"))
-            _icons.put(name, iconpath);
-
+    public static void registerApp(String appName, String displayName, String path, String tooltip, String iconpath) {
+        if (iconpath != null && !iconpath.startsWith("/"))
+            iconpath = null;
+        _apps.put(appName, new App(displayName, tooltip, path, iconpath));
     }
 
+    /**
+     * @param name standard name for the app
+     */
     public static void unregisterApp(String name) {
         _apps.remove(name);
-        _tooltips.remove(name);
-        _icons.remove(name);
     }
     
     /**
@@ -67,76 +65,77 @@ public class NavHelper {
 
     /**
      *  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())
-            return;
-        List<String> l = new ArrayList<String>(_apps.keySet());
-        Collections.sort(l);
-        for (String name : l) {
-            String path = _apps.get(name);
+            return null;
+        Map<String, String> rv = new HashMap<String, String>(_apps.size());
+        StringBuilder buf = new StringBuilder(128);
+        for (Map.Entry<String, App> e : _apps.entrySet()) {
+            String appName = e.getKey();
+            App app = e.getValue();
+            String path = app.url;
             if (path == null)
                 continue;
+            String name = app.name;
+            buf.setLength(0);
             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("\" ");
-            String tip = _tooltips.get(name);
+            String tip = app.desc;
             if (tip != null)
                 buf.append("title=\"").append(tip).append("\" ");
             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
-     *  @param name warning this is the display name aka ConsoleLinkName, not the plugin name
+     *  Get 16x16 icon img and append to buf
+     *  @param name standard app name
      *  @since 0.9.45
      */
-    static void getClientAppImg(StringBuilder buf, String name) {
-        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);
+    private static void getClientAppImg(StringBuilder buf, String name, String iconpath) {
             if (iconpath != null) {
                 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=\"\">");
             } else if (name.equals("i2pbote")) {
                 buf.append("<img src=\"/themes/console/light/images/mail_black.png\" alt=\"\">");
             } else {
                 buf.append("<img src=\"/themes/console/images/plugin.png\" height=\"16\" width=\"16\" alt=\"\">");
             }
-        }
     }
 
     /**
-     *  For HomeHelper
+     *  For HomeHelper. 32x32 icon paths.
      *  @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
      */
     public static List<App> getClientApps(I2PAppContext ctx) {
         if (_apps.isEmpty())
             return Collections.emptyList();
         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 path = e.getValue();
-            if (path == null)
+            App mapp = e.getValue();
+            if (mapp.url == null)
                 continue;
-            String tip = _tooltips.get(name);
+            String tip = mapp.desc;
             if (tip == null)
                 tip = "";
-            String icon;
-            if (_icons.containsKey(name))
-                icon = _icons.get(name);
-            // hardcoded hack
-            else if (path.equals("/i2pbote/index.jsp"))
-                icon = "/themes/console/images/email.png";
-            else
-                icon = "/themes/console/images/plugin.png";
-            App app = new App(name, tip, path, icon);
+            String icon = mapp.icon;
+            if (icon == null) {
+                // hardcoded hack
+                if (name.equals("i2pbote"))
+                    icon = "/themes/console/images/email.png";
+                else
+                    icon = "/themes/console/images/plugin.png";
+            }
+            App app = new App(mapp.name, tip, mapp.url, icon);
             rv.add(app);
         }
         return rv;
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java
index efd99e2257..4fd0666cd8 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java
@@ -3,8 +3,10 @@ package net.i2p.router.web.helpers;
 import java.io.File;
 import java.io.IOException;
 import java.io.Writer;
+import java.text.Collator;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.TreeMap;
 import java.util.List;
 import java.util.Map;
 
@@ -201,47 +203,66 @@ class SummaryBarRenderer {
            .append("</a></h3>\n" +
                    "<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();
         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\">");
-           buf.append("<a href=\"/webmail\" target=\"_top\" title=\"")
-           .append(_t("Anonymous webmail client"))
-           .append("\">")
-           .append(nbsp(_t("Email")))
-           .append("</a></td></tr>\n");
+            String tx = _t("Email");
+            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("\">")
+                .append(nbsp(tx))
+                .append("</a></td></tr>\n");
+            svcs.put(tx, rbuf.toString());
         }
 
         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\">");
-           buf.append("<a href=\"/jsonrpc/\" target=\"_top\" title=\"")
-           .append(_t("RPC Service"))
-           .append("\">")
-           .append(nbsp(_t("I2PControl")))
-           .append("</a></td></tr>\n");
+            String tx = _t("I2PControl");
+            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("\">")
+                .append(nbsp(tx))
+                .append("</a></td></tr>\n");
+            svcs.put(tx, rbuf.toString());
         }
 
         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\">");
-           buf.append("<a href=\"/torrents\" target=\"_top\" title=\"")
-           .append(_t("Built-in anonymous BitTorrent Client"))
-           .append("\">")
-           .append(nbsp(_t("Torrents")))
-           .append("</a></td></tr>\n");
+            String tx = _t("Torrents");
+            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("\">")
+                .append(nbsp(tx))
+                .append("</a></td></tr>\n");
+            svcs.put(tx, rbuf.toString());
         }
 
         String url = getEepsiteURL(pm);
         if (url != null) {
-            buf.append("<tr><td><img src=\"/themes/console/images/server.png\" height=\"16\" width=\"16\" alt=\"\"></td><td align=\"left\">");
-            buf.append("<a href=\"")
-               .append(url)
-               .append("\" target=\"_blank\" title=\"")
-               .append(_t("Local web server"))
-               .append("\">")
-               .append(nbsp(_t("Web Server")))
-               .append("</a></td></tr>\n");
+            String tx = _t("Web Server");
+            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("\" target=\"_blank\" title=\"")
+                .append(_t("Local web server"))
+               . append("\">")
+                .append(nbsp(tx))
+                .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");
         return buf.toString();
     }
-- 
GitLab