]> source.dussan.org Git - gitblit.git/commitdiff
first working version of tree model
authorMartin Spielmann <mail@martinspielmann.de>
Sat, 4 Nov 2017 12:10:24 +0000 (13:10 +0100)
committerMartin Spielmann <mail@martinspielmann.de>
Sat, 4 Nov 2017 12:10:24 +0000 (13:10 +0100)
src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java

index c3f07099d3265a6029343bbb0c742e1320bab7b2..804fb299ea487c933143b3c7c83b8fa23ab9368e 100644 (file)
@@ -28,7 +28,9 @@ import org.apache.wicket.PageParameters;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;\r
 import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;\r
 import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;\r
+import org.apache.wicket.markup.html.WebMarkupContainer;\r
 import org.apache.wicket.markup.html.basic.Label;\r
+import org.apache.wicket.markup.html.basic.MultiLineLabel;\r
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
 import org.apache.wicket.markup.html.link.Link;\r
 import org.apache.wicket.markup.html.panel.Fragment;\r
@@ -57,380 +59,406 @@ import com.gitblit.wicket.pages.UserPage;
 \r
 public class RepositoriesPanel extends BasePanel {\r
 \r
-       private static final long serialVersionUID = 1L;\r
-\r
-       public RepositoriesPanel(String wicketId, final boolean showAdmin, final boolean showManagement,\r
-                       List<RepositoryModel> models, boolean enableLinks,\r
-                       final Map<AccessRestrictionType, String> accessRestrictionTranslations) {\r
-               super(wicketId);\r
-\r
-               final boolean linksActive = enableLinks;\r
-               final boolean showSize = app().settings().getBoolean(Keys.web.showRepositorySizes, true);\r
-\r
-               final UserModel user = GitBlitWebSession.get().getUser();\r
-\r
-               final IDataProvider<RepositoryModel> dp;\r
-\r
-               Fragment managementLinks;\r
-               if (showAdmin) {\r
-                       // user is admin\r
-                       managementLinks = new Fragment("managementPanel", "adminLinks", this);\r
-                       managementLinks.add(new Link<Void>("clearCache") {\r
-\r
-                               private static final long serialVersionUID = 1L;\r
-\r
-                               @Override\r
-                               public void onClick() {\r
-                                       app().repositories().resetRepositoryListCache();\r
-                                       setResponsePage(RepositoriesPage.class);\r
-                               }\r
-                       }.setVisible(app().settings().getBoolean(Keys.git.cacheRepositoryList, true)));\r
-                       managementLinks.add(new BookmarkablePageLink<Void>("newRepository", app().getNewRepositoryPage()));\r
-                       add(managementLinks);\r
-               } else if (showManagement && user != null && user.canCreate()) {\r
-                       // user can create personal repositories\r
-                       managementLinks = new Fragment("managementPanel", "personalLinks", this);\r
-                       managementLinks.add(new BookmarkablePageLink<Void>("newRepository", app().getNewRepositoryPage()));\r
-                       add(managementLinks);\r
-               } else {\r
-                       // user has no management permissions\r
-                       add (new Label("managementPanel").setVisible(false));\r
-               }\r
-\r
-               if (app().settings().getString(Keys.web.repositoryListType, "flat").equalsIgnoreCase("grouped")) {\r
-                       List<RepositoryModel> rootRepositories = new ArrayList<RepositoryModel>();\r
-                       Map<String, List<RepositoryModel>> groups = new HashMap<String, List<RepositoryModel>>();\r
-                       for (RepositoryModel model : models) {\r
-                               String rootPath = StringUtils.getRootPath(model.name);\r
-                               if (StringUtils.isEmpty(rootPath)) {\r
-                                       // root repository\r
-                                       rootRepositories.add(model);\r
-                               } else {\r
-                                       // non-root, grouped repository\r
-                                       if (!groups.containsKey(rootPath)) {\r
-                                               groups.put(rootPath, new ArrayList<RepositoryModel>());\r
-                                       }\r
-                                       groups.get(rootPath).add(model);\r
-                               }\r
-                       }\r
-                       List<String> roots = new ArrayList<String>(groups.keySet());\r
-                       Collections.sort(roots);\r
-\r
-                       if (rootRepositories.size() > 0) {\r
-                               // inject the root repositories at the top of the page\r
-                               roots.add(0, "");\r
-                               groups.put("", rootRepositories);\r
-                       }\r
-\r
-                       List<RepositoryModel> groupedModels = new ArrayList<RepositoryModel>();\r
-                       for (String root : roots) {\r
-                               List<RepositoryModel> subModels = groups.get(root);\r
-                               ProjectModel project = app().projects().getProjectModel(root);\r
-                               GroupRepositoryModel group = new GroupRepositoryModel(project == null ? root : project.name, subModels.size());\r
-                               if (project != null) {\r
-                                       group.title = project.title;\r
-                                       group.description = project.description;\r
-                               }\r
-                               groupedModels.add(group);\r
-                               Collections.sort(subModels);\r
-                               groupedModels.addAll(subModels);\r
-                       }\r
-                       dp = new ListDataProvider<RepositoryModel>(groupedModels);\r
-               } else {\r
-                       dp = new SortableRepositoriesProvider(models);\r
-               }\r
-\r
-               final boolean showSwatch = app().settings().getBoolean(Keys.web.repositoryListSwatches, true);\r
-\r
-               DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("row", dp) {\r
-                       private static final long serialVersionUID = 1L;\r
-                       int counter;\r
-                       String currGroupName;\r
-\r
-                       @Override\r
-                       protected void onBeforeRender() {\r
-                               super.onBeforeRender();\r
-                               counter = 0;\r
-                       }\r
-\r
-                       @Override\r
-                       public void populateItem(final Item<RepositoryModel> item) {\r
-                               final RepositoryModel entry = item.getModelObject();\r
-                               if (entry instanceof GroupRepositoryModel) {\r
-                                       GroupRepositoryModel groupRow = (GroupRepositoryModel) entry;\r
-                                       currGroupName = entry.name;\r
-                                       Fragment row = new Fragment("rowContent", "groupRepositoryRow", this);\r
-                                       item.add(row);\r
-\r
-                                       String name = groupRow.name;\r
-                                       if (name.startsWith(ModelUtils.getUserRepoPrefix())) {\r
-                                               // user page\r
-                                               String username = ModelUtils.getUserNameFromRepoPath(name);\r
-                                               UserModel user = app().users().getUserModel(username);\r
-                                               row.add(new LinkPanel("groupName", null, (user == null ? username : user.getDisplayName()) + " (" + groupRow.count + ")", UserPage.class, WicketUtils.newUsernameParameter(username)));\r
-                                               row.add(new Label("groupDescription", getString("gb.personalRepositories")));\r
-                                       } else {\r
-                                               // project page\r
-                                               row.add(new LinkPanel("groupName", null, groupRow.toString(), ProjectPage.class, WicketUtils.newProjectParameter(entry.name)));\r
-                                               row.add(new Label("groupDescription", entry.description == null ? "":entry.description));\r
-                                       }\r
-                                       WicketUtils.setCssClass(item, "group");\r
-                                       // reset counter so that first row is light background\r
-                                       counter = 0;\r
-                                       return;\r
-                               }\r
-                               Fragment row = new Fragment("rowContent", "repositoryRow", this);\r
-                               item.add(row);\r
-\r
-                               // show colored repository type icon\r
-                               Fragment iconFragment;\r
-                               if (entry.isMirror) {\r
-                                       iconFragment = new Fragment("repoIcon", "mirrorIconFragment", this);\r
-                               } else if (entry.isFork()) {\r
-                                       iconFragment = new Fragment("repoIcon", "forkIconFragment", this);\r
-                               } else if (entry.isBare) {\r
-                                       iconFragment = new Fragment("repoIcon", "repoIconFragment", this);\r
-                               } else {\r
-                                       iconFragment = new Fragment("repoIcon", "cloneIconFragment", this);\r
-                               }\r
-                               if (showSwatch) {\r
-                                       WicketUtils.setCssStyle(iconFragment, "color:" + StringUtils.getColor(entry.toString()));\r
-                               }\r
-                               row.add(iconFragment);\r
-\r
-                               // try to strip group name for less cluttered list\r
-                               String repoName = entry.toString();\r
-                               if (!StringUtils.isEmpty(currGroupName) && (repoName.indexOf('/') > -1)) {\r
-                                       repoName = repoName.substring(currGroupName.length() + 1);\r
-                               }\r
-\r
-                               if (linksActive) {\r
-                                       Class<? extends BasePage> linkPage = SummaryPage.class;\r
-                                       PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);\r
-                                       row.add(new LinkPanel("repositoryName", "list", repoName, linkPage, pp));\r
-                                       row.add(new LinkPanel("repositoryDescription", "list", entry.description,\r
-                                                       linkPage, pp));\r
-                               } else {\r
-                                       // no links like on a federation page\r
-                                       row.add(new Label("repositoryName", repoName));\r
-                                       row.add(new Label("repositoryDescription", entry.description));\r
-                               }\r
-                               if (entry.hasCommits) {\r
-                                       // Existing repository\r
-                                       row.add(new Label("repositorySize", entry.size).setVisible(showSize));\r
-                               } else {\r
-                                       // New repository\r
-                                       row.add(new Label("repositorySize", "<span class='empty'>(" + getString("gb.empty") + ")</span>")\r
-                                                       .setEscapeModelStrings(false));\r
-                               }\r
-\r
-                               if (entry.isSparkleshared()) {\r
-                                       row.add(WicketUtils.newImage("sparkleshareIcon", "star_16x16.png",\r
-                                                       getString("gb.isSparkleshared")));\r
-                               } else {\r
-                                       row.add(WicketUtils.newClearPixel("sparkleshareIcon").setVisible(false));\r
-                               }\r
-\r
-                               if (!entry.isMirror && entry.isFrozen) {\r
-                                       row.add(WicketUtils.newImage("frozenIcon", "cold_16x16.png",\r
-                                                       getString("gb.isFrozen")));\r
-                               } else {\r
-                                       row.add(WicketUtils.newClearPixel("frozenIcon").setVisible(false));\r
-                               }\r
-\r
-                               if (entry.isFederated) {\r
-                                       row.add(WicketUtils.newImage("federatedIcon", "federated_16x16.png",\r
-                                                       getString("gb.isFederated")));\r
-                               } else {\r
-                                       row.add(WicketUtils.newClearPixel("federatedIcon").setVisible(false));\r
-                               }\r
-\r
-                               if (entry.isMirror) {\r
-                                       row.add(WicketUtils.newImage("accessRestrictionIcon", "mirror_16x16.png",\r
-                                                       getString("gb.isMirror")));\r
-                               } else {\r
-                                       switch (entry.accessRestriction) {\r
-                                       case NONE:\r
-                                               row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
-                                               break;\r
-                                       case PUSH:\r
-                                               row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",\r
-                                                               accessRestrictionTranslations.get(entry.accessRestriction)));\r
-                                               break;\r
-                                       case CLONE:\r
-                                               row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",\r
-                                                               accessRestrictionTranslations.get(entry.accessRestriction)));\r
-                                               break;\r
-                                       case VIEW:\r
-                                               row.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",\r
-                                                               accessRestrictionTranslations.get(entry.accessRestriction)));\r
-                                               break;\r
-                                       default:\r
-                                               row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
-                                       }\r
-                               }\r
-\r
-                               String owner = "";\r
-                               if (!ArrayUtils.isEmpty(entry.owners)) {\r
-                                       // display first owner\r
-                                       for (String username : entry.owners) {\r
-                                               UserModel ownerModel = app().users().getUserModel(username);\r
-                                               if (ownerModel != null) {\r
-                                                       owner = ownerModel.getDisplayName();\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-                                       if (entry.owners.size() > 1) {\r
-                                               owner += ", ...";\r
-                                       }\r
-                               }\r
-                               Label ownerLabel = new Label("repositoryOwner", owner);\r
-                               WicketUtils.setHtmlTooltip(ownerLabel, ArrayUtils.toString(entry.owners));\r
-                               row.add(ownerLabel);\r
-\r
-                               String lastChange;\r
-                               if (entry.lastChange.getTime() == 0) {\r
-                                       lastChange = "--";\r
-                               } else {\r
-                                       lastChange = getTimeUtils().timeAgo(entry.lastChange);\r
-                               }\r
-                               Label lastChangeLabel = new Label("repositoryLastChange", lastChange);\r
-                               row.add(lastChangeLabel);\r
-                               WicketUtils.setCssClass(lastChangeLabel, getTimeUtils().timeAgoCss(entry.lastChange));\r
-                               if (!StringUtils.isEmpty(entry.lastChangeAuthor)) {\r
-                                       WicketUtils.setHtmlTooltip(lastChangeLabel, getString("gb.author") + ": " + entry.lastChangeAuthor);\r
-                               }\r
-\r
-                               WicketUtils.setAlternatingBackground(item, counter);\r
-                               counter++;\r
-                       }\r
-               };\r
-               add(dataView);\r
-\r
-               if (dp instanceof SortableDataProvider<?>) {\r
-                       // add sortable header\r
-                       SortableDataProvider<?> sdp = (SortableDataProvider<?>) dp;\r
-                       Fragment fragment = new Fragment("headerContent", "flatRepositoryHeader", this);\r
-                       fragment.add(newSort("orderByRepository", SortBy.repository, sdp, dataView));\r
-                       fragment.add(newSort("orderByDescription", SortBy.description, sdp, dataView));\r
-                       fragment.add(newSort("orderByOwner", SortBy.owner, sdp, dataView));\r
-                       fragment.add(newSort("orderByDate", SortBy.date, sdp, dataView));\r
-                       add(fragment);\r
-               } else {\r
-                       // not sortable\r
-                       Fragment fragment = new Fragment("headerContent", "groupRepositoryHeader", this);\r
-                       add(fragment);\r
-               }\r
-       }\r
-\r
-       private static class GroupRepositoryModel extends RepositoryModel {\r
-\r
-               private static final long serialVersionUID = 1L;\r
-\r
-               int count;\r
-               String title;\r
-\r
-               GroupRepositoryModel(String name, int count) {\r
-                       super(name, "", "", new Date(0));\r
-                       this.count = count;\r
-               }\r
-\r
-               @Override\r
-               public String toString() {\r
-                       return (StringUtils.isEmpty(title) ? name  : title) + " (" + count + ")";\r
-               }\r
-       }\r
-\r
-       protected enum SortBy {\r
-               repository, description, owner, date;\r
-       }\r
-\r
-       protected OrderByBorder newSort(String wicketId, SortBy field, SortableDataProvider<?> dp,\r
-                       final DataView<?> dataView) {\r
-               return new OrderByBorder(wicketId, field.name(), dp) {\r
-                       private static final long serialVersionUID = 1L;\r
-\r
-                       @Override\r
-                       protected void onSortChanged() {\r
-                               dataView.setCurrentPage(0);\r
-                       }\r
-               };\r
-       }\r
-\r
-       private static class SortableRepositoriesProvider extends SortableDataProvider<RepositoryModel> {\r
-\r
-               private static final long serialVersionUID = 1L;\r
-\r
-               private List<RepositoryModel> list;\r
-\r
-               protected SortableRepositoriesProvider(List<RepositoryModel> list) {\r
-                       this.list = list;\r
-                       setSort(SortBy.date.name(), false);\r
-               }\r
-\r
-               @Override\r
-               public int size() {\r
-                       if (list == null) {\r
-                               return 0;\r
-                       }\r
-                       return list.size();\r
-               }\r
-\r
-               @Override\r
-               public IModel<RepositoryModel> model(RepositoryModel header) {\r
-                       return new Model<RepositoryModel>(header);\r
-               }\r
-\r
-               @Override\r
-               public Iterator<RepositoryModel> iterator(int first, int count) {\r
-                       SortParam sp = getSort();\r
-                       String prop = sp.getProperty();\r
-                       final boolean asc = sp.isAscending();\r
-\r
-                       if (prop == null || prop.equals(SortBy.date.name())) {\r
-                               Collections.sort(list, new Comparator<RepositoryModel>() {\r
-                                       @Override\r
-                                       public int compare(RepositoryModel o1, RepositoryModel o2) {\r
-                                               if (asc) {\r
-                                                       return o1.lastChange.compareTo(o2.lastChange);\r
-                                               }\r
-                                               return o2.lastChange.compareTo(o1.lastChange);\r
-                                       }\r
-                               });\r
-                       } else if (prop.equals(SortBy.repository.name())) {\r
-                               Collections.sort(list, new Comparator<RepositoryModel>() {\r
-                                       @Override\r
-                                       public int compare(RepositoryModel o1, RepositoryModel o2) {\r
-                                               if (asc) {\r
-                                                       return o1.name.compareTo(o2.name);\r
-                                               }\r
-                                               return o2.name.compareTo(o1.name);\r
-                                       }\r
-                               });\r
-                       } else if (prop.equals(SortBy.owner.name())) {\r
-                               Collections.sort(list, new Comparator<RepositoryModel>() {\r
-                                       @Override\r
-                                       public int compare(RepositoryModel o1, RepositoryModel o2) {\r
-                                               String own1 = ArrayUtils.toString(o1.owners);\r
-                                               String own2 = ArrayUtils.toString(o2.owners);\r
-                                               if (asc) {\r
-                                                       return own1.compareTo(own2);\r
-                                               }\r
-                                               return own2.compareTo(own1);\r
-                                       }\r
-                               });\r
-                       } else if (prop.equals(SortBy.description.name())) {\r
-                               Collections.sort(list, new Comparator<RepositoryModel>() {\r
-                                       @Override\r
-                                       public int compare(RepositoryModel o1, RepositoryModel o2) {\r
-                                               if (asc) {\r
-                                                       return o1.description.compareTo(o2.description);\r
-                                               }\r
-                                               return o2.description.compareTo(o1.description);\r
-                                       }\r
-                               });\r
-                       }\r
-                       return list.subList(first, first + count).iterator();\r
-               }\r
-       }\r
+    private static final long serialVersionUID = 1L;\r
+\r
+    public RepositoriesPanel(String wicketId, final boolean showAdmin, final boolean showManagement, List<RepositoryModel> models, boolean enableLinks,\r
+            final Map<AccessRestrictionType, String> accessRestrictionTranslations) {\r
+        super(wicketId);\r
+\r
+        final boolean linksActive = enableLinks;\r
+        final boolean showSize = app().settings().getBoolean(Keys.web.showRepositorySizes, true);\r
+\r
+        final UserModel user = GitBlitWebSession.get().getUser();\r
+\r
+        IDataProvider<RepositoryModel> dp = null;\r
+\r
+        Fragment managementLinks;\r
+        if (showAdmin) {\r
+            // user is admin\r
+            managementLinks = new Fragment("managementPanel", "adminLinks", this);\r
+            managementLinks.add(new Link<Void>("clearCache") {\r
+\r
+                private static final long serialVersionUID = 1L;\r
+\r
+                @Override\r
+                public void onClick() {\r
+                    app().repositories().resetRepositoryListCache();\r
+                    setResponsePage(RepositoriesPage.class);\r
+                }\r
+            }.setVisible(app().settings().getBoolean(Keys.git.cacheRepositoryList, true)));\r
+            managementLinks.add(new BookmarkablePageLink<Void>("newRepository", app().getNewRepositoryPage()));\r
+            add(managementLinks);\r
+        } else if (showManagement && user != null && user.canCreate()) {\r
+            // user can create personal repositories\r
+            managementLinks = new Fragment("managementPanel", "personalLinks", this);\r
+            managementLinks.add(new BookmarkablePageLink<Void>("newRepository", app().getNewRepositoryPage()));\r
+            add(managementLinks);\r
+        } else {\r
+            // user has no management permissions\r
+            add(new Label("managementPanel").setVisible(false));\r
+        }\r
+\r
+        if (true) {\r
+            // if (app().settings().getString(Keys.web.repositoryListType,\r
+            // "flat").equalsIgnoreCase("tree")) {\r
+            TreeNodeModel tree = new TreeNodeModel();\r
+            for (RepositoryModel model : models) {\r
+                String rootPath = StringUtils.getRootPath(model.name);\r
+                if (StringUtils.isEmpty(rootPath)) {\r
+                    // root repository\r
+                    // rootRepositories.add(model);\r
+                    tree.add(model);\r
+                } else {\r
+                    // create folder structure\r
+                    tree.add(rootPath, model);\r
+                    // non-root, grouped repository\r
+                    // if (!groups.containsKey(rootPath)) {\r
+                    // groups.put(rootPath, new ArrayList<RepositoryModel>());\r
+                    // }\r
+                    // groups.get(rootPath).add(model);\r
+                }\r
+            }\r
+\r
+            WebMarkupContainer row = new WebMarkupContainer("row");\r
+            add(row);\r
+            row.add(new MultiLineLabel("rowContent", tree.toString()));\r
+\r
+\r
+            Fragment fragment = new Fragment("headerContent", "groupRepositoryHeader", this);\r
+            add(fragment);\r
+\r
+\r
+\r
+\r
+        } else if (app().settings().getString(Keys.web.repositoryListType, "flat").equalsIgnoreCase("grouped")) {\r
+            List<RepositoryModel> rootRepositories = new ArrayList<RepositoryModel>();\r
+            Map<String, List<RepositoryModel>> groups = new HashMap<String, List<RepositoryModel>>();\r
+            for (RepositoryModel model : models) {\r
+                String rootPath = StringUtils.getRootPath(model.name);\r
+                if (StringUtils.isEmpty(rootPath)) {\r
+                    // root repository\r
+                    rootRepositories.add(model);\r
+                } else {\r
+                    // non-root, grouped repository\r
+                    if (!groups.containsKey(rootPath)) {\r
+                        groups.put(rootPath, new ArrayList<RepositoryModel>());\r
+                    }\r
+                    groups.get(rootPath).add(model);\r
+                }\r
+            }\r
+            List<String> roots = new ArrayList<String>(groups.keySet());\r
+            Collections.sort(roots);\r
+\r
+            if (rootRepositories.size() > 0) {\r
+                // inject the root repositories at the top of the page\r
+                roots.add(0, "");\r
+                groups.put("", rootRepositories);\r
+            }\r
+\r
+            List<RepositoryModel> groupedModels = new ArrayList<RepositoryModel>();\r
+            for (String root : roots) {\r
+                List<RepositoryModel> subModels = groups.get(root);\r
+                ProjectModel project = app().projects().getProjectModel(root);\r
+                GroupRepositoryModel group = new GroupRepositoryModel(project == null ? root : project.name, subModels.size());\r
+                if (project != null) {\r
+                    group.title = project.title;\r
+                    group.description = project.description;\r
+                }\r
+                groupedModels.add(group);\r
+                Collections.sort(subModels);\r
+                groupedModels.addAll(subModels);\r
+            }\r
+            dp = new ListDataProvider<RepositoryModel>(groupedModels);\r
+        } else {\r
+            dp = new SortableRepositoriesProvider(models);\r
+        }\r
+\r
+        if (dp != null) {\r
+            final boolean showSwatch = app().settings().getBoolean(Keys.web.repositoryListSwatches, true);\r
+\r
+            DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("row", dp) {\r
+                private static final long serialVersionUID = 1L;\r
+                int counter;\r
+                String currGroupName;\r
+\r
+                @Override\r
+                protected void onBeforeRender() {\r
+                    super.onBeforeRender();\r
+                    counter = 0;\r
+                }\r
+\r
+                @Override\r
+                public void populateItem(final Item<RepositoryModel> item) {\r
+                    final RepositoryModel entry = item.getModelObject();\r
+                    if (entry instanceof GroupRepositoryModel) {\r
+                        GroupRepositoryModel groupRow = (GroupRepositoryModel) entry;\r
+                        currGroupName = entry.name;\r
+                        Fragment row = new Fragment("rowContent", "groupRepositoryRow", this);\r
+                        item.add(row);\r
+\r
+                        String name = groupRow.name;\r
+                        if (name.startsWith(ModelUtils.getUserRepoPrefix())) {\r
+                            // user page\r
+                            String username = ModelUtils.getUserNameFromRepoPath(name);\r
+                            UserModel user = app().users().getUserModel(username);\r
+                            row.add(new LinkPanel("groupName", null, (user == null ? username : user.getDisplayName()) + " (" + groupRow.count + ")", UserPage.class,\r
+                                    WicketUtils.newUsernameParameter(username)));\r
+                            row.add(new Label("groupDescription", getString("gb.personalRepositories")));\r
+                        } else {\r
+                            // project page\r
+                            row.add(new LinkPanel("groupName", null, groupRow.toString(), ProjectPage.class, WicketUtils.newProjectParameter(entry.name)));\r
+                            row.add(new Label("groupDescription", entry.description == null ? "" : entry.description));\r
+                        }\r
+                        WicketUtils.setCssClass(item, "group");\r
+                        // reset counter so that first row is light background\r
+                        counter = 0;\r
+                        return;\r
+                    }\r
+                    Fragment row = new Fragment("rowContent", "repositoryRow", this);\r
+                    item.add(row);\r
+\r
+                    // show colored repository type icon\r
+                    Fragment iconFragment;\r
+                    if (entry.isMirror) {\r
+                        iconFragment = new Fragment("repoIcon", "mirrorIconFragment", this);\r
+                    } else if (entry.isFork()) {\r
+                        iconFragment = new Fragment("repoIcon", "forkIconFragment", this);\r
+                    } else if (entry.isBare) {\r
+                        iconFragment = new Fragment("repoIcon", "repoIconFragment", this);\r
+                    } else {\r
+                        iconFragment = new Fragment("repoIcon", "cloneIconFragment", this);\r
+                    }\r
+                    if (showSwatch) {\r
+                        WicketUtils.setCssStyle(iconFragment, "color:" + StringUtils.getColor(entry.toString()));\r
+                    }\r
+                    row.add(iconFragment);\r
+\r
+                    // try to strip group name for less cluttered list\r
+                    String repoName = entry.toString();\r
+                    if (!StringUtils.isEmpty(currGroupName) && (repoName.indexOf('/') > -1)) {\r
+                        repoName = repoName.substring(currGroupName.length() + 1);\r
+                    }\r
+\r
+                    if (linksActive) {\r
+                        Class<? extends BasePage> linkPage = SummaryPage.class;\r
+                        PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);\r
+                        row.add(new LinkPanel("repositoryName", "list", repoName, linkPage, pp));\r
+                        row.add(new LinkPanel("repositoryDescription", "list", entry.description, linkPage, pp));\r
+                    } else {\r
+                        // no links like on a federation page\r
+                        row.add(new Label("repositoryName", repoName));\r
+                        row.add(new Label("repositoryDescription", entry.description));\r
+                    }\r
+                    if (entry.hasCommits) {\r
+                        // Existing repository\r
+                        row.add(new Label("repositorySize", entry.size).setVisible(showSize));\r
+                    } else {\r
+                        // New repository\r
+                        row.add(new Label("repositorySize", "<span class='empty'>(" + getString("gb.empty") + ")</span>").setEscapeModelStrings(false));\r
+                    }\r
+\r
+                    if (entry.isSparkleshared()) {\r
+                        row.add(WicketUtils.newImage("sparkleshareIcon", "star_16x16.png", getString("gb.isSparkleshared")));\r
+                    } else {\r
+                        row.add(WicketUtils.newClearPixel("sparkleshareIcon").setVisible(false));\r
+                    }\r
+\r
+                    if (!entry.isMirror && entry.isFrozen) {\r
+                        row.add(WicketUtils.newImage("frozenIcon", "cold_16x16.png", getString("gb.isFrozen")));\r
+                    } else {\r
+                        row.add(WicketUtils.newClearPixel("frozenIcon").setVisible(false));\r
+                    }\r
+\r
+                    if (entry.isFederated) {\r
+                        row.add(WicketUtils.newImage("federatedIcon", "federated_16x16.png", getString("gb.isFederated")));\r
+                    } else {\r
+                        row.add(WicketUtils.newClearPixel("federatedIcon").setVisible(false));\r
+                    }\r
+\r
+                    if (entry.isMirror) {\r
+                        row.add(WicketUtils.newImage("accessRestrictionIcon", "mirror_16x16.png", getString("gb.isMirror")));\r
+                    } else {\r
+                        switch (entry.accessRestriction) {\r
+                        case NONE:\r
+                            row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
+                            break;\r
+                        case PUSH:\r
+                            row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
+                            break;\r
+                        case CLONE:\r
+                            row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
+                            break;\r
+                        case VIEW:\r
+                            row.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
+                            break;\r
+                        default:\r
+                            row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
+                        }\r
+                    }\r
+\r
+                    String owner = "";\r
+                    if (!ArrayUtils.isEmpty(entry.owners)) {\r
+                        // display first owner\r
+                        for (String username : entry.owners) {\r
+                            UserModel ownerModel = app().users().getUserModel(username);\r
+                            if (ownerModel != null) {\r
+                                owner = ownerModel.getDisplayName();\r
+                                break;\r
+                            }\r
+                        }\r
+                        if (entry.owners.size() > 1) {\r
+                            owner += ", ...";\r
+                        }\r
+                    }\r
+                    Label ownerLabel = new Label("repositoryOwner", owner);\r
+                    WicketUtils.setHtmlTooltip(ownerLabel, ArrayUtils.toString(entry.owners));\r
+                    row.add(ownerLabel);\r
+\r
+                    String lastChange;\r
+                    if (entry.lastChange.getTime() == 0) {\r
+                        lastChange = "--";\r
+                    } else {\r
+                        lastChange = getTimeUtils().timeAgo(entry.lastChange);\r
+                    }\r
+                    Label lastChangeLabel = new Label("repositoryLastChange", lastChange);\r
+                    row.add(lastChangeLabel);\r
+                    WicketUtils.setCssClass(lastChangeLabel, getTimeUtils().timeAgoCss(entry.lastChange));\r
+                    if (!StringUtils.isEmpty(entry.lastChangeAuthor)) {\r
+                        WicketUtils.setHtmlTooltip(lastChangeLabel, getString("gb.author") + ": " + entry.lastChangeAuthor);\r
+                    }\r
+\r
+                    WicketUtils.setAlternatingBackground(item, counter);\r
+                    counter++;\r
+                }\r
+            };\r
+            add(dataView);\r
+\r
+            if (dp instanceof SortableDataProvider<?>) {\r
+                // add sortable header\r
+                SortableDataProvider<?> sdp = (SortableDataProvider<?>) dp;\r
+                Fragment fragment = new Fragment("headerContent", "flatRepositoryHeader", this);\r
+                fragment.add(newSort("orderByRepository", SortBy.repository, sdp, dataView));\r
+                fragment.add(newSort("orderByDescription", SortBy.description, sdp, dataView));\r
+                fragment.add(newSort("orderByOwner", SortBy.owner, sdp, dataView));\r
+                fragment.add(newSort("orderByDate", SortBy.date, sdp, dataView));\r
+                add(fragment);\r
+            } else {\r
+                // not sortable\r
+                Fragment fragment = new Fragment("headerContent", "groupRepositoryHeader", this);\r
+                add(fragment);\r
+            }\r
+        }\r
+\r
+\r
+    }\r
+\r
+    private static class GroupRepositoryModel extends RepositoryModel {\r
+\r
+        private static final long serialVersionUID = 1L;\r
+\r
+        int count;\r
+        String title;\r
+\r
+        GroupRepositoryModel(String name, int count) {\r
+            super(name, "", "", new Date(0));\r
+            this.count = count;\r
+        }\r
+\r
+        @Override\r
+        public String toString() {\r
+            return (StringUtils.isEmpty(title) ? name : title) + " (" + count + ")";\r
+        }\r
+    }\r
+\r
+    protected enum SortBy {\r
+        repository, description, owner, date;\r
+    }\r
+\r
+    protected OrderByBorder newSort(String wicketId, SortBy field, SortableDataProvider<?> dp, final DataView<?> dataView) {\r
+        return new OrderByBorder(wicketId, field.name(), dp) {\r
+            private static final long serialVersionUID = 1L;\r
+\r
+            @Override\r
+            protected void onSortChanged() {\r
+                dataView.setCurrentPage(0);\r
+            }\r
+        };\r
+    }\r
+\r
+    private static class SortableRepositoriesProvider extends SortableDataProvider<RepositoryModel> {\r
+\r
+        private static final long serialVersionUID = 1L;\r
+\r
+        private List<RepositoryModel> list;\r
+\r
+        protected SortableRepositoriesProvider(List<RepositoryModel> list) {\r
+            this.list = list;\r
+            setSort(SortBy.date.name(), false);\r
+        }\r
+\r
+        @Override\r
+        public int size() {\r
+            if (list == null) {\r
+                return 0;\r
+            }\r
+            return list.size();\r
+        }\r
+\r
+        @Override\r
+        public IModel<RepositoryModel> model(RepositoryModel header) {\r
+            return new Model<RepositoryModel>(header);\r
+        }\r
+\r
+        @Override\r
+        public Iterator<RepositoryModel> iterator(int first, int count) {\r
+            SortParam sp = getSort();\r
+            String prop = sp.getProperty();\r
+            final boolean asc = sp.isAscending();\r
+\r
+            if (prop == null || prop.equals(SortBy.date.name())) {\r
+                Collections.sort(list, new Comparator<RepositoryModel>() {\r
+                    @Override\r
+                    public int compare(RepositoryModel o1, RepositoryModel o2) {\r
+                        if (asc) {\r
+                            return o1.lastChange.compareTo(o2.lastChange);\r
+                        }\r
+                        return o2.lastChange.compareTo(o1.lastChange);\r
+                    }\r
+                });\r
+            } else if (prop.equals(SortBy.repository.name())) {\r
+                Collections.sort(list, new Comparator<RepositoryModel>() {\r
+                    @Override\r
+                    public int compare(RepositoryModel o1, RepositoryModel o2) {\r
+                        if (asc) {\r
+                            return o1.name.compareTo(o2.name);\r
+                        }\r
+                        return o2.name.compareTo(o1.name);\r
+                    }\r
+                });\r
+            } else if (prop.equals(SortBy.owner.name())) {\r
+                Collections.sort(list, new Comparator<RepositoryModel>() {\r
+                    @Override\r
+                    public int compare(RepositoryModel o1, RepositoryModel o2) {\r
+                        String own1 = ArrayUtils.toString(o1.owners);\r
+                        String own2 = ArrayUtils.toString(o2.owners);\r
+                        if (asc) {\r
+                            return own1.compareTo(own2);\r
+                        }\r
+                        return own2.compareTo(own1);\r
+                    }\r
+                });\r
+            } else if (prop.equals(SortBy.description.name())) {\r
+                Collections.sort(list, new Comparator<RepositoryModel>() {\r
+                    @Override\r
+                    public int compare(RepositoryModel o1, RepositoryModel o2) {\r
+                        if (asc) {\r
+                            return o1.description.compareTo(o2.description);\r
+                        }\r
+                        return o2.description.compareTo(o1.description);\r
+                    }\r
+                });\r
+            }\r
+            return list.subList(first, first + count).iterator();\r
+        }\r
+    }\r
 }\r