1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.sf.statcvs.charts;
23
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.Font;
27 import java.awt.Rectangle;
28 import java.text.DecimalFormat;
29 import java.util.ArrayList;
30 import java.util.Calendar;
31 import java.util.Collections;
32 import java.util.Date;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.SortedSet;
36
37 import net.sf.statcvs.Messages;
38 import net.sf.statcvs.model.Author;
39 import net.sf.statcvs.model.Repository;
40 import net.sf.statcvs.model.Revision;
41 import net.sf.statcvs.output.ReportConfig;
42
43 import org.jfree.chart.JFreeChart;
44 import org.jfree.chart.annotations.XYAnnotation;
45 import org.jfree.chart.axis.DateAxis;
46 import org.jfree.chart.axis.NumberAxis;
47 import org.jfree.chart.axis.NumberTickUnit;
48 import org.jfree.chart.plot.CombinedDomainXYPlot;
49 import org.jfree.chart.plot.XYPlot;
50 import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
51 import org.jfree.chart.renderer.xy.XYItemRenderer;
52 import org.jfree.data.time.Second;
53 import org.jfree.data.time.TimeSeries;
54 import org.jfree.data.time.TimeSeriesCollection;
55
56 /**
57 * Produces the commit scatter chart.
58 * @author jentzsch
59 * @author Richard Cyganiak (richard@cyganiak.de)
60 */
61 public class CommitScatterChartMaker {
62 private static final String CHART_NAME = "commitscatterauthors";
63 private final static Color ALL_COMMITS_COLOR = new Color(128, 128, 255);
64 private final ReportConfig config;
65 private final Repository repository;
66 private final int width;
67
68 /**
69 * Creates a new CommitScatterChartMaker.
70 * @param repository The repository to be analyzed
71 * @param width The width of the chart in pixels
72 */
73 public CommitScatterChartMaker(final ReportConfig config, final int width) {
74 this.config = config;
75 this.repository = config.getRepository();
76 this.width = width;
77 }
78
79 /**
80 * @return An image file for the chart
81 */
82 public ChartImage toFile() {
83 final DateAxis timeAxis = new DateAxis(Messages.getString("TIME_CSC_DOMAIN"));
84 timeAxis.setVerticalTickLabels(true);
85 final CombinedDomainXYPlot combinedPlot = new CombinedDomainXYPlot(timeAxis);
86 List annotations = SymbolicNameAnnotation.createAnnotations(repository.getSymbolicNames());
87 combinedPlot.add(createPlot(createTimeSeries(this.repository.getRevisions()), "All (" + Messages.getString("TIME_CSC_RANGE") + ")", ALL_COMMITS_COLOR,
88 annotations));
89 annotations = SymbolicNameAnnotation.createAnnotations(repository.getSymbolicNames(), SymbolicNameAnnotation.STYLE_NO_LABELS);
90 final List authors = new ArrayList(this.repository.getAuthors());
91 Collections.sort(authors);
92 final Iterator it = authors.iterator();
93 while (it.hasNext()) {
94 final Author author = (Author) it.next();
95 final Color color = this.config.isDeveloper(author) ? Color.RED : Color.GRAY;
96 combinedPlot.add(createPlot(createTimeSeries(author.getRevisions()), author.getName(), color, annotations));
97 }
98 combinedPlot.setGap(10);
99 final JFreeChart chart = new JFreeChart(this.config.getProjectName() + ": " + Messages.getString("TIME_CSC_SUBTITLE"), JFreeChart.DEFAULT_TITLE_FONT,
100 combinedPlot, false);
101
102 combinedPlot.setBackgroundPaint(ChartConfigUtil.getPlotColor(CHART_NAME));
103 chart.setBackgroundPaint(ChartConfigUtil.getBackgroundColor(CHART_NAME));
104 final XYItemRenderer renderer = combinedPlot.getRenderer();
105 ChartConfigUtil.configureShapes(CHART_NAME, renderer);
106 ChartConfigUtil.configureCopyrightNotice(CHART_NAME, chart);
107 ChartConfigUtil.configureChartBackgroungImage(CHART_NAME, chart);
108 ChartConfigUtil.configurePlotImage(CHART_NAME, chart);
109
110 final Dimension dim = ChartConfigUtil.getDimension(CHART_NAME, config.getLargeChartSize());
111
112 return this.config.createChartImage(CHART_NAME + ".png", Messages.getString("TIME_CSC_SUBTITLE"), chart, getSize(dim));
113 }
114
115 private TimeSeries createTimeSeries(final SortedSet revisions) {
116 final TimeSeries result = new TimeSeries("Dummy", Second.class);
117 final Iterator it = revisions.iterator();
118 Date lastDate = new Date();
119 while (it.hasNext()) {
120 final Revision rev = (Revision) it.next();
121 if (lastDate != null) {
122 final Calendar cal = Calendar.getInstance();
123 cal.setTime(lastDate);
124 final double lastDateSeconds = cal.get(Calendar.SECOND);
125 cal.setTime(rev.getDate());
126 final double dateSeconds = cal.get(Calendar.SECOND);
127 if (lastDateSeconds == dateSeconds) {
128 continue;
129 }
130 }
131 lastDate = rev.getDate();
132 final Calendar cal = Calendar.getInstance();
133 cal.setTime(lastDate);
134 final double hour = cal.get(Calendar.HOUR_OF_DAY);
135 final double minutes = cal.get(Calendar.MINUTE);
136 result.add(new Second(lastDate), hour + minutes / 60.0);
137 }
138 return result;
139 }
140
141 private XYPlot createPlot(final TimeSeries series, final String label, final Color color, final List annotations) {
142 final NumberAxis valueAxis = new NumberAxis(label);
143 valueAxis.setTickUnit(new NumberTickUnit(6.0, new DecimalFormat("0")));
144 valueAxis.setAutoRangeIncludesZero(false);
145 valueAxis.setRange(0.0, 24.0);
146 valueAxis.setLabelFont(new Font("SansSerif", Font.PLAIN, 9));
147 final XYItemRenderer renderer = new StandardXYItemRenderer(StandardXYItemRenderer.SHAPES);
148 renderer.setShape(new Rectangle(new Dimension(2, 2)));
149 final XYPlot result = new XYPlot(new TimeSeriesCollection(series), null, valueAxis, renderer);
150 result.getRenderer().setSeriesPaint(0, color);
151 final Iterator it = annotations.iterator();
152 while (it.hasNext()) {
153 final XYAnnotation annotation = (XYAnnotation) it.next();
154 result.addAnnotation(annotation);
155 }
156 return result;
157 }
158
159 private Dimension getSize(final Dimension dim) {
160 return new Dimension(dim.width, 70 * (this.repository.getAuthors().size() + 1) + 110);
161 }
162 }