| // Copyright (C) 2010 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.changes; |
| |
| import com.google.gerrit.client.Gerrit; |
| import com.google.gerrit.common.PageLinks; |
| import com.google.gerrit.common.data.ChangeDetail; |
| import com.google.gerrit.reviewdb.AccountGeneralPreferences; |
| import com.google.gerrit.reviewdb.PatchSet; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.event.dom.client.KeyPressEvent; |
| import com.google.gwt.event.logical.shared.OpenEvent; |
| import com.google.gwt.event.logical.shared.OpenHandler; |
| import com.google.gwt.event.shared.HandlerRegistration; |
| import com.google.gwt.user.client.ui.Composite; |
| import com.google.gwt.user.client.ui.DisclosurePanel; |
| import com.google.gwt.user.client.ui.FlowPanel; |
| 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.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Composite that displays the patch sets of a change. This composite ensures |
| * that keyboard navigation to each changed file in all patch sets is possible. |
| */ |
| public class PatchSetsBlock extends Composite { |
| |
| private final Map<PatchSet.Id, PatchSetComplexDisclosurePanel> patchSetPanels = |
| new HashMap<PatchSet.Id, PatchSetComplexDisclosurePanel>(); |
| |
| private final ChangeScreen parent; |
| private final FlowPanel body; |
| private HandlerRegistration regNavigation; |
| |
| private List<PatchSetComplexDisclosurePanel> patchSetPanelsList; |
| |
| /** |
| * the patch set id of the patch set for which is the keyboard navigation is |
| * currently enabled |
| */ |
| private PatchSet.Id activePatchSetId; |
| |
| /** the patch set id of the current (latest) patch set */ |
| private PatchSet.Id currentPatchSetId; |
| |
| /** Patch sets on this change, in order. */ |
| private List<PatchSet> patchSets; |
| |
| PatchSetsBlock(final ChangeScreen parent) { |
| this.parent = parent; |
| body = new FlowPanel(); |
| initWidget(body); |
| } |
| |
| /** Adds UI elements for each patch set of the given change to this composite. */ |
| public void display(final ChangeDetail detail, final PatchSet.Id diffBaseId) { |
| clear(); |
| |
| final PatchSet currps = detail.getCurrentPatchSet(); |
| currentPatchSetId = currps.getId(); |
| patchSets = detail.getPatchSets(); |
| |
| final List<PatchSet.Id> changePatchSets = new ArrayList<PatchSet.Id>(); |
| |
| for (final PatchSet ps : patchSets) { |
| changePatchSets.add(ps.getId()); |
| } |
| |
| if (Gerrit.isSignedIn()) { |
| final AccountGeneralPreferences p = |
| Gerrit.getUserAccount().getGeneralPreferences(); |
| if (p.isDisplayPatchSetsInReverseOrder()) { |
| Collections.reverse(patchSets); |
| } |
| } |
| |
| patchSetPanelsList = new ArrayList<PatchSetComplexDisclosurePanel>(); |
| |
| for (final PatchSet ps : patchSets) { |
| final PatchSetComplexDisclosurePanel p; |
| if (ps == currps) { |
| p = new PatchSetComplexDisclosurePanel(parent, detail, detail |
| .getCurrentPatchSetDetail()); |
| if (diffBaseId != null) { |
| p.setDiffBaseId(diffBaseId); |
| p.refresh(); |
| } |
| } else { |
| p = new PatchSetComplexDisclosurePanel(parent, detail, ps); |
| if (diffBaseId != null) { |
| p.setDiffBaseId(diffBaseId); |
| } |
| } |
| add(p); |
| patchSetPanelsList.add(p); |
| } |
| } |
| |
| private void clear() { |
| setRegisterKeys(false); |
| body.clear(); |
| patchSetPanels.clear(); |
| } |
| |
| public void refresh(final PatchSet.Id diffBaseId) { |
| if (patchSetPanelsList != null) { |
| for (final PatchSetComplexDisclosurePanel p : patchSetPanelsList) { |
| p.setDiffBaseId(diffBaseId); |
| if (p.isOpen()) { |
| p.refresh(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Adds the given patch set panel to this composite and ensures that handler |
| * to activate / deactivate keyboard navigation for the patch set panel are |
| * registered. |
| */ |
| private void add(final PatchSetComplexDisclosurePanel patchSetPanel) { |
| body.add(patchSetPanel); |
| |
| final PatchSet.Id id = patchSetPanel.getPatchSet().getId(); |
| ActivationHandler activationHandler = new ActivationHandler(id); |
| patchSetPanel.addOpenHandler(activationHandler); |
| patchSetPanel.addClickHandler(activationHandler); |
| patchSetPanels.put(id, patchSetPanel); |
| } |
| |
| public void setRegisterKeys(final boolean on) { |
| if (on) { |
| KeyCommandSet keysNavigation = |
| new KeyCommandSet(Gerrit.C.sectionNavigation()); |
| keysNavigation.add(new PreviousPatchSetKeyCommand(0, 'p', Util.C |
| .previousPatchSet())); |
| keysNavigation.add(new NextPatchSetKeyCommand(0, 'n', Util.C |
| .nextPatchSet())); |
| regNavigation = GlobalKey.add(this, keysNavigation); |
| if (activePatchSetId != null) { |
| activate(activePatchSetId); |
| } else { |
| activate(currentPatchSetId); |
| } |
| } else { |
| if (regNavigation != null) { |
| regNavigation.removeHandler(); |
| regNavigation = null; |
| } |
| deactivate(); |
| } |
| } |
| |
| @Override |
| protected void onUnload() { |
| setRegisterKeys(false); |
| super.onUnload(); |
| } |
| |
| /** |
| * Activates keyboard navigation for the patch set panel that displays the |
| * patch set with the given patch set id. |
| * The keyboard navigation for the previously active patch set panel is |
| * automatically deactivated. |
| * This method also ensures that the current row is only highlighted in the |
| * table of the active patch set panel. |
| */ |
| public void activate(final PatchSet.Id patchSetId) { |
| if (indexOf(patchSetId) != -1) { |
| if (!patchSetId.equals(activePatchSetId)) { |
| deactivate(); |
| PatchSetComplexDisclosurePanel patchSetPanel = |
| patchSetPanels.get(patchSetId); |
| patchSetPanel.setOpen(true); |
| patchSetPanel.setActive(true); |
| activePatchSetId = patchSetId; |
| } |
| } else { |
| Gerrit.display(PageLinks.toChange(patchSetId.getParentKey())); |
| } |
| } |
| |
| /** Deactivates the keyboard navigation for the currently active patch set panel. */ |
| private void deactivate() { |
| if (activePatchSetId != null) { |
| PatchSetComplexDisclosurePanel patchSetPanel = |
| patchSetPanels.get(activePatchSetId); |
| patchSetPanel.setActive(false); |
| activePatchSetId = null; |
| } |
| } |
| |
| public PatchSet getCurrentPatchSet() { |
| PatchSetComplexDisclosurePanel patchSetPanel = |
| patchSetPanels.get(currentPatchSetId); |
| if (patchSetPanel != null) { |
| return patchSetPanel.getPatchSet(); |
| } else { |
| return null; |
| } |
| } |
| |
| private int indexOf(PatchSet.Id id) { |
| for (int i = 0; i < patchSets.size(); i++) { |
| if (patchSets.get(i).getId().equals(id)) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| private class ActivationHandler implements OpenHandler<DisclosurePanel>, |
| ClickHandler { |
| |
| private final PatchSet.Id patchSetId; |
| |
| ActivationHandler(PatchSet.Id patchSetId) { |
| this.patchSetId = patchSetId; |
| } |
| |
| @Override |
| public void onOpen(OpenEvent<DisclosurePanel> event) { |
| // when a patch set panel is opened by the user |
| // it should automatically become active |
| activate(patchSetId); |
| } |
| |
| @Override |
| public void onClick(ClickEvent event) { |
| // when a user clicks on a patch table the corresponding |
| // patch set panel should automatically become active |
| activate(patchSetId); |
| } |
| |
| } |
| |
| public class PreviousPatchSetKeyCommand extends KeyCommand { |
| public PreviousPatchSetKeyCommand(int mask, char key, String help) { |
| super(mask, key, help); |
| } |
| |
| @Override |
| public void onKeyPress(final KeyPressEvent event) { |
| int index = indexOf(activePatchSetId) - 1; |
| if (0 <= index) { |
| activate(patchSets.get(index).getId()); |
| } |
| } |
| } |
| |
| public class NextPatchSetKeyCommand extends KeyCommand { |
| public NextPatchSetKeyCommand(int mask, char key, String help) { |
| super(mask, key, help); |
| } |
| |
| @Override |
| public void onKeyPress(final KeyPressEvent event) { |
| int index = indexOf(activePatchSetId) + 1; |
| if (index < patchSets.size()) { |
| activate(patchSets.get(index).getId()); |
| } |
| } |
| } |
| } |