InlineEdit: Make cursor blink rate customizable

Codemirror supports out of the box customizability of cursor blink
rate. Half-period in milliseconds is used for cursor blinking. The
default blink rate in Codemirror is 530ms. Default in inline editor
is 0: blinking is disabled.

Change-Id: Ie54063f3ba11e98dcebaf727e29b50093258c028
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index cb17c5d..26c6fcc 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -1342,6 +1342,7 @@
     "key_map_type": "VIM",
     "tab_size": 4,
     "line_length": 80,
+    "cursor_blink_rate": 530,
     "hide_top_menu": true,
     "show_whitespace_errors": true,
     "hide_line_numbers": true
@@ -1369,6 +1370,7 @@
     "key_map_type": "VIM",
     "tab_size": 4,
     "line_length": 80,
+    "cursor_blink_rate": 530,
     "hide_top_menu": true,
     "show_tabs": true,
     "show_whitespace_errors": true,
@@ -1766,6 +1768,9 @@
 Number of spaces that should be used to display one tab.
 |`line_length`                 ||
 Number of characters that should be displayed per line.
+|`cursor_blink_rate`           ||
+Half-period in milliseconds used for cursor blinking.
+Setting it to 0 disables cursor blinking.
 |`hide_top_menu`               |not set if `false`|
 If true the top menu header and site header is hidden.
 |`show_tabs`                   |not set if `false`|
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java
index d58133c..c225c32 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/EditPreferencesIT.java
@@ -37,6 +37,7 @@
 
     assertThat(out.lineLength).isEqualTo(100);
     assertThat(out.tabSize).isEqualTo(8);
+    assertThat(out.cursorBlinkRate).isEqualTo(0);
     assertThat(out.hideTopMenu).isNull();
     assertThat(out.showTabs).isTrue();
     assertThat(out.showWhitespaceErrors).isNull();
@@ -48,6 +49,7 @@
     // change some default values
     out.lineLength = 80;
     out.tabSize = 4;
+    out.cursorBlinkRate = 500;
     out.hideTopMenu = true;
     out.showTabs = false;
     out.showWhitespaceErrors = true;
@@ -75,6 +77,7 @@
       EditPreferencesInfo in) {
     assertThat(out.lineLength).isEqualTo(in.lineLength);
     assertThat(out.tabSize).isEqualTo(in.tabSize);
+    assertThat(out.cursorBlinkRate).isEqualTo(in.cursorBlinkRate);
     assertThat(out.hideTopMenu).isEqualTo(in.hideTopMenu);
     assertThat(out.showTabs).isNull();
     assertThat(out.showWhitespaceErrors).isEqualTo(in.showWhitespaceErrors);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java
index aafd60ad..74527e3 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java
@@ -18,6 +18,7 @@
 public class EditPreferencesInfo {
   public Integer tabSize;
   public Integer lineLength;
+  public Integer cursorBlinkRate;
   public Boolean hideTopMenu;
   public Boolean showTabs;
   public Boolean showWhitespaceErrors;
@@ -30,6 +31,7 @@
     EditPreferencesInfo i = new EditPreferencesInfo();
     i.tabSize = 8;
     i.lineLength = 100;
+    i.cursorBlinkRate = 0;
     i.hideTopMenu = false;
     i.showTabs = true;
     i.showWhitespaceErrors = false;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
index e2cda8f..9297bff 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
@@ -24,6 +24,7 @@
     EditPreferences p = createObject().cast();
     p.tabSize(in.tabSize);
     p.lineLength(in.lineLength);
+    p.cursorBlinkRate(in.cursorBlinkRate);
     p.hideTopMenu(in.hideTopMenu);
     p.showTabs(in.showTabs);
     p.showWhitespaceErrors(in.showWhitespaceErrors);
@@ -37,6 +38,7 @@
   public final void copyTo(EditPreferencesInfo p) {
     p.tabSize = tabSize();
     p.lineLength = lineLength();
+    p.cursorBlinkRate = cursorBlinkRate();
     p.hideTopMenu = hideTopMenu();
     p.showTabs = showTabs();
     p.showWhitespaceErrors = showWhitespaceErrors();
@@ -58,6 +60,7 @@
 
   public final native void tabSize(int t) /*-{ this.tab_size = t }-*/;
   public final native void lineLength(int c) /*-{ this.line_length = c }-*/;
+  public final native void cursorBlinkRate(int r) /*-{ this.cursor_blink_rate = r }-*/;
   public final native void hideTopMenu(boolean s) /*-{ this.hide_top_menu = s }-*/;
   public final native void showTabs(boolean s) /*-{ this.show_tabs = s }-*/;
   public final native void showWhitespaceErrors(boolean s) /*-{ this.show_whitespace_errors = s }-*/;
@@ -78,6 +81,7 @@
 
   public final int tabSize() {return get("tab_size", 8); }
   public final int lineLength() {return get("line_length", 100); }
+  public final int cursorBlinkRate() {return get("cursor_blink_rate", 0); }
   public final native boolean hideTopMenu() /*-{ return this.hide_top_menu || false }-*/;
   public final native boolean showTabs() /*-{ return this.show_tabs || false }-*/;
   public final native boolean showWhitespaceErrors() /*-{ return this.show_whitespace_errors || false }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java
index 62b226a..5fd39d2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java
@@ -56,6 +56,7 @@
   @UiField Anchor close;
   @UiField NpIntTextBox tabWidth;
   @UiField NpIntTextBox lineLength;
+  @UiField NpIntTextBox cursorBlinkRate;
   @UiField ToggleButton topMenu;
   @UiField ToggleButton syntaxHighlighting;
   @UiField ToggleButton showTabs;
@@ -78,6 +79,7 @@
 
     tabWidth.setIntValue(prefs.tabSize());
     lineLength.setIntValue(prefs.lineLength());
+    cursorBlinkRate.setIntValue(prefs.cursorBlinkRate());
     topMenu.setValue(!prefs.hideTopMenu());
     syntaxHighlighting.setValue(prefs.syntaxHighlighting());
     showTabs.setValue(prefs.showTabs());
@@ -105,6 +107,17 @@
     }
   }
 
+  @UiHandler("cursorBlinkRate")
+  void onCursoBlinkRate(ValueChangeEvent<String> e) {
+    String v = e.getValue();
+    if (v != null && v.length() > 0) {
+      // A negative value hides the cursor entirely:
+      // don't let user shoot himself in the foot.
+      prefs.cursorBlinkRate(Math.max(0, Integer.parseInt(v)));
+      view.getEditor().setOption("cursorBlinkRate", prefs.cursorBlinkRate());
+    }
+  }
+
   @UiHandler("topMenu")
   void onTopMenu(ValueChangeEvent<Boolean> e) {
     prefs.hideTopMenu(!e.getValue());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml
index 0b610b2..0ae8374 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml
@@ -182,6 +182,12 @@
             alignment='RIGHT'/></td>
       </tr>
       <tr>
+        <th><ui:msg>Cursor Blink Rate</ui:msg></th>
+        <td><x:NpIntTextBox ui:field='cursorBlinkRate'
+            visibleLength='4'
+            alignment='RIGHT'/></td>
+      </tr>
+      <tr>
         <th><ui:msg>Top Menu</ui:msg></th>
         <td><g:ToggleButton ui:field='topMenu'>
           <g:upFace><ui:msg>Hide</ui:msg></g:upFace>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
index 7526d4e..f99261c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
@@ -441,7 +441,7 @@
     cm = CodeMirror.create(editor, Configuration.create()
         .set("value", content)
         .set("readOnly", false)
-        .set("cursorBlinkRate", 0)
+        .set("cursorBlinkRate", prefs.cursorBlinkRate())
         .set("cursorHeight", 0.85)
         .set("lineNumbers", prefs.hideLineNumbers())
         .set("tabSize", prefs.tabSize())