summaryrefslogtreecommitdiffstats
path: root/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java')
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java357
1 files changed, 357 insertions, 0 deletions
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
new file mode 100644
index 0000000000..7e6805233b
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
@@ -0,0 +1,357 @@
+// Copyright (C) 2008 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.patches;
+
+import static com.google.gerrit.client.patches.PatchLine.Type.CONTEXT;
+import static com.google.gerrit.client.patches.PatchLine.Type.DELETE;
+import static com.google.gerrit.client.patches.PatchLine.Type.INSERT;
+
+import com.google.gerrit.common.data.CommentDetail;
+import com.google.gerrit.common.data.EditList;
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.common.data.SparseFileContent;
+import com.google.gerrit.common.data.EditList.Hunk;
+import com.google.gerrit.common.data.PatchScript.DisplayMethod;
+import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.PatchLineComment;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
+import com.google.gwtexpui.safehtml.client.PrettyFormatter;
+import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
+import com.google.gwtorm.client.KeyUtil;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+public class UnifiedDiffTable extends AbstractPatchContentTable {
+ private static final int PC = 3;
+ private static final Comparator<PatchLineComment> BY_DATE =
+ new Comparator<PatchLineComment>() {
+ public int compare(final PatchLineComment o1, final PatchLineComment o2) {
+ return o1.getWrittenOn().compareTo(o2.getWrittenOn());
+ }
+ };
+
+ @Override
+ protected void onCellDoubleClick(final int row, final int column) {
+ if (getRowItem(row) instanceof PatchLine) {
+ final PatchLine pl = (PatchLine) getRowItem(row);
+ switch (pl.getType()) {
+ case DELETE:
+ case CONTEXT:
+ createCommentEditor(row + 1, PC, pl.getLineA(), (short) 0);
+ break;
+ case INSERT:
+ createCommentEditor(row + 1, PC, pl.getLineB(), (short) 1);
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void onInsertComment(final PatchLine pl) {
+ final int row = getCurrentRow();
+ switch (pl.getType()) {
+ case DELETE:
+ case CONTEXT:
+ createCommentEditor(row + 1, PC, pl.getLineA(), (short) 0);
+ break;
+ case INSERT:
+ createCommentEditor(row + 1, PC, pl.getLineB(), (short) 1);
+ break;
+ }
+ }
+
+ private void appendImgTag(SafeHtmlBuilder nc, String url) {
+ nc.openElement("img");
+ nc.setAttribute("src", url);
+ nc.closeElement("img");
+ }
+
+ @Override
+ protected void render(final PatchScript script) {
+ final SparseFileContent a = script.getA();
+ final SparseFileContent b = script.getB();
+ final SafeHtmlBuilder nc = new SafeHtmlBuilder();
+ final PrettyFormatter fmtA = PrettyFormatter.newFormatter(formatLanguage);
+ final PrettyFormatter fmtB = PrettyFormatter.newFormatter(formatLanguage);
+
+ fmtB.setShowWhiteSpaceErrors(true);
+
+ // Display the patch header
+ for (final String line : script.getPatchHeader()) {
+ appendFileHeader(nc, line);
+ }
+
+ if (script.getDisplayMethodA() == DisplayMethod.IMG
+ || script.getDisplayMethodB() == DisplayMethod.IMG) {
+ final String rawBase = GWT.getHostPageBaseURL() + "cat/";
+
+ nc.openTr();
+ nc.setAttribute("valign", "center");
+ nc.setAttribute("align", "center");
+
+ nc.openTd();
+ nc.nbsp();
+ nc.closeTd();
+
+ nc.openTd();
+ nc.nbsp();
+ nc.closeTd();
+
+ nc.openTd();
+ nc.nbsp();
+ nc.closeTd();
+
+ nc.openTd();
+ if (script.getDisplayMethodA() == DisplayMethod.IMG) {
+ if (idSideA == null) {
+ appendImgTag(nc, rawBase + KeyUtil.encode(patchKey.toString()) + "^1");
+ } else {
+ Patch.Key k = new Patch.Key(idSideA, patchKey.get());
+ appendImgTag(nc, rawBase + KeyUtil.encode(k.toString()) + "^0");
+ }
+ }
+ if (script.getDisplayMethodB() == DisplayMethod.IMG) {
+ appendImgTag(nc, rawBase + KeyUtil.encode(patchKey.toString()) + "^0");
+ }
+ nc.closeTd();
+
+ nc.closeTr();
+ }
+
+ final ArrayList<PatchLine> lines = new ArrayList<PatchLine>();
+ for (final EditList.Hunk hunk : script.getHunks()) {
+ appendHunkHeader(nc, hunk);
+ while (hunk.next()) {
+ if (hunk.isContextLine()) {
+ openLine(nc);
+ appendLineNumber(nc, hunk.getCurA());
+ appendLineNumber(nc, hunk.getCurB());
+ appendLineText(nc, CONTEXT, a, hunk.getCurA(), fmtA, fmtB);
+ closeLine(nc);
+ hunk.incBoth();
+ lines.add(new PatchLine(CONTEXT, hunk.getCurA(), hunk.getCurB()));
+
+ } else if (hunk.isDeletedA()) {
+ openLine(nc);
+ appendLineNumber(nc, hunk.getCurA());
+ padLineNumber(nc);
+ appendLineText(nc, DELETE, a, hunk.getCurA(), fmtA, fmtB);
+ closeLine(nc);
+ hunk.incA();
+ lines.add(new PatchLine(DELETE, hunk.getCurA(), 0));
+ if (a.size() == hunk.getCurA() && a.isMissingNewlineAtEnd())
+ appendNoLF(nc);
+
+ } else if (hunk.isInsertedB()) {
+ openLine(nc);
+ padLineNumber(nc);
+ appendLineNumber(nc, hunk.getCurB());
+ appendLineText(nc, INSERT, b, hunk.getCurB(), fmtA, fmtB);
+ closeLine(nc);
+ hunk.incB();
+ lines.add(new PatchLine(INSERT, 0, hunk.getCurB()));
+ if (b.size() == hunk.getCurB() && b.isMissingNewlineAtEnd())
+ appendNoLF(nc);
+ }
+ }
+ }
+ resetHtml(nc);
+ initScript(script);
+
+ int row = script.getPatchHeader().size();
+ final CellFormatter fmt = table.getCellFormatter();
+ final Iterator<PatchLine> iLine = lines.iterator();
+ while (iLine.hasNext()) {
+ final PatchLine l = iLine.next();
+ final String n = "DiffText-" + l.getType().name();
+ while (!fmt.getStyleName(row, PC).contains(n)) {
+ row++;
+ }
+ setRowItem(row++, l);
+ }
+ }
+
+ @Override
+ public void display(final CommentDetail cd) {
+ if (cd.isEmpty()) {
+ return;
+ }
+ setAccountInfoCache(cd.getAccounts());
+
+ final ArrayList<PatchLineComment> all = new ArrayList<PatchLineComment>();
+ for (int row = 0; row < table.getRowCount();) {
+ if (getRowItem(row) instanceof PatchLine) {
+ final PatchLine pLine = (PatchLine) getRowItem(row);
+ final List<PatchLineComment> fora = cd.getForA(pLine.getLineA());
+ final List<PatchLineComment> forb = cd.getForB(pLine.getLineB());
+ row++;
+
+ if (!fora.isEmpty() && !forb.isEmpty()) {
+ all.clear();
+ all.addAll(fora);
+ all.addAll(forb);
+ Collections.sort(all, BY_DATE);
+ row = insert(all, row);
+
+ } else if (!fora.isEmpty()) {
+ row = insert(fora, row);
+
+ } else if (!forb.isEmpty()) {
+ row = insert(forb, row);
+ }
+ } else {
+ row++;
+ }
+ }
+ }
+
+
+ @Override
+ protected void insertRow(final int row) {
+ super.insertRow(row);
+ final CellFormatter fmt = table.getCellFormatter();
+ fmt.addStyleName(row, PC - 2, "LineNumber");
+ fmt.addStyleName(row, PC - 1, "LineNumber");
+ fmt.addStyleName(row, PC, "DiffText");
+ }
+
+ private int insert(final List<PatchLineComment> in, int row) {
+ for (Iterator<PatchLineComment> ci = in.iterator(); ci.hasNext();) {
+ final PatchLineComment c = ci.next();
+ insertRow(row);
+ bindComment(row, PC, c, !ci.hasNext());
+ row++;
+ }
+ return row;
+ }
+
+ private void appendFileHeader(final SafeHtmlBuilder m, final String line) {
+ openLine(m);
+ padLineNumber(m);
+ padLineNumber(m);
+
+ m.openTd();
+ m.addStyleName("DiffText");
+ m.addStyleName("DiffText-FILE_HEADER");
+ m.append(line);
+ m.closeTd();
+ closeLine(m);
+ }
+
+ private void appendHunkHeader(final SafeHtmlBuilder m, final Hunk hunk) {
+ openLine(m);
+ padLineNumber(m);
+ padLineNumber(m);
+
+ m.openTd();
+ m.addStyleName("DiffText");
+ m.addStyleName("DiffText-HUNK_HEADER");
+ m.append("@@ -");
+ appendRange(m, hunk.getCurA() + 1, hunk.getEndA() - hunk.getCurA());
+ m.append(" +");
+ appendRange(m, hunk.getCurB() + 1, hunk.getEndB() - hunk.getCurB());
+ m.append(" @@");
+ m.closeTd();
+
+ closeLine(m);
+ }
+
+ private void appendRange(final SafeHtmlBuilder m, final int begin,
+ final int cnt) {
+ switch (cnt) {
+ case 0:
+ m.append(begin - 1);
+ m.append(",0");
+ break;
+
+ case 1:
+ m.append(begin);
+ break;
+
+ default:
+ m.append(begin);
+ m.append(',');
+ m.append(cnt);
+ break;
+ }
+ }
+
+ private void appendLineText(final SafeHtmlBuilder m,
+ final PatchLine.Type type, final SparseFileContent src, final int i,
+ final PrettyFormatter fmtA, final PrettyFormatter fmtB) {
+ final String text = src.get(i);
+ m.openTd();
+ m.addStyleName("DiffText");
+ m.addStyleName("DiffText-" + type.name());
+ switch (type) {
+ case CONTEXT:
+ m.nbsp();
+ m.append(fmtA.format(text));
+ fmtB.update(text);
+ break;
+ case DELETE:
+ m.append("-");
+ m.append(fmtA.format(text));
+ break;
+ case INSERT:
+ m.append("+");
+ m.append(fmtB.format(text));
+ break;
+ }
+ m.closeTd();
+ }
+
+ private void appendNoLF(final SafeHtmlBuilder m) {
+ openLine(m);
+ padLineNumber(m);
+ padLineNumber(m);
+ m.openTd();
+ m.addStyleName("DiffText");
+ m.addStyleName("DiffText-NO_LF");
+ m.append("\\ No newline at end of file");
+ m.closeTd();
+ closeLine(m);
+ }
+
+ private void openLine(final SafeHtmlBuilder m) {
+ m.openTr();
+ m.setAttribute("valign", "top");
+ m.openTd();
+ m.setStyleName(S_ICON_CELL);
+ m.closeTd();
+ }
+
+ private void closeLine(final SafeHtmlBuilder m) {
+ m.closeTr();
+ }
+
+ private void padLineNumber(final SafeHtmlBuilder m) {
+ m.openTd();
+ m.setStyleName("LineNumber");
+ m.closeTd();
+ }
+
+ private void appendLineNumber(final SafeHtmlBuilder m, final int idx) {
+ m.openTd();
+ m.setStyleName("LineNumber");
+ m.append(idx + 1);
+ m.closeTd();
+ }
+}