diff options
author | Mika Hamalainen <mika.hamalainen@accenture.com> | 2011-06-22 17:32:38 +0200 |
---|---|---|
committer | Mika Hamalainen <mika.hamalainen@accenture.com> | 2011-08-10 12:30:29 +0300 |
commit | 737400d1bad4fa8bfd39cb326636a0307014901f (patch) | |
tree | e3c1508d2bc87abde46c8e3edef4707f9448e994 | |
parent | b845077a35fba82271c96502d33086a3156ef1d2 (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
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()); |