Support boolean project specific plugin parameters for edit in UI

Change-Id: I2a2955f3e1f158b5aa6d0f45fb5adf5ef7da6e84
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 16e901a..2b07cf7 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -688,9 +688,12 @@
 variable name is case-insensitive, allows only alphanumeric characters
 and '-', and must start with an alphabetic character.
 
-The example below shows how the parameter `plugin.helloworld.language`
-is bound to be editable from the WebUI. "Preferred Language" is
-provided as display name and "en" is set as default value.
+The example below shows how the parameters `plugin.helloworld.enabled`
+and `plugin.helloworld.language` are bound to be editable from the
+WebUI. For the parameter `plugin.helloworld.enabled` "Enable Greeting"
+is provided as display name and the default value is set to `true`.
+For the parameter `plugin.helloworld.language` "Preferred Language"
+is provided as display name and "en" is set as default value.
 
 [source,java]
 ----
@@ -698,6 +701,9 @@
   @Override
   protected void configure() {
     bind(ProjectConfigEntry.class)
+        .annotatedWith(Exports.named("enabled"))
+        .toInstance(new ProjectConfigEntry("Enable Greeting", true));
+    bind(ProjectConfigEntry.class)
         .annotatedWith(Exports.named("language"))
         .toInstance(new ProjectConfigEntry("Preferred Language", "en"));
   }
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index f1bfac2..5b2d7c2 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -1295,8 +1295,8 @@
 |`display_name`    |optional|
 The display name of the configuration parameter.
 |`type`            ||
-The type of the configuration parameter, can be `STRING`, `INT` or
-`LONG`.
+The type of the configuration parameter, can be `STRING`, `INT`, `LONG`
+or `BOOLEAN`.
 |`value`           |optional|
 The value of the configuration parameter as string.
 |===============================
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index 154355a..bd5cc0b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -42,6 +42,7 @@
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
 import com.google.gwt.user.client.ui.FlexTable;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.FocusWidget;
@@ -368,6 +369,8 @@
           w = renderTextBox(g, param, false);
         } else if ("INT".equals(param.type()) || "LONG".equals(param.type())) {
           w = renderTextBox(g, param, true);
+        } else if ("BOOLEAN".equals(param.type())) {
+          w = renderCheckBox(g, param);
         } else {
           continue;
         }
@@ -382,12 +385,24 @@
       ConfigParameterInfo param, boolean numbersOnly) {
     NpTextBox textBox = numbersOnly ? new NpIntTextBox() : new NpTextBox();
     textBox.setValue(param.value());
-    g.add(param.displayName() != null
-        ? param.displayName() : param.name(), textBox);
+    g.add(getDisplayName(param), textBox);
     saveEnabler.listenTo(textBox);
     return textBox;
   }
 
+  private CheckBox renderCheckBox(LabeledWidgetsGrid g,
+      ConfigParameterInfo param) {
+    CheckBox checkBox = new CheckBox(getDisplayName(param));
+    checkBox.setValue(Boolean.parseBoolean(param.value()));
+    g.add(null, checkBox);
+    saveEnabler.listenTo(checkBox);
+    return checkBox;
+  }
+
+  private String getDisplayName(ConfigParameterInfo param) {
+    return param.displayName() != null ? param.displayName() : param.name();
+  }
+
   private void initProjectActions(ConfigInfo info) {
     actionsGrid.clear(true);
     actionsGrid.removeAllRows();
@@ -443,6 +458,8 @@
         FocusWidget widget = e2.getValue();
         if (widget instanceof TextBox) {
           values.put(e2.getKey(), ((TextBox) widget).getValue().trim());
+        } else if (widget instanceof CheckBox) {
+          values.put(e2.getKey(), Boolean.toString(((CheckBox) widget).getValue()));
         }
       }
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectConfigEntry.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectConfigEntry.java
index df6e36b..5871d96 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectConfigEntry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectConfigEntry.java
@@ -19,7 +19,7 @@
 @ExtensionPoint
 public class ProjectConfigEntry {
   public enum Type {
-    STRING, INT, LONG
+    STRING, INT, LONG, BOOLEAN
   }
 
   private final String displayName;
@@ -38,6 +38,10 @@
     this(displayName, Long.toString(defaultValue), Type.LONG);
   }
 
+  public ProjectConfigEntry(String displayName, boolean defaultValue) {
+    this(displayName, Boolean.toString(defaultValue), Type.BOOLEAN);
+  }
+
   private ProjectConfigEntry(String displayName, String defaultValue, Type type) {
     this.displayName = displayName;
     this.defaultValue = defaultValue;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
index 9e5c00c..fb18c1a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
@@ -192,6 +192,9 @@
           if (v.getValue() != null) {
             try {
               switch (projectConfigEntry.getType()) {
+                case BOOLEAN:
+                  cfg.setBoolean(v.getKey(), Boolean.parseBoolean(v.getValue()));
+                  break;
                 case INT:
                   cfg.setInt(v.getKey(), Integer.parseInt(v.getValue()));
                   break;