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

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

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