source: trunk/src/org/expeditee/items/widgets/charts/AbstractChart.java@ 919

Last change on this file since 919 was 919, checked in by jts21, 10 years ago

Added license headers to all files, added full GPL3 license file, moved license header generator script to dev/bin/scripts

File size: 11.4 KB
Line 
1/**
2 * AbstractChart.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.items.widgets.charts;
20
21import java.awt.BasicStroke;
22import java.awt.Color;
23import java.awt.Component;
24import java.awt.Font;
25import java.awt.Paint;
26import java.awt.Point;
27import java.awt.event.KeyEvent;
28import java.awt.event.KeyListener;
29import java.awt.event.MouseEvent;
30import java.awt.event.MouseListener;
31import java.util.Collection;
32import java.util.LinkedHashMap;
33import java.util.Map;
34
35import javax.swing.JPanel;
36
37import org.expeditee.gui.ColorUtils;
38import org.expeditee.gui.Frame;
39import org.expeditee.gui.FrameGraphics;
40import org.expeditee.gui.FrameIO;
41import org.expeditee.gui.FrameKeyboardActions;
42import org.expeditee.gui.FrameMouseActions;
43import org.expeditee.gui.FunctionKey;
44import org.expeditee.items.Text;
45import org.expeditee.items.widgets.DataFrameWidget;
46import org.expeditee.settings.templates.TemplateSettings;
47import org.jfree.chart.ChartPanel;
48import org.jfree.chart.JFreeChart;
49import org.jfree.chart.block.BlockBorder;
50import org.jfree.chart.plot.Plot;
51import org.jfree.chart.title.LegendTitle;
52import org.jfree.chart.title.TextTitle;
53import org.jfree.chart.title.Title;
54import org.jfree.ui.RectangleInsets;
55
56public abstract class AbstractChart extends DataFrameWidget {
57
58 protected static final String DEFAULT_TITLE = "";
59
60 protected static final String DEFAULT_XAXIS = "X";
61
62 protected static final String DEFAULT_YAXIS = "Y";
63
64 private JFreeChart _chart = null;
65
66 private LegendTitle _legend = null;
67
68 protected Map<String, Paint> _paints;
69
70 protected JFreeChart getChart() {
71 return _chart;
72 }
73
74 public AbstractChart(Text source, String[] args) {
75 super(source, new JPanel(), 100, 300, -1, 100, 300, -1);
76 _paints = new LinkedHashMap<String, Paint>();
77 init();
78 refresh();
79 }
80
81 @Override
82 protected String[] getArgs() {
83 return null;
84 }
85
86 protected void init() {
87 // create a chart...
88 _chart = createNewChart();
89 _chart.getPlot().setNoDataMessage("Add data to chart");
90 _legend = _chart.getLegend();
91 ChartPanel cp = new ChartPanel(_chart);
92 cp.setPopupMenu(null);
93 cp.addKeyListener(new KeyListener() {
94 public void keyPressed(KeyEvent e) {
95 int index = e.getKeyCode() - KeyEvent.VK_F1 + 1;
96 // Make sure the key is within range
97 if (index < 0 || index >= FunctionKey.values().length) {
98 return;
99 }
100
101 FunctionKey key = FunctionKey.values()[index];
102 switch (key) {
103 case SizeUp:
104 invalidateLink();
105 FrameKeyboardActions.SetSize(getFirstCorner(), 1, false,
106 true, false);
107 invalidateSelf();
108 FrameGraphics.refresh(true);
109 // FrameGraphics.requestRefresh(true);
110 break;
111 case SizeDown:
112 invalidateLink();
113 FrameKeyboardActions.SetSize(getFirstCorner(), -1, false,
114 true, false);
115 invalidateSelf();
116 FrameGraphics.refresh(true);
117 // FrameGraphics.ForceRepaint();
118 // FrameGraphics.refresh(true);
119 // FrameGraphics.requestRefresh(true);
120 break;
121 case ChangeColor:
122 if (e.isControlDown()) {
123
124 if (e.isShiftDown()) {
125 setSourceFillColor(null);
126 } else {
127 Color newColor = ColorUtils.getNextColor(
128 getSource().getFillColor(),
129 TemplateSettings.BackgroundColorWheel.get(), null);
130 setSourceFillColor(newColor);
131 }
132 } else {
133 if (e.isShiftDown()) {
134 setBackgroundColor(null);
135 } else {
136 Color newColor = ColorUtils.getNextColor(
137 getSource().getColor(), TemplateSettings.ColorWheel.get(),
138 null);
139 setSourceColor(newColor);
140 }
141 }
142 break;
143 }
144 }
145
146 public void keyReleased(KeyEvent e) {
147 }
148
149 public void keyTyped(KeyEvent e) {
150 FrameKeyboardActions.processChar(e.getKeyChar(), e
151 .isShiftDown());
152 }
153 });
154 cp.addMouseListener(new MouseListener() {
155
156 public void mouseClicked(MouseEvent e) {
157 FrameMouseActions.getInstance().mouseClicked(translateEvent(e));
158 }
159
160 public void mouseEntered(MouseEvent e) {
161 // FrameMouseActions.getInstance().mouseEntered(translateEvent(e));
162 }
163
164 public void mouseExited(MouseEvent e) {
165 // FrameMouseActions.getInstance().mouseExited(translateEvent(e));
166 }
167
168 public void mousePressed(MouseEvent e) {
169 FrameMouseActions.getInstance().mousePressed(translateEvent(e));
170 }
171
172 private MouseEvent translateEvent(MouseEvent e) {
173 Point origin = getOrigin();
174 return new MouseEvent((Component) e.getSource(), e.getID(), e
175 .getWhen(), e.getModifiers(), origin.x + e.getX(),
176 origin.y + e.getY(), e.getXOnScreen(),
177 e.getYOnScreen(), e.getClickCount(), false, e
178 .getButton());
179 }
180
181 public void mouseReleased(MouseEvent e) {
182 FrameMouseActions.getInstance()
183 .mouseReleased(translateEvent(e));
184 }
185
186 });
187 super._swingComponent = cp;
188
189 setSourceColor(getSource().getColor());
190 setSourceBorderColor(getSource().getBorderColor());
191 setSourceFillColor(getSource().getFillColor());
192 setBackgroundColor(getSource().getBackgroundColor());
193 setSourceThickness(getSource().getThickness(), false);
194 }
195
196 protected abstract JFreeChart createNewChart();
197
198 @Override
199 public final void refresh() {
200 super.refresh();
201 clearData();
202 // Get the data from the linked frame
203 Frame dataFrame = getDataFrame();
204 _paints.clear();
205 _chart.clearSubtitles();
206
207 if (dataFrame != null) {
208 _chart.setTitle(dataFrame.getTitle());
209
210 refreshData(dataFrame);
211
212 if (dataFrame.hasAnnotation("legend")) {
213 _chart.addLegend(_legend);
214 }
215 if (dataFrame.hasAnnotation("subtitle")) {
216 getChart().addSubtitle(
217 new TextTitle(dataFrame.getAnnotationValue("subtitle"),
218 JFreeChart.DEFAULT_TITLE_FONT.deriveFont(
219 Font.ITALIC,
220 JFreeChart.DEFAULT_TITLE_FONT
221 .getSize2D() * .7F)));
222 }
223
224 refreshPlot(dataFrame, _chart.getPlot());
225
226 } else {
227 _chart.setTitle(this.getClass().getSimpleName() + " Chart");
228 }
229 _chart.getPlot().setDataPaints(_paints);
230 super._swingComponent.invalidate();
231 }
232
233 /**
234 * @param dataFrame
235 */
236 protected abstract void refreshPlot(Frame dataFrame, Plot simplePlot);
237
238 /**
239 * @param dataFrame
240 */
241 protected void refreshData(Frame dataFrame) {
242 clearSubjects();
243
244 boolean swap = false;
245 if (dataFrame.hasAnnotation("swap")) {
246 swap = true;
247 }
248 boolean foundData = false;
249 // First do a pass to see if there are any line ends
250 Collection<Text> textItems = dataFrame.getNonAnnotationText(true);
251 textItems.remove(dataFrame.getTitleItem());
252
253 // Search for line ends
254 for (Text text : textItems) {
255 if (!text.isLineEnd()) {
256 continue;
257 }
258 foundData |= addCategoryData(text.getText(), text
259 .getEnclosedNonAnnotationText(), swap);
260 }
261
262 // As a second option look for linked items on the frame
263 if (!foundData) {
264 for (Text category : textItems) {
265 if (category.isLineEnd() || category.getLink() == null)
266 continue;
267 Frame linkFrame = FrameIO.LoadFrame(category.getAbsoluteLink());
268 if (linkFrame == null)
269 continue;
270
271 String categoryName = category.getText();
272 if (foundData |= addCategoryData(categoryName, linkFrame
273 .getNonAnnotationText(true), swap)) {
274 Color backgroundColor = category.getBackgroundColor();
275 if (backgroundColor != null)
276 _paints.put(categoryName, backgroundColor);
277 addSubject(linkFrame);
278 }
279 }
280 }
281
282 // If there were no groupings in boxes then just get all the values on
283 // the frame
284 if (!foundData) {
285 foundData |= addCategoryData("", textItems, swap);
286 }
287 /* if (foundData) */{
288 /*
289 * At minimum add the data frame as a subject even if there is no data
290 * on it... yet
291 */
292 addSubject(dataFrame);
293 }
294 }
295
296 protected boolean addCategoryData(String categoryName,
297 Collection<Text> items, boolean swap) {
298 return true;
299 }
300
301 @Override
302 public float getMinimumBorderThickness() {
303 return 1.0F;
304 }
305
306 protected abstract void clearData();
307
308 @Override
309 public void setBackgroundColor(Color c) {
310 super.setBackgroundColor(c);
311 if (_chart == null)
312 return;
313 if (c == null) {
314 _chart.setBackgroundPaint(JFreeChart.DEFAULT_BACKGROUND_PAINT);
315 } else {
316 _chart.setBackgroundPaint(c);
317 }
318 }
319
320 @Override
321 public void setSourceColor(Color c) {
322 super.setSourceColor(c);
323 if (_chart == null)
324 return;
325 if (c == null) {
326 _chart.getTitle().setPaint(TextTitle.DEFAULT_TEXT_PAINT);
327 } else {
328 _chart.getTitle().setPaint(c);
329 }
330 for (Title t : _chart.getSubtitles()) {
331 if (c == null) {
332 t.setPaint(TextTitle.DEFAULT_TEXT_PAINT);
333 } else {
334 t.setPaint(c);
335 }
336 }
337 LegendTitle legend = _chart.getLegend();
338 if (legend != null) {
339 if (c == null) {
340 legend.setFrame(new BlockBorder(Color.black));
341 } else {
342 legend.setFrame(new BlockBorder(c));
343 }
344 }
345 }
346
347 @Override
348 public void setSourceBorderColor(Color c) {
349 super.setSourceBorderColor(c);
350 if (_chart == null)
351 return;
352 if (c == null) {
353 _chart.getPlot().setOutlinePaint(Plot.DEFAULT_OUTLINE_PAINT);
354 } else {
355 _chart.getPlot().setOutlinePaint(c);
356 }
357 }
358
359 @Override
360 public void setSourceFillColor(Color c) {
361 super.setSourceFillColor(c);
362 if (_chart == null)
363 return;
364 LegendTitle legend = _chart.getLegend();
365 if (c == null) {
366 _chart.getPlot().setBackgroundPaint(Plot.DEFAULT_BACKGROUND_PAINT);
367 if (legend != null)
368 legend.setBackgroundPaint(null);
369 } else {
370 _chart.getPlot().setBackgroundPaint(c);
371 if (legend != null)
372 legend.setBackgroundPaint(c);
373 }
374 }
375
376 @Override
377 public void setSourceThickness(float newThickness, boolean setConnected) {
378 super.setSourceThickness(newThickness, setConnected);
379 if (_chart == null)
380 return;
381 _chart.setBorderStroke(new BasicStroke(newThickness));
382 _chart.getPlot().setOutlineStroke(new BasicStroke(newThickness));
383
384 float fontSize = getFontSize(newThickness, TextTitle.DEFAULT_FONT
385 .getSize2D());
386 LegendTitle legend = _chart.getLegend();
387 if (legend != null) {
388 legend.setFrame(new BlockBorder(newThickness, newThickness,
389 newThickness, newThickness, getSource().getPaintColor()));
390 legend.setItemFont(legend.getItemFont().deriveFont(fontSize));
391 float pad = newThickness + 1;
392 float pad2 = pad;
393 legend.setItemLabelPadding(new RectangleInsets(pad, pad, pad, pad));
394 legend.setLegendItemGraphicPadding(new RectangleInsets(pad2, pad2,
395 pad2, pad2));
396 legend.setMargin(newThickness, newThickness, newThickness,
397 newThickness);
398 }
399 float pad0 = newThickness - 1;
400 _chart.setPadding(new RectangleInsets(pad0, pad0, pad0, pad0));
401 TextTitle title = _chart.getTitle();
402 title.setFont(title.getFont().deriveFont(
403 getFontSize(newThickness, JFreeChart.DEFAULT_TITLE_FONT
404 .getSize2D())));
405
406 for (Title t : _chart.getSubtitles()) {
407 if (t instanceof TextTitle) {
408 ((TextTitle) t).setFont(legend.getItemFont().deriveFont(
409 fontSize));
410 }
411 t.setPadding(pad0, pad0, pad0, pad0);
412 }
413 }
414
415 static protected float getFontSize(float newThickness, float oldFontSize) {
416 return (newThickness + 5) * oldFontSize / 6;
417 }
418}
Note: See TracBrowser for help on using the repository browser.