diff options
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.java | 357 |
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(); + } +} |