From 8b7774d2843fc7156e5da514e71e144fd59d24d7 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 3 Apr 2011 14:24:52 +0200 Subject: [PATCH] added paging to ChangesetViewer --- .../scm/repository/HgChangesetViewer.java | 73 ++++++---- .../main/java/sonia/scm/io/SimpleCommand.java | 9 +- .../scm/repository/ChangesetPagingResult.java | 131 ++++++++++++++++++ .../sonia/scm/repository/ChangesetViewer.java | 19 +-- .../rest/resources/RepositoryResource.java | 29 ++-- .../webapp/resources/js/sonia.repository.js | 15 +- 6 files changed, 213 insertions(+), 63 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/ChangesetPagingResult.java diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java index eba4bc7c23..07df39aa03 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgChangesetViewer.java @@ -54,7 +54,6 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.List; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -73,9 +72,12 @@ public class HgChangesetViewer implements ChangesetViewer public static final String ID_TIP = "tip"; /** Field description */ - public static final String TEMPLATE = + public static final String TEMPLATE_CHANGESETS = "{rev}:{node|short}{author|escape}{desc|escape}{date|isodatesec}\n"; + /** Field description */ + public static final String TEMPLATE_TOTAL = "{rev}"; + /** the logger for HgChangesetViewer */ private static final Logger logger = LoggerFactory.getLogger(HgChangesetViewer.class); @@ -104,23 +106,34 @@ public class HgChangesetViewer implements ChangesetViewer /** * - * @param startId + * + * @param start * @param max * * @return */ @Override - public List getChangesets(String startId, int max) + public ChangesetPagingResult getChangesets(int start, int max) { - List changesets = null; + ChangesetPagingResult changesets = null; InputStream in = null; try { String repositoryPath = getRepositoryPath(repository); + int total = getTotalChangesets(repositoryPath); + int startRev = total - start; + int endRev = startRev - max; + + if (endRev < 0) + { + endRev = 0; + } + Command command = new SimpleCommand(handler.getConfig().getHgBinary(), - "-R", repositoryPath, "log", "-r", "tip:0", "-l", - String.valueOf(max), "--template", TEMPLATE); + "-R", repositoryPath, "log", "-r", + startRev + ":" + endRev, "--template", + TEMPLATE_CHANGESETS); CommandResult result = command.execute(); if (result.isSuccessfull()) @@ -132,12 +145,12 @@ public class HgChangesetViewer implements ChangesetViewer if ((cs != null) && Util.isNotEmpty(cs.getChangesets())) { - changesets = cs.getChangesets(); + changesets = new ChangesetPagingResult(total, cs.getChangesets()); } else if (logger.isWarnEnabled()) { - logger.warn("could not find any changeset from {} to +{}", startId, - max); + logger.warn("could not find any changeset from {} to {}", start, + start + max); } } else @@ -166,20 +179,6 @@ public class HgChangesetViewer implements ChangesetViewer return changesets; } - /** - * Method description - * - * - * @param max - * - * @return - */ - @Override - public List getLastChangesets(int max) - { - return getChangesets(ID_TIP, max); - } - /** * Method description * @@ -231,6 +230,32 @@ public class HgChangesetViewer implements ChangesetViewer return handler.getDirectory(repository).getAbsolutePath(); } + /** + * Method description + * + * + * @param repositoryPath + * + * @return + * + * @throws IOException + */ + private int getTotalChangesets(String repositoryPath) throws IOException + { + int total = 0; + Command command = new SimpleCommand(handler.getConfig().getHgBinary(), + "-R", repositoryPath, "tip", "--template", + TEMPLATE_TOTAL); + CommandResult result = command.execute(); + + if (result.isSuccessfull()) + { + total = Integer.parseInt(result.getOutput().trim()); + } + + return total; + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/io/SimpleCommand.java b/scm-core/src/main/java/sonia/scm/io/SimpleCommand.java index 37a09018f2..f85717f0df 100644 --- a/scm-core/src/main/java/sonia/scm/io/SimpleCommand.java +++ b/scm-core/src/main/java/sonia/scm/io/SimpleCommand.java @@ -117,7 +117,14 @@ public class SimpleCommand implements Command { if (logger.isDebugEnabled()) { - logger.debug("start external process {}", command); + StringBuilder cmd = new StringBuilder(); + + for (String c : command) + { + cmd.append(c).append(" "); + } + + logger.debug("start external process '{}'", cmd.toString()); } ProcessBuilder processBuilder = new ProcessBuilder(command); diff --git a/scm-core/src/main/java/sonia/scm/repository/ChangesetPagingResult.java b/scm-core/src/main/java/sonia/scm/repository/ChangesetPagingResult.java new file mode 100644 index 0000000000..86c3a7694b --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/ChangesetPagingResult.java @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.repository; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author Sebastian Sdorra + */ +@XmlRootElement(name = "changeset-paging") +@XmlAccessorType(XmlAccessType.FIELD) +public class ChangesetPagingResult +{ + + /** + * Constructs ... + * + */ + public ChangesetPagingResult() {} + + /** + * Constructs ... + * + * + * @param total + * @param changesets + */ + public ChangesetPagingResult(int total, List changesets) + { + this.total = total; + this.changesets = changesets; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public List getChangesets() + { + return changesets; + } + + /** + * Method description + * + * + * @return + */ + public int getTotal() + { + return total; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param changesets + */ + public void setChangesets(List changesets) + { + this.changesets = changesets; + } + + /** + * Method description + * + * + * @param total + */ + public void setTotal(int total) + { + this.total = total; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + @XmlElement(name = "changeset") + @XmlElementWrapper(name = "changesets") + private List changesets; + + /** Field description */ + private int total; +} diff --git a/scm-core/src/main/java/sonia/scm/repository/ChangesetViewer.java b/scm-core/src/main/java/sonia/scm/repository/ChangesetViewer.java index 0d5c473f52..44285028f0 100644 --- a/scm-core/src/main/java/sonia/scm/repository/ChangesetViewer.java +++ b/scm-core/src/main/java/sonia/scm/repository/ChangesetViewer.java @@ -33,10 +33,6 @@ package sonia.scm.repository; -//~--- JDK imports ------------------------------------------------------------ - -import java.util.List; - /** * * @author Sebastian Sdorra @@ -49,20 +45,11 @@ public interface ChangesetViewer * * * - * @param startId + * + * @param start * @param max * * @return */ - public List getChangesets(String startId, int max); - - /** - * Method description - * - * - * @param max - * - * @return - */ - public List getLastChangesets(int max); + public ChangesetPagingResult getChangesets(int start, int max); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java index 81fc735c5e..54248905e1 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java @@ -40,7 +40,7 @@ import com.google.inject.Provider; import com.google.inject.Singleton; import sonia.scm.config.ScmConfiguration; -import sonia.scm.repository.Changeset; +import sonia.scm.repository.ChangesetPagingResult; import sonia.scm.repository.ChangesetViewer; import sonia.scm.repository.Permission; import sonia.scm.repository.PermissionType; @@ -50,14 +50,12 @@ import sonia.scm.repository.RepositoryException; import sonia.scm.repository.RepositoryHandler; import sonia.scm.repository.RepositoryManager; import sonia.scm.util.HttpUtil; -import sonia.scm.util.Util; import sonia.scm.web.security.WebSecurityContext; //~--- JDK imports ------------------------------------------------------------ import java.util.ArrayList; import java.util.Collection; -import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -116,8 +114,8 @@ public class RepositoryResource * * * @param id - * @param startId - * @param max + * @param start + * @param limit * * @return * @@ -126,9 +124,9 @@ public class RepositoryResource @GET @Path("{id}/changesets") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) - public Response getChangesets(@PathParam("id") String id, - @QueryParam("changeset") String startId, - @DefaultValue("25") @QueryParam("max") int max) + public Response getChangesets(@PathParam("id") String id, + @DefaultValue("0") @QueryParam("start") int start, + @DefaultValue("25") @QueryParam("limit") int limit) throws RepositoryException { Response response = null; @@ -141,19 +139,10 @@ public class RepositoryResource if (changesetViewer != null) { - List changesets = null; + ChangesetPagingResult changesets = changesetViewer.getChangesets(start, + limit); - if (Util.isNotEmpty(startId)) - { - changesets = changesetViewer.getChangesets(startId, max); - } - else - { - changesets = changesetViewer.getLastChangesets(max); - } - - response = Response.ok(new GenericEntity>(changesets) {} - ).build(); + response = Response.ok(changesets).build(); } else { diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.repository.js b/scm-webapp/src/main/webapp/resources/js/sonia.repository.js index aab73030c2..11d7fd92aa 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.repository.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.repository.js @@ -695,9 +695,14 @@ Sonia.repository.ChangesetViewerGrid = Ext.extend(Ext.grid.GridPanel, { var changesetStore = new Ext.data.JsonStore({ id: 'changesetStore', - url: restUrl + 'repositories/' + this.repository.id + '/changesets.json', + proxy: new Ext.data.HttpProxy({ + url: restUrl + 'repositories/' + this.repository.id + '/changesets.json', + method: 'GET' + }), fields: ['id', 'date', 'author', 'description'], + root: 'changesets', idProperty: 'id', + totalProperty: 'total', autoLoad: true, autoDestroy: true }); @@ -718,7 +723,13 @@ Sonia.repository.ChangesetViewerGrid = Ext.extend(Ext.grid.GridPanel, { autoExpandColumn: 'changeset', autoHeight: true, store: changesetStore, - colModel: changesetColModel + colModel: changesetColModel, + bbar: new Ext.PagingToolbar({ + store: changesetStore, + displayInfo: true, + pageSize: 25, + prependButtons: true + }) } Ext.apply(this, Ext.apply(this.initialConfig, config));