ChangeScreen: Show file size increase/decrease for binary files

Reviewers are interested in the size of a change that was done to a
file. This is why for non-binary files the number of inserted/deleted
lines is shown. So far for binary files there was no indication of how
big the change was, but now the file size increase/decrease is shown.

Change-Id: Ie595754af1536ce430206c2553a7656f526d7769
Signed-off-by: Edwin Kempin <ekempin@google.com>
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
index b21078e..d95f9ef 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
@@ -30,6 +30,15 @@
   public final native boolean binary() /*-{ return this.binary || false; }-*/;
   public final native String status() /*-{ return this.status; }-*/;
 
+
+  // JSNI methods cannot have 'long' as a parameter type or a return type and
+  // it's suggested to use double in this case:
+  // http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html#important
+  public final long sizeDelta() {
+    return (long)_sizeDelta();
+  }
+  private final native double _sizeDelta() /*-{ return this.size_delta || 0; }-*/;
+
   public final native int _row() /*-{ return this._row }-*/;
   public final native void _row(int r) /*-{ this._row = r }-*/;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
index 80aa9cc..08fe75d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
@@ -17,6 +17,7 @@
 import com.google.gerrit.client.info.AccountInfo;
 import com.google.gerrit.client.info.AccountPreferencesInfo;
 import com.google.gerrit.reviewdb.client.Account;
+import com.google.gwt.i18n.client.NumberFormat;
 
 import java.util.Date;
 
@@ -107,4 +108,19 @@
   private static AccountFormatter createAccountFormatter() {
     return new AccountFormatter(Gerrit.info().user().anonymousCowardName());
   }
+
+  public static String formatBytes(long bytes) {
+    if (bytes == 0) {
+      return "+/- 0 B";
+    }
+
+    if (Math.abs(bytes) < 1024) {
+      return (bytes > 0 ? "+" : "") + bytes + " B";
+    }
+
+    int exp = (int) (Math.log(Math.abs(bytes)) / Math.log(1024));
+    return (bytes > 0 ? "+" : "")
+        + NumberFormat.getFormat("#.0").format(bytes / Math.pow(1024, exp))
+        + " " + "KMGTPE".charAt(exp - 1) + "iB";
+  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index ad61446..932cda4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.client.change;
 
 import com.google.gerrit.client.Dispatcher;
+import com.google.gerrit.client.FormatUtil;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.VoidResult;
 import com.google.gerrit.client.changes.ChangeApi;
@@ -750,6 +751,8 @@
               .append(info.linesDeleted());
           }
         }
+      } else if (info.binary()) {
+        sb.append(FormatUtil.formatBytes(info.sizeDelta()));
       }
       sb.closeTd();
     }
diff --git a/gerrit-gwtui/src/test/java/com/google/gerrit/client/FormatUtilTest.java b/gerrit-gwtui/src/test/java/com/google/gerrit/client/FormatUtilTest.java
new file mode 100644
index 0000000..6ea09fd
--- /dev/null
+++ b/gerrit-gwtui/src/test/java/com/google/gerrit/client/FormatUtilTest.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client;
+
+import static org.junit.Assert.assertEquals;
+
+import com.googlecode.gwt.test.GwtModule;
+import com.googlecode.gwt.test.GwtTest;
+
+import static com.google.gerrit.client.FormatUtil.formatBytes;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+@GwtModule("com.google.gerrit.GerritGwtUI")
+@Ignore
+public class FormatUtilTest extends GwtTest {
+  @Test
+  public void testFormatBytes() {
+    assertEquals("+/- 0 B", formatBytes(0));
+    assertEquals("+27 B", formatBytes(27));
+    assertEquals("+999 B", formatBytes(999));
+    assertEquals("+1000 B", formatBytes(1000));
+    assertEquals("+1023 B", formatBytes(1023));
+    assertEquals("+1.0 KiB", formatBytes(1024));
+    assertEquals("+1.7 KiB", formatBytes(1728));
+    assertEquals("+108.0 KiB", formatBytes(110592));
+    assertEquals("+6.8 MiB", formatBytes(7077888));
+    assertEquals("+432.0 MiB", formatBytes(452984832));
+    assertEquals("+27.0 GiB", formatBytes(28991029248L));
+    assertEquals("+1.7 TiB", formatBytes(1855425871872L));
+    assertEquals("+8.0 EiB", formatBytes(9223372036854775807L));
+
+    assertEquals("-27 B", formatBytes(-27));
+    assertEquals("-1.7 MiB", formatBytes(-1728));
+  }
+}