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.statcvs.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          final Map changePerRevision = new HashMap();
73          final SortedSet revisions = config.getRepository().getRevisions();
74          for (final Iterator it = revisions.iterator(); it.hasNext();) {
75              final Revision rev = (Revision) it.next();
76              final Date dateToUse = blastTime(rev.getDate());
77              final 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          final List annotations = SymbolicNameAnnotation.createAnnotations(config.getRepository().getSymbolicNames());
86          final TimeSeries timeLine = new TimeSeries(Messages.getString("CHURN_TOUCHED_LINE"), Day.class);
87  
88          for (final Iterator it = changePerRevision.entrySet().iterator(); it.hasNext();) {
89              final 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          final TimeSeries locSeries = getLOCTimeSeries(revisions, Messages.getString("TIME_LOC_SUBTITLE"));
96  
97          final LOCChurnChartMaker chart = new LOCChurnChartMaker(config, timeLine, locSeries, Messages.getString("LOC_CHURN_CHART_TITLE"), "locandchurn.png",
98                  config.getLargeChartSize(), annotations);
99          return chart.toFile();
100     }
101 
102     private Date blastTime(final Date date) {
103         final 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(final 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 }