View Javadoc

1   /*
2    StatSVN - SVN Subversion statistics generation 
3    Copyright (C) 2006 Benoit Xhenseval
4    http://www.statsvn.org
5    
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10  
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with this library; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   
20  */
21  package net.sf.statsvn.output;
22  
23  import java.util.Calendar;
24  import java.util.Date;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.SortedSet;
30  import java.util.Map.Entry;
31  
32  import net.sf.statcvs.Messages;
33  import net.sf.statcvs.charts.ChartImage;
34  import net.sf.statcvs.charts.SymbolicNameAnnotation;
35  import net.sf.statcvs.model.Revision;
36  import net.sf.statcvs.output.ReportConfig;
37  import net.sf.statcvs.pages.NavigationNode;
38  import net.sf.statcvs.pages.Page;
39  import net.sf.statcvs.reports.LOCSeriesBuilder;
40  
41  import org.jfree.data.time.Day;
42  import org.jfree.data.time.TimeSeries;
43  
44  /**
45   * A LOC and Churn Chart shows both the LOC and the number of lines touched per
46   * day, this allows you to see the evolution of lines of code and the amount of
47   * changes. A flat LOC with a lot of Churn implies a lot of refactoring, an
48   * increase in LOC in line with churn implies new functionality.
49   * 
50   * @author Benoit Xhenseval (www.ObjectLab.co.uk)
51   */
52  public class ChurnPageMaker {
53  	private final ReportConfig config;
54  
55  	/**
56  	 * @see net.sf.statcvs.output.HTMLPage#HTMLPage(Repository)
57  	 */
58  	public ChurnPageMaker(final ReportConfig config) {
59  		this.config = config;
60  	}
61  
62  	public NavigationNode toFile() {
63  		final Page page = this.config.createPage("churn", Messages.getString("CHURN_TITLE"), Messages.getString("CHURN_TITLE"));
64  		page.addRawContent("\n\n<!-- The LOC and Churn Report was designed by Benoit Xhenseval (http://www.objectlab.co.uk/open)-->");
65  		page.addRawContent("\n<!-- Initially part of StatSVN -->\n\n");
66  		page.addRawContent("<p>" + Messages.getString("CHURN_DESCRIPTION") + "</p>");
67  		page.add(buildChart());
68  		return page;
69  	}
70  
71  	private ChartImage buildChart() {
72  		Map changePerRevision = new HashMap();
73  		SortedSet revisions = config.getRepository().getRevisions();
74  		for (Iterator it = revisions.iterator(); it.hasNext();) {
75  			Revision rev = (Revision) it.next();
76  			Date dateToUse = blastTime(rev.getDate());
77  			Integer changes = (Integer) changePerRevision.get(dateToUse);
78  			if (changes == null) {
79  				changePerRevision.put(dateToUse, new Integer(Math.abs(getLineChanges(rev))));
80  			} else {
81  				changePerRevision.put(dateToUse, new Integer(Math.abs(changes.intValue()) + getLineChanges(rev)));
82  			}
83  		}
84  
85  		List annotations = SymbolicNameAnnotation.createAnnotations(config.getRepository().getSymbolicNames());
86  		TimeSeries timeLine = new TimeSeries(Messages.getString("CHURN_TOUCHED_LINE"), Day.class);
87  
88  		for (Iterator it = changePerRevision.entrySet().iterator(); it.hasNext();) {
89  			Map.Entry entry = (Entry) it.next();
90  
91  			SvnConfigurationOptions.getTaskLogger().log("Churn on " + entry.getKey() + " ==> " + entry.getValue());
92  			timeLine.add(new Day((Date) entry.getKey()), ((Integer) entry.getValue()).intValue());
93  		}
94  
95  		TimeSeries locSeries = getLOCTimeSeries(revisions, Messages.getString("TIME_LOC_SUBTITLE"));
96  
97  		LOCChurnChartMaker chart = new LOCChurnChartMaker(config, timeLine, locSeries, Messages.getString("LOC_CHURN_CHART_TITLE"), "locandchurn.png", config
98  		        .getLargeChartSize(), annotations);
99  		return chart.toFile();
100 	}
101 
102 	private Date blastTime(final Date date) {
103 		Calendar cal = Calendar.getInstance();
104 		cal.setTime(date);
105 		cal.set(Calendar.MILLISECOND, 0);
106 		cal.set(Calendar.HOUR_OF_DAY, 0);
107 		cal.set(Calendar.MINUTE, 0);
108 		cal.set(Calendar.SECOND, 0);
109 		return cal.getTime();
110 	}
111 
112 	private int getLineChanges(Revision rev) {
113 		if (rev.isDead()) {
114 			return rev.getLinesDelta();
115 		}
116 		return Math.abs(rev.getLinesDelta()) + 2 * rev.getReplacedLines();
117 	}
118 
119 	private TimeSeries getLOCTimeSeries(final SortedSet revisions, final String title) {
120 		final Iterator it = revisions.iterator();
121 		final LOCSeriesBuilder locCounter = new LOCSeriesBuilder(title, true);
122 		while (it.hasNext()) {
123 			locCounter.addRevision((Revision) it.next());
124 		}
125 		return locCounter.getTimeSeries();
126 	}
127 }