1 package net.sf.statcvs.charts;
2
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.Paint;
6 import java.util.ArrayList;
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.Date;
11 import java.util.HashMap;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.SortedSet;
16
17 import net.sf.statcvs.Messages;
18 import net.sf.statcvs.model.Author;
19 import net.sf.statcvs.model.Directory;
20 import net.sf.statcvs.model.Repository;
21 import net.sf.statcvs.model.Revision;
22 import net.sf.statcvs.output.ReportConfig;
23 import net.sf.statcvs.pages.HTML;
24 import net.sf.statcvs.reports.LOCSeriesBuilder;
25 import net.sf.statcvs.util.IntegerMap;
26
27 import org.jfree.chart.ChartFactory;
28 import org.jfree.chart.JFreeChart;
29 import org.jfree.chart.annotations.XYAnnotation;
30 import org.jfree.chart.axis.DateAxis;
31 import org.jfree.chart.axis.ValueAxis;
32 import org.jfree.chart.plot.XYPlot;
33 import org.jfree.chart.renderer.xy.XYStepRenderer;
34 import org.jfree.data.time.TimeSeries;
35 import org.jfree.data.time.TimeSeriesCollection;
36
37
38
39
40
41
42
43
44
45
46 public class LOCChartMaker {
47 private final ReportConfig config;
48 private ChartImage chartFile = null;
49
50
51
52
53
54
55
56
57
58
59 public LOCChartMaker(final ReportConfig config, final TimeSeries locSeries, final String title, final String fileName, final Dimension size,
60 final List annotations) {
61 this.config = config;
62 if (locSeries == null) {
63 return;
64 }
65 final Paint[] colors = new Paint[1];
66 colors[0] = Color.RED;
67
68 final TimeSeriesCollection collection = new TimeSeriesCollection();
69 collection.addSeries(locSeries);
70 final JFreeChart chart = createLOCChart(collection, colors, title, annotations);
71 this.chartFile = this.config.createChartImage(fileName, title, chart, size);
72 }
73
74
75
76
77
78
79
80
81
82 public LOCChartMaker(final ReportConfig config, final List locSeriesList, final String title, final String fileName, final Dimension size,
83 final List annotations) {
84 this.config = config;
85 if (locSeriesList.isEmpty()) {
86 return;
87 }
88 int i = 0;
89 final TimeSeriesCollection collection = new TimeSeriesCollection();
90 final Iterator it = locSeriesList.iterator();
91 while (it.hasNext()) {
92 final TimeSeries series = (TimeSeries) it.next();
93 collection.addSeries(series);
94 i++;
95 }
96 final JFreeChart chart = createLOCChart(collection, null, title, annotations);
97 this.chartFile = this.config.createChartImage(fileName, title, chart, size);
98 }
99
100 private JFreeChart createLOCChart(final TimeSeriesCollection data, final Paint[] colors, final String title, final List annotations) {
101 final String domain = Messages.getString("TIME_LOC_DOMAIN");
102 final String range = Messages.getString("TIME_LOC_RANGE");
103
104 final boolean legend = (data.getSeriesCount() > 1);
105 final JFreeChart chart = ChartFactory.createTimeSeriesChart(this.config.getProjectName() + ": " + title, domain, range, data, legend, false, false);
106
107 final XYPlot plot = chart.getXYPlot();
108 plot.setRenderer(new XYStepRenderer());
109 if (colors == null) {
110
111 for (int i = 0; i < plot.getSeriesCount(); i++) {
112 final Paint seriesPaint = plot.getRenderer().getSeriesPaint(i);
113 if (seriesPaint != null && seriesPaint.equals(new Color(0xFF, 0xFF, 0x55))) {
114 plot.getRenderer().setSeriesPaint(i, new Color(240, 220, 0x55));
115 }
116 }
117 } else {
118 for (int i = 0; i < colors.length; i++) {
119 plot.getRenderer().setSeriesPaint(i, colors[i]);
120 }
121 }
122 final DateAxis domainAxis = (DateAxis) plot.getDomainAxis();
123 domainAxis.setVerticalTickLabels(true);
124 final ValueAxis valueAxis = plot.getRangeAxis();
125 valueAxis.setLowerBound(0);
126
127 if (annotations != null) {
128 for (final Iterator it = annotations.iterator(); it.hasNext();) {
129 plot.addAnnotation((XYAnnotation) it.next());
130 }
131 }
132 return chart;
133 }
134
135 public ChartImage toFile() {
136 return this.chartFile;
137 }
138
139 private static TimeSeries getLOCTimeSeries(final SortedSet revisions, final String title) {
140 final LOCSeriesBuilder locCounter = new LOCSeriesBuilder(title, true);
141 final Iterator it = revisions.iterator();
142 while (it.hasNext()) {
143 locCounter.addRevision((Revision) it.next());
144 }
145 if (locCounter.getMaximum() == 0) {
146 return null;
147 }
148 return locCounter.getTimeSeries();
149 }
150
151 public static class MainLOCChartMaker extends LOCChartMaker {
152 public MainLOCChartMaker(final ReportConfig config, final String fileName, final Dimension size) {
153 super(config, getLOCTimeSeries(config.getRepository().getRevisions(), Messages.getString("TIME_LOC_SUBTITLE")), Messages
154 .getString("TIME_LOC_SUBTITLE"), fileName, size, SymbolicNameAnnotation.createAnnotations(config.getRepository().getSymbolicNames()));
155 }
156 }
157
158 public static class DirectoryLOCChartMaker extends LOCChartMaker {
159 private static String getTitle(final Directory directory) {
160 return directory.getPath() + (directory.getPath() != null && directory.getPath().length() > 1 ? " " : "") + Messages.getString("TIME_LOC_SUBTITLE");
161 }
162
163 private static String getFilename(final Directory directory) {
164 return "loc_module" + HTML.escapeDirectoryName(directory.getPath()) + ".png";
165 }
166
167 public DirectoryLOCChartMaker(final ReportConfig config, final Directory directory) {
168 super(config, getLOCTimeSeries(directory.getRevisions(), getTitle(directory)), getTitle(directory), getFilename(directory), config
169 .getLargeChartSize(), SymbolicNameAnnotation.createAnnotations(config.getRepository().getSymbolicNames()));
170 }
171 }
172
173 public static class AllDevelopersLOCChartMaker extends LOCChartMaker {
174 private static List createAllDevelopersLOCSeries(final ReportConfig config) {
175 Iterator it = config.getRepository().getAuthors().iterator();
176 final Map authorSeriesMap = new HashMap();
177 while (it.hasNext()) {
178 final Author author = (Author) it.next();
179 if (!config.isDeveloper(author)) {
180 continue;
181 }
182 authorSeriesMap.put(author, new LOCSeriesBuilder(author.getRealName(), false));
183 }
184 it = config.getRepository().getRevisions().iterator();
185 while (it.hasNext()) {
186 final Revision rev = (Revision) it.next();
187 if (rev.isBeginOfLog()) {
188 continue;
189 }
190 final LOCSeriesBuilder builder = (LOCSeriesBuilder) authorSeriesMap.get(rev.getAuthor());
191 if (builder != null) {
192 builder.addRevision(rev);
193 }
194 }
195 final List authors = new ArrayList(authorSeriesMap.keySet());
196 Collections.sort(authors);
197 final List result = new ArrayList();
198 it = authors.iterator();
199 while (it.hasNext()) {
200 final Author author = (Author) it.next();
201 final LOCSeriesBuilder builder = (LOCSeriesBuilder) authorSeriesMap.get(author);
202 final TimeSeries series = builder.getTimeSeries();
203 if (series != null) {
204 result.add(series);
205 }
206 }
207 return result;
208 }
209
210 public AllDevelopersLOCChartMaker(final ReportConfig config, final Dimension size) {
211 super(config, createAllDevelopersLOCSeries(config), "Contributed Lines of Code", "loc_per_author.png", size, SymbolicNameAnnotation
212 .createAnnotations(config.getRepository().getSymbolicNames()));
213 }
214 }
215
216 public static class AllDirectoriesLOCChartMaker extends LOCChartMaker {
217 private static Collection getMajorDirectories(final Repository repository, final int max) {
218 if (repository.getFirstDate() == null || repository.getLastDate() == null || repository.getFirstDate().equals(repository.getLastDate())) {
219 return Collections.EMPTY_LIST;
220 }
221 final IntegerMap importances = new IntegerMap();
222 final Iterator it = repository.getDirectories().iterator();
223 while (it.hasNext()) {
224 final Directory directory = (Directory) it.next();
225 importances.put(directory, getImportance(directory, repository.getFirstDate(), repository.getLastDate()));
226 }
227 final List result = new ArrayList(repository.getDirectories());
228 Collections.sort(result, new Comparator() {
229 public int compare(final Object o1, final Object o2) {
230 final int importance1 = importances.get(o1);
231 final int importance2 = importances.get(o2);
232 if (importance1 > importance2) {
233 return -1;
234 }
235 if (importance1 == importance2) {
236 return 0;
237 }
238 return 1;
239 }
240 });
241 return firstN(result, max);
242 }
243
244 private static int getImportance(final Directory dir, final Date start, final Date end) {
245 final long timeRange = end.getTime() - start.getTime();
246 double maxImportance = 0;
247 int currentLines = 0;
248 final Iterator it = dir.getRevisions().iterator();
249 while (it.hasNext()) {
250 final Revision revision = (Revision) it.next();
251 currentLines += revision.getLinesDelta();
252 final long timeInRange = revision.getDate().getTime() - start.getTime();
253 final double timeFraction = (timeInRange / timeRange) * 0.9 + 0.1;
254 maxImportance = Math.max(maxImportance, (currentLines) * (timeFraction));
255 }
256 return (int) (maxImportance * 10);
257 }
258
259 private static List firstN(final List list, final int n) {
260 return list.subList(0, Math.min(list.size(), n));
261 }
262
263 private static List createAllDirectoriesLOCSeries(final Repository repository, final int max) {
264 Iterator it = getMajorDirectories(repository, max).iterator();
265 final Map directorySeriesMap = new HashMap();
266 while (it.hasNext()) {
267 final Directory directory = (Directory) it.next();
268 directorySeriesMap.put(directory, new LOCSeriesBuilder(directory.getPath(), true));
269 }
270 it = repository.getRevisions().iterator();
271 while (it.hasNext()) {
272 final Revision rev = (Revision) it.next();
273 if (rev.isBeginOfLog()) {
274 continue;
275 }
276 final LOCSeriesBuilder builder = (LOCSeriesBuilder) directorySeriesMap.get(rev.getFile().getDirectory());
277 if (builder == null) {
278 continue;
279 }
280 builder.addRevision(rev);
281 }
282 final List directories = new ArrayList(directorySeriesMap.keySet());
283 Collections.sort(directories);
284 final List result = new ArrayList();
285 it = directories.iterator();
286 while (it.hasNext()) {
287 final Directory directory = (Directory) it.next();
288 final LOCSeriesBuilder builder = (LOCSeriesBuilder) directorySeriesMap.get(directory);
289 final TimeSeries series = builder.getTimeSeries();
290 if (series != null) {
291 result.add(series);
292 }
293 }
294 return result;
295 }
296
297 public AllDirectoriesLOCChartMaker(final ReportConfig config, final int showMaxDirectories) {
298 super(config, createAllDirectoriesLOCSeries(config.getRepository(), showMaxDirectories), "Lines of Code Per Directory",
299 "directories_loc_timeline.png", config.getLargeChartSize(), SymbolicNameAnnotation.createAnnotations(config.getRepository()
300 .getSymbolicNames()));
301 }
302 }
303 }