1 package net.sf.statcvs.pages; 2 3 import java.text.NumberFormat; 4 import java.util.ArrayList; 5 import java.util.Collection; 6 import java.util.Collections; 7 import java.util.Iterator; 8 import java.util.List; 9 10 import net.sf.statcvs.Messages; 11 import net.sf.statcvs.charts.ChartImage; 12 import net.sf.statcvs.charts.DirectoryPieChartMaker.CodeDistributionChartMaker; 13 import net.sf.statcvs.charts.TimeBarChartMaker.HourBarChartMaker; 14 import net.sf.statcvs.charts.TimeBarChartMaker.WeekdayBarChartMaker; 15 import net.sf.statcvs.model.Author; 16 import net.sf.statcvs.model.Commit; 17 import net.sf.statcvs.model.Repository; 18 import net.sf.statcvs.model.Revision; 19 import net.sf.statcvs.output.ConfigurationOptions; 20 import net.sf.statcvs.output.ReportConfig; 21 import net.sf.statcvs.reports.DirectoriesForAuthorTableReport; 22 import net.sf.statcvs.util.StringUtils; 23 24 /** 25 * @author anja 26 * @author Richard Cyganiak (richard@cyganiak.de) 27 * @version $Id: DeveloperPageMaker.java,v 1.18 2009/08/20 08:57:00 benoitx Exp $ 28 */ 29 public class DeveloperPageMaker { 30 private final static int RECENT_COMMITS_LENGTH = 20; 31 private final static NumberFormat PERCENT_FORMAT = NumberFormat.getPercentInstance(); 32 33 static { 34 PERCENT_FORMAT.setMinimumFractionDigits(1); 35 PERCENT_FORMAT.setMaximumFractionDigits(1); 36 } 37 38 public static String getURL(final Author developer) { 39 return getFilename(developer) + ".html"; 40 } 41 42 private static String getFilename(final Author developer) { 43 return "user_" + HTML.escapeAuthorName(developer.getName()); 44 } 45 46 private final ReportConfig config; 47 private final Author developer; 48 private final Repository repository; 49 50 public DeveloperPageMaker(final ReportConfig config, final Author developer) { 51 this.config = config; 52 this.developer = developer; 53 this.repository = config.getRepository(); 54 } 55 56 public Page toFile() { 57 final ChartImage hourChart = new HourBarChartMaker("activity_time", this.config, this.developer.getRevisions(), Messages 58 .getString("ACTIVITY_TIME_FOR_AUTHOR_TITLE") 59 + " " + this.developer.getRealName(), "activity_time_" + HTML.escapeAuthorName(this.developer.getName()) + ".png").toFile(); 60 final ChartImage weekdayChart = new WeekdayBarChartMaker("activity_day", this.config, this.developer.getRevisions(), Messages 61 .getString("ACTIVITY_DAY_FOR_AUTHOR_TITLE") 62 + " " + this.developer.getRealName(), "activity_day_" + HTML.escapeAuthorName(this.developer.getName()) + ".png").toFile(); 63 final ChartImage codeDistributionChart = new CodeDistributionChartMaker(this.config, this.developer).toFile(); 64 65 String title; 66 if (this.config.isDeveloper(this.developer)) { 67 title = this.config.getProjectName() + " Developers: " + this.developer.getRealName(); 68 } else { 69 title = "Non-developer Login: " + this.developer.getRealName(); 70 } 71 final Page page = this.config.createPage(getFilename(this.developer), this.developer.getRealName(), title); 72 page.addAttribute("Login name", this.developer.getName()); 73 if (this.developer.getRealName() != null && !this.developer.getRealName().equals(this.developer.getName())) { 74 page.addAttribute("Real name", this.developer.getRealName()); 75 } 76 if (StringUtils.isNotEmpty(this.developer.getTwitterUserName())) { 77 page.addRawAttribute("Twitter", "@<a href=\"http://twitter.com/" + this.developer.getTwitterUserName() + "\">" 78 + this.developer.getTwitterUserName() + "</a>"); 79 } 80 if (StringUtils.isNotEmpty(this.developer.getEmail())) { 81 page.addRawAttribute("Email", "<a href=\"mailto:" + this.developer.getEmail() + "\">" + this.developer.getEmail() + "</a>"); 82 } 83 if (StringUtils.isNotEmpty(this.developer.getHomePageUrl())) { 84 page.addRawAttribute("Home Page", "<a href=\"" + this.developer.getHomePageUrl() + "\">" + this.developer.getHomePageUrl() + "</a>"); 85 } 86 if (StringUtils.isNotEmpty(this.developer.getImageUrl())) { 87 page.addRawAttribute("Image", "<img src=\"" + this.developer.getImageUrl() + "\" alt=\"" + this.developer.getRealName() + "\"/>"); 88 } 89 90 page.addAttribute("Total Commits", getNumberAndPercentage(this.developer.getRevisions().size(), this.repository.getRevisions().size())); 91 String loc = getNumberAndPercentage(countContributedLines(this.developer.getRevisions()), countContributedLines(this.repository.getRevisions())); 92 page.addAttribute("Lines of Code", loc); 93 page.addAttribute("Most Recent Commit", ((Revision) this.developer.getRevisions().last()).getDate()); 94 if (ConfigurationOptions.isEnableTwitterButton()) { 95 page.addRawAttribute("Tweet this", TwitterHelp.buildDeveloperLink(developer, loc, repository, config)); 96 } 97 page.addSection(Messages.getString("ACTIVITY_TITLE")); 98 page.add(hourChart); 99 page.add(weekdayChart); 100 101 if (StringUtils.isNotEmpty(this.developer.getTwitterUserName()) && this.developer.isTwitterIncludeHtml()) { 102 page.addSection("Twitter"); 103 page.addRawContent("<div id=\"twitter_div\">"); 104 page.addRawContent("<ul id=\"twitter_update_list\"/>"); 105 page.addRawContent("<a href=\"http://twitter.com/" + developer.getTwitterUserName() 106 + "\" id=\"twitter-link\" style=\"display:block;text-align:right;\">follow me on Twitter</a>"); 107 page.addRawContent("</div>"); 108 page.addRawContent("<script type=\"text/javascript\" src=\"http://twitter.com/javascripts/blogger.js\"></script>"); 109 page.addRawContent("<script type=\"text/javascript\" src=\"http://twitter.com/statuses/user_timeline/" + developer.getTwitterUserName() 110 + ".json?callback=twitterCallback2&count=5\"></script>"); 111 } 112 if (StringUtils.isNotEmpty(this.developer.getTwitterUserId()) && this.developer.isTwitterIncludeFlash()) { 113 page.addSection("Twitter"); 114 page 115 .addRawContent("<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,124,0\" width=\"550\" height=\"350\" id=\"TwitterWidget\" align=\"middle\">"); 116 page.addRawContent("<param name=\"allowScriptAccess\" value=\"sameDomain\" />"); 117 page.addRawContent("<param name=\"allowFullScreen\" value=\"false\" />"); 118 page.addRawContent("<param name=\"movie\" value=\"http://static.twitter.com/flash/widgets/profile/TwitterWidget.swf\" />"); 119 page.addRawContent("<param name=\"quality\" value=\"high\" />"); 120 page.addRawContent("<param name=\"bgcolor\" value=\"#000000\" />"); 121 page.addRawContent("<param name=\"FlashVars\" value=\"userID=" + developer.getTwitterUserId() 122 + "&styleURL=http://static.twitter.com/flash/widgets/profile/velvetica.xml\"/>"); 123 page 124 .addRawContent("<embed src=\"http://static.twitter.com/flash/widgets/profile/TwitterWidget.swf\" quality=\"high\" bgcolor=\"#000000\" width=\"550\" height=\"350\" name=\"TwitterWidget\" align=\"middle\" allowScriptAccess=\"sameDomain\" allowFullScreen=\"false\" type=\"application/x-shockwave-flash\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" FlashVars=\"userID=" 125 + developer.getTwitterUserId() + "&styleURL=http://static.twitter.com/flash/widgets/profile/velvetica.xml\"/></object>"); 126 } 127 128 page.addSection("Activity in Directories"); 129 page.add(new DirectoriesForAuthorTableReport(this.config, this.developer)); 130 if (codeDistributionChart != null) { 131 page.add(codeDistributionChart); 132 } 133 page.addSection(Messages.getString("MOST_RECENT_COMMITS")); 134 page.addRawContent(new CommitListFormatter(this.config, getRecentCommits(), Collections.EMPTY_LIST, RECENT_COMMITS_LENGTH, false).render()); 135 return page; 136 } 137 138 private List getRecentCommits() { 139 final List results = new ArrayList(); 140 final Iterator it = this.repository.getCommits().iterator(); 141 while (it.hasNext()) { 142 final Commit commit = (Commit) it.next(); 143 if (this.developer.equals(commit.getAuthor())) { 144 results.add(commit); 145 } 146 } 147 return results; 148 } 149 150 private int countContributedLines(final Collection revisions) { 151 int result = 0; 152 final Iterator it = revisions.iterator(); 153 while (it.hasNext()) { 154 final Revision element = (Revision) it.next(); 155 result += element.getNewLines(); 156 } 157 return result; 158 } 159 160 /** 161 * returns the percentage of a given total count and the count. 162 * This will work, because division by zero is not a problem with doubles: 163 * you get NaN (and the formatter will format that too). 164 * @author Jan Dockx 165 * @param value 166 * @param total 167 * @return String percentage string 168 */ 169 private String getNumberAndPercentage(final int value, final int total) { 170 final double factor = (double) value / (double) total; 171 return NumberFormat.getNumberInstance().format(value) + " (" + PERCENT_FORMAT.format(factor) + ")"; 172 } 173 }