Java tutorial
/* DistributionView.java * * Copyright (C) 2014 Florian Brosch * * Based on work from Andreas Mauczka * * This program is developed as part of the research project * "Lexical Repository Analyis" which is part of the PhD thesis * "Design and evaluation for identification, mapping and profiling * of medium sized software chunks" by Andreas Mauczka at * INSO - University of Technology Vienna. For questions in regard * to the research project contact andreas.mauczka(at)inso.tuwien.ac.at * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License 2.0 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Florian Brosch <flo.brosch@gmail.com> */ package at.ac.tuwien.inso.subcat.ui.widgets; import java.awt.Paint; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.labels.StandardCategoryToolTipGenerator; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.CombinedDomainCategoryPlot; import org.jfree.chart.plot.DrawingSupplier; import org.jfree.chart.renderer.category.BarRenderer; import org.jfree.chart.renderer.category.BoxAndWhiskerRenderer; import org.jfree.data.category.DefaultCategoryDataset; import org.jfree.data.statistics.BoxAndWhiskerItem; import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset; import at.ac.tuwien.inso.subcat.config.DistributionAttributeConfig; import at.ac.tuwien.inso.subcat.config.DistributionAttributesConfig; import at.ac.tuwien.inso.subcat.config.DistributionChartOptionConfig; import at.ac.tuwien.inso.subcat.model.DistributionChartConfigData; import at.ac.tuwien.inso.subcat.model.DistributionChartData; import at.ac.tuwien.inso.subcat.model.DistributionChartOptionConfigData; import at.ac.tuwien.inso.subcat.model.DropDownData; import at.ac.tuwien.inso.subcat.ui.events.DistributionChartListener; public class DistributionChart extends Composite { private TimeChartControlPanel<SelectedChart> timeChart; private ScrolledComposite scrolledComposite; private Composite optionComposite; private LinkedList<DistributionChartListener> listeners; private LinkedList<ChartIdentifier> identifiers; private DrawingSupplier drawingSupplier; private CategoryPlot sizePlot; private CategoryPlot boxPlot; private DefaultBoxAndWhiskerCategoryDataset boxDataSet; private DefaultCategoryDataset sizeDataSet; private CombinedDomainCategoryPlot plot; private SelectionListener configSelectionListener; private int optionCount = 0; public enum SelectedChart { SIZE, DISTRIBUTION, BOTH } public static class ChartIdentifier implements Comparable<ChartIdentifier> { private Paint paint; private DistributionChartOptionConfig config; private LinkedList<Combo> filter; private Combo attributes; private Integer weight; public ChartIdentifier(DistributionChartOptionConfig config, Integer weight) { assert (config != null); assert (weight != null); this.filter = new LinkedList<Combo>(); this.config = config; this.weight = weight; } public DistributionChartOptionConfig getDistributionChartOptionConfig() { return config; } public DistributionAttributeConfig getSelectedAttributeConfig() { int selectionIndex = attributes.getSelectionIndex(); DistributionAttributesConfig config = (DistributionAttributesConfig) attributes.getData(); return config.getData().get(selectionIndex); } public Map<DropDownData, Integer> getSelectedFilterConfigs() { HashMap<DropDownData, Integer> map = new HashMap<DropDownData, Integer>(); for (Combo combo : filter) { DropDownData data = (DropDownData) combo.getData(); int selection = combo.getSelectionIndex(); map.put(data, selection); } return map; } @Override public int compareTo(ChartIdentifier o) { assert (o != null); return weight.compareTo(o.weight); } } public DistributionChart(Composite parent, int style) { super(parent, style); listeners = new LinkedList<DistributionChartListener>(); identifiers = new LinkedList<ChartIdentifier>(); initCharts(); setLayout(new FillLayout()); SashForm sashForm = new SashForm(this, SWT.VERTICAL); timeChart = new TimeChartControlPanel<SelectedChart>(sashForm, SWT.BORDER); timeChart.addChartSelectionEntry("Distribution View", SelectedChart.DISTRIBUTION); timeChart.addChartSelectionEntry("Bar View", SelectedChart.SIZE); timeChart.addChartSelectionEntry("Both", SelectedChart.BOTH); JFreeChart chart = createChart(SelectedChart.DISTRIBUTION); setChart(chart); scrolledComposite = new ScrolledComposite(sashForm, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); scrolledComposite.setLayout(new FillLayout()); optionComposite = new Composite(scrolledComposite, SWT.NONE); optionComposite.setLayout(new GridLayout(3, false)); scrolledComposite.setContent(optionComposite); scrolledComposite.setMinSize(optionComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); scrolledComposite.setExpandVertical(true); scrolledComposite.setExpandHorizontal(true); scrolledComposite.setAlwaysShowScrollBars(false); configSelectionListener = new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { Combo combo = (Combo) e.getSource(); ChartIdentifier identifier = (ChartIdentifier) combo.getData("identifier"); assert (identifier != null); for (DistributionChartListener listener : listeners) { listener.optionChanged(identifier); } } @Override public void widgetDefaultSelected(SelectionEvent e) { } }; } private void initCharts() { boxDataSet = new DefaultBoxAndWhiskerCategoryDataset(); sizeDataSet = new DefaultCategoryDataset(); // Box: NumberAxis yAxis = new NumberAxis("Values"); BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer(); renderer.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator()); boxPlot = new CategoryPlot(boxDataSet, null, yAxis, renderer); drawingSupplier = boxPlot.getDrawingSupplier(); // Bar. NumberAxis rangeAxis2 = new NumberAxis("Values"); rangeAxis2.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); BarRenderer renderer2 = new BarRenderer(); renderer2.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator()); sizePlot = new CategoryPlot(sizeDataSet, null, rangeAxis2, renderer2); sizePlot.setDomainGridlinesVisible(true); } public void addConfiguration(DistributionChartConfigData config, List<String> flags) { assert (config != null); for (DistributionChartOptionConfigData optionConf : config.getOptions()) { if (optionConf.getConfig().show(flags)) { addOptionConfiguration(optionConf, flags); } } } private void addOptionConfiguration(DistributionChartOptionConfigData config, List<String> flags) { assert (config != null); assert (config.getAttributes() != null); if (config.getAttributes().getData().size() == 0) { return; } if (optionCount > 0) { Helper.separator(optionComposite, 3); } ChartIdentifier identifier = new ChartIdentifier(config.getConfig(), optionCount); identifiers.add(identifier); Label lblTitle = new Label(optionComposite, SWT.NONE); lblTitle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); Helper.setLabelStyle(lblTitle, SWT.BOLD); lblTitle.setText(config.getName()); DropDownData firstDropdownData = null; Iterator<DropDownData> filterIter = config.getFilter().iterator(); while (filterIter.hasNext()) { DropDownData data = filterIter.next(); if (data.getConfig().show(flags)) { firstDropdownData = data; break; } } if (firstDropdownData != null) { Combo filterCombo = new Combo(optionComposite, SWT.DROP_DOWN | SWT.READ_ONLY); filterCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); fillCombo(filterCombo, firstDropdownData, identifier); identifier.filter.add(filterCombo); } else { new Label(optionComposite, SWT.NONE); } Combo attCombo = new Combo(optionComposite, SWT.DROP_DOWN | SWT.READ_ONLY); fillAttributeCombo(attCombo, config.getAttributes(), flags, identifier); attCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); identifier.attributes = attCombo; while (filterIter.hasNext()) { DropDownData iterValue = filterIter.next(); if (iterValue.getConfig().show(flags)) { new Label(optionComposite, SWT.NONE); Combo filterCombo = new Combo(optionComposite, SWT.DROP_DOWN | SWT.READ_ONLY); filterCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); new Label(optionComposite, SWT.NONE); fillCombo(filterCombo, iterValue, identifier); identifier.filter.add(filterCombo); } } identifier.paint = drawingSupplier.getNextPaint(); optionCount++; } private void fillAttributeCombo(Combo combo, DistributionAttributesConfig attributes, List<String> flags, ChartIdentifier identifier) { assert (combo != null); assert (attributes != null); assert (identifier != null); combo.setData("identifier", identifier); combo.setData(attributes); for (DistributionAttributeConfig item : attributes.getData()) { if (item.show(flags)) { combo.add(item.getName()); } } combo.select(0); combo.addSelectionListener(configSelectionListener); } private void fillCombo(Combo combo, DropDownData data, ChartIdentifier identifier) { assert (combo != null); assert (data != null); assert (identifier != null); combo.setData("identifier", identifier); combo.setData(data); for (DropDownData.Pair item : data.getData()) { combo.add(item.name); } combo.select(0); combo.addSelectionListener(configSelectionListener); } public void addData(ChartIdentifier identifier, DistributionChartData data) { assert (identifier != null); assert (data != null); LinkedList<Double> emptyList = new LinkedList<Double>(); for (int i = 0; i < 12; i++) { double mean = data.getMean(i); double median = data.getMedian(i); double q1 = data.getQ1(i); double q3 = data.getQ3(i); double min = data.getMin(i); double max = data.getMax(i); double count = data.getCount(i); // Box Plot Dataset: BoxAndWhiskerItem item = new BoxAndWhiskerItem(mean, median, q1, q3, min, max, null, null, emptyList); boxDataSet.add(item, identifier, TimeChartControlPanel.MONTHS[i]); // Bar Dataset: sizeDataSet.addValue(count, identifier, TimeChartControlPanel.MONTHS[i]); } fixChartColours(); } public void removeData(ChartIdentifier identifier) { assert (identifier != null); boxDataSet.removeRow(identifier); sizeDataSet.removeRow(identifier); fixChartColours(); } private void fixChartColours() { for (int i = 0; i < boxDataSet.getRowCount(); i++) { boxPlot.getRenderer().setSeriesPaint(i, ((ChartIdentifier) boxDataSet.getRowKey(i)).paint); sizePlot.getRenderer().setSeriesPaint(i, ((ChartIdentifier) boxDataSet.getRowKey(i)).paint); } } public void setYearRange(int startYear, int endYear) { timeChart.setYearRange(startYear, endYear); } public Integer getSelectedYear() { return timeChart.getSelectedYear(); } public void saveChartAsJPEG(File file) throws IOException { timeChart.saveChartAsJPEG(file, 800, 600); } public void saveChartAsJPEG(File file, int width, int height) throws IOException { timeChart.saveChartAsJPEG(file, width, height); } public void saveChartAsPNG(File file) throws IOException { timeChart.saveChartAsJPEG(file, 800, 600); } public void saveChartAsPNG(File file, int width, int height) throws IOException { timeChart.saveChartAsPNG(file, width, height); } public boolean hasNextChart() { return timeChart.hasNextChart(); } public boolean hasPrevChart() { return timeChart.hasPrevChart(); } public SelectedChart getSelectedChart() { return timeChart.getSelectedChart(); } public void setChart(JFreeChart chart) { timeChart.setChart(chart); // Force the view to update the chart: chart.clearSubtitles(); } public List<ChartIdentifier> getIdentifiers() { return identifiers; } public JFreeChart createChart(SelectedChart chart) { CategoryAxis domainAxis = new CategoryAxis("Date"); plot = new CombinedDomainCategoryPlot(domainAxis); if (drawingSupplier == null) { drawingSupplier = plot.getDrawingSupplier(); } else { plot.setDrawingSupplier(drawingSupplier); } switch (chart) { case DISTRIBUTION: plot.add(boxPlot, 1); break; case SIZE: plot.add(sizePlot, 1); break; case BOTH: plot.add(boxPlot, 1); plot.add(sizePlot, 2); break; default: assert (false); } JFreeChart result = new JFreeChart(null, null, plot, true); return result; } // // Listeners: // public void addDistributionViewListener(DistributionChartListener listener) { assert (listener != null); this.timeChart.addPanelListener(listener); this.listeners.add(listener); } public void removeDistributionViewListener(DistributionChartListener listener) { assert (listener != null); this.timeChart.removePanelListener(listener); this.listeners.remove(listener); } // // Test Main: // /* public static void main (String[] args) { // UI: Display display = new Display (); Shell shell = new Shell (display); shell.setLayout (new FillLayout ()); DistributionView view = new DistributionView (shell, SWT.NONE); view.addOption("Bugs", new String[][]{ {"Filter 1", "Filter 2"}, {"Filter 1", "Filter 2"} }, new String[] {"Att1", "Att2", "Att3"}); shell.open (); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) { display.sleep (); } } display.dispose(); } */ }