summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Hamalainen <mika.hamalainen@accenture.com>2011-06-22 17:32:38 +0200
committerMika Hamalainen <mika.hamalainen@accenture.com>2011-08-10 12:30:29 +0300
commit737400d1bad4fa8bfd39cb326636a0307014901f (patch)
treee3c1508d2bc87abde46c8e3edef4707f9448e994
parentb845077a35fba82271c96502d33086a3156ef1d2 (diff)
One-page review
A complete change can be reviewed from single page. The new screen is launched from 'Diff All Side-by-Side' and 'Diff All Unified' buttons on the change screen. v2.2.1 compatible - Removed top view - Reverted navigation link (token) format Additionally - Fixed cursor when clicking sidebyside table Bug: issue 938 Change-Id: I5ed6ce2b861cf481c4d33b10bf677355039a3333
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java50
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java5
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java1
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/NotFoundScreen.java11
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java6
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java11
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java31
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java4
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java12
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java19
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css9
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java265
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchScreen.java146
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AllInOnePatchScreen.java541
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java10
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java144
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AbstractKeyNavigation.java152
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Approvals.java297
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ContentTableKeyNavigation.java158
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Diff.java198
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java2
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Message.java81
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java129
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java15
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java13
25 files changed, 1895 insertions, 415 deletions
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index b3bfd8efc2..ce52d9b65a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -58,6 +58,8 @@ import com.google.gerrit.client.changes.PatchTable;
import com.google.gerrit.client.changes.PublishCommentScreen;
import com.google.gerrit.client.changes.PublishTopicCommentScreen;
import com.google.gerrit.client.changes.QueryScreen;
+import com.google.gerrit.client.patches.AbstractPatchScreen;
+import com.google.gerrit.client.patches.AllInOnePatchScreen;
import com.google.gerrit.client.patches.PatchScreen;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.auth.SignInMode;
@@ -75,6 +77,25 @@ import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwtorm.client.KeyUtil;
public class Dispatcher {
+ public static String toPatchAll(final AbstractPatchScreen.Type type,
+ final PatchSetDetail detail) {
+ if (type == AbstractPatchScreen.Type.SIDE_BY_SIDE) {
+ return toPatchAllSideBySide(detail);
+ } else {
+ return toPatchAllUnified(detail);
+ }
+ }
+
+ public static String toPatchAllSideBySide(final PatchSetDetail detail) {
+ PatchSet.Id patchSetId = detail.getPatchSet().getId();
+ return "patch,all," + patchSetId.toString();
+ }
+
+ public static String toPatchAllUnified(final PatchSetDetail detail) {
+ PatchSet.Id patchSetId = detail.getPatchSet().getId();
+ return "patch,all_unified," + patchSetId.toString();
+ }
+
public static String toPatchSideBySide(final Patch.Key id) {
return toPatch("sidebyside", id);
}
@@ -87,6 +108,10 @@ public class Dispatcher {
return "patch," + type + "," + id.toString();
}
+ public static String toPublish(PatchSet.Id id) {
+ return "change,publish," + id;
+ }
+
public static String toPublish(ChangeSet.Id cs) {
Topic.Id c = cs.getParentKey();
return "/t/" + c + "/" + cs.get() + ",publish";
@@ -373,10 +398,31 @@ public class Dispatcher {
patchIndex, //
patchSetDetail, //
patchTable //
- );
+ );
}
- return new NotFoundScreen();
+ p = "patch,all,";
+ if(token.startsWith(p)) {
+
+ return new AllInOnePatchScreen(
+ id != null ? id.getParentKey() : PatchSet.Id.parse(skip(p, token)),
+ patchSetDetail,
+ patchTable,
+ AbstractPatchScreen.Type.SIDE_BY_SIDE
+ );
+ }
+
+ p = "patch,all_unified,";
+ if(token.startsWith(p)) {
+ return new AllInOnePatchScreen(
+ id != null ? id.getParentKey() : PatchSet.Id.parse(skip(p, token)),
+ patchSetDetail,
+ patchTable,
+ AbstractPatchScreen.Type.UNIFIED
+ );
+ }
+
+ return new NotFoundScreen("Failed to select() patch screen");
}
});
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index 00516b5a15..ad38d0af84 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -17,6 +17,8 @@ package com.google.gerrit.client;
import com.google.gerrit.client.auth.openid.OpenIdSignInDialog;
import com.google.gerrit.client.auth.userpass.UserPassSignInDialog;
import com.google.gerrit.client.changes.ChangeListScreen;
+import com.google.gerrit.client.patches.AbstractPatchScreen;
+import com.google.gerrit.client.patches.AllInOnePatchScreen;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.LinkMenuBar;
import com.google.gerrit.client.ui.LinkMenuItem;
@@ -31,6 +33,7 @@ import com.google.gerrit.reviewdb.Account;
import com.google.gerrit.reviewdb.AccountDiffPreference;
import com.google.gerrit.reviewdb.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.PatchSet;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
@@ -83,7 +86,7 @@ public class Gerrit implements EntryPoint {
private static SearchPanel searchPanel;
private static final Dispatcher dispatcher = new Dispatcher();
private static ViewSite<Screen> body;
-
+ private static AbstractPatchScreen patchScreen;
private static String lastChangeListToken;
static {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
index 993d06abef..2d5716ee0b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
@@ -89,6 +89,7 @@ public interface GerritCss extends CssResource {
String diffTextHunkHeader();
String diffTextINSERT();
String diffTextNoLF();
+ String diffFileName();
String downloadLink();
String downloadLink_Active();
String downloadLinkListCell();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/NotFoundScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/NotFoundScreen.java
index 29bbf85c8d..a813a0e851 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/NotFoundScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/NotFoundScreen.java
@@ -19,11 +19,22 @@ import com.google.gwt.user.client.ui.Label;
/** Displays an error message letting the user know the page doesn't exist. */
public class NotFoundScreen extends Screen {
+ String text;
+
+ public NotFoundScreen() {
+
+ }
+
+ public NotFoundScreen(final String text) {
+ this.text = text;
+ }
@Override
protected void onInitUI() {
super.onInitUI();
setPageTitle(Gerrit.C.notFoundTitle());
add(new Label(Gerrit.C.notFoundBody()));
+ if (text != null)
+ add(new Label(text));
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
index 41f0540c00..50e8cdf04f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
@@ -214,12 +214,6 @@ public class MyWatchedProjectsScreen extends SettingsScreen implements
});
projectsTab = new ProjectsTable() {
- {
- keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.projectListOpen()));
- keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER,
- Util.C.projectListOpen()));
- }
-
@Override
protected void movePointerTo(final int row, final boolean scroll) {
super.movePointerTo(row, scroll);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
index 18a3761f4f..55386b6cd5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
@@ -18,6 +18,7 @@ import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.ui.Hyperlink;
import com.google.gerrit.client.ui.NavigationTable;
+import com.google.gerrit.client.ui.AbstractKeyNavigation.Action;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -40,11 +41,11 @@ public class GroupTable extends NavigationTable<AccountGroup> {
this.enableLink = enableLink;
setSavePointerId(pointerId);
- keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.groupListPrev()));
- keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.groupListNext()));
- keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.groupListOpen()));
- keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, Util.C
- .groupListOpen()));
+ keyNavigation = new DefaultKeyNavigation(this);
+ keyNavigation.setKeyHelp(Action.NEXT, Util.C.groupListNext());
+ keyNavigation.setKeyHelp(Action.PREV, Util.C.groupListPrev());
+ keyNavigation.setKeyHelp(Action.OPEN, Util.C.groupListOpen());
+ keyNavigation.initializeKeys();
table.setText(0, 1, Util.C.columnGroupName());
table.setText(0, 2, Util.C.columnGroupDescription());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
index 249e9bd93d..8ac346641b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
@@ -20,6 +20,7 @@ import com.google.gerrit.client.FormatUtil;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.ui.AbstractKeyNavigation.Action;
import com.google.gerrit.client.ui.AccountDashboardLink;
import com.google.gerrit.client.ui.ChangeLink;
import com.google.gerrit.client.ui.BranchTopicLink;
@@ -43,7 +44,6 @@ import com.google.gerrit.reviewdb.PatchSetApproval;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
@@ -78,6 +78,21 @@ public class ChangeTable extends NavigationTable<ChangeInfo> {
private final List<ApprovalType> approvalTypes;
private final int columns;
+ private class KeyNavigation extends DefaultKeyNavigation {
+
+ public KeyNavigation(Widget parent) {
+ super(parent);
+ }
+
+ @Override
+ public void initializeKeys() {
+ super.initializeKeys();
+ if (Gerrit.isSignedIn()) {
+ keysAction.add(new StarKeyCommand(0, 's', Util.C.changeTableStar()));
+ }
+ }
+ }
+
public ChangeTable() {
this(false);
}
@@ -90,15 +105,11 @@ public class ChangeTable extends NavigationTable<ChangeInfo> {
columns = BASE_COLUMNS;
}
- keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.changeTablePrev()));
- keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.changeTableNext()));
- keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.changeTableOpen()));
- keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, Util.C
- .changeTableOpen()));
-
- if (Gerrit.isSignedIn()) {
- keysAction.add(new StarKeyCommand(0, 's', Util.C.changeTableStar()));
- }
+ keyNavigation = new KeyNavigation(this);
+ keyNavigation.setKeyHelp(Action.NEXT, Util.C.changeTableNext());
+ keyNavigation.setKeyHelp(Action.PREV, Util.C.changeTablePrev());
+ keyNavigation.setKeyHelp(Action.OPEN, Util.C.changeTableOpen());
+ keyNavigation.initializeKeys();
sections = new ArrayList<Section>();
table.setText(0, C_STAR, "");
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
index 6ca102f33d..d24d1ec979 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
@@ -73,9 +73,9 @@ public abstract class PagedSingleListScreen extends Screen {
table = new ChangeTable(true) {
{
- keysNavigation.add(new DoLinkCommand(0, 'p', Util.C
+ keyNavigation.addNavigationKey(new DoLinkCommand(0, 'p', Util.C
.changeTablePagePrev(), prev));
- keysNavigation.add(new DoLinkCommand(0, 'n', Util.C
+ keyNavigation.addNavigationKey(new DoLinkCommand(0, 'n', Util.C
.changeTablePageNext(), next));
}
};
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
index 2ab4dcc058..b1fbd83f8e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
@@ -332,10 +332,8 @@ class PatchSetComplexDisclosurePanel extends CommonComplexDisclosurePanel {
@Override
public void onClick(ClickEvent event) {
- for (Patch p : detail.getPatches()) {
- Window.open(Window.Location.getPath() + "#"
- + Dispatcher.toPatchSideBySide(p.getKey()), "_blank", null);
- }
+ final String token = Dispatcher.toPatchAllSideBySide(detail);
+ Gerrit.display(token);
}
});
actionsPanel.add(diffAllSideBySide);
@@ -345,10 +343,8 @@ class PatchSetComplexDisclosurePanel extends CommonComplexDisclosurePanel {
@Override
public void onClick(ClickEvent event) {
- for (Patch p : detail.getPatches()) {
- Window.open(Window.Location.getPath() + "#"
- + Dispatcher.toPatchUnified(p.getKey()), "_blank", null);
- }
+ final String token = Dispatcher.toPatchAllUnified(detail);
+ Gerrit.display(token);
}
});
actionsPanel.add(diffAllUnified);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
index a0286190ca..b59611e72c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
@@ -20,6 +20,7 @@ import com.google.gerrit.client.ui.InlineHyperlink;
import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
import com.google.gerrit.client.ui.NavigationTable;
import com.google.gerrit.client.ui.PatchLink;
+import com.google.gerrit.client.ui.AbstractKeyNavigation.Action;
import com.google.gerrit.common.data.PatchSetDetail;
import com.google.gerrit.reviewdb.Patch;
import com.google.gerrit.reviewdb.PatchSet;
@@ -74,6 +75,10 @@ public class PatchTable extends Composite {
this(new ListenableAccountDiffPreference());
}
+ public List<Patch> getPatchList() {
+ return patchList;
+ }
+
public int indexOf(Patch.Key patch) {
for (int i = 0; i < patchList.size(); i++) {
if (patchList.get(i).getKey().equals(patch)) {
@@ -291,14 +296,16 @@ public class PatchTable extends Composite {
private int activeRow = -1;
MyTable() {
- keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.patchTablePrev()));
- keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.patchTableNext()));
- keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.patchTableOpenDiff()));
- keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, Util.C
- .patchTableOpenDiff()));
- keysNavigation.add(new OpenUnifiedDiffKeyCommand(0, 'O', Util.C
+ keyNavigation = new DefaultKeyNavigation(this);
+ keyNavigation.setKeyHelp(Action.NEXT, Util.C.patchTableNext());
+ keyNavigation.setKeyHelp(Action.PREV, Util.C.patchTablePrev());
+ keyNavigation.setKeyHelp(Action.OPEN, Util.C.patchTableOpenDiff());
+
+ keyNavigation.addNavigationKey(new OpenUnifiedDiffKeyCommand(0, 'O', Util.C
.patchTableOpenUnifiedDiff()));
+ keyNavigation.initializeKeys();
+
table.addClickHandler(new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index a281393b59..a067c1dc8a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -617,6 +617,15 @@
color: #006000;
}
+.diffFileName {
+ font-family: mono-font;
+ font-size: 9pt;
+ background: trimColor;
+ font-weight: bold;
+ text-align: center;
+ padding: 4px 4px;
+}
+
.patchContentTable tr.commentHolder {
background: #E5ECF9;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
index d5a5367522..8d75b0d390 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
@@ -14,14 +14,13 @@
package com.google.gerrit.client.patches;
+import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.PatchTable;
-import com.google.gerrit.client.changes.PublishCommentScreen;
-import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.CommentPanel;
+import com.google.gerrit.client.ui.ContentTableKeyNavigation;
import com.google.gerrit.client.ui.NavigationTable;
-import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
import com.google.gerrit.common.data.AccountInfo;
import com.google.gerrit.common.data.AccountInfoCache;
import com.google.gerrit.common.data.CommentDetail;
@@ -36,9 +35,6 @@ import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -48,57 +44,106 @@ import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.KeyCommand;
-import com.google.gwtexpui.globalkey.client.KeyCommandSet;
-
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public abstract class AbstractPatchContentTable extends NavigationTable<Object>
implements CommentEditorContainer, FocusHandler, BlurHandler {
+
+ public interface Delegate {
+ void onClick();
+ }
+
protected PatchTable fileList;
protected AccountInfoCache accountCache = AccountInfoCache.empty();
protected Patch.Key patchKey;
protected PatchSet.Id idSideA;
protected PatchSet.Id idSideB;
protected boolean onlyOneHunk;
+ private Set<Delegate> delegates;
- private final KeyCommandSet keysComment;
- private HandlerRegistration regComment;
- private final KeyCommandSet keysOpenByEnter;
- private HandlerRegistration regOpenByEnter;
+ private class KeyNavigation extends ContentTableKeyNavigation {
+ public KeyNavigation(Widget parent) {
+ super(parent);
+ initializeKeys();
+ }
- protected AbstractPatchContentTable() {
- keysNavigation.add(new PrevKeyCommand(0, 'k', PatchUtil.C.linePrev()));
- keysNavigation.add(new NextKeyCommand(0, 'j', PatchUtil.C.lineNext()));
- keysNavigation.add(new PrevChunkKeyCmd(0, 'p', PatchUtil.C.chunkPrev()));
- keysNavigation.add(new NextChunkKeyCmd(0, 'n', PatchUtil.C.chunkNext()));
- keysNavigation.add(new PrevCommentCmd(0, 'P', PatchUtil.C.commentPrev()));
- keysNavigation.add(new NextCommentCmd(0, 'N', PatchUtil.C.commentNext()));
+ @Override
+ protected void onOpen() {
+ ensurePointerVisible();
+ onOpenCurrent();
+ }
- keysAction.add(new OpenKeyCommand(0, 'o', PatchUtil.C.expandComment()));
- keysOpenByEnter = new KeyCommandSet(Gerrit.C.sectionNavigation());
- keysOpenByEnter.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, PatchUtil.C.expandComment()));
+ @Override
+ protected void onNext() {
+ ensurePointerVisible();
+ onDown();
+ }
- if (Gerrit.isSignedIn()) {
- keysAction.add(new InsertCommentCommand(0, 'c', PatchUtil.C
- .commentInsert()));
- keysAction.add(new PublishCommentsKeyCommand(0, 'r', Util.C
- .keyPublishComments()));
-
- // See CommentEditorPanel
- //
- keysComment = new KeyCommandSet(PatchUtil.C.commentEditorSet());
- keysComment.add(new NoOpKeyCommand(KeyCommand.M_CTRL, 's', PatchUtil.C
- .commentSaveDraft()));
- keysComment.add(new NoOpKeyCommand(0, KeyCodes.KEY_ESCAPE, PatchUtil.C
- .commentCancelEdit()));
- } else {
- keysComment = null;
+ @Override
+ protected void onPrev() {
+ ensurePointerVisible();
+ onUp();
+ }
+
+ @Override
+ protected void onChunkNext() {
+ ensurePointerVisible();
+ moveToNextChunk(getCurrentRow());
+ }
+
+ @Override
+ protected void onChunkPrev() {
+ ensurePointerVisible();
+ moveToPrevChunk(getCurrentRow());
}
+ @Override
+ protected void onCommentNext() {
+ ensurePointerVisible();
+ moveToNextComment(getCurrentRow());
+ }
+
+ @Override
+ protected void onCommentPrev() {
+ ensurePointerVisible();
+ moveToPrevComment(getCurrentRow());
+ }
+
+ @Override
+ protected void onInsertComment() {
+ ensurePointerVisible();
+ for (int row = getCurrentRow(); 0 <= row; row--) {
+ final Object item = getRowItem(row);
+ if (item instanceof PatchLine) {
+ AbstractPatchContentTable.this.onInsertComment((PatchLine) item);
+ return;
+ } else if (item instanceof CommentList) {
+ continue;
+ } else {
+ return;
+ }
+ }
+ }
+
+ @Override
+ protected void onPublishComments() {
+ final PatchSet.Id id = patchKey.getParentKey();
+ Gerrit.display(Dispatcher.toPublish(id));
+ }
+ }
+
+ protected AbstractPatchContentTable() {
+ keyNavigation = new KeyNavigation(this);
+ keyNavigation.initializeKeys();
table.setStyleName(Gerrit.RESOURCES.css().patchContentTable());
+ delegates = new HashSet<Delegate>();
+ }
+
+ public void addDelegate(final Delegate delegate) {
+ delegates.add(delegate);
}
public void notifyDraftDelta(final int delta) {
@@ -144,24 +189,6 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
}
}
- @Override
- public void setRegisterKeys(final boolean on) {
- super.setRegisterKeys(on);
- if (on && keysComment != null && regComment == null) {
- regComment = GlobalKey.add(this, keysComment);
- } else if (!on && regComment != null) {
- regComment.removeHandler();
- regComment = null;
- }
-
- if (on && keysOpenByEnter != null && regOpenByEnter == null) {
- regOpenByEnter = GlobalKey.add(this, keysOpenByEnter);
- } else if (!on && regOpenByEnter != null) {
- regOpenByEnter.removeHandler();
- regOpenByEnter = null;
- }
- }
-
public void display(final Patch.Key k, final PatchSet.Id a,
final PatchSet.Id b, final PatchScript s) {
patchKey = k;
@@ -171,6 +198,17 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
render(s);
}
+
+ public boolean isOnFirstRow() {
+ int firstRow = findChunkStart(getCurrentRow());
+ return getCurrentRow() == firstRow || getCurrentRow() == 1 || getRowItem(getCurrentRow() - 1) == null;
+ }
+
+ public boolean isOnLastRow() {
+ int lastRow = findChunkEnd(getCurrentRow());
+ return getCurrentRow() == lastRow || getRowItem(getCurrentRow() + 1) == null;
+ }
+
protected abstract void render(PatchScript script);
protected abstract void onInsertComment(PatchLine pl);
@@ -236,7 +274,7 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
return end + 1 < table.getRowCount() ? end + 1 : end;
}
- private void moveToPrevChunk(int row) {
+ public void moveToPrevChunk(int row) {
while (0 <= row && isChunk(row)) {
row--;
}
@@ -259,7 +297,7 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
}
}
- private void moveToNextChunk(int row) {
+ public void moveToNextChunk(int row) {
final int max = table.getRowCount();
while (row < max && isChunk(row)) {
row++;
@@ -282,7 +320,7 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
}
}
- private void moveToPrevComment(int row) {
+ public void moveToPrevComment(int row) {
while (0 <= row && isComment(row)) {
row--;
}
@@ -304,7 +342,7 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
}
}
- private void moveToNextComment(int row) {
+ public void moveToNextComment(int row) {
final int max = table.getRowCount();
while (row < max && isComment(row)) {
row++;
@@ -566,10 +604,7 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
// ENTER that expands/collapses the comment panel, if we don't do this the
// focused button in the comment panel cannot be triggered by pressing ENTER
// since ENTER would then be already consumed by this key binding
- if (regOpenByEnter != null) {
- regOpenByEnter.removeHandler();
- regOpenByEnter = null;
- }
+ keyNavigation.setRegisterEnter(true);
}
@Override
@@ -577,9 +612,7 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
// when the comment panel gets blurred (actually when a button inside the
// comment panel gets blurred) we have to re-register the key binding for
// ENTER that expands/collapses the comment panel
- if (keysOpenByEnter != null && regOpenByEnter == null) {
- regOpenByEnter = GlobalKey.add(this, keysOpenByEnter);
- }
+ keyNavigation.setRegisterEnter(false);
}
private void styleCommentRow(final int row) {
@@ -620,6 +653,9 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
final int row = rowOf(td);
if (getRowItem(row) != null) {
movePointerTo(row);
+ for (Delegate delegate : delegates) {
+ delegate.onClick();
+ }
return;
}
break;
@@ -638,99 +674,6 @@ public abstract class AbstractPatchContentTable extends NavigationTable<Object>
}
}
- public static class NoOpKeyCommand extends NeedsSignInKeyCommand {
- public NoOpKeyCommand(int mask, int key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- }
- }
-
- public class InsertCommentCommand extends NeedsSignInKeyCommand {
- public InsertCommentCommand(int mask, int key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- for (int row = getCurrentRow(); 0 <= row; row--) {
- final Object item = getRowItem(row);
- if (item instanceof PatchLine) {
- onInsertComment((PatchLine) item);
- return;
- } else if (item instanceof CommentList) {
- continue;
- } else {
- return;
- }
- }
- }
- }
-
- public class PublishCommentsKeyCommand extends NeedsSignInKeyCommand {
- public PublishCommentsKeyCommand(int mask, char key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- final PatchSet.Id id = patchKey.getParentKey();
- Gerrit.display("change,publish," + id.toString(),
- new PublishCommentScreen(id));
- }
- }
-
- public class PrevChunkKeyCmd extends KeyCommand {
- public PrevChunkKeyCmd(int mask, int key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- moveToPrevChunk(getCurrentRow());
- }
- }
-
- public class NextChunkKeyCmd extends KeyCommand {
- public NextChunkKeyCmd(int mask, int key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- moveToNextChunk(getCurrentRow());
- }
- }
-
- public class PrevCommentCmd extends KeyCommand {
- public PrevCommentCmd(int mask, int key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- moveToPrevComment(getCurrentRow());
- }
- }
-
- public class NextCommentCmd extends KeyCommand {
- public NextCommentCmd(int mask, int key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- moveToNextComment(getCurrentRow());
- }
- }
-
private class PublishedCommentPanel extends CommentPanel implements
ClickHandler {
final PatchLineComment comment;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchScreen.java
new file mode 100644
index 0000000000..02b6b5cb46
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchScreen.java
@@ -0,0 +1,146 @@
+// Copyright (C) 2011 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.CommitMessageBlock;
+import com.google.gerrit.client.changes.PatchTable;
+import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
+import com.google.gerrit.client.ui.Screen;
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.common.data.PatchSetDetail;
+import com.google.gerrit.prettify.client.ClientSideFormatter;
+import com.google.gerrit.prettify.common.PrettyFactory;
+import com.google.gerrit.reviewdb.AccountDiffPreference;
+import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.user.client.ui.DisclosurePanel;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+public abstract class AbstractPatchScreen extends Screen implements
+ CommentEditorContainer {
+ static final PrettyFactory PRETTY = ClientSideFormatter.FACTORY;
+
+ /**
+ * How this patch should be displayed in the patch screen.
+ */
+ public static enum Type {
+ UNIFIED, SIDE_BY_SIDE
+ }
+
+ // Which patch set id's are being diff'ed
+ protected static PatchSet.Id diffSideA = null;
+ protected static PatchSet.Id diffSideB = null;
+ protected PatchSet.Id idSideA;
+ protected PatchSet.Id idSideB;
+ protected HistoryTable historyTable;
+ protected FlowPanel topPanel;
+ protected CommitMessageBlock commitMessageBlock;
+ protected PatchSetDetail patchSetDetail;
+ protected PatchTable fileList;
+ protected Patch.Key patchKey;
+ protected PatchScriptSettingsPanel settingsPanel;
+ protected ListenableAccountDiffPreference prefs;
+ protected PatchScript lastScript;
+
+ public AbstractPatchScreen(final Patch.Key patchKey, final PatchSet.Id id,
+ final PatchSetDetail patchSetDetail, final PatchTable patchTable) {
+ this.patchKey = patchKey;
+ this.patchSetDetail = patchSetDetail;
+ fileList = patchTable;
+
+ if (patchTable != null) {
+ diffSideA = patchTable.getPatchSetIdToCompareWith();
+ } else {
+ diffSideA = null;
+ }
+
+ idSideA = diffSideA; // null here means we're diff'ing from the Base
+ idSideB = diffSideB != null ? diffSideB : id;
+
+ prefs = fileList != null ? fileList.getPreferences() :
+ new ListenableAccountDiffPreference();
+ prefs.addValueChangeHandler(
+ new ValueChangeHandler<AccountDiffPreference>() {
+ @Override
+ public void onValueChange(ValueChangeEvent<AccountDiffPreference> event) {
+ update(event.getValue());
+ }
+ });
+
+ settingsPanel = new PatchScriptSettingsPanel(prefs);
+ }
+
+ @Override
+ protected void onInitUI() {
+ super.onInitUI();
+
+ historyTable = new HistoryTable(this);
+ commitMessageBlock = new CommitMessageBlock();
+
+ // Pre-topview style top layout.
+ VerticalPanel vp = new VerticalPanel();
+ DisclosurePanel historyPanel =
+ new DisclosurePanel(PatchUtil.C.patchHistoryTitle());
+ historyPanel.add(historyTable);
+ vp.add(historyPanel);
+ vp.add(settingsPanel);
+
+ HorizontalPanel hp = new HorizontalPanel();
+ hp.setWidth("100%");
+ hp.add(vp);
+ hp.add(commitMessageBlock);
+
+ add(hp);
+ }
+
+ PatchSet.Id getSideA() {
+ return diffSideA;
+ }
+
+ void setSideA(PatchSet.Id id) {
+ diffSideA = id;
+ idSideA = id;
+ if (fileList != null) {
+ fileList.setPatchSetIdToCompareWith(id);
+ }
+ }
+
+ PatchSet.Id getSideB() {
+ return diffSideB;
+ }
+
+ void setSideB(PatchSet.Id id) {
+ diffSideB = id;
+ idSideB = id;
+ }
+
+ public Patch.Key getPatchKey() {
+ return patchKey;
+ }
+
+ abstract void refresh(boolean first);
+ abstract public AbstractPatchScreen.Type getPatchScreenType();
+ abstract protected void update(AccountDiffPreference dp);
+
+ public PatchSetDetail getPatchSetDetail() {
+ return patchSetDetail;
+ }
+ public PatchTable getFileList() {
+ return fileList;
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AllInOnePatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AllInOnePatchScreen.java
new file mode 100644
index 0000000000..90fb7e3d0b
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AllInOnePatchScreen.java
@@ -0,0 +1,541 @@
+// Copyright (C) 2011 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.Dispatcher;
+import com.google.gerrit.client.ErrorDialog;
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.RpcStatus;
+import com.google.gerrit.client.changes.ChangeScreen;
+import com.google.gerrit.client.changes.PatchTable;
+import com.google.gerrit.client.changes.Util;
+import com.google.gerrit.client.patches.AbstractPatchContentTable.CommentList;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.ui.Approvals;
+import com.google.gerrit.client.ui.ContentTableKeyNavigation;
+import com.google.gerrit.client.ui.Diff;
+import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.common.data.PatchSetDetail;
+import com.google.gerrit.reviewdb.AccountDiffPreference;
+import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.globalkey.client.KeyCommand;
+import com.google.gwtjsonrpc.client.VoidResult;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AllInOnePatchScreen extends AbstractPatchScreen implements
+ Diff.Delegate, Approvals.Delegate {
+ private class KeyNavigation extends ContentTableKeyNavigation {
+ private class NextFileCmd extends KeyCommand {
+ public NextFileCmd(int mask, char key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onFileNext();
+ }
+ }
+ private class PrevFileCmd extends KeyCommand {
+ public PrevFileCmd(int mask, char key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onFilePrev();
+ }
+ }
+
+ private Diff diff;
+
+ private AbstractPatchContentTable contentTable;
+
+ public KeyNavigation(Widget parent) {
+ super(parent);
+ }
+
+ public void clear() {
+ diff = null;
+ contentTable = null;
+ }
+
+ public Diff getDiff() {
+ return diff;
+ }
+
+ @Override
+ public void initializeKeys() {
+ if (!initialized) {
+ keysNavigation.add(new NextFileCmd(0, 'w', PatchUtil.C.nextFileHelp()));
+ keysNavigation.add(new PrevFileCmd(0, 'q', PatchUtil.C
+ .previousFileHelp()));
+ super.initializeKeys();
+ }
+ }
+
+ public void setDiff(Diff diff) {
+ this.diff = diff;
+ if (diff != null) {
+ contentTable = diff.getContentTable();
+ contentTable.ensurePointerVisible();
+ } else {
+ contentTable = null;
+ }
+ }
+
+ @Override
+ protected void onChunkNext() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ contentTable.moveToNextChunk(contentTable.getCurrentRow());
+ }
+ }
+
+ @Override
+ protected void onChunkPrev() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ contentTable.moveToPrevChunk(contentTable.getCurrentRow());
+ }
+ }
+
+ @Override
+ protected void onCommentNext() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ contentTable.moveToNextComment(contentTable.getCurrentRow());
+ }
+ }
+
+ @Override
+ protected void onCommentPrev() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ contentTable.moveToPrevComment(contentTable.getCurrentRow());
+ }
+ }
+
+ protected void onFileNext() {
+ contentTable.hideCursor();
+ diff = getNextDiff();
+ contentTable = diff.getContentTable();
+ Window.scrollTo(0, diff.getAbsoluteTop());
+ contentTable.ensurePointerVisible();
+ contentTable.showCursor();
+ }
+
+ protected void onFilePrev() {
+ contentTable.hideCursor();
+ diff = getPrevDiff();
+ contentTable = diff.getContentTable();
+ Window.scrollTo(0, diff.getAbsoluteTop());
+ contentTable.ensurePointerVisible();
+ contentTable.showCursor();
+ }
+
+ @Override
+ protected void onInsertComment() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ for (int row = contentTable.getCurrentRow(); 0 <= row; row--) {
+ final Object item = contentTable.getRowItem(row);
+ if (item instanceof PatchLine) {
+ contentTable.onInsertComment((PatchLine) item);
+ return;
+ } else if (item instanceof CommentList) {
+ continue;
+ } else {
+ return;
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onNext() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ contentTable.onDown();
+ }
+ }
+
+ @Override
+ protected void onOpen() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ contentTable.onOpenCurrent();
+ }
+ }
+
+ @Override
+ protected void onPrev() {
+ if (contentTable != null) {
+ contentTable.ensurePointerVisible();
+ contentTable.onUp();
+ }
+ }
+
+ @Override
+ protected void onPublishComments() {
+ final PatchSet.Id id = patchKey.getParentKey();
+ Gerrit.display(Dispatcher.toPublish(id));
+ }
+ }
+
+ private boolean intralineFailure;
+ private VerticalPanel files;
+ private Panel approvalPanel;
+ private Approvals approvals;
+ private KeyNavigation keyNavigation;
+ private List<Diff> diffs;
+ private Diff.Factory diffFactory;
+
+ public AllInOnePatchScreen(final PatchSet.Id patchSetId,
+ final PatchSetDetail detail, final PatchTable patchTable,
+ AbstractPatchScreen.Type patchScreenType) {
+ super(null, patchSetId, detail, patchTable);
+ diffs = new ArrayList<Diff>();
+ keyNavigation = new KeyNavigation(this);
+ keyNavigation.addNavigationKey(new UpToChangeCommand(patchSetId, 0, 'u'));
+
+ if (patchScreenType == AbstractPatchScreen.Type.SIDE_BY_SIDE) {
+ diffFactory = new Diff.SideBySideFactory();
+ } else {
+ diffFactory = new Diff.UnifiedFactory();
+ }
+ }
+
+ public PatchScreen.Type getPatchScreenType() {
+ return diffFactory.getType();
+ }
+
+ @Override
+ public void notifyDraftDelta(int delta) {
+ lastScript = null;
+ }
+
+ @Override
+ public void onCancel() {
+ goChange();
+ }
+
+ @Override
+ public void onFocus(final Diff diff) {
+ if (diff != keyNavigation.getDiff()) {
+ keyNavigation.getDiff().getContentTable().hideCursor();
+ }
+ keyNavigation.setDiff(diff);
+ }
+
+ @Override
+ public void onLoad(final Diff diff) {
+ intralineFailure = diff.hasIntralineFailure();
+ if (keyNavigation.getDiff() == null) {
+ keyNavigation.setDiff(diff);
+ }
+ diffs.add(diff);
+
+ // Delay displaying diff if previous diffs are not loaded yet.
+ for (Widget widget : files) {
+ final Diff df = (Diff) widget;
+ if (df.isLoaded()) {
+ if (!df.isVisible()) {
+ df.setVisible(true);
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onPublish() {
+ goChange();
+ }
+
+ @Override
+ public void onShowView() {
+ super.onShowView();
+ if (intralineFailure) {
+ intralineFailure = false;
+ new ErrorDialog(PatchUtil.C.intralineFailure()).show();
+ }
+ }
+
+ @Override
+ public void onStage() {
+ goChange();
+ }
+
+ @Override
+ public void onSubmit() {
+ goChange();
+ }
+
+ public void refresh(final boolean isFirst) {
+ files.clear();
+ diffs.clear();
+ keyNavigation.clear();
+ loadDiffs();
+ // historyTable.enableAll(true);
+ }
+
+ @Override
+ public void registerKeys() {
+ super.registerKeys();
+ keyNavigation.setRegisterKeys(false);
+ keyNavigation.setRegisterKeys(true);
+ }
+
+ @Override
+ public void remove(CommentEditorPanel panel) {
+ lastScript = null;
+ }
+
+ private boolean canReuse(AccountDiffPreference dp, PatchScript last) {
+ if (last.getDiffPrefs().getIgnoreWhitespace() != dp.getIgnoreWhitespace()) {
+ // Whitespace ignore setting requires server computation.
+ return false;
+ }
+
+ final int ctx = dp.getContext();
+ if (ctx == AccountDiffPreference.WHOLE_FILE_CONTEXT
+ && !last.getA().isWholeFile()) {
+ // We don't have the entire file here, so we can't render it.
+ return false;
+ }
+
+ if (last.getDiffPrefs().getContext() < ctx && !last.getA().isWholeFile()) {
+ // We don't have sufficient context.
+ return false;
+ }
+
+ if (dp.isSyntaxHighlighting() && !last.getA().isWholeFile()) {
+ // We need the whole file to syntax highlight accurately.
+ return false;
+ }
+
+ return true;
+ }
+
+ private Diff getNextDiff() {
+ if (keyNavigation.getDiff() == null) {
+ if (!diffs.isEmpty()) {
+ return diffs.get(0);
+ } else {
+ return null;
+ }
+ } else {
+ int index = diffs.indexOf(keyNavigation.getDiff());
+ if (index + 1 < diffs.size()) {
+ return diffs.get(index + 1);
+ } else {
+ return diffs.get(0);
+ }
+ }
+ }
+
+ private Diff getPrevDiff() {
+ if (keyNavigation.getDiff() == null) {
+ if (!diffs.isEmpty()) {
+ return diffs.get(0);
+ } else {
+ return null;
+ }
+ } else {
+ int index = diffs.indexOf(keyNavigation.getDiff());
+ if (index - 1 >= 0) {
+ return diffs.get(index - 1);
+ } else {
+ return diffs.get(diffs.size() - 1);
+ }
+ }
+ }
+
+ private void goChange() {
+ final Change.Id ck = idSideB.getParentKey();
+ Gerrit.display(PageLinks.toChange(ck), new ChangeScreen(ck));
+ }
+
+ private void loadDiffs() {
+ final List<Patch> patchList = fileList.getPatchList();
+ for (int i = 0; i < patchList.size(); ++i) {
+ final Patch patch = patchList.get(i);
+ Diff diff =
+ diffFactory.createDiff(patch.getKey(), idSideA, idSideB,
+ settingsPanel.getValue());
+ diff.addDelegate(this);
+ diff.setVisible(false);
+ files.add(diff);
+ diff.load();
+ }
+ }
+
+ private void loadFileList() {
+ if (patchSetDetail == null) {
+ Util.DETAIL_SVC.patchSetDetail(idSideB,
+ new GerritCallback<PatchSetDetail>() {
+ @Override
+ public void onSuccess(PatchSetDetail result) {
+ patchSetDetail = result;
+ setSideB(patchSetDetail.getPatchSet().getId());
+
+ if (fileList == null) {
+ fileList = new PatchTable(prefs);
+ fileList.display(result);
+ }
+
+ if (!result.getPatches().isEmpty()) {
+ patchKey = result.getPatches().get(0).getKey();
+ }
+ loadDiffs();
+ updateCommitInformation(patchKey);
+ updateHistory(patchKey);
+ }
+ });
+ } else {
+ loadDiffs();
+ }
+ }
+
+ private void updateCommitInformation(final Patch.Key patchKey) {
+ final Change.Id cid = patchKey.getParentKey().getParentKey();
+
+ setWindowTitle(cid.toString());
+ final String subject = patchSetDetail.getInfo().getSubject();
+ setPageTitle(cid.toString() + ": " + subject);
+
+ if (idSideB.equals(patchSetDetail.getPatchSet().getId())) {
+ commitMessageBlock.setVisible(true);
+ commitMessageBlock.display(patchSetDetail.getInfo().getMessage());
+ } else {
+ commitMessageBlock.setVisible(false);
+ Util.DETAIL_SVC.patchSetDetail(idSideB,
+ new GerritCallback<PatchSetDetail>() {
+ @Override
+ public void onSuccess(PatchSetDetail result) {
+ commitMessageBlock.setVisible(true);
+ commitMessageBlock.display(result.getInfo().getMessage());
+ }
+ });
+ }
+ }
+
+ private void updateHistory(final Patch.Key patchKey) {
+ // historyTable.display(script.getHistory());
+ PatchUtil.DETAIL_SVC.patchScript(patchKey, idSideA, idSideB,
+ settingsPanel.getValue(), new GerritCallback<PatchScript>() {
+ @Override
+ public void onSuccess(final PatchScript result) {
+ historyTable.display(result.getHistory());
+ }
+ });
+ }
+
+ @Override
+ protected void onInitUI() {
+ super.onInitUI();
+
+ Window.scrollTo(0, getAbsoluteTop());
+
+ files = new VerticalPanel();
+
+ approvalPanel = new FlowPanel();
+ approvals = new Approvals(idSideB);
+ approvals.addDelegate(this);
+ approvalPanel.add(approvals);
+
+ add(files);
+ if (Gerrit.isSignedIn()) {
+ add(approvalPanel);
+ }
+
+ keyNavigation.initializeKeys();
+ }
+
+ @Override
+ protected void onLoad() {
+ super.onLoad();
+
+ keyNavigation.setRegisterKeys(true);
+ loadFileList();
+ if (Gerrit.isSignedIn()) {
+ approvals.load();
+ }
+
+ if (!isCurrentView()) {
+ display();
+ }
+ }
+
+ @Override
+ protected void onUnload() {
+ super.onUnload();
+ keyNavigation.setRegisterKeys(false);
+ }
+
+ protected void update(AccountDiffPreference dp) {
+ if (lastScript != null && canReuse(dp, lastScript)) {
+ lastScript.setDiffPrefs(dp);
+ RpcStatus.INSTANCE.onRpcStart(null);
+ settingsPanel.setEnabled(false);
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ try {
+ // onResult(lastScript, false /* not the first time */);
+ } finally {
+ RpcStatus.INSTANCE.onRpcComplete(null);
+ }
+ }
+ });
+ } else {
+ refresh(false);
+ }
+ }
+
+ void setReviewedByCurrentUser(boolean reviewed) {
+ if (fileList != null) {
+ fileList.updateReviewedStatus(patchKey, reviewed);
+ }
+
+ PatchUtil.DETAIL_SVC.setReviewedByCurrentUser(patchKey, reviewed,
+ new AsyncCallback<VoidResult>() {
+ @Override
+ public void onFailure(Throwable arg0) {
+ // nop
+ }
+
+ @Override
+ public void onSuccess(VoidResult result) {
+ // nop
+ }
+ });
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
index cb85c2448e..78eb6a0698 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
@@ -32,10 +32,10 @@ import java.util.List;
* A table used to specify which two patch sets should be diff'ed.
*/
class HistoryTable extends FancyFlexTable<Patch> {
- private final PatchScreen screen;
+ private final AbstractPatchScreen screen;
final List<HistoryRadio> all = new ArrayList<HistoryRadio>();
- HistoryTable(final PatchScreen parent) {
+ HistoryTable(final AbstractPatchScreen parent) {
setStyleName(Gerrit.RESOURCES.css().patchHistoryTable());
screen = parent;
table.setWidth("auto");
@@ -79,13 +79,13 @@ class HistoryTable extends FancyFlexTable<Patch> {
{
final Patch k = new Patch(new Patch.Key(null, ""));
setRowItem(row, k);
- installRadio(row, k, 0, screen.idSideA);
+ installRadio(row, k, 0, screen.getSideA());
row++;
}
for (final Patch k : result) {
setRowItem(row, k);
- installRadio(row, k, 0, screen.idSideA);
- installRadio(row, k, 1, screen.idSideB);
+ installRadio(row, k, 0, screen.getSideA());
+ installRadio(row, k, 1, screen.getSideB());
row++;
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
index df523b9c6c..5a816f7793 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
@@ -18,17 +18,12 @@ import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.ErrorDialog;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.RpcStatus;
-import com.google.gerrit.client.changes.CommitMessageBlock;
import com.google.gerrit.client.changes.PatchTable;
import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
-import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
-import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.prettify.client.ClientSideFormatter;
-import com.google.gerrit.prettify.common.PrettyFactory;
import com.google.gerrit.reviewdb.AccountDiffPreference;
import com.google.gerrit.reviewdb.Change;
import com.google.gerrit.reviewdb.Patch;
@@ -36,27 +31,16 @@ import com.google.gerrit.reviewdb.PatchSet;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.logical.shared.CloseEvent;
-import com.google.gwt.event.logical.shared.CloseHandler;
-import com.google.gwt.event.logical.shared.OpenEvent;
-import com.google.gwt.event.logical.shared.OpenHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwtexpui.globalkey.client.GlobalKey;
import com.google.gwtexpui.globalkey.client.KeyCommand;
import com.google.gwtexpui.globalkey.client.KeyCommandSet;
import com.google.gwtjsonrpc.client.VoidResult;
-public abstract class PatchScreen extends Screen implements
- CommentEditorContainer {
- static final PrettyFactory PRETTY = ClientSideFormatter.FACTORY;
+public abstract class PatchScreen extends AbstractPatchScreen {
public static class SideBySide extends PatchScreen {
public SideBySide(final Patch.Key id, final int patchIndex,
@@ -70,8 +54,8 @@ public abstract class PatchScreen extends Screen implements
}
@Override
- protected PatchScreen.Type getPatchScreenType() {
- return PatchScreen.Type.SIDE_BY_SIDE;
+ public AbstractPatchScreen.Type getPatchScreenType() {
+ return AbstractPatchScreen.Type.SIDE_BY_SIDE;
}
}
@@ -87,103 +71,31 @@ public abstract class PatchScreen extends Screen implements
}
@Override
- protected PatchScreen.Type getPatchScreenType() {
- return PatchScreen.Type.UNIFIED;
+ public AbstractPatchScreen.Type getPatchScreenType() {
+ return AbstractPatchScreen.Type.UNIFIED;
}
}
- // Which patch set id's are being diff'ed
- private static PatchSet.Id diffSideA = null;
- private static PatchSet.Id diffSideB = null;
-
- private static Boolean historyOpen = null;
- private static final OpenHandler<DisclosurePanel> cacheOpenState =
- new OpenHandler<DisclosurePanel>() {
- @Override
- public void onOpen(OpenEvent<DisclosurePanel> event) {
- historyOpen = true;
- }
- };
- private static final CloseHandler<DisclosurePanel> cacheCloseState =
- new CloseHandler<DisclosurePanel>() {
- @Override
- public void onClose(CloseEvent<DisclosurePanel> event) {
- historyOpen = false;
- }
- };
-
- protected final Patch.Key patchKey;
- protected PatchSetDetail patchSetDetail;
- protected PatchTable fileList;
- protected PatchSet.Id idSideA;
- protected PatchSet.Id idSideB;
- protected PatchScriptSettingsPanel settingsPanel;
-
- private DisclosurePanel historyPanel;
- private HistoryTable historyTable;
private FlowPanel contentPanel;
private Label noDifference;
private AbstractPatchContentTable contentTable;
- private CommitMessageBlock commitMessageBlock;
private NavLinks topNav;
private NavLinks bottomNav;
private int rpcSequence;
- private PatchScript lastScript;
/** The index of the file we are currently looking at among the fileList */
private int patchIndex;
- private ListenableAccountDiffPreference prefs;
/** Keys that cause an action on this screen */
private KeyCommandSet keysNavigation;
private HandlerRegistration regNavigation;
private boolean intralineFailure;
- /**
- * How this patch should be displayed in the patch screen.
- */
- public static enum Type {
- UNIFIED, SIDE_BY_SIDE
- }
-
protected PatchScreen(final Patch.Key id, final int patchIndex,
final PatchSetDetail detail, final PatchTable patchTable) {
- patchKey = id;
- patchSetDetail = detail;
- fileList = patchTable;
-
- if (patchTable != null) {
- diffSideA = patchTable.getPatchSetIdToCompareWith();
- } else {
- diffSideA = null;
- }
- if (diffSideA == null) {
- historyOpen = null;
- }
-
- idSideA = diffSideA; // null here means we're diff'ing from the Base
- idSideB = diffSideB != null ? diffSideB : id.getParentKey();
+ super(id, id.getParentKey(), detail, patchTable);
this.patchIndex = patchIndex;
-
- prefs = fileList != null ? fileList.getPreferences() :
- new ListenableAccountDiffPreference();
- prefs.addValueChangeHandler(
- new ValueChangeHandler<AccountDiffPreference>() {
- @Override
- public void onValueChange(ValueChangeEvent<AccountDiffPreference> event) {
- update(event.getValue());
- }
- });
-
- settingsPanel = new PatchScriptSettingsPanel(prefs);
- settingsPanel.getReviewedCheckBox().addValueChangeHandler(
- new ValueChangeHandler<Boolean>() {
- @Override
- public void onValueChange(ValueChangeEvent<Boolean> event) {
- setReviewedByCurrentUser(event.getValue());
- }
- });
}
@Override
@@ -196,7 +108,8 @@ public abstract class PatchScreen extends Screen implements
lastScript = null;
}
- private void update(AccountDiffPreference dp) {
+ @Override
+ protected void update(AccountDiffPreference dp) {
if (lastScript != null && canReuse(dp, lastScript)) {
lastScript.setDiffPrefs(dp);
RpcStatus.INSTANCE.onRpcStart(null);
@@ -250,28 +163,6 @@ public abstract class PatchScreen extends Screen implements
keysNavigation.add(new UpToChangeCommand(patchKey.getParentKey(), 0, 'u'));
keysNavigation.add(new FileListCmd(0, 'f', PatchUtil.C.fileList()));
- historyTable = new HistoryTable(this);
- historyPanel = new DisclosurePanel(PatchUtil.C.patchHistoryTitle());
- historyPanel.setContent(historyTable);
- historyPanel.setVisible(false);
- // If the user selected a different patch set than the default for either
- // side, expand the history panel
- historyPanel.setOpen(diffSideA != null || diffSideB != null
- || (historyOpen != null && historyOpen));
- historyPanel.addOpenHandler(cacheOpenState);
- historyPanel.addCloseHandler(cacheCloseState);
-
-
- VerticalPanel vp = new VerticalPanel();
- vp.add(historyPanel);
- vp.add(settingsPanel);
- commitMessageBlock = new CommitMessageBlock("6em");
- HorizontalPanel hp = new HorizontalPanel();
- hp.setWidth("100%");
- hp.add(vp);
- hp.add(commitMessageBlock);
- add(hp);
-
noDifference = new Label(PatchUtil.C.noDifference());
noDifference.setStyleName(Gerrit.RESOURCES.css().patchNoDifference());
noDifference.setVisible(false);
@@ -325,6 +216,7 @@ public abstract class PatchScreen extends Screen implements
@Override
public void onSuccess(PatchSetDetail result) {
patchSetDetail = result;
+ setSideB(patchSetDetail.getPatchSet().getId());
if (fileList == null) {
fileList = new PatchTable(prefs);
fileList.display(result);
@@ -360,9 +252,7 @@ public abstract class PatchScreen extends Screen implements
protected abstract AbstractPatchContentTable createContentTable();
- protected abstract PatchScreen.Type getPatchScreenType();
-
- protected void refresh(final boolean isFirst) {
+ public void refresh(final boolean isFirst) {
final int rpcseq = ++rpcSequence;
lastScript = null;
settingsPanel.setEnabled(false);
@@ -414,7 +304,6 @@ public abstract class PatchScreen extends Screen implements
}
historyTable.display(script.getHistory());
- historyPanel.setVisible(true);
// True if there are differences between the two patch sets
boolean hasEdits = !script.getEdits().isEmpty();
@@ -476,19 +365,6 @@ public abstract class PatchScreen extends Screen implements
contentTable.setRegisterKeys(isCurrentView() && showPatch);
}
- public void setSideA(PatchSet.Id patchSetId) {
- idSideA = patchSetId;
- diffSideA = patchSetId;
- if (fileList != null) {
- fileList.setPatchSetIdToCompareWith(patchSetId);
- }
- }
-
- public void setSideB(PatchSet.Id patchSetId) {
- idSideB = patchSetId;
- diffSideB = patchSetId;
- }
-
public class FileListCmd extends KeyCommand {
public FileListCmd(int mask, int key, String help) {
super(mask, key, help);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AbstractKeyNavigation.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AbstractKeyNavigation.java
new file mode 100644
index 0000000000..dea2813173
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AbstractKeyNavigation.java
@@ -0,0 +1,152 @@
+// Copyright (C) 2011 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.ui;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.globalkey.client.GlobalKey;
+import com.google.gwtexpui.globalkey.client.KeyCommand;
+import com.google.gwtexpui.globalkey.client.KeyCommandSet;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class AbstractKeyNavigation {
+ public enum Action { NEXT, PREV, OPEN };
+
+ protected final KeyCommandSet keysNavigation;
+ protected final KeyCommandSet keysAction;
+ private HandlerRegistration regNavigation;
+ private HandlerRegistration regAction;
+ private final KeyCommandSet keysOpenByEnter;
+ private HandlerRegistration regOpenByEnter;
+ protected final Widget parent;
+ private Map<Action, String> help;
+ protected static boolean initialized = false;
+
+ protected void onNext() {};
+ protected void onPrev() {};
+ protected void onOpen() {};
+
+ public AbstractKeyNavigation(final Widget parent) {
+ this.parent = parent;
+ help = new HashMap<AbstractKeyNavigation.Action, String>();
+ keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
+ keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
+ keysOpenByEnter = new KeyCommandSet(Gerrit.C.sectionNavigation());
+ }
+
+ public void setKeyHelp(final Action action, final String text) {
+ help.put(action, text);
+ }
+
+ public void initializeKeys() {
+ keysNavigation.add(new NextKeyCommand(0, 'j', help.get(Action.NEXT)));
+ keysNavigation.add(new PrevKeyCommand(0, 'k', help.get(Action.PREV)));
+ keysAction.add(new OpenKeyCommand(0, 'o', help.get(Action.OPEN)));
+ keysOpenByEnter.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, help.get(Action.OPEN)));
+ }
+
+ public void addNavigationKey(final KeyCommand keyCommand) {
+ keysNavigation.add(keyCommand);
+ }
+
+ public void setRegisterKeys(final boolean on) {
+ if (on) {
+ if (regNavigation == null) {
+ regNavigation = GlobalKey.add(parent, keysNavigation);
+ }
+ if (regAction == null) {
+ regAction = GlobalKey.add(parent, keysAction);
+ }
+ if (regOpenByEnter == null) {
+ regOpenByEnter = GlobalKey.add(parent, keysOpenByEnter);
+ }
+ } else {
+ if (regNavigation != null) {
+ regNavigation.removeHandler();
+ regNavigation = null;
+ }
+
+ if (regAction != null) {
+ regAction.removeHandler();
+ regAction = null;
+ }
+
+ if (regOpenByEnter != null) {
+ regOpenByEnter.removeHandler();
+ regOpenByEnter = null;
+ }
+ }
+ }
+
+ public void setRegisterEnter(final boolean on) {
+ if (on) {
+ if (regOpenByEnter != null) {
+ regOpenByEnter.removeHandler();
+ regOpenByEnter = null;
+ }
+ } else {
+ if (keysOpenByEnter != null && regOpenByEnter == null) {
+ regOpenByEnter = GlobalKey.add(parent, keysOpenByEnter);
+ }
+ }
+ }
+
+ private class PrevKeyCommand extends KeyCommand {
+ public PrevKeyCommand(int mask, char key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onPrev();
+ }
+ }
+
+ private class NextKeyCommand extends KeyCommand {
+ public NextKeyCommand(int mask, char key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onNext();
+ }
+ }
+
+ private class OpenKeyCommand extends KeyCommand {
+ public OpenKeyCommand(int mask, int key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onOpen();
+ }
+ }
+
+ protected class NoOpKeyCommand extends NeedsSignInKeyCommand {
+ public NoOpKeyCommand(int mask, int key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Approvals.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Approvals.java
new file mode 100644
index 0000000000..d8a348dade
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Approvals.java
@@ -0,0 +1,297 @@
+// Copyright (C) 2011 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.ui;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.common.data.ApprovalType;
+import com.google.gerrit.common.data.ApprovalTypes;
+import com.google.gerrit.common.data.ChangeDetail;
+import com.google.gerrit.common.data.PatchSetPublishDetail;
+import com.google.gerrit.common.data.PermissionRange;
+import com.google.gerrit.reviewdb.ApprovalCategory;
+import com.google.gerrit.reviewdb.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.client.changes.Util;
+import com.google.gerrit.client.patches.PatchUtil;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.RadioButton;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwtjsonrpc.client.VoidResult;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class Approvals extends Composite {
+ public interface Delegate {
+ void onCancel();
+ void onPublish();
+ void onStage();
+ void onSubmit();
+ }
+
+ private static class SavedState {
+ final PatchSet.Id patchSetId;
+ final Map<ApprovalCategory.Id, ApprovalCategoryValue> approvalValues;
+
+ SavedState(final Approvals approvals) {
+ this.patchSetId = approvals.patchSetId;
+ approvalValues = new HashMap<ApprovalCategory.Id, ApprovalCategoryValue>();
+ for (final ValueRadioButton b : approvals.approvalButtons) {
+ if (b.getValue()) {
+ approvalValues.put(b.value.getCategoryId(), b.value);
+ }
+ }
+ }
+ }
+
+ private static class ValueRadioButton extends RadioButton {
+ final ApprovalCategoryValue value;
+
+ ValueRadioButton(final ApprovalCategoryValue v, final String label) {
+ super(label);
+ value = v;
+ }
+ }
+
+ private static SavedState lastState;
+ private boolean saveState = true;
+ private final VerticalPanel body;
+ private final PatchSet.Id patchSetId;
+ private Collection<ValueRadioButton> approvalButtons;
+ private Message message;
+
+ private FlowPanel actionsPanel;
+ private Set<Delegate> delegates;
+
+ public Approvals(final PatchSet.Id patchSetId) {
+ this.patchSetId = patchSetId;
+ body = new VerticalPanel();
+ approvalButtons = new ArrayList<ValueRadioButton>();
+ message = new Message(patchSetId);
+
+ actionsPanel = new FlowPanel();
+ actionsPanel.setStyleName(Gerrit.RESOURCES.css().patchSetActions());
+ delegates = new HashSet<Approvals.Delegate>();
+
+ initWidget(body);
+ }
+
+ public void addDelegate(final Delegate delegate) {
+ delegates.add(delegate);
+ }
+
+ public Map<ApprovalCategory.Id, ApprovalCategoryValue.Id> getValues() {
+ HashMap<ApprovalCategory.Id, ApprovalCategoryValue.Id> values =
+ new HashMap<ApprovalCategory.Id, ApprovalCategoryValue.Id>();
+ for (final ValueRadioButton b : approvalButtons) {
+ if (b.getValue()) {
+ values.put(b.value.getCategoryId(), b.value.getId());
+ }
+ }
+
+ return values;
+ }
+
+ public void load() {
+ Util.DETAIL_SVC.patchSetPublishDetail(patchSetId,
+ new GerritCallback<PatchSetPublishDetail>() {
+ @Override
+ public void onSuccess(final PatchSetPublishDetail result) {
+ if (result.getChange().getStatus().isOpen()) {
+ initApprovals(result);
+ body.add(message);
+ populateActions(result);
+ }
+ }
+ });
+ }
+
+ public void removeDelegate(final Delegate delegate) {
+ delegates.remove(delegate);
+ }
+
+ public void setSaveState(boolean saveState) {
+ this.saveState = saveState;
+ message.setSaveState(saveState);
+ }
+
+ private void initApprovals(final PatchSetPublishDetail r) {
+ ApprovalTypes types = Gerrit.getConfig().getApprovalTypes();
+ for (PermissionRange range : r.getLabels()) {
+ ApprovalType type = types.byLabel(range.getLabel());
+ if (type != null) {
+ // Legacy type, use radio buttons.
+ initApprovalType(r, body, type, range);
+ } else {
+ // TODO Newer style label.
+ }
+ }
+ }
+
+ private void initApprovalType(final PatchSetPublishDetail r,
+ final Panel body, final ApprovalType ct, final PermissionRange range) {
+ body.add(new SmallHeading(ct.getCategory().getName() + ":"));
+
+ final VerticalPanel vp = new VerticalPanel();
+ vp.setStyleName(Gerrit.RESOURCES.css().approvalCategoryList());
+ final List<ApprovalCategoryValue> lst =
+ new ArrayList<ApprovalCategoryValue>(ct.getValues());
+ Collections.reverse(lst);
+ final ApprovalCategory.Id catId = ct.getCategory().getId();
+ final PatchSetApproval prior = r.getChangeApproval(catId);
+
+ for (final ApprovalCategoryValue buttonValue : lst) {
+ if (!range.contains(buttonValue.getValue())) {
+ continue;
+ }
+
+ final ValueRadioButton b =
+ new ValueRadioButton(buttonValue, ct.getCategory().getName());
+ b.setText(buttonValue.format());
+
+ if (lastState != null && patchSetId.equals(lastState.patchSetId)
+ && lastState.approvalValues.containsKey(buttonValue.getCategoryId())) {
+ b.setValue(lastState.approvalValues.get(buttonValue.getCategoryId()).equals(
+ buttonValue));
+ } else {
+ b.setValue(prior != null ? buttonValue.getValue() == prior.getValue()
+ : buttonValue.getValue() == 0);
+ }
+
+ approvalButtons.add(b);
+ vp.add(b);
+ }
+ body.add(vp);
+ }
+
+ private void populateActions(final PatchSetPublishDetail result) {
+ final boolean isOpen = result.getChange().getStatus().isOpen();
+ final boolean isNew = result.getChange().getStatus() == Change.Status.NEW;
+
+ {
+ final Button button = new Button(Util.C.buttonPublishCommentsSend());
+ button.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ publishComments(new GerritCallback<VoidResult>() {
+ @Override
+ public void onSuccess(VoidResult result) {
+ setSaveState(false);
+ for (Delegate delegate : delegates) {
+ delegate.onPublish();
+ }
+ }
+ });
+ }
+ });
+ actionsPanel.add(button);
+ }
+
+ if (isNew && result.canStage()) {
+ final Button button = new Button(Util.C.buttonPublishStagingSend());
+ button.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ publishComments(new GerritCallback<VoidResult>() {
+ @Override
+ public void onSuccess(VoidResult result) {
+ stage();
+ setSaveState(false);
+ }
+ });
+ }
+ });
+ actionsPanel.add(button);
+ }
+
+ if (isOpen && result.canSubmit()) {
+ final Button button = new Button(Util.C.buttonPublishSubmitSend());
+ button.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ publishComments(new GerritCallback<VoidResult>() {
+ @Override
+ public void onSuccess(VoidResult result) {
+ submit();
+ setSaveState(false);
+ }
+ });
+ }
+ });
+ actionsPanel.add(button);
+ }
+
+ {
+ final Button button = new Button(Util.C.buttonPublishCommentsCancel());
+ button.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ setSaveState(false);
+ for (Delegate delegate : delegates) {
+ delegate.onCancel();
+ }
+ }
+ });
+ actionsPanel.add(button);
+ }
+
+ body.add(actionsPanel);
+ }
+
+ private void publishComments(final GerritCallback<VoidResult> callback) {
+ PatchUtil.DETAIL_SVC.publishComments(patchSetId, message.getText().trim(),
+ new HashSet<ApprovalCategoryValue.Id>(getValues().values()), callback);
+ }
+
+ private void stage() {
+ Util.MANAGE_SVC.stage(patchSetId, new GerritCallback<ChangeDetail>() {
+ @Override
+ public void onSuccess(ChangeDetail result) {
+ for (Delegate delegate : delegates) {
+ delegate.onStage();
+ }
+ }
+ });
+ }
+
+ private void submit() {
+ Util.MANAGE_SVC.submit(patchSetId,
+ new GerritCallback<ChangeDetail>() {
+ public void onSuccess(ChangeDetail result) {
+ for (Delegate delegate : delegates) {
+ delegate.onSubmit();
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void onUnload() {
+ lastState = saveState ? new SavedState(this) : null;
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ContentTableKeyNavigation.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ContentTableKeyNavigation.java
new file mode 100644
index 0000000000..8bf17cf1ef
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ContentTableKeyNavigation.java
@@ -0,0 +1,158 @@
+// Copyright (C) 2011 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.ui;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.changes.Util;
+import com.google.gerrit.client.patches.PatchUtil;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.globalkey.client.GlobalKey;
+import com.google.gwtexpui.globalkey.client.KeyCommand;
+import com.google.gwtexpui.globalkey.client.KeyCommandSet;
+
+public abstract class ContentTableKeyNavigation extends AbstractKeyNavigation {
+ private class InsertCommentCommand extends NeedsSignInKeyCommand {
+ public InsertCommentCommand(int mask, int key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onInsertComment();
+ }
+ }
+ private class NextChunkKeyCmd extends KeyCommand {
+ public NextChunkKeyCmd(int mask, int key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onChunkNext();
+ }
+ }
+
+ private class NextCommentCmd extends KeyCommand {
+ public NextCommentCmd(int mask, int key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onCommentNext();
+ }
+ };
+ private class PrevChunkKeyCmd extends KeyCommand {
+ public PrevChunkKeyCmd(int mask, int key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onChunkPrev();
+ }
+ };
+ private class PrevCommentCmd extends KeyCommand {
+ public PrevCommentCmd(int mask, int key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onCommentPrev();
+ }
+ };
+ private class PublishCommentsKeyCommand extends NeedsSignInKeyCommand {
+ public PublishCommentsKeyCommand(int mask, char key, String help) {
+ super(mask, key, help);
+ }
+
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ onPublishComments();
+ }
+ };
+
+ private final KeyCommandSet keysComment;;
+ private HandlerRegistration regComment;;
+ public ContentTableKeyNavigation(final Widget parent) {
+ super(parent);
+
+ if (Gerrit.isSignedIn()) {
+ keysComment = new KeyCommandSet(PatchUtil.C.commentEditorSet());
+ } else {
+ keysComment = null;
+ }
+
+ setKeyHelp(Action.NEXT, PatchUtil.C.lineNext());
+ setKeyHelp(Action.PREV, PatchUtil.C.linePrev());
+ setKeyHelp(Action.OPEN, PatchUtil.C.expandComment());
+ };
+ public void initializeKeys() {
+ super.initializeKeys();
+
+ keysNavigation.add(new PrevChunkKeyCmd(0, 'p', PatchUtil.C.chunkPrev()));
+ keysNavigation.add(new NextChunkKeyCmd(0, 'n', PatchUtil.C.chunkNext()));
+ keysNavigation.add(new PrevCommentCmd(0, 'P', PatchUtil.C.commentPrev()));
+ keysNavigation.add(new NextCommentCmd(0, 'N', PatchUtil.C.commentNext()));
+
+ if (Gerrit.isSignedIn()) {
+ keysAction.add(new InsertCommentCommand(0, 'c', PatchUtil.C
+ .commentInsert()));
+ keysAction.add(new PublishCommentsKeyCommand(0, 'r', Util.C
+ .keyPublishComments()));
+
+ // See CommentEditorPanel
+ //
+
+ keysComment.add(new NoOpKeyCommand(KeyCommand.M_CTRL, 's', PatchUtil.C
+ .commentSaveDraft()));
+ keysComment.add(new NoOpKeyCommand(0, KeyCodes.KEY_ESCAPE, PatchUtil.C
+ .commentCancelEdit()));
+ }
+ };
+
+ public void setRegisterKeys(final boolean on) {
+ super.setRegisterKeys(on);
+ if (on) {
+ if (Gerrit.isSignedIn()) {
+ regComment = GlobalKey.add(parent, keysComment);
+ }
+ } else {
+ if (regComment != null) {
+ regComment.removeHandler();
+ regComment = null;
+ }
+ }
+ }
+
+ protected void onCancelEdit() {}
+
+ protected void onChunkNext() {}
+
+ protected void onChunkPrev() {}
+
+ protected void onCommentNext() {}
+
+ protected void onCommentPrev() {}
+
+ protected void onInsertComment() {}
+
+ protected void onPublishComments() {}
+
+ protected void onSaveDraft() {}
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Diff.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Diff.java
new file mode 100644
index 0000000000..7d98268cfb
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Diff.java
@@ -0,0 +1,198 @@
+// Copyright (C) 2011 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.ui;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.changes.PatchTable;
+import com.google.gerrit.client.patches.AbstractPatchContentTable;
+import com.google.gerrit.client.patches.PatchScreen;
+import com.google.gerrit.client.patches.PatchUtil;
+import com.google.gerrit.client.patches.SideBySideTable;
+import com.google.gerrit.client.patches.UnifiedDiffTable;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.reviewdb.AccountDiffPreference;
+import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.PatchSet.Id;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public abstract class Diff extends Composite implements
+ AbstractPatchContentTable.Delegate {
+ public interface Delegate {
+ void onFocus(Diff diff);
+ void onLoad(Diff diff);
+ }
+ public interface Factory {
+ Diff createDiff(Patch.Key patchKey, Id sideA, Id sideB,
+ AccountDiffPreference prefs);
+ PatchScreen.Type getType();
+ }
+ public static class SideBySide extends Diff {
+ public SideBySide(Patch.Key patchKey, Id sideA,
+ Id sideB, AccountDiffPreference prefs) {
+ super(patchKey, sideA, sideB, prefs);
+ }
+
+ @Override
+ protected AbstractPatchContentTable createContentTable() {
+ return new SideBySideTable();
+ }
+
+ @Override
+ protected PatchScreen.Type getPatchScreenType() {
+ return PatchScreen.Type.SIDE_BY_SIDE;
+ }
+ }
+ public static class SideBySideFactory implements Factory {
+ public Diff createDiff(Patch.Key patchKey, Id sideA, Id sideB,
+ AccountDiffPreference prefs) {
+ return new SideBySide(patchKey, sideA, sideB, prefs);
+ }
+
+ public PatchScreen.Type getType() {
+ return PatchScreen.Type.SIDE_BY_SIDE;
+ }
+ }
+ public static class Unified extends Diff {
+ public Unified(Patch.Key patchKey, Id sideA,
+ Id sideB, AccountDiffPreference prefs) {
+ super(patchKey, sideA, sideB, prefs);
+ setShowFileName(false);
+ }
+
+ @Override
+ protected AbstractPatchContentTable createContentTable() {
+ return new UnifiedDiffTable();
+ }
+
+ @Override
+ protected PatchScreen.Type getPatchScreenType() {
+ return PatchScreen.Type.UNIFIED;
+ }
+ }
+ public static class UnifiedFactory implements Factory {
+ public Diff createDiff(Patch.Key patchKey, Id sideA, Id sideB,
+ AccountDiffPreference prefs) {
+ return new Unified(patchKey, sideA, sideB, prefs);
+ }
+
+ public PatchScreen.Type getType() {
+ return PatchScreen.Type.UNIFIED;
+ }
+ }
+
+ private final Patch.Key patchKey;
+ private final PatchSet.Id sideA;
+ private final PatchSet.Id sideB;
+ private AccountDiffPreference diffPreference;
+ private final Panel body;
+ private AbstractPatchContentTable contentTable;
+ private boolean intralineFailure = false;
+ private Set<Delegate> delegates;
+ private boolean loaded = false;
+ private boolean showFileName = true;
+
+ public Diff(final Patch.Key patchKey,
+ final PatchSet.Id sideA, final PatchSet.Id sideB,
+ final AccountDiffPreference prefs) {
+ this.patchKey = patchKey;
+ this.sideA = sideA;
+ this.sideB = sideB;
+ this.diffPreference = prefs;
+ delegates = new HashSet<Diff.Delegate>();
+
+ body = new VerticalPanel();
+ body.setStyleName(Gerrit.RESOURCES.css().patchContentTable());
+
+ initWidget(body);
+ }
+
+ @Override
+ public void onClick() {
+ for (Delegate delegate : delegates) {
+ delegate.onFocus(this);
+ }
+ }
+
+ public void addDelegate(final Delegate delegate) {
+ delegates.add(delegate);
+ }
+
+ public AbstractPatchContentTable getContentTable() {
+ return contentTable;
+ }
+
+ public boolean hasIntralineFailure() {
+ return intralineFailure;
+ }
+
+ public boolean isLoaded() {
+ return loaded;
+ }
+
+ public void load() {
+ PatchUtil.DETAIL_SVC.patchScript(patchKey, sideA, sideB,
+ diffPreference, new GerritCallback<PatchScript>() {
+ @Override
+ public void onSuccess(final PatchScript result) {
+ updateContent(result);
+ intralineFailure = result.hasIntralineFailure();
+ }
+ });
+ }
+
+ public void removeDelegate(final Delegate delegate) {
+ delegates.remove(delegate);
+ }
+
+ private void updateContent(final PatchScript patchScript) {
+ contentTable.display(patchKey, sideA, sideB, patchScript);
+ contentTable.display(patchScript.getCommentDetail(), true);
+ }
+
+ protected abstract AbstractPatchContentTable createContentTable();
+
+ protected abstract PatchScreen.Type getPatchScreenType();
+
+ @Override
+ protected void onLoad() {
+ super.onLoad();
+
+ if (showFileName) {
+ final String path = PatchTable.getDisplayFileName(patchKey);
+ final Label fileNameLabel = new Label(path);
+ fileNameLabel.setStyleName(Gerrit.RESOURCES.css().diffFileName());
+ body.add(fileNameLabel);
+ }
+ contentTable = createContentTable();
+ contentTable.addDelegate(this);
+ body.add(contentTable);
+
+ loaded = true;
+ for (Delegate delegate : delegates) {
+ delegate.onLoad(this);
+ }
+ }
+
+ protected void setShowFileName(final boolean showFileName) {
+ this.showFileName = showFileName;
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
index 3fca1b1bef..38539029ba 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
@@ -49,7 +49,7 @@ public abstract class FancyFlexTable<RowItem> extends Composite {
return new MyFlexTable();
}
- protected RowItem getRowItem(final int row) {
+ public RowItem getRowItem(final int row) {
return FancyFlexTable.<RowItem> getRowItem(table.getCellFormatter()
.getElement(row, 0));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Message.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Message.java
new file mode 100644
index 0000000000..bfddbf3d7f
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Message.java
@@ -0,0 +1,81 @@
+// Copyright (C) 2011 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.ui;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.changes.Util;
+import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwtexpui.globalkey.client.NpTextArea;
+
+public class Message extends Composite {
+ private class SavedState {
+ final PatchSet.Id patchSetId;
+ final String text;
+ public SavedState(final Message message) {
+ patchSetId = message.patchSetId;
+ text = message.getText();
+ }
+ }
+ private static SavedState lastState;
+ private boolean saveState = true;
+ private PatchSet.Id patchSetId;
+
+ private NpTextArea message;
+
+ public Message(final PatchSet.Id patchSetId) {
+ this.patchSetId = patchSetId;
+
+ VerticalPanel body = new VerticalPanel();
+
+ body.add(new SmallHeading(Util.C.headingCoverMessage()));
+
+ final VerticalPanel editAreaContainer = new VerticalPanel();
+ editAreaContainer.setStyleName(Gerrit.RESOURCES.css().coverMessage());
+ body.add(editAreaContainer);
+
+ message = new NpTextArea();
+ message.setCharacterWidth(60);
+ message.setVisibleLines(10);
+ message.setSpellCheck(true);
+ editAreaContainer.add(message);
+
+ initWidget(body);
+ }
+
+ public String getText() {
+ return message.getText();
+ }
+
+ public void setFocus(final boolean focus) {
+ message.setFocus(focus);
+ }
+
+ public void setSaveState(boolean saveState) {
+ this.saveState = saveState;
+ }
+
+ @Override
+ protected void onLoad() {
+ if (lastState != null && patchSetId.equals(lastState.patchSetId)) {
+ message.setText(lastState.text);
+ }
+ }
+
+ @Override
+ protected void onUnload() {
+ lastState = saveState ? new SavedState(this) : null;
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java
index 0d45529f16..5fe9f9d994 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java
@@ -16,8 +16,6 @@ package com.google.gerrit.client.ui;
import com.google.gerrit.client.Gerrit;
import com.google.gwt.dom.client.Document;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Image;
@@ -25,9 +23,6 @@ import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.KeyCommand;
-import com.google.gwtexpui.globalkey.client.KeyCommandSet;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import java.util.LinkedHashMap;
@@ -43,28 +38,48 @@ public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
}
};
+ protected class DefaultKeyNavigation extends AbstractKeyNavigation {
+ public DefaultKeyNavigation(Widget parent) {
+ super(parent);
+ }
+
+ @Override
+ protected void onNext() {
+ ensurePointerVisible();
+ onDown();
+ }
+
+ @Override
+ protected void onPrev() {
+ ensurePointerVisible();
+ onUp();
+ }
+
+ @Override
+ protected void onOpen() {
+ ensurePointerVisible();
+ onOpenCurrent();
+ }
+ }
+
private final Image pointer;
- protected final KeyCommandSet keysNavigation;
- protected final KeyCommandSet keysAction;
- private HandlerRegistration regNavigation;
- private HandlerRegistration regAction;
private int currentRow = -1;
private String saveId;
private boolean computedScrollType;
private ScrollPanel parentScrollPanel;
+ protected AbstractKeyNavigation keyNavigation;
+
protected NavigationTable() {
pointer = new Image(Gerrit.RESOURCES.arrowRight());
- keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
- keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
}
protected abstract void onOpenRow(int row);
protected abstract Object getRowItemKey(RowItem item);
- private void onUp() {
+ public void onUp() {
for (int row = currentRow - 1; row >= 0; row--) {
if (getRowItem(row) != null) {
movePointerTo(row);
@@ -73,7 +88,7 @@ public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
}
}
- private void onDown() {
+ public void onDown() {
final int max = table.getRowCount();
for (int row = currentRow + 1; row < max; row++) {
if (getRowItem(row) != null) {
@@ -83,7 +98,7 @@ public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
}
}
- private void onOpen() {
+ public void onOpenCurrent() {
if (0 <= currentRow && currentRow < table.getRowCount()) {
if (getRowItem(currentRow) != null) {
onOpenRow(currentRow);
@@ -91,11 +106,15 @@ public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
}
}
- protected int getCurrentRow() {
+ public int getCurrentRow() {
return currentRow;
}
- protected void ensurePointerVisible() {
+ public int getMaxRows() {
+ return table.getRowCount();
+ }
+
+ public void ensurePointerVisible() {
final int max = table.getRowCount();
int row = currentRow;
final int init = row;
@@ -128,6 +147,28 @@ public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
}
}
+ public void hideCursor() {
+ final int noCursor = -1;
+ if (currentRow != noCursor) {
+ final CellFormatter fmt = table.getCellFormatter();
+ final Element tr = DOM.getParent(fmt.getElement(currentRow, C_ARROW));
+ UIObject.setStyleName(tr, Gerrit.RESOURCES.css().activeRow(), false);
+
+ table.setWidget(currentRow, C_ARROW, null);
+ pointer.removeFromParent();
+ }
+ }
+
+ public void showCursor() {
+ final int noCursor = -1;
+ if (currentRow != noCursor) {
+ final CellFormatter fmt = table.getCellFormatter();
+ table.setWidget(currentRow, C_ARROW, pointer);
+ final Element tr = DOM.getParent(fmt.getElement(currentRow, C_ARROW));
+ UIObject.setStyleName(tr, Gerrit.RESOURCES.css().activeRow(), true);
+ }
+ }
+
protected void movePointerTo(final int newRow) {
movePointerTo(newRow, true);
}
@@ -218,21 +259,11 @@ public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
}
public void setRegisterKeys(final boolean on) {
- if (on && isAttached()) {
- if (regNavigation == null) {
- regNavigation = GlobalKey.add(this, keysNavigation);
- }
- if (regAction == null) {
- regAction = GlobalKey.add(this, keysAction);
- }
- } else {
- if (regNavigation != null) {
- regNavigation.removeHandler();
- regNavigation = null;
- }
- if (regAction != null) {
- regAction.removeHandler();
- regAction = null;
+ if (keyNavigation != null) {
+ if (on && isAttached()) {
+ keyNavigation.setRegisterKeys(true);
+ } else {
+ keyNavigation.setRegisterKeys(false);
}
}
}
@@ -258,40 +289,4 @@ public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
parentScrollPanel = null;
super.onUnload();
}
-
- public class PrevKeyCommand extends KeyCommand {
- public PrevKeyCommand(int mask, char key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- onUp();
- }
- }
-
- public class NextKeyCommand extends KeyCommand {
- public NextKeyCommand(int mask, char key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- onDown();
- }
- }
-
- public class OpenKeyCommand extends KeyCommand {
- public OpenKeyCommand(int mask, int key, String help) {
- super(mask, key, help);
- }
-
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- ensurePointerVisible();
- onOpen();
- }
- }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java
index 9979edf659..11a362fa47 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java
@@ -16,6 +16,8 @@ package com.google.gerrit.client.ui;
import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.changes.PatchTable;
+import com.google.gerrit.client.patches.AbstractPatchScreen;
+import com.google.gerrit.client.patches.AllInOnePatchScreen;
import com.google.gerrit.common.data.PatchSetDetail;
import com.google.gerrit.reviewdb.Patch;
@@ -44,6 +46,19 @@ public abstract class PatchLink extends InlineHyperlink {
this.parentPatchTable = parentPatchTable;
}
+ public static class All extends PatchLink {
+ public All(final String text, final AbstractPatchScreen.Type type,
+ final AllInOnePatchScreen patchScreen) {
+ super(text, //
+ patchScreen.getPatchKey(), //
+ 0, //
+ Dispatcher.toPatchAll(type, patchScreen.getPatchSetDetail()), //
+ patchScreen.getPatchSetDetail(), //
+ patchScreen.getFileList() //
+ );
+ }
+ }
+
@Override
public void go() {
Dispatcher.patch( //
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
index 96089b902b..f1aea52966 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
@@ -16,8 +16,8 @@ package com.google.gerrit.client.ui;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.ui.NavigationTable;
+import com.google.gerrit.client.ui.AbstractKeyNavigation.Action;
import com.google.gerrit.reviewdb.Project;
-import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -26,13 +26,12 @@ import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import java.util.List;
public class ProjectsTable extends NavigationTable<Project> {
-
public ProjectsTable() {
- keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.projectListPrev()));
- keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.projectListNext()));
- keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.projectListOpen()));
- keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER,
- Util.C.projectListOpen()));
+ keyNavigation = new DefaultKeyNavigation(this);
+ keyNavigation.setKeyHelp(Action.NEXT, Util.C.projectListNext());
+ keyNavigation.setKeyHelp(Action.PREV, Util.C.projectListPrev());
+ keyNavigation.setKeyHelp(Action.OPEN, Util.C.projectListOpen());
+ keyNavigation.initializeKeys();
table.setText(0, 1, Util.C.projectName());
table.setText(0, 2, Util.C.projectDescription());