Merge changes I4ada8109,I483822f8 * changes: Add action to edit the project configuration in the browser EditScreen: Wait until CodeMirror Library is initialized
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java index 371a472..b18e219 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
@@ -82,7 +82,8 @@ private final static String FILE_NAME3 = "foo3"; private final static byte[] CONTENT_OLD = "bar".getBytes(UTF_8); private final static byte[] CONTENT_NEW = "baz".getBytes(UTF_8); - private final static byte[] CONTENT_NEW2 = "quxÄÜÖßµ".getBytes(UTF_8); + private final static String CONTENT_NEW2_STR = "quxÄÜÖßµ"; + private final static byte[] CONTENT_NEW2 = CONTENT_NEW2_STR.getBytes(UTF_8); @Inject private SchemaFactory<ReviewDb> reviewDbProvider; @@ -302,7 +303,7 @@ .isEqualTo(SC_NOT_FOUND); EditMessage.Input in = new EditMessage.Input(); in.message = String.format("New commit message\n\n" + - CONTENT_NEW2 + "\n\nChange-Id: %s", + CONTENT_NEW2_STR + "\n\nChange-Id: %s", change.getKey()); assertThat(adminSession.put(urlEditMessage(), in).getStatusCode()) .isEqualTo(SC_NO_CONTENT);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ConfirmationDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ConfirmationDialog.java index e85633f..ab3ff5d 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ConfirmationDialog.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ConfirmationDialog.java
@@ -25,8 +25,8 @@ public class ConfirmationDialog extends AutoCenterDialogBox { - private Button cancelButton; + private Button okButton; public ConfirmationDialog(final String dialogTitle, final SafeHtml message, final ConfirmationCallback callback) { @@ -36,7 +36,7 @@ final FlowPanel buttons = new FlowPanel(); - final Button okButton = new Button(); + okButton = new Button(); okButton.setText(Gerrit.C.confirmationDialogOk()); okButton.addClickHandler(new ClickHandler() { @Override @@ -76,4 +76,11 @@ GlobalKey.dialog(this); cancelButton.setFocus(true); } + + public void setCancelVisible(boolean visible) { + cancelButton.setVisible(visible); + if (!visible) { + okButton.setFocus(true); + } + } }
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 d7bd00d8..6d94f1d 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
@@ -846,6 +846,11 @@ return new NotFoundScreen(); } + int q = rest.lastIndexOf('?'); + if (q > 0 && rest.lastIndexOf(',', q) > 0) { + c = rest.substring(0, q - 1).lastIndexOf(','); + } + Project.NameKey k = Project.NameKey.parse(rest.substring(0, c)); String panel = rest.substring(c + 1); @@ -853,7 +858,8 @@ return new ProjectInfoScreen(k); } - if (ProjectScreen.BRANCH.equals(panel)) { + if (ProjectScreen.BRANCH.equals(panel) + || matchPrefix(ProjectScreen.BRANCH, panel)) { return new ProjectBranchesScreen(k); }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java index 64025db..6bbc8f1 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -36,6 +36,9 @@ String confirmationDialogOk(); String confirmationDialogCancel(); + String branchCreationDialogTitle(); + String branchCreationConfirmationMessage(); + String branchDeletionDialogTitle(); String branchDeletionConfirmationMessage();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties index a335d6b..05de983 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -17,6 +17,9 @@ confirmationDialogOk = OK confirmationDialogCancel = Cancel +branchCreationDialogTitle = Branch Creation +branchCreationConfirmationMessage = The following branch was successfully created: + branchDeletionDialogTitle = Branch Deletion branchDeletionConfirmationMessage = Do you really want to delete the following branches?
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 cbf906e..c919c6b 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
@@ -31,6 +31,7 @@ String addWatchPanel(); String avatarInfoPanel(); String bottomheader(); + String branchTablePrevNextLinks(); String cAPPROVAL(); String cLastUpdate(); String cOWNER();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java index 66d9d67..9ec8c6c 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
@@ -31,10 +31,12 @@ import com.google.gerrit.client.rpc.NativeString; import com.google.gerrit.client.rpc.Natives; import com.google.gerrit.client.rpc.ScreenLoadCallback; -import com.google.gerrit.client.ui.FancyFlexTable; import com.google.gerrit.client.ui.HintTextBox; +import com.google.gerrit.client.ui.Hyperlink; +import com.google.gerrit.client.ui.NavigationTable; import com.google.gerrit.client.ui.OnEditEnabler; import com.google.gerrit.common.PageLinks; +import com.google.gerrit.reviewdb.client.AccountGeneralPreferences; import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.RefNames; @@ -48,12 +50,14 @@ import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.http.client.URL; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.TextBox; @@ -67,15 +71,62 @@ import java.util.Set; public class ProjectBranchesScreen extends ProjectScreen { + private Hyperlink prev; + private Hyperlink next; private BranchesTable branchTable; private Button delBranch; private Button addBranch; private HintTextBox nameTxtBox; private HintTextBox irevTxtBox; private FlowPanel addPanel; + private int pageSize; + private int start; + private Query query; public ProjectBranchesScreen(final Project.NameKey toShow) { super(toShow); + configurePageSize(); + } + + private void configurePageSize() { + if (Gerrit.isSignedIn()) { + AccountGeneralPreferences p = + Gerrit.getUserAccount().getGeneralPreferences(); + short m = p.getMaximumPageSize(); + pageSize = 0 < m ? m : AccountGeneralPreferences.DEFAULT_PAGESIZE; + } else { + pageSize = AccountGeneralPreferences.DEFAULT_PAGESIZE; + } + } + + private void parseToken() { + String token = getToken(); + + for (String kvPair : token.split("[,;&/?]")) { + String[] kv = kvPair.split("=", 2); + if (kv.length != 2 || kv[0].isEmpty()) { + continue; + } + + if ("skip".equals(kv[0]) + && URL.decodeQueryString(kv[1]).matches("^[\\d]+")) { + start = Integer.parseInt(URL.decodeQueryString(kv[1])); + } + } + } + + private void setupNavigationLink(Hyperlink link, int skip) { + link.setTargetHistoryToken(getTokenForScreen(skip)); + link.setVisible(true); + } + + private String getTokenForScreen(int skip) { + String token = PageLinks.toProjectBranches(getProjectKey()); + + if (skip > 0) { + token += "?skip=" + skip; + } + return token; } @Override @@ -89,28 +140,10 @@ addPanel.setVisible(result.canAddRefs()); } }); - refreshBranches(); + query = new Query().start(start).run(); savedPanel = BRANCH; } - private void refreshBranches() { - ProjectApi.getBranches(getProjectKey(), - new ScreenLoadCallback<JsArray<BranchInfo>>(this) { - @Override - public void preDisplay(final JsArray<BranchInfo> result) { - Set<String> checkedRefs = branchTable.getCheckedRefs(); - display(Natives.asList(result)); - branchTable.setChecked(checkedRefs); - updateForm(); - } - }); - } - - private void display(final List<BranchInfo> branches) { - branchTable.display(branches); - delBranch.setVisible(branchTable.hasBranchCanDelete()); - } - private void updateForm() { branchTable.updateDeleteButton(); addBranch.setEnabled(true); @@ -121,6 +154,13 @@ @Override protected void onInitUI() { super.onInitUI(); + parseToken(); + + prev = new Hyperlink(Util.C.pagedListPrev(), true, ""); + prev.setVisible(false); + + next = new Hyperlink(Util.C.pagedListNext(), true, ""); + next.setVisible(false); addPanel = new FlowPanel(); @@ -175,9 +215,13 @@ branchTable.deleteChecked(); } }); - + HorizontalPanel buttons = new HorizontalPanel(); + buttons.setStyleName(Gerrit.RESOURCES.css().branchTablePrevNextLinks()); + buttons.add(delBranch); + buttons.add(prev); + buttons.add(next); add(branchTable); - add(delBranch); + add(buttons); add(addPanel); } @@ -206,6 +250,7 @@ new GerritCallback<BranchInfo>() { @Override public void onSuccess(BranchInfo branch) { + showAddedBranch(branch); addBranch.setEnabled(true); nameTxtBox.setText(""); irevTxtBox.setText(""); @@ -213,21 +258,43 @@ delBranch.setVisible(branchTable.hasBranchCanDelete()); } - @Override - public void onFailure(Throwable caught) { - addBranch.setEnabled(true); - selectAllAndFocus(nameTxtBox); - new ErrorDialog(caught.getMessage()).center(); - } - }); + @Override + public void onFailure(Throwable caught) { + addBranch.setEnabled(true); + selectAllAndFocus(nameTxtBox); + new ErrorDialog(caught.getMessage()).center(); + } + }); } - private static void selectAllAndFocus(final TextBox textBox) { + void showAddedBranch(BranchInfo branch) { + SafeHtmlBuilder b = new SafeHtmlBuilder(); + b.openElement("b"); + b.append(Gerrit.C.branchCreationConfirmationMessage()); + b.closeElement("b"); + + b.openElement("p"); + b.append(branch.ref()); + b.closeElement("p"); + + ConfirmationDialog confirmationDialog = + new ConfirmationDialog(Gerrit.C.branchCreationDialogTitle(), + b.toSafeHtml(), new ConfirmationCallback() { + @Override + public void onOk() { + //do nothing + } + }); + confirmationDialog.center(); + confirmationDialog.setCancelVisible(false); + } + + private static void selectAllAndFocus(TextBox textBox) { textBox.selectAll(); textBox.setFocus(true); } - private class BranchesTable extends FancyFlexTable<BranchInfo> { + private class BranchesTable extends NavigationTable<BranchInfo> { private ValueChangeHandler<Boolean> updateDeleteHandler; boolean canDelete; @@ -332,19 +399,23 @@ @Override public void onFailure(Throwable caught) { - refreshBranches(); + query = new Query().start(start).run(); super.onFailure(caught); } }); } void display(List<BranchInfo> branches) { + displaySubset(branches, 0, branches.size()); + } + + void displaySubset(List<BranchInfo> branches, int fromIndex, int toIndex) { canDelete = false; while (1 < table.getRowCount()) table.removeRow(table.getRowCount() - 1); - for (final BranchInfo k : branches) { + for (BranchInfo k : branches.subList(fromIndex, toIndex)) { final int row = table.getRowCount(); table.insertRow(row); applyDataRowStyle(row); @@ -353,17 +424,21 @@ } void insert(BranchInfo info) { - Comparator<BranchInfo> c = new Comparator<BranchInfo>() { - @Override - public int compare(BranchInfo a, BranchInfo b) { - return a.ref().compareTo(b.ref()); + if (table.getRowCount() <= pageSize || pageSize == 0) { + Comparator<BranchInfo> c = new Comparator<BranchInfo>() { + @Override + public int compare(BranchInfo a, BranchInfo b) { + return a.ref().compareTo(b.ref()); + } + }; + int insertPos = getInsertRow(c, info); + if (insertPos >= 0) { + table.insertRow(insertPos); + applyDataRowStyle(insertPos); + populate(insertPos, info); } - }; - int insertPos = getInsertRow(c, info); - if (insertPos >= 0) { - table.insertRow(insertPos); - applyDataRowStyle(insertPos); - populate(insertPos, info); + } else { + setupNavigationLink(next, ProjectBranchesScreen.this.start + pageSize); } } @@ -530,5 +605,74 @@ } delBranch.setEnabled(on); } + + @Override + protected void onOpenRow(int row) { + if (row > 0) { + movePointerTo(row); + } + } + + @Override + protected Object getRowItemKey(BranchInfo item) { + return item.ref(); + } + } + + private class Query { + private int qStart; + + Query start(int start) { + this.qStart = start; + return this; + } + + Query run() { + // Retrieve one more branch than page size to determine if there are more + // branches to display + ProjectApi.getBranches(getProjectKey(), pageSize + 1, qStart, + new ScreenLoadCallback<JsArray<BranchInfo>>(ProjectBranchesScreen.this) { + @Override + public void preDisplay(JsArray<BranchInfo> result) { + if (!isAttached()) { + // View has been disposed. + } else if (query == Query.this) { + query = null; + showList(result); + } else { + query.run(); + } + } + }); + return this; + } + + void showList(JsArray<BranchInfo> result) { + setToken(getTokenForScreen(qStart)); + ProjectBranchesScreen.this.start = qStart; + + if (result.length() <= pageSize) { + branchTable.display(Natives.asList(result)); + next.setVisible(false); + } else { + branchTable.displaySubset(Natives.asList(result), 0, + result.length() - 1); + setupNavigationLink(next, qStart + pageSize); + } + if (qStart > 0) { + setupNavigationLink(prev, qStart - pageSize); + } else { + prev.setVisible(false); + } + + delBranch.setVisible(branchTable.hasBranchCanDelete()); + Set<String> checkedRefs = branchTable.getCheckedRefs(); + branchTable.setChecked(checkedRefs); + updateForm(); + + if (!isCurrentView()) { + display(); + } + } } }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java index fd9f4bc..f9054fe 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
@@ -351,7 +351,6 @@ final String id = lv.info.name(); final CheckBox b = new CheckBox(); b.setText(id); - b.setTitle(lv.info.value_text("+1")); b.setEnabled(lv.permitted.contains((short) 1)); if (self != null && self.value() == 1) { b.setValue(true); @@ -364,6 +363,10 @@ }); b.setStyleName(style.label_name()); labelsTable.setWidget(row, 0, b); + + CellFormatter fmt = labelsTable.getCellFormatter(); + fmt.setStyleName(row, labelHelpColumn, style.label_help()); + labelsTable.setText(row, labelHelpColumn, lv.info.value_text("+1")); } private static boolean isCheckBox(Set<Short> values) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java index bd25d60..5cf7d62 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
@@ -403,7 +403,7 @@ InlineHyperlink unified = new InlineHyperlink(); unified.setHTML(new ImageResourceRenderer() .render(Gerrit.RESOURCES.unifiedDiff())); - sbs.setTargetHistoryToken( + unified.setTargetHistoryToken( Dispatcher.toPatch("unified", base, new Patch.Key(revision, path))); unified.setTitle(PatchUtil.C.unifiedDiff()); linkPanel.add(unified);
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 38b2f69..0d0f793 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
@@ -1232,6 +1232,20 @@ cursor: pointer; } +.branchTablePrevNextLinks { + position: relative; +} +.branchTablePrevNextLinks td { + float: left; + width: 5em; + text-align: left; + padding-right: 10px; +} +.branchTablePrevNextLinks .gwt-Hyperlink { + font-size: 9pt; + color: #2a5db0; +} + /** PluginListScreen **/ .pluginsTable { }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java index f4f7087..b657f23 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
@@ -58,6 +58,14 @@ project(name).view("branches").get(cb); } + public static void getBranches(Project.NameKey name, int limit, int start, + AsyncCallback<JsArray<BranchInfo>> cb) { + RestApi call = project(name).view("branches"); + call.addParameter("n", limit); + call.addParameter("s", start); + call.get(cb); + } + /** * Delete branches. One call is fired to the server to delete all the * branches.
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java index f5ab20a..b02c591 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
@@ -22,6 +22,7 @@ import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventTypes; import com.google.gerrit.server.git.WorkQueue; import com.google.gerrit.server.git.WorkQueue.CancelableRunnable; import com.google.gerrit.sshd.BaseCommand; @@ -64,10 +65,17 @@ private final Gson gson = new Gson(); /** Special event to notify clients they missed other events. */ - private final Object droppedOutputEvent = new Object() { - @SuppressWarnings("unused") - final String type = "dropped-output"; - }; + private static final class DroppedOutputEvent extends Event { + public DroppedOutputEvent() { + super("dropped-output"); + } + } + + private static final DroppedOutputEvent droppedOutputEvent = new DroppedOutputEvent(); + + static { + EventTypes.registerClass(droppedOutputEvent); + } private final EventListener listener = new EventListener() { @Override