Support CSS themes

This allows administrators to configure multiple default CSS themes
and projects can simply choose which one should be used. Also projects
can define CSS themes, e.g. if a new CSS theme is developed, this can
be done while still using the old theme and then switch to the new
theme when it is ready.

Change-Id: Ia7a36b8367d9d09da3775e9cb8e4e04122a319fe
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
index 473b740..4d859b5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
@@ -24,6 +24,7 @@
   public static final String SECTION_FORMATTER = "formatter";
   public static final String KEY_ALLOW_HTML = "allowHtml";
   public static final String KEY_APPEND_CSS = "appendCss";
+  public static final String KEY_CSS_THEME = "cssTheme";
   public static final String KEY_ENABLED = "enabled";
   public static final String KEY_EXT = "ext";
   public static final String KEY_FORMATTER = "formatter";
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
index eb3d4ae..fe57a90 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
@@ -16,6 +16,7 @@
 
 import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_ALLOW_HTML;
 import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_APPEND_CSS;
+import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_CSS_THEME;
 import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_INCLUDE_TOC;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
@@ -91,8 +92,9 @@
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         ByteStreams.copy(input, out);
         String html = out.toString(UTF_8.name());
-        String globalCss = util.getGlobalCss("asciidoctor");
-        String projectCss = util.getCss(projectName, "asciidoctor");
+        String cssTheme = projectCfg.getString(KEY_CSS_THEME);
+        String globalCss = util.getGlobalCss("asciidoctor", cssTheme);
+        String projectCss = util.getCss(projectName, "asciidoctor", cssTheme);
         if (projectCfg.getBoolean(KEY_APPEND_CSS, true)) {
           return util.insertCss(html,
               MoreObjects.firstNonNull(globalCss, defaultCss), projectCss);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
index 255876e..47aedf4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
@@ -17,6 +17,7 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
 
+import com.google.common.base.Strings;
 import com.google.gerrit.extensions.annotations.PluginData;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.reviewdb.client.Project;
@@ -56,6 +57,26 @@
   }
 
   /**
+   * Returns the CSS from the file "<plugin-name>/<name>-<theme>.css" in the
+   * refs/meta/config branch of the project.
+   *
+   * If theme is <code>null</code> or empty, the CSS from the file
+   * "<plugin-name>/<name>.css" is returned.
+   *
+   * @param name the name of the file in the "<plugin-name>/" folder without
+   *        theme and without the ".css" file extension
+   * @param theme the name of the CSS theme, may be <code>null</code>, if given
+   *        it is included into the CSS file name: '<name>-<theme>.css'
+   * @return the CSS from the file; HTML characters are escaped;
+   *         <code>null</code> if the file doesn't exist
+   */
+  public String getCss(String projectName, String name, String theme) {
+    return Strings.isNullOrEmpty(theme)
+        ? getCss(projectName, name)
+        : getCss(projectName, name + "-" + theme);
+  }
+
+  /**
    * Returns the CSS from the file "<plugin-name>/<name>.css" in the
    * refs/meta/config branch of the project.
    *
@@ -70,6 +91,28 @@
 
   /**
    * Returns the CSS from the file
+   * "<review-site>/data/<plugin-name>/css/<name>-<theme>.css".
+   *
+   * If theme is <code>null</code> or empty, the CSS from the file
+   * "<review-site>/data/<plugin-name>/css/<name>.css" is returned.
+   *
+   * @param name the name of the CSS file without theme and without the ".css"
+   *        file extension
+   * @param theme the name of the CSS theme, may be <code>null</code>, if given
+   *        it is included into the CSS file name: '<name>-<theme>.css'
+   * @return the CSS from the file; HTML characters are escaped;
+   *         <code>null</code> if the file doesn't exist
+   * @throws IOException thrown in case of an I/O Error while reading the CSS
+   *         file
+   */
+  public String getGlobalCss(String name, String theme) throws IOException {
+    return Strings.isNullOrEmpty(theme)
+        ? getGlobalCss(name)
+        : getGlobalCss(name + "-" + theme);
+  }
+
+  /**
+   * Returns the CSS from the file
    * "<review-site>/data/<plugin-name>/css/<name>.css".
    *
    * @param name the name of the CSS file without the ".css" file extension
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
index 4f23ad9..f4aa3a8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/MarkdownFormatter.java
@@ -16,6 +16,7 @@
 
 import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_ALLOW_HTML;
 import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_APPEND_CSS;
+import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_CSS_THEME;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.inject.Inject;
@@ -48,8 +49,9 @@
     if (!globalCfg.getBoolean(KEY_ALLOW_HTML, false)) {
       f.suppressHtml();
     }
-    String globalCss = util.getGlobalCss("markdown");
-    String projectCss = util.getCss(projectName, "markdown");
+    String cssTheme = projectCfg.getString(KEY_CSS_THEME);
+    String globalCss = util.getGlobalCss("markdown", cssTheme);
+    String projectCss = util.getCss(projectName, "markdown", cssTheme);
     if (projectCfg.getBoolean(KEY_APPEND_CSS, true)) {
       // if there is no global CSS and f.setCss(null) is invoked
       // com.google.gerrit.server.documentation.MarkdownFormatter applies the
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index aef00c5..8cdf98c 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -84,6 +84,21 @@
 
 	Default: `true` (project-specific CSS is appended to the default CSS)
 
+<a id="cssTheme">
+formatter.<formatter>.cssTheme
+:	The name of the CSS theme that should be used.
+
+	The theme name is included into the file name when loading a CSS
+	file, e.g. `@PLUGIN@/markdown-<theme-name>.css` when loading
+	project specific CSS from the project's `refs/meta/config` branch.
+
+	Overrides the [global configuration of `cssTheme`](#formatterCssTheme)
+	for this formatter.
+
+	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+
+	By default not set.
+
 <a id="prio">
 formatter.<formatter>.prio
 :	The priority of this formatter.
@@ -215,6 +230,19 @@
 
 	Default: `true` (project-specific CSS is appended to the default CSS)
 
+<a id="formatterCssTheme">
+formatter.<formatter>.cssTheme
+:	The name of the CSS theme that should be used.
+
+	The theme name is included into the file name when loading a CSS
+	file, e.g. `<review-site>/data/@PLUGIN@/css/markdown-<theme-name>.css`
+
+	Can be overridden on [project-level](#cssTheme).
+
+	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+
+	By default not set.
+
 <a id="formatterPrio">
 formatter.<formatter>.prio
 :	The priority of this formatter.