From 232890f03476b8bb231d17883eb0faff93ec5049 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Tue, 05 Apr 2011 22:26:37 -0400
Subject: [PATCH] Simplified links some more.  Added TicGit browser.

---
 src/com/gitblit/wicket/pages/SummaryPage.html       |   22 
 src/com/gitblit/wicket/pages/TagsPage.java          |   10 
 src/com/gitblit/wicket/models/RefModel.java         |   10 
 src/com/gitblit/utils/TicGitTicket.java             |   77 +++++
 src/com/gitblit/wicket/RepositoryPage.java          |    2 
 src/com/gitblit/wicket/pages/TicGitPage.java        |   65 +++++
 src/com/gitblit/wicket/panels/BranchLinksPanel.java |    8 
 src/com/gitblit/wicket/panels/PageLinksPanel.html   |    2 
 src/com/gitblit/wicket/BasePage.java                |   10 
 src/com/gitblit/wicket/panels/BranchLinksPanel.html |    0 
 /dev/null                                           |   63 ----
 src/com/gitblit/wicket/pages/TicGitTicketPage.java  |   70 +++++
 src/com/gitblit/wicket/pages/BranchesPage.java      |   71 +++++
 src/com/gitblit/wicket/panels/PageLinksPanel.java   |   22 -
 src/com/gitblit/wicket/pages/TicGitTicketPage.html  |   39 +++
 src/com/gitblit/wicket/GitBlitWebApp.java           |   12 
 src/com/gitblit/tests/JGitUtilsTest.java            |   11 
 src/com/gitblit/wicket/pages/TicGitPage.html        |   26 ++
 resources/gitblit.css                               |   26 ++
 src/com/gitblit/wicket/pages/BranchesPage.html      |   26 ++
 src/com/gitblit/wicket/pages/SummaryPage.java       |   46 ++-
 src/com/gitblit/utils/JGitUtils.java                |  113 ++++++++
 22 files changed, 605 insertions(+), 126 deletions(-)

diff --git a/resources/gitblit.css b/resources/gitblit.css
index 032b26e..d126a8a 100644
--- a/resources/gitblit.css
+++ b/resources/gitblit.css
@@ -175,6 +175,32 @@
 	border-width: 1px 0px 1px;
 }
 
+div.bug_open {
+	padding: 2px;
+	background-color: #800000;
+	color: white;	
+	text-align: center;
+}
+
+div.bug_resolved {
+	padding: 2px;
+	background-color: #008000;
+	color: white;
+	text-align: center;
+}
+
+div.bug_invalid {
+	padding: 2px;
+	background-color: gray;
+	text-align: center;
+}
+
+div.bug_hold {
+	padding: 2px;
+	background-color: orange;
+	text-align: center;
+}
+
 a.list {
 	text-decoration: none;
 	color: #000000;
diff --git a/src/com/gitblit/tests/JGitUtilsTest.java b/src/com/gitblit/tests/JGitUtilsTest.java
index c04ceef..6c39840 100644
--- a/src/com/gitblit/tests/JGitUtilsTest.java
+++ b/src/com/gitblit/tests/JGitUtilsTest.java
@@ -15,6 +15,8 @@
 import org.eclipse.jgit.storage.file.FileRepository;
 
 import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.TicGitTicket;
+import com.gitblit.wicket.models.RefModel;
 
 
 public class JGitUtilsTest extends TestCase {
@@ -67,5 +69,14 @@
 		r.close();
 		assertTrue("Content is null!", content != null);
 	}
+	
+	public void testTicGit() throws Exception {
+		Repository r = new FileRepository(new File(repositoriesFolder, "ticgit") + "/" + Constants.DOT_GIT);
+		RefModel ticgit = JGitUtils.getTicGitBranch(r);
+		assertTrue("Ticgit branch does not exist!", ticgit != null);
+		List<TicGitTicket> tickets = JGitUtils.getTicGitTickets(r);
+		assertTrue("No tickets found!", tickets.size() > 0);
+		r.close();
+	}
 
 }
diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java
index 0c29eab..b4e0b15 100644
--- a/src/com/gitblit/utils/JGitUtils.java
+++ b/src/com/gitblit/utils/JGitUtils.java
@@ -6,6 +6,7 @@
 import java.io.InputStream;
 import java.io.RandomAccessFile;
 import java.text.DateFormat;
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -37,6 +38,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.gitblit.utils.TicGitTicket.Comment;
 import com.gitblit.wicket.models.Metric;
 import com.gitblit.wicket.models.PathModel;
 import com.gitblit.wicket.models.RefModel;
@@ -333,8 +335,12 @@
 		return getRefs(r, Constants.R_TAGS, maxCount);
 	}
 
-	public static List<RefModel> getHeads(Repository r, int maxCount) {
+	public static List<RefModel> getLocalBranches(Repository r, int maxCount) {
 		return getRefs(r, Constants.R_HEADS, maxCount);
+	}
+
+	public static List<RefModel> getRemoteBranches(Repository r, int maxCount) {
+		return getRefs(r, Constants.R_REMOTES, maxCount);
 	}
 
 	public static List<RefModel> getRefs(Repository r, String refs, int maxCount) {
@@ -448,9 +454,110 @@
 		List<String> keys = new ArrayList<String>(map.keySet());
 		Collections.sort(keys);
 		List<Metric> metrics = new ArrayList<Metric>();
-		for (String key:keys) {
+		for (String key : keys) {
 			metrics.add(map.get(key));
-		}		
+		}
 		return metrics;
 	}
+
+	public static RefModel getTicGitBranch(Repository r) {
+		RefModel ticgitBranch = null;
+		try {
+			// search for ticgit branch in local heads
+			for (RefModel ref : getLocalBranches(r, -1)) {
+				if (ref.getDisplayName().endsWith("ticgit") || ref.getDisplayName().endsWith("ticgit-ng")) {
+					ticgitBranch = ref;
+					break;
+				}
+			}
+
+			// search for ticgit branch in remote heads
+			if (ticgitBranch == null) {
+				for (RefModel ref : getRemoteBranches(r, -1)) {
+					if (ref.getDisplayName().endsWith("ticgit") || ref.getDisplayName().endsWith("ticgit-ng")) {
+						ticgitBranch = ref;
+						break;
+					}
+				}
+			}
+		} catch (Throwable t) {
+			LOGGER.error("Failed to find ticgit branch!", t);
+		}
+		return ticgitBranch;
+	}
+
+	public static List<TicGitTicket> getTicGitTickets(Repository r) {
+		RefModel ticgitBranch = getTicGitBranch(r);
+		List<PathModel> paths = getFilesInPath(r, null, ticgitBranch.getCommit());
+		List<TicGitTicket> tickets = new ArrayList<TicGitTicket>();
+		for (PathModel ticketFolder : paths) {
+			if (ticketFolder.isTree()) {
+				try {
+					TicGitTicket t = new TicGitTicket(ticketFolder.name);
+					readTicketContents(r, ticgitBranch, t);
+					tickets.add(t);
+				} catch (Throwable t) {
+					LOGGER.error("Failed to get a ticgit ticket!", t);
+				}
+			}
+		}
+		Collections.sort(tickets);
+		Collections.reverse(tickets);
+		return tickets;
+	}
+
+	public static TicGitTicket getTicGitTicket(Repository r, String ticketFolder) {
+		RefModel ticgitBranch = getTicGitBranch(r);
+		if (ticgitBranch != null) {
+			try {
+				TicGitTicket ticket = new TicGitTicket(ticketFolder);
+				readTicketContents(r, ticgitBranch, ticket);
+				return ticket;
+			} catch (Throwable t) {
+				LOGGER.error("Failed to get ticgit ticket " + ticketFolder, t);
+			}
+		}
+		return null;
+	}
+	
+	private static void readTicketContents(Repository r, RefModel ticgitBranch, TicGitTicket ticket) {
+		List<PathModel> ticketFiles = getFilesInPath(r, ticket.name, ticgitBranch.getCommit());
+		for (PathModel file : ticketFiles) {
+			String content = getRawContentAsString(r, ticgitBranch.getCommit(), file.path).trim();
+			if (file.name.equals("TICKET_ID")) {
+				ticket.id = content;
+			} else if (file.name.equals("TITLE")) {
+				ticket.title = content;
+			} else {
+				String[] chunks = file.name.split("_");
+				if (chunks[0].equals("ASSIGNED")) {
+					ticket.handler = content;
+				} else if (chunks[0].equals("COMMENT")) {
+					try {
+						Comment c = new Comment(file.name, content);
+						ticket.comments.add(c);
+					} catch (ParseException e) {
+						e.printStackTrace();
+					}
+				} else if (chunks[0].equals("TAG")) {
+					if (content.startsWith("TAG_")) {
+						ticket.tags.add(content.substring(4));
+					} else {
+						ticket.tags.add(content);
+					}
+				} else if (chunks[0].equals("STATE")) {
+					ticket.state = content;
+				}
+			}
+		}
+		Collections.sort(ticket.comments);
+	}
+
+	public static String getTicGitContent(Repository r, String filePath) {
+		RefModel ticgitBranch = getTicGitBranch(r);
+		if (ticgitBranch != null) {
+			return getRawContentAsString(r, ticgitBranch.getCommit(), filePath);
+		}
+		return "";
+	}
 }
diff --git a/src/com/gitblit/utils/TicGitTicket.java b/src/com/gitblit/utils/TicGitTicket.java
new file mode 100644
index 0000000..48491a6
--- /dev/null
+++ b/src/com/gitblit/utils/TicGitTicket.java
@@ -0,0 +1,77 @@
+package com.gitblit.utils;
+
+import java.io.Serializable;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import com.gitblit.wicket.models.PathModel;
+
+public class TicGitTicket implements Serializable, Comparable<TicGitTicket> {
+
+	private static final long serialVersionUID = 1L;
+
+	public String id;
+	public String name;
+	public String title;
+	public String state;
+	public Date date;
+	public String handler;
+	public String milestone;
+	public String email;
+	public String author;
+	public List<Comment> comments;
+	public List<String> tags;
+
+	public TicGitTicket() {
+		state = "open";
+		comments = new ArrayList<Comment>();
+		tags = new ArrayList<String>();
+	}
+
+	public TicGitTicket(String ticketName) throws ParseException {
+		state = "";
+		name = ticketName;
+		comments = new ArrayList<Comment>();
+		tags = new ArrayList<String>();
+
+		String[] chunks = name.split("_");
+		if (chunks.length == 3) {
+			date = new Date(Long.parseLong(chunks[0]) * 1000l);
+			title = chunks[1].replace('-', ' ');
+		}		
+	}
+
+	public static class Comment implements Serializable, Comparable<Comment> {
+		
+		private static final long serialVersionUID = 1L;
+		
+		public String text;
+		public String author;
+		public Date date;
+
+		public Comment(String text, Date date) {
+			this.text = text;
+			this.date = date;
+		}
+
+		public Comment(String filename, String content) throws ParseException {
+			String[] chunks = filename.split("_", -1);
+			this.date = new Date(Long.parseLong(chunks[1]) * 1000l);
+			this.author = chunks[2];
+			this.text = content;
+		}
+
+		@Override
+		public int compareTo(Comment o) {
+			return date.compareTo(o.date);
+		}
+	}
+
+	@Override
+	public int compareTo(TicGitTicket o) {
+		return date.compareTo(o.date);
+	}
+}
diff --git a/src/com/gitblit/wicket/BasePage.java b/src/com/gitblit/wicket/BasePage.java
index 5d8176a..5c29eac 100644
--- a/src/com/gitblit/wicket/BasePage.java
+++ b/src/com/gitblit/wicket/BasePage.java
@@ -56,10 +56,14 @@
 	}
 
 	protected String trimShortLog(String string) {
-		if (string.length() > 60) {
-			return string.substring(0, 60) + "...";
+		return trimString(string, 60);
+	}
+	
+	protected String trimString(String value, int max) {
+		if (value.length() <= max) {
+			return value;
 		}
-		return string;
+		return value.substring(0, max - 3) + "...";
 	}
 
 	public void error(String message, Throwable t) {
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.java b/src/com/gitblit/wicket/GitBlitWebApp.java
index b5baa65..6e8a6dd 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/com/gitblit/wicket/GitBlitWebApp.java
@@ -29,13 +29,15 @@
 import com.gitblit.utils.JGitUtils;
 import com.gitblit.wicket.models.RepositoryModel;
 import com.gitblit.wicket.pages.BlobPage;
+import com.gitblit.wicket.pages.BranchesPage;
 import com.gitblit.wicket.pages.CommitPage;
-import com.gitblit.wicket.pages.HeadsPage;
 import com.gitblit.wicket.pages.RepositoriesPage;
 import com.gitblit.wicket.pages.ShortLogPage;
 import com.gitblit.wicket.pages.SummaryPage;
 import com.gitblit.wicket.pages.TagPage;
 import com.gitblit.wicket.pages.TagsPage;
+import com.gitblit.wicket.pages.TicGitPage;
+import com.gitblit.wicket.pages.TicGitTicketPage;
 import com.gitblit.wicket.pages.TreePage;
 
 
@@ -58,16 +60,20 @@
 		// Grab Browser info (like timezone, etc)
 		getRequestCycleSettings().setGatherExtendedBrowserInfo(true);
 
-		// setup the url paths
+		// setup the standard gitweb-ish urls
 		mount(new MixedParamUrlCodingStrategy("/summary", SummaryPage.class, new String[] { "p" }));
 		mount(new MixedParamUrlCodingStrategy("/shortlog", ShortLogPage.class, new String[] { "p", "h" }));
 		mount(new MixedParamUrlCodingStrategy("/tags", TagsPage.class, new String[] { "p" }));
-		mount(new MixedParamUrlCodingStrategy("/heads", HeadsPage.class, new String[] { "p" }));
+		mount(new MixedParamUrlCodingStrategy("/branches", BranchesPage.class, new String[] { "p" }));
 		mount(new MixedParamUrlCodingStrategy("/commit", CommitPage.class, new String[] { "p", "h" }));
 		mount(new MixedParamUrlCodingStrategy("/tag", TagPage.class, new String[] { "p", "h" }));
 		mount(new MixedParamUrlCodingStrategy("/tree", TreePage.class, new String[] { "p", "h", "f" }));
 		mount(new MixedParamUrlCodingStrategy("/blob", BlobPage.class, new String[] { "p", "h", "f" }));
 		
+		// setup extended urls
+		mount(new MixedParamUrlCodingStrategy("/ticgit", TicGitPage.class, new String[] { "p" }));
+		mount(new MixedParamUrlCodingStrategy("/ticgittkt", TicGitTicketPage.class, new String[] { "p", "f" }));
+		
 		repositories = new File(StoredSettings.getString("repositoriesFolder", "repos"));
 		exportAll = StoredSettings.getBoolean("exportAll", true);
 		repositoryResolver = new FileResolver(repositories, exportAll);
diff --git a/src/com/gitblit/wicket/RepositoryPage.java b/src/com/gitblit/wicket/RepositoryPage.java
index 4371052..b4f6fdc 100644
--- a/src/com/gitblit/wicket/RepositoryPage.java
+++ b/src/com/gitblit/wicket/RepositoryPage.java
@@ -114,5 +114,5 @@
 			return newCommitParameter();
 		}
 		return new PageParameters("p=" + repositoryName + ",h=" + commitId + ",f=" + path);
-	}
+	}	
 }
diff --git a/src/com/gitblit/wicket/models/RefModel.java b/src/com/gitblit/wicket/models/RefModel.java
index e76b489..08de110 100644
--- a/src/com/gitblit/wicket/models/RefModel.java
+++ b/src/com/gitblit/wicket/models/RefModel.java
@@ -34,6 +34,10 @@
 	public String getName() {
 		return ref.getName();
 	}
+	
+	public RevCommit getCommit() {
+		return commit;
+	}
 
 	public ObjectId getCommitId() {
 		return commit.getId();
@@ -46,7 +50,11 @@
 	public ObjectId getObjectId() {
 		return ref.getObjectId();
 	}
-
+	
+	public boolean isAnnotatedTag() {
+		return ref.isPeeled();
+	}
+		
 	@Override
 	public int compareTo(RefModel o) {
 		return getDate().compareTo(o.getDate());
diff --git a/src/com/gitblit/wicket/pages/BranchesPage.html b/src/com/gitblit/wicket/pages/BranchesPage.html
new file mode 100644
index 0000000..d4e5919
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/BranchesPage.html
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" >
+<body>
+	<!-- page header -->
+	<div wicket:id="pageHeader"></div>
+
+	<!-- page nav links -->	
+	<div wicket:id="pageLinks"></div>
+	
+	<!-- shortlog -->	
+	<div style="margin-top:5px;" class="header" wicket:id="summary"></div>	
+	<table class="pretty">
+		<tbody>
+       		<tr wicket:id="branch">
+         		<td><i><span wicket:id="branchDate"></span></i></td>
+         		<td><div wicket:id="branchName"></div></td>
+         		<td><div wicket:id="branchType"></div></td>
+         		<td class="rightAlign"><span wicket:id="branchLinks"></span></td>
+       		</tr>
+    	</tbody>
+	</table>	
+	
+	<!-- footer -->
+	<div wicket:id="pageFooter"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/BranchesPage.java b/src/com/gitblit/wicket/pages/BranchesPage.java
new file mode 100644
index 0000000..1fc5f88
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/BranchesPage.java
@@ -0,0 +1,71 @@
+package com.gitblit.wicket.pages;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.Utils;
+import com.gitblit.wicket.LinkPanel;
+import com.gitblit.wicket.RepositoryPage;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.models.RefModel;
+import com.gitblit.wicket.panels.BranchLinksPanel;
+
+
+public class BranchesPage extends RepositoryPage {
+
+	public BranchesPage(PageParameters params) {
+		super(params, "branches");
+
+		Repository r = getRepository();
+		List<RefModel> branches = new ArrayList<RefModel>();
+		branches.addAll(JGitUtils.getLocalBranches(r, -1));
+		branches.addAll(JGitUtils.getRemoteBranches(r, -1));
+		r.close();
+
+		// shortlog
+		add(new LinkPanel("summary", "title", repositoryName, SummaryPage.class, newRepositoryParameter()));
+
+		ListDataProvider<RefModel> branchesDp = new ListDataProvider<RefModel>(branches);
+		DataView<RefModel> branchView = new DataView<RefModel>("branch", branchesDp) {
+			private static final long serialVersionUID = 1L;
+			int counter = 0;
+
+			public void populateItem(final Item<RefModel> item) {
+				final RefModel entry = item.getModelObject();
+				String date;
+				if (entry.getDate() != null) {
+					date = Utils.timeAgo(entry.getDate());
+				} else {
+					date = "";
+				}
+				Label branchDateLabel = new Label("branchDate", date);
+				item.add(branchDateLabel);
+				WicketUtils.setCssClass(branchDateLabel, Utils.timeAgoCss(entry.getDate()));
+
+				item.add(new LinkPanel("branchName", "list name", entry.getDisplayName(), ShortLogPage.class, newCommitParameter(entry.getName())));
+
+				boolean remote = entry.getName().startsWith(Constants.R_REMOTES);
+				item.add(new Label("branchType", remote ? "remote":"local"));
+				
+				item.add(new BranchLinksPanel("branchLinks", repositoryName, entry));
+				
+				String clazz = counter % 2 == 0 ? "dark" : "light";
+				WicketUtils.setCssClass(item, clazz);
+				counter++;
+			}
+		};
+		add(branchView);
+
+		// footer
+		addFooter();
+	}
+}
diff --git a/src/com/gitblit/wicket/pages/HeadsPage.html b/src/com/gitblit/wicket/pages/HeadsPage.html
deleted file mode 100644
index ed99c89..0000000
--- a/src/com/gitblit/wicket/pages/HeadsPage.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<html xmlns="http://www.w3.org/1999/xhtml" >
-<body>
-	<!-- page header -->
-	<div wicket:id="pageHeader"></div>
-
-	<!-- page nav links -->	
-	<div wicket:id="pageLinks"></div>
-	
-	<!-- shortlog -->	
-	<div class="header" wicket:id="summary"></div>	
-	<table>
-		<tbody>
-       		<tr wicket:id="head">
-         		<td><i><span wicket:id="headDate"></span></i></td>
-         		<td><div wicket:id="headName"></div></td>
-         		<td></td>
-       		</tr>
-    	</tbody>
-	</table>	
-	
-	<!-- footer -->
-	<div wicket:id="pageFooter"></div>
-</body>
-</html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/HeadsPage.java b/src/com/gitblit/wicket/pages/HeadsPage.java
deleted file mode 100644
index df5e00f..0000000
--- a/src/com/gitblit/wicket/pages/HeadsPage.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.gitblit.wicket.pages;
-
-import java.util.List;
-
-import org.apache.wicket.PageParameters;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.repeater.Item;
-import org.apache.wicket.markup.repeater.data.DataView;
-import org.apache.wicket.markup.repeater.data.ListDataProvider;
-import org.eclipse.jgit.lib.Repository;
-
-import com.gitblit.utils.JGitUtils;
-import com.gitblit.utils.Utils;
-import com.gitblit.wicket.GitBlitWebApp;
-import com.gitblit.wicket.LinkPanel;
-import com.gitblit.wicket.RepositoryPage;
-import com.gitblit.wicket.WicketUtils;
-import com.gitblit.wicket.models.RefModel;
-
-
-public class HeadsPage extends RepositoryPage {
-
-	public HeadsPage(PageParameters params) {
-		super(params, "heads");
-
-		Repository r = getRepository();
-		List<RefModel> tags = JGitUtils.getHeads(r, -1);
-		r.close();
-
-		// shortlog
-		add(new LinkPanel("summary", "title", repositoryName, SummaryPage.class, newRepositoryParameter()));
-
-		ListDataProvider<RefModel> tagsDp = new ListDataProvider<RefModel>(tags);
-		DataView<RefModel> tagView = new DataView<RefModel>("head", tagsDp) {
-			private static final long serialVersionUID = 1L;
-			int counter = 0;
-
-			public void populateItem(final Item<RefModel> item) {
-				final RefModel entry = item.getModelObject();
-				String date;
-				if (entry.getDate() != null) {
-					date = Utils.timeAgo(entry.getDate());
-				} else {
-					date = "";
-				}
-				Label headDateLabel = new Label("headDate", date);
-				item.add(headDateLabel);
-				WicketUtils.setCssClass(headDateLabel, Utils.timeAgoCss(entry.getDate()));
-
-				item.add(new LinkPanel("headName", "list name", entry.getDisplayName(), ShortLogPage.class, newCommitParameter(entry.getName())));
-
-				String clazz = counter % 2 == 0 ? "dark" : "light";
-				WicketUtils.setCssClass(item, clazz);
-				counter++;
-			}
-		};
-		tagView.setItemsPerPage(GitBlitWebApp.PAGING_ITEM_COUNT);
-		add(tagView);
-
-		// footer
-		addFooter();
-	}
-}
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.html b/src/com/gitblit/wicket/pages/SummaryPage.html
index f5697cd..6a103e4 100644
--- a/src/com/gitblit/wicket/pages/SummaryPage.html
+++ b/src/com/gitblit/wicket/pages/SummaryPage.html
@@ -39,25 +39,25 @@
 	</table>	
 	<div class="pager" wicket:id="shortlogMore"></div>
 
-	<!-- Open Heads Body -->
-	<div style="width:300px;float:right;">
+	<!-- Open Branches Body -->
+	<div style="width:400px; float:left;">
 		<!-- heads -->
-		<div class="header" wicket:id="heads"></div>	
+		<div class="header" wicket:id="branches"></div>	
 		<table style="width:100%" class="pretty">
 			<tbody>
-   				<tr wicket:id="head">
-       				<td class="date"><span wicket:id="headDate"></span></td>
-       				<td><div wicket:id="headName"></div></td>
-       				<td class="rightAlign"><span wicket:id="headLinks"></span></td>
+   				<tr wicket:id="branch">
+       				<td class="date"><span wicket:id="branchDate"></span></td>
+       				<td><div wicket:id="branchName"></div></td>
+       				<td class="rightAlign"><span wicket:id="branchLinks"></span></td>
    				</tr>
    			</tbody>
 		</table>
-		<div class="pager" wicket:id="allHeads"></div>
-		<!-- Close Heads Body -->
+		<div class="pager" wicket:id="allBranches"></div>
+		<!-- Close Branches Body -->
 	</div>
-	
+
 	<!-- Open Tags body -->
-	<div style="margin-right:305px;">
+	<div style="margin-left:405px;">
 		<!-- tags -->
 		<div class="header" wicket:id="tags"></div>	
 			<table style="width:100%" class="pretty">
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.java b/src/com/gitblit/wicket/pages/SummaryPage.java
index 507ba24..b7be71a 100644
--- a/src/com/gitblit/wicket/pages/SummaryPage.java
+++ b/src/com/gitblit/wicket/pages/SummaryPage.java
@@ -1,6 +1,8 @@
 package com.gitblit.wicket.pages;
 
 import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -32,7 +34,7 @@
 import com.gitblit.wicket.models.Metric;
 import com.gitblit.wicket.models.RefModel;
 import com.gitblit.wicket.panels.AnnotatedTagLinksPanel;
-import com.gitblit.wicket.panels.HeadLinksPanel;
+import com.gitblit.wicket.panels.BranchLinksPanel;
 import com.gitblit.wicket.panels.RefsPanel;
 import com.gitblit.wicket.panels.ShortLogLinksPanel;
 import com.gitblit.wicket.panels.TagLinksPanel;
@@ -126,14 +128,14 @@
 
 				item.add(new LinkPanel("tagName", "list name", entry.getDisplayName(), CommitPage.class, newCommitParameter(entry.getCommitId().getName())));
 
-				if (entry.getCommitId().equals(entry.getObjectId())) {
-					// simple tag
-					item.add(new Label("tagDescription", ""));
-					item.add(new TagLinksPanel("tagLinks", repositoryName, entry));
-				} else {
+				if (entry.isAnnotatedTag()) {
 					// annotated tag
 					item.add(new LinkPanel("tagDescription", "list subject", entry.getShortLog(), TagPage.class, newCommitParameter(entry.getObjectId().getName())));
 					item.add(new AnnotatedTagLinksPanel("tagLinks", repositoryName, entry));
+				} else {
+					// simple tag on commit object
+					item.add(new Label("tagDescription", ""));
+					item.add(new TagLinksPanel("tagLinks", repositoryName, entry));
 				}
 
 				setAlternatingBackground(item, counter);
@@ -147,33 +149,41 @@
 			add(new LinkPanel("allTags", "link", "all tags...", TagsPage.class, newRepositoryParameter()));
 		}
 
-		// heads
-		List<RefModel> heads = JGitUtils.getHeads(r, numberRefs);
-		add(new LinkPanel("heads", "title", "heads", HeadsPage.class, newRepositoryParameter()));
+		// branches
+		List<RefModel> branches = new ArrayList<RefModel>();
+		branches.addAll(JGitUtils.getLocalBranches(r, numberRefs));
+		branches.addAll(JGitUtils.getRemoteBranches(r, numberRefs));
+		Collections.sort(branches);
+		Collections.reverse(branches);
+		if (numberRefs > 0 && branches.size() > numberRefs) {
+			branches = new ArrayList<RefModel>(branches.subList(0, numberRefs));
+		}
 
-		ListDataProvider<RefModel> headsDp = new ListDataProvider<RefModel>(heads);
-		DataView<RefModel> headsView = new DataView<RefModel>("head", headsDp) {
+		add(new LinkPanel("branches", "title", "branches", BranchesPage.class, newRepositoryParameter()));
+
+		ListDataProvider<RefModel> branchesDp = new ListDataProvider<RefModel>(branches);
+		DataView<RefModel> branchesView = new DataView<RefModel>("branch", branchesDp) {
 			private static final long serialVersionUID = 1L;
 			int counter = 0;
 
 			public void populateItem(final Item<RefModel> item) {
 				final RefModel entry = item.getModelObject();
 
-				item.add(createDateLabel("headDate", entry.getDate()));
+				item.add(createDateLabel("branchDate", entry.getDate()));
 
-				item.add(new LinkPanel("headName", "list name", entry.getDisplayName(), ShortLogPage.class, newCommitParameter(entry.getName())));
+				item.add(new LinkPanel("branchName", "list name", trimString(entry.getDisplayName(), 28), ShortLogPage.class, newCommitParameter(entry.getName())));
 
-				item.add(new HeadLinksPanel("headLinks", repositoryName, entry));
+				item.add(new BranchLinksPanel("branchLinks", repositoryName, entry));
 
 				setAlternatingBackground(item, counter);
 				counter++;
 			}
 		};
-		add(headsView);
-		if (heads.size() < numberRefs) {
-			add(new Label("allHeads", "").setVisible(false));
+		add(branchesView);
+		if (branches.size() < numberRefs) {
+			add(new Label("allBranches", "").setVisible(false));
 		} else {
-			add(new LinkPanel("allHeads", "link", "all heads...", HeadsPage.class, newRepositoryParameter()));
+			add(new LinkPanel("allBranches", "link", "all branches...", BranchesPage.class, newRepositoryParameter()));
 		}
 		
 		// Display an activity line graph
diff --git a/src/com/gitblit/wicket/pages/TagsPage.java b/src/com/gitblit/wicket/pages/TagsPage.java
index 5cfd1af..1f73ed0 100644
--- a/src/com/gitblit/wicket/pages/TagsPage.java
+++ b/src/com/gitblit/wicket/pages/TagsPage.java
@@ -39,14 +39,14 @@
 
 				item.add(new LinkPanel("tagName", "list name", entry.getDisplayName(), CommitPage.class, newCommitParameter(entry.getObjectId().getName())));
 
-				if (entry.getCommitId().equals(entry.getObjectId())) {
-					// simple tag on commit object
-					item.add(new Label("tagDescription", ""));
-					item.add(new TagLinksPanel("tagLinks", repositoryName, entry));
-				} else {
+				if (entry.isAnnotatedTag()) {
 					// annotated tag
 					item.add(new LinkPanel("tagDescription", "list subject", entry.getShortLog(), TagPage.class, newCommitParameter(entry.getObjectId().getName())));
 					item.add(new AnnotatedTagLinksPanel("tagLinks", repositoryName, entry));
+				} else {
+					// simple tag on commit object
+					item.add(new Label("tagDescription", ""));
+					item.add(new TagLinksPanel("tagLinks", repositoryName, entry));
 				}
 
 				setAlternatingBackground(item, counter);
diff --git a/src/com/gitblit/wicket/pages/TicGitPage.html b/src/com/gitblit/wicket/pages/TicGitPage.html
new file mode 100644
index 0000000..e3b9ed8
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/TicGitPage.html
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" >
+<body>
+	<!-- page header -->
+	<div wicket:id="pageHeader"></div>
+
+	<!-- page nav links -->	
+	<div wicket:id="pageLinks"></div>
+
+	<!-- shortlog -->	
+	<div style="margin-top:5px;" class="header" wicket:id="summary"></div>	
+	<table style="width:100%" class="pretty">
+		<tbody>
+       		<tr wicket:id="ticket">
+         		<td style="padding:0; margin:0;" ><div wicket:id="ticketState"></div></td>
+         		<td class="date"><span wicket:id="ticketDate"></span></td>
+         		<td><div wicket:id="ticketHandler"></div></td>
+         		<td><div wicket:id="ticketTitle"></div></td>
+       		</tr>
+    	</tbody>
+	</table>	
+	
+	<!-- footer -->
+	<div wicket:id="pageFooter"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/TicGitPage.java b/src/com/gitblit/wicket/pages/TicGitPage.java
new file mode 100644
index 0000000..889093d
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/TicGitPage.java
@@ -0,0 +1,65 @@
+package com.gitblit.wicket.pages;
+
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.TicGitTicket;
+import com.gitblit.wicket.LinkPanel;
+import com.gitblit.wicket.RepositoryPage;
+import com.gitblit.wicket.WicketUtils;
+
+public class TicGitPage extends RepositoryPage {
+
+	public TicGitPage(PageParameters params) {
+		super(params, "ticgit");
+
+		Repository r = getRepository();
+		List<TicGitTicket> tickets = JGitUtils.getTicGitTickets(r);
+		r.close();
+
+		// shortlog
+		add(new LinkPanel("summary", "title", repositoryName, SummaryPage.class, newRepositoryParameter()));
+
+		ListDataProvider<TicGitTicket> ticketsDp = new ListDataProvider<TicGitTicket>(tickets);
+		DataView<TicGitTicket> ticketsView = new DataView<TicGitTicket>("ticket", ticketsDp) {
+			private static final long serialVersionUID = 1L;
+			int counter = 0;
+
+			public void populateItem(final Item<TicGitTicket> item) {
+				final TicGitTicket entry = item.getModelObject();
+				Label stateLabel = new Label("ticketState", entry.state);
+				String css = null;
+				if (entry.state.equals("open")) {
+					css = "bug_open";
+				} else if (entry.state.equals("hold")) {
+					css = "bug_hold";
+				} else if (entry.state.equals("resolved")) {
+					css = "bug_resolved";
+				} else if (entry.state.equals("invalid")) {
+					css = "bug_invalid";
+				}
+				if (css != null) {
+					WicketUtils.setCssClass(stateLabel, css);
+				}
+				item.add(stateLabel);
+				item.add(createDateLabel("ticketDate", entry.date));
+				item.add(new Label("ticketHandler", trimString(entry.handler, 30)));
+				item.add(new LinkPanel("ticketTitle", null, trimString(entry.title, 80), TicGitTicketPage.class, newPathParameter(entry.name)));
+
+				setAlternatingBackground(item, counter);
+				counter++;
+			}
+		};
+		add(ticketsView);
+
+		// footer
+		addFooter();
+	}
+}
diff --git a/src/com/gitblit/wicket/pages/TicGitTicketPage.html b/src/com/gitblit/wicket/pages/TicGitTicketPage.html
new file mode 100644
index 0000000..b66bf50
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/TicGitTicketPage.html
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" >
+<body>
+	<!-- page header -->
+	<div wicket:id="pageHeader"></div>
+
+	<!-- page nav links -->	
+	<div wicket:id="pageLinks"></div>
+	
+	<!-- ticket title -->
+	<div style="font-size:150%;padding-top:5px;" wicket:id="ticketTitle"></div>
+		
+	<!-- ticket info -->
+	<table class="plain">
+		<tr><th>ticket id</th><td class="sha1"><span wicket:id="ticketId">Message goes here</span></td></tr>
+		<tr><th>assigned</th><td><span wicket:id=ticketHandler>Message goes here</span></td></tr>
+		<tr><th>open date</th><td><span wicket:id="ticketOpenDate">Message goes here</span></td></tr>
+		<tr><th>state</th><td><span wicket:id="ticketState">Message goes here</span></td></tr>
+		<tr><th>tags</th><td><span wicket:id="ticketTags">Message goes here</span></td></tr>
+	</table>
+	
+	<!-- comments header -->
+	<div class="header">Comments</div>
+	
+	<!-- comments -->
+	<table style="width:100%;" class="pretty">
+		<tbody>
+			<tr wicket:id="comment">
+         		<td class="date"><span wicket:id="commentDate"></span></td>
+         		<td><b><div wicket:id="commentAuthor"></div></b></td>
+         		<td><div wicket:id="commentText"></div></td>
+       		</tr>
+       	</tbody>
+    </table>
+    
+	<!-- footer -->
+	<div wicket:id="pageFooter"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/TicGitTicketPage.java b/src/com/gitblit/wicket/pages/TicGitTicketPage.java
new file mode 100644
index 0000000..6390500
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/TicGitTicketPage.java
@@ -0,0 +1,70 @@
+package com.gitblit.wicket.pages;
+
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.TicGitTicket;
+import com.gitblit.utils.TicGitTicket.Comment;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.RepositoryPage;
+import com.gitblit.wicket.WicketUtils;
+
+public class TicGitTicketPage extends RepositoryPage {
+
+	public TicGitTicketPage(PageParameters params) {
+		super(params, "ticgit ticket");
+
+		final String ticketFolder = params.getString("f", "");
+
+		Repository r = getRepository();
+		TicGitTicket t = JGitUtils.getTicGitTicket(r, ticketFolder);
+		r.close();
+
+		add(new Label("ticketTitle", t.title));
+		add(new Label("ticketId", t.id));
+		add(new Label("ticketHandler", t.handler));
+		String openDate = GitBlitWebSession.get().formatDateTimeLong(t.date);
+		add(new Label("ticketOpenDate", openDate));
+		add(new Label("ticketState", t.state));
+		add(new Label("ticketTags", flattenStrings(t.tags)));
+
+		ListDataProvider<Comment> commentsDp = new ListDataProvider<Comment>(t.comments);
+		DataView<Comment> commentsView = new DataView<Comment>("comment", commentsDp) {
+			private static final long serialVersionUID = 1L;
+			int counter = 0;
+
+			public void populateItem(final Item<Comment> item) {
+				final Comment entry = item.getModelObject();
+				item.add(createDateLabel("commentDate", entry.date));
+				item.add(new Label("commentAuthor", entry.author));
+				item.add(new Label("commentText", prepareComment(entry.text)).setEscapeModelStrings(false));
+				setAlternatingBackground(item, counter);
+				counter++;
+			}
+		};
+		add(commentsView);
+
+		// footer
+		addFooter();
+	}
+
+	private String prepareComment(String comment) {
+		String html = WicketUtils.breakLines(comment).trim();
+		return html.replaceAll("\\bcommit\\s*([A-Za-z0-9]*)\\b", "<a href=\"/commit/" + repositoryName + "/$1\">commit $1</a>");
+	}
+
+	private String flattenStrings(List<String> values) {
+		StringBuilder sb = new StringBuilder();
+		for (String value : values) {
+			sb.append(value).append(" ");
+		}
+		return sb.toString().trim();
+	}
+}
diff --git a/src/com/gitblit/wicket/panels/HeadLinksPanel.html b/src/com/gitblit/wicket/panels/BranchLinksPanel.html
similarity index 100%
rename from src/com/gitblit/wicket/panels/HeadLinksPanel.html
rename to src/com/gitblit/wicket/panels/BranchLinksPanel.html
diff --git a/src/com/gitblit/wicket/panels/HeadLinksPanel.java b/src/com/gitblit/wicket/panels/BranchLinksPanel.java
similarity index 61%
rename from src/com/gitblit/wicket/panels/HeadLinksPanel.java
rename to src/com/gitblit/wicket/panels/BranchLinksPanel.java
index eeb2ae4..bc74317 100644
--- a/src/com/gitblit/wicket/panels/HeadLinksPanel.java
+++ b/src/com/gitblit/wicket/panels/BranchLinksPanel.java
@@ -1,21 +1,21 @@
 package com.gitblit.wicket.panels;
 
 import org.apache.wicket.PageParameters;
-import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Panel;
 
 import com.gitblit.wicket.LinkPanel;
 import com.gitblit.wicket.models.RefModel;
 import com.gitblit.wicket.pages.ShortLogPage;
+import com.gitblit.wicket.pages.TreePage;
 
 
-public class HeadLinksPanel extends Panel {
+public class BranchLinksPanel extends Panel {
 
 	private static final long serialVersionUID = 1L;
 
-	public HeadLinksPanel(String id, String repositoryName, RefModel tag) {
+	public BranchLinksPanel(String id, String repositoryName, RefModel tag) {
 		super(id);
 		add(new LinkPanel("shortlog", null, "shortlog", ShortLogPage.class, new PageParameters("p=" + repositoryName + ",h=" + tag.getName())));
-		add(new Label("tree", "tree"));
+		add(new LinkPanel("tree", null, "tree", TreePage.class, new PageParameters("p=" + repositoryName + ",h=" + tag.getName())));
 	}
 }
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/panels/PageLinksPanel.html b/src/com/gitblit/wicket/panels/PageLinksPanel.html
index 5a2f8ec..072221f 100644
--- a/src/com/gitblit/wicket/panels/PageLinksPanel.html
+++ b/src/com/gitblit/wicket/panels/PageLinksPanel.html
@@ -3,7 +3,7 @@
 <wicket:panel>
 	<!-- page nav links -->	
 	<div class="page_nav">
-		<span wicket:id="summary"></span> | <span wicket:id="shortlog"></span> | <span wicket:id="tags"></span> | <span wicket:id="commit"></span> | <span wicket:id="commitdiff"></span> | <span wicket:id="tree"></span>
+		<span wicket:id="summary"></span> | <span wicket:id="shortlog"></span> | <span wicket:id="branches"></span> | <span wicket:id="tags"></span> | <span wicket:id="tree"></span>
 	</div>	
 </wicket:panel>
 </html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/panels/PageLinksPanel.java b/src/com/gitblit/wicket/panels/PageLinksPanel.java
index 02491bc..23f3383 100644
--- a/src/com/gitblit/wicket/panels/PageLinksPanel.java
+++ b/src/com/gitblit/wicket/panels/PageLinksPanel.java
@@ -5,6 +5,7 @@
 import org.apache.wicket.markup.html.panel.Panel;
 
 import com.gitblit.wicket.LinkPanel;
+import com.gitblit.wicket.pages.BranchesPage;
 import com.gitblit.wicket.pages.CommitPage;
 import com.gitblit.wicket.pages.ShortLogPage;
 import com.gitblit.wicket.pages.SummaryPage;
@@ -32,25 +33,20 @@
 			add(new LinkPanel("shortlog", null, "shortlog", ShortLogPage.class, new PageParameters("p=" + repositoryName)));
 		}
 		
+		// branches
+		if (pageName.equals("branches")) {
+			add(new Label("branches", pageName));
+		} else {
+			add(new LinkPanel("branches", null, "branches", BranchesPage.class, new PageParameters("p=" + repositoryName)));
+		}
+		
 		// tags
 		if (pageName.equals("tags")) {
 			add(new Label("tags", pageName));
 		} else {
 			add(new LinkPanel("tags", null, "tags", TagsPage.class, new PageParameters("p=" + repositoryName)));
 		}
-
-		// commit
-		if (pageName.equals("commit")) {
-			add(new Label("commit", pageName));
-		} else {
-			add(new LinkPanel("commit", null, "commit", CommitPage.class, new PageParameters("p=" + repositoryName + ",h=HEAD")));
-		}
-		// commitdiff
-		if (pageName.equals("commitdiff")) {
-			add(new Label("commitdiff", pageName));
-		} else {
-			add(new Label("commitdiff", "commitdiff"));
-		}
+		
 		// tree
 		if (pageName.equals("tree")) {
 			add(new Label("tree", pageName));

--
Gitblit v1.9.1