blob: 99ff68540fcee96e9c050e8386400959b356d407 [file] [log] [blame]
// 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 com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.data.SideBySidePatchDetail;
import com.google.gerrit.client.reviewdb.Patch;
import com.google.gerrit.client.reviewdb.PatchSet;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NoDifferencesException;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.FancyFlexTable;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.SourcesTableEvents;
import com.google.gwt.user.client.ui.TableListener;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import com.google.gwtjsonrpc.client.RemoteJsonException;
import java.util.ArrayList;
import java.util.List;
public class PatchSideBySideScreen extends PatchScreen {
private DisclosurePanel historyPanel;
private HistoryTable historyTable;
private FlowPanel sbsPanel;
private SideBySideTable sbsTable;
public PatchSideBySideScreen(final Patch.Key id) {
super(id);
}
@Override
public void onLoad() {
if (sbsTable == null) {
initUI();
}
super.onLoad();
PatchUtil.DETAIL_SVC.sideBySidePatchDetail(patchId, null,
new ScreenLoadCallback<SideBySidePatchDetail>() {
public void onSuccess(final SideBySidePatchDetail r) {
// TODO Actually we want to cancel the RPC if detached.
if (isAttached()) {
display(r);
}
}
});
}
private void initUI() {
historyTable = new HistoryTable();
historyPanel = new DisclosurePanel(PatchUtil.C.patchHistoryTitle());
historyPanel.setContent(historyTable);
historyPanel.setVisible(false);
add(historyPanel);
sbsPanel = new FlowPanel();
sbsPanel.setStyleName("gerrit-SideBySideScreen-SideBySideTable");
sbsTable = new SideBySideTable();
sbsPanel.add(sbsTable);
add(sbsPanel);
}
private void display(final SideBySidePatchDetail detail) {
showSideBySide(detail);
if (detail.getHistory() != null && detail.getHistory().size() > 1) {
historyTable.display(detail.getHistory());
historyPanel.setOpen(false);
historyPanel.setVisible(true);
} else {
historyPanel.setVisible(false);
}
}
private void showSideBySide(final SideBySidePatchDetail r) {
sbsTable.setAccountInfoCache(r.getAccounts());
sbsTable.display(r);
sbsTable.finishDisplay(true);
}
private class HistoryTable extends FancyFlexTable<Patch> {
final List<HistoryRadio> all = new ArrayList<HistoryRadio>();
HistoryTable() {
table.addStyleName("gerrit-PatchHistoryTable");
table.addTableListener(new TableListener() {
public void onCellClicked(SourcesTableEvents sender, int row, int cell) {
if (row > 0) {
movePointerTo(row);
}
}
});
}
@Override
protected Object getRowItemKey(final Patch item) {
return item.getKey();
}
@Override
protected boolean onKeyPress(final char keyCode, final int modifiers) {
if (super.onKeyPress(keyCode, modifiers)) {
return true;
}
if (modifiers == 0 && getCurrentRow() > 0) {
switch (keyCode) {
case 'o':
case 'l': {
final Widget w = table.getWidget(getCurrentRow(), radioCell(0));
if (w != null) {
fakeClick((HistoryRadio) w);
}
break;
}
case 'r':
case 'n': {
final int fileCnt = sbsTable.getFileCount();
final Widget w =
table.getWidget(getCurrentRow(), radioCell(fileCnt - 1));
if (w != null) {
fakeClick((HistoryRadio) w);
}
break;
}
}
}
return false;
}
private void fakeClick(final HistoryRadio b) {
if (!b.isChecked() && b.isEnabled()) {
for (final HistoryRadio a : all) {
if (a.isChecked() && a.getName().equals(b.getName())) {
a.setChecked(false);
break;
}
}
b.setChecked(true);
onClick(b);
}
}
public void onClick(final HistoryRadio b) {
sbsTable.setVersion(b.file, b.patchSetId);
boolean diff = false;
PatchSet.Id last = sbsTable.getVersion(0);
for (int i = 1; i < sbsTable.getFileCount(); i++) {
if (!last.equals(sbsTable.getVersion(i))) {
diff = true;
}
}
enable(false);
PatchUtil.DETAIL_SVC.sideBySidePatchDetail(patchId, sbsTable
.getVersions(), new GerritCallback<SideBySidePatchDetail>() {
public void onSuccess(final SideBySidePatchDetail r) {
enable(true);
sbsPanel.setVisible(true);
showSideBySide(r);
}
@Override
public void onFailure(final Throwable caught) {
enable(true);
if (isNoDifferences(caught)) {
sbsPanel.setVisible(false);
} else {
super.onFailure(caught);
}
}
boolean isNoDifferences(final Throwable caught) {
if (caught instanceof NoDifferencesException) {
return true;
}
return caught instanceof RemoteJsonException
&& caught.getMessage().equals(NoDifferencesException.MESSAGE);
}
});
}
private void enable(final boolean on) {
for (final HistoryRadio a : all) {
a.setEnabled(on);
}
}
void display(final List<Patch> result) {
all.clear();
final SafeHtmlBuilder nc = new SafeHtmlBuilder();
appendHeader(nc);
for (int p = result.size() - 1; p >= 0; p--) {
final Patch k = result.get(p);
appendRow(nc, k);
}
appendRow(nc, null);
resetHtml(nc);
final int fileCnt = sbsTable.getFileCount();
int row = 1;
for (int p = result.size() - 1; p >= 0; p--, row++) {
final Patch k = result.get(p);
setRowItem(row, k);
for (int file = 0; file < fileCnt; file++) {
final PatchSet.Id psid = k.getKey().getParentKey();
final HistoryRadio b = new HistoryRadio(psid, file);
b.setChecked(psid.equals(sbsTable.getVersion(file)));
installRadio(row, file, b);
}
}
for (int file = 0; file < fileCnt - 1; file++) {
setRowItem(row, new Patch(new Patch.Key(PatchSet.BASE, "")));
final HistoryRadio b = new HistoryRadio(PatchSet.BASE, file);
b.setChecked(b.patchSetId.equals(sbsTable.getVersion(file)));
installRadio(row, file, b);
}
}
private void installRadio(final int row, final int file,
final HistoryRadio b) {
final int cell = radioCell(file);
table.setWidget(row, cell, b);
table.getCellFormatter().setHorizontalAlignment(row, cell,
HasHorizontalAlignment.ALIGN_CENTER);
all.add(b);
}
private int radioCell(final int file) {
return 2 + file;
}
private void appendHeader(final SafeHtmlBuilder m) {
m.openTr();
m.openTd();
m.addStyleName(S_ICON_HEADER);
m.addStyleName("LeftMostCell");
m.nbsp();
m.closeTd();
m.openTd();
m.setStyleName(S_DATA_HEADER);
m.nbsp();
m.closeTd();
for (int file = 0; file < sbsTable.getFileCount(); file++) {
m.openTd();
m.setStyleName(S_DATA_HEADER);
m.append(sbsTable.getFileTitle(file));
m.closeTd();
}
m.openTd();
m.setStyleName(S_DATA_HEADER);
m.append(Util.C.patchTableColumnComments());
m.closeTd();
m.closeTr();
}
private void appendRow(final SafeHtmlBuilder m, final Patch k) {
m.openTr();
m.openTd();
m.addStyleName(S_ICON_CELL);
m.addStyleName("LeftMostCell");
m.nbsp();
m.closeTd();
m.openTd();
m.setStyleName(S_DATA_CELL);
m.setAttribute("align", "right");
if (k != null) {
final PatchSet.Id psId = k.getKey().getParentKey();
m.append(Util.M.patchSetHeader(psId.get()));
} else {
m.append("Base");
}
m.closeTd();
for (int file = 0; file < sbsTable.getFileCount(); file++) {
m.openTd();
m.setStyleName(S_DATA_CELL);
m.nbsp();
m.closeTd();
}
m.openTd();
m.setStyleName(S_DATA_CELL);
if (k != null && k.getCommentCount() > 0) {
m.append(Util.M.patchTableComments(k.getCommentCount()));
} else {
m.nbsp();
}
m.closeTd();
m.closeTr();
}
private class HistoryRadio extends RadioButton {
final PatchSet.Id patchSetId;
final int file;
HistoryRadio(final PatchSet.Id ps, final int f) {
super(String.valueOf(f));
sinkEvents(Event.ONCLICK);
patchSetId = ps;
file = f;
}
@Override
public void onBrowserEvent(final Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONCLICK:
onClick(this);
break;
default:
super.onBrowserEvent(event);
}
}
}
}
}