at.ac.tuwien.inso.subcat.ui.widgets.TrendChart.java Source code

Java tutorial

Introduction

Here is the source code for at.ac.tuwien.inso.subcat.ui.widgets.TrendChart.java

Source

/* TrendView.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.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

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.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
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.LineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;

import at.ac.tuwien.inso.subcat.config.DropDownConfig;
import at.ac.tuwien.inso.subcat.config.OptionListConfig;
import at.ac.tuwien.inso.subcat.config.TrendChartPlotConfig;
import at.ac.tuwien.inso.subcat.model.DropDownData;
import at.ac.tuwien.inso.subcat.model.OptionListConfigData;
import at.ac.tuwien.inso.subcat.model.TrendChartConfigData;
import at.ac.tuwien.inso.subcat.model.TrendChartData;
import at.ac.tuwien.inso.subcat.ui.events.TrendChartListener;

public class TrendChart extends Composite {
    private LinkedList<TrendChartListener> listeners = new LinkedList<TrendChartListener>();

    private TimeChartControlPanel<SelectedChart> timeChart;
    private CategoryPlot trendPlot;
    private DefaultCategoryDataset dataset;
    private CategoryPlot sizePlot;
    private CombinedDomainCategoryPlot plot;
    private DrawingSupplier drawingSupplier;
    private ScrolledComposite scrolledComposite;
    private Composite optionComposite;

    private int boxWeight;
    private SelectionListener boxListener;
    private SelectionListener comboListener;

    public enum SelectedChart {
        LINE, BAR, BOTH
    }

    public static class ChartIdentifier implements Comparable<ChartIdentifier> {
        private final TrendChartPlotConfig topConfig;
        private final OptionListConfig leftConfig;

        private final int left;
        private final Combo top;
        private final Integer weight;
        private Paint paint;

        public ChartIdentifier(TrendChartPlotConfig topConfig, Combo top, OptionListConfig leftConfig, int left,
                int weight) {
            assert (top != null);
            assert (topConfig != null);
            assert (leftConfig != null);

            this.topConfig = topConfig;
            this.leftConfig = leftConfig;
            this.top = top;
            this.left = left;
            this.weight = weight;
        }

        @Override
        public int compareTo(ChartIdentifier o) {
            assert (o != null);

            return weight.compareTo(o.weight);
        }

        public DropDownData getDropDownData() {
            DropDownData dropData = (DropDownData) top.getData();
            assert (dropData != null);
            return dropData;
        }

        public int getLeftId() {
            return left;
        }

        public int getTopId() {
            return getDropDownData().getData().get(top.getSelectionIndex()).id;
        }

        public Paint getPaint() {
            return paint;
        }

        public DropDownConfig getTopConfig() {
            return topConfig;
        }

        public OptionListConfig getLeftConfig() {
            return leftConfig;
        }
    }

    //
    // GUI:
    //

    public TrendChart(Composite parent, int style) {
        super(parent, style);
        initCharts();

        setLayout(new FillLayout());

        SashForm sashForm = new SashForm(this, SWT.VERTICAL);

        timeChart = new TimeChartControlPanel<SelectedChart>(sashForm, SWT.BORDER);
        timeChart.addChartSelectionEntry("Trend View", SelectedChart.LINE);
        timeChart.addChartSelectionEntry("Bar View", SelectedChart.BAR);
        timeChart.addChartSelectionEntry("Both", SelectedChart.BOTH);

        JFreeChart chart = createChart(SelectedChart.LINE);
        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);

        // Signals:
        boxListener = new SelectionListener() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                Button button = (Button) e.getSource();
                ChartIdentifier boxData = (ChartIdentifier) button.getData();
                assert (boxData != null);

                boolean checked = button.getSelection();

                if (boxData.paint == null) {
                    boxData.paint = drawingSupplier.getNextPaint();
                }

                if (checked) {
                    java.awt.Color paintColor = (java.awt.Color) boxData.paint;
                    Color color = new Color(null, paintColor.getRed(), paintColor.getGreen(), paintColor.getBlue());
                    button.setBackground(color);
                } else {
                    button.setBackground(null);
                }

                for (TrendChartListener listener : listeners) {
                    listener.optionSelected(boxData, checked);
                }
            }

            @Override
            public void widgetDefaultSelected(SelectionEvent e) {
            }
        };

        comboListener = new SelectionListener() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                Combo combo = (Combo) e.getSource();
                DropDownData data = (DropDownData) combo.getData();
                assert (data != null);
                DropDownConfig config = data.getConfig();

                for (TrendChartListener listener : listeners) {
                    listener.comboChanged(config);
                }
            }

            @Override
            public void widgetDefaultSelected(SelectionEvent e) {
            }
        };
    }

    private void initCharts() {
        dataset = new DefaultCategoryDataset();

        // XY:s
        NumberAxis rangeAxis1 = new NumberAxis("Values");
        rangeAxis1.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        LineAndShapeRenderer renderer1 = new LineAndShapeRenderer();
        renderer1.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
        trendPlot = new CategoryPlot(dataset, null, rangeAxis1, renderer1);
        trendPlot.setDomainGridlinesVisible(true);

        // Box:
        NumberAxis rangeAxis2 = new NumberAxis("Values");
        rangeAxis2.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        BarRenderer renderer2 = new BarRenderer();
        renderer2.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
        sizePlot = new CategoryPlot(dataset, null, rangeAxis2, renderer2);
        sizePlot.setDomainGridlinesVisible(true);
    }

    public JFreeChart createChart(SelectedChart chart) {
        assert (chart != null);

        CategoryAxis domainAxis = new CategoryAxis("Date");
        plot = new CombinedDomainCategoryPlot(domainAxis);
        if (drawingSupplier == null) {
            drawingSupplier = plot.getDrawingSupplier();
        } else {
            plot.setDrawingSupplier(drawingSupplier);
        }

        switch (chart) {
        case LINE:
            plot.add(trendPlot, 1);
            break;

        case BAR:
            plot.add(sizePlot, 1);
            break;

        case BOTH:
            plot.add(trendPlot, 1);
            plot.add(sizePlot, 2);
            break;

        default:
            assert (false);
        }

        JFreeChart result = new JFreeChart(null, null, plot, true);

        result.removeLegend();

        return result;
    }

    private void fixChartColours() {
        for (int i = 0; i < dataset.getRowCount(); i++) {
            sizePlot.getRenderer().setSeriesPaint(i, ((ChartIdentifier) dataset.getRowKey(i)).paint);
            trendPlot.getRenderer().setSeriesPaint(i, ((ChartIdentifier) dataset.getRowKey(i)).paint);
        }
    }

    public void addConfiguration(TrendChartConfigData config, List<String> flags) {
        assert (config != null);

        ArrayList<Combo> combos = new ArrayList<Combo>();

        // Title Row:
        Label lblGrpTitle = new Label(optionComposite, SWT.NONE);
        lblGrpTitle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));

        Helper.setLabelStyle(lblGrpTitle, SWT.BOLD);
        lblGrpTitle.setText(config.getName());

        Composite topOptions = new Composite(optionComposite, SWT.NONE);
        topOptions.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
        topOptions.setLayout(new GridLayout(config.getDropDowns().size(), true));

        for (DropDownData dropData : config.getDropDowns()) {
            if (dropData.getConfig().show(flags)) {
                Combo comboDropDown = new Combo(topOptions, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
                comboDropDown.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));
                comboDropDown.setData(dropData);
                combos.add(comboDropDown);

                for (DropDownData.Pair data : dropData.getData()) {
                    comboDropDown.add(data.name);
                }

                comboDropDown.select(0);

                comboDropDown.addSelectionListener(this.comboListener);
            }
        }

        // Separator:
        Helper.separator(optionComposite, 3);

        // Left Option Labels:
        new Label(optionComposite, SWT.NONE);

        Composite leftOptions = new Composite(optionComposite, SWT.NONE);
        leftOptions.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));

        leftOptions.setLayout(new GridLayout(1, true));
        for (OptionListConfigData.Pair pair : config.getOptionList().getData()) {
            Label lblOpt = new Label(leftOptions, SWT.NONE);
            lblOpt.setText(pair.name);
        }

        // Check Boxes:
        Composite selectionComposite = new Composite(optionComposite, SWT.NONE);
        selectionComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
        selectionComposite.setLayout(new GridLayout(combos.size(), true));

        OptionListConfig leftConfig = config.getOptionList().getConfig();

        for (OptionListConfigData.Pair pair : config.getOptionList().getData()) {
            int x = 0;
            for (Combo combo : combos) {
                TrendChartPlotConfig topConfig = (TrendChartPlotConfig) config.getDropDowns().get(x).getConfig();

                Button button = new Button(selectionComposite, SWT.CHECK);
                button.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));
                button.setData(new ChartIdentifier(topConfig, combo, leftConfig, pair.id, boxWeight++));
                button.addSelectionListener(boxListener);
                x++;
            }
        }

        // Scrolling area size update:
        scrolledComposite.setMinSize(optionComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    }

    //
    // API:
    //

    public void setYearRange(int start, int end) {
        timeChart.setYearRange(start, end);
    }

    @SuppressWarnings("unchecked")
    public List<ChartIdentifier> getSelectedIdentifiers() {
        return (List<ChartIdentifier>) dataset.getRowKeys();
    }

    public List<ChartIdentifier> getSelectedIdentifiers(DropDownConfig config) {
        assert (config != null);

        LinkedList<ChartIdentifier> result = new LinkedList<ChartIdentifier>();
        List<ChartIdentifier> selection = getSelectedIdentifiers();

        for (ChartIdentifier id : selection) {
            if (id.getTopConfig() == config) {
                result.add(id);
            }
        }

        return result;
    }

    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();
    }

    //
    // Data:
    //

    public void addData(ChartIdentifier identifier, TrendChartData data) {
        assert (identifier != null);
        assert (data != null);

        for (int i = 0; i < 12; i++) {
            dataset.addValue(data.getData()[i], identifier, TimeChartControlPanel.MONTHS[i]);
        }

        fixChartColours();
    }

    public void removeData(ChartIdentifier chart) {
        assert (chart != null);

        dataset.removeRow(chart);

        fixChartColours();
    }

    public void removeData(Collection<ChartIdentifier> charts) {
        assert (charts != null);

        for (ChartIdentifier id : charts) {
            removeData(id);
        }
    }

    //
    // Listeners:
    //

    public void addTrendViewListener(TrendChartListener listener) {
        assert (listener != null);

        this.timeChart.addPanelListener(listener);
        this.listeners.add(listener);
    }

    public void removeTrendViewListener(TrendChartListener listener) {
        assert (listener != null);

        this.timeChart.removePanelListener(listener);
        this.listeners.remove(listener);
    }

    //
    // Test Method:
    //

    /*
    public static void main (String[] args) {
       // Option Configuration:
       Project proj = new Project (null, new Date (), "My Project", "", "");
       LinkedList<NamedContainer> rows = new LinkedList<NamedContainer> ();
       rows.add (new Category (1, proj, "Foo"));
       rows.add (new Category (2, proj, "Bar"));
       rows.add (new Category (3, proj, "Baz"));
        
       // UI:
       Display display = new Display ();
       Shell shell = new Shell (display);
       shell.setLayout (new FillLayout ());
        
       TrendView view = new TrendView (shell, SWT.NONE);
        
        shell.open ();
       while (!shell.isDisposed ()) {
     if (!display.readAndDispatch ()) {
        display.sleep ();
     }
       }
           
       display.dispose();
    }
    */
}