org.jajuk.ui.views.StatView.java Source code

Java tutorial

Introduction

Here is the source code for org.jajuk.ui.views.StatView.java

Source

/*
 *  Jajuk
 *  Copyright (C) The Jajuk Team
 *  http://jajuk.info
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or any later version.
 *
 *  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *  
 */
package org.jajuk.ui.views;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.swing.SwingUtilities;

import net.miginfocom.swing.MigLayout;

import org.jajuk.base.Device;
import org.jajuk.base.DeviceManager;
import org.jajuk.base.File;
import org.jajuk.base.FileManager;
import org.jajuk.base.Genre;
import org.jajuk.base.GenreManager;
import org.jajuk.base.Track;
import org.jajuk.base.TrackManager;
import org.jajuk.events.JajukEvent;
import org.jajuk.events.JajukEvents;
import org.jajuk.events.ObservationManager;
import org.jajuk.util.Conf;
import org.jajuk.util.Messages;
import org.jajuk.util.ReadOnlyIterator;
import org.jajuk.util.UtilGUI;
import org.jajuk.util.UtilString;
import org.jajuk.util.log.Log;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryAxis3D;
import org.jfree.chart.axis.CategoryLabelPosition;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.CategoryLabelWidthType;
import org.jfree.chart.axis.NumberAxis3D;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer3D;
import org.jfree.chart.urls.StandardCategoryURLGenerator;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.text.TextBlockAnchor;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.TextAnchor;
import org.jfree.util.SortOrder;

/**
 * Statistics view
 * <p>
 * Help perspective.
 */
public class StatView extends ViewAdapter {
    /** Generated serialVersionUID. */
    private static final long serialVersionUID = 1L;

    /*
     * (non-Javadoc)
     * 
     * @see org.jajuk.ui.IView#display()
     */
    @Override
    public void initUI() {
        setLayout(new MigLayout("ins 0,gapx 4,gapy 5", "[grow][grow]", "[grow][grow]"));
        ObservationManager.register(this);
        update(new JajukEvent(JajukEvents.DEVICE_REFRESH));
    }

    /* (non-Javadoc)
     * @see org.jajuk.events.Observer#getRegistrationKeys()
     */
    @Override
    public Set<JajukEvents> getRegistrationKeys() {
        Set<JajukEvents> eventSubjectSet = new HashSet<JajukEvents>();
        eventSubjectSet.add(JajukEvents.DEVICE_DELETE);
        eventSubjectSet.add(JajukEvents.DEVICE_REFRESH);
        return eventSubjectSet;
    }

    /**
     * Genre repartition pie.
     * 
     * @return the chart
     */
    private ChartPanel createGenreRepartition() {
        try {
            DefaultPieDataset pdata = null;
            JFreeChart jfchart = null;
            // data
            pdata = new DefaultPieDataset();
            int iTotal = TrackManager.getInstance().getElementCount();
            double dOthers = 0;
            // Prepare a map genre -> nb tracks
            Map<Genre, Integer> genreNbTracks = new HashMap<Genre, Integer>(
                    GenreManager.getInstance().getElementCount());
            ReadOnlyIterator<Track> it = TrackManager.getInstance().getTracksIterator();
            while (it.hasNext()) {
                Track track = it.next();
                Genre genre = track.getGenre();
                Integer nbTracks = genreNbTracks.get(genre);
                if (nbTracks == null) {
                    genreNbTracks.put(genre, 1);
                } else {
                    genreNbTracks.put(genre, nbTracks + 1);
                }
            }
            // Cleanup genre with weight < 5 %
            for (Map.Entry<Genre, Integer> entry : genreNbTracks.entrySet()) {
                double d = entry.getValue();
                if (iTotal > 0 && d / iTotal < Conf.getFloat(CONF_STATS_MIN_VALUE_GENRE_DISPLAY) / 100) {
                    // less than 5% -> go to others
                    dOthers += d;
                } else {
                    double dValue = Math.round(100 * (d / iTotal));
                    pdata.setValue(entry.getKey().getName2(), dValue);
                }
            }
            if (iTotal > 0 && dOthers > 0) {
                double dValue = Math.round(100 * (dOthers / iTotal));
                pdata.setValue(Messages.getString("StatView.0"), dValue);
            }
            // chart
            jfchart = ChartFactory.createPieChart3D(Messages.getString("StatView.1"), pdata, true, true, true);
            // set the background color for the chart...
            PiePlot plot = (PiePlot) jfchart.getPlot();
            plot.setLabelFont(PiePlot.DEFAULT_LABEL_FONT);
            plot.setNoDataMessage(Messages.getString("StatView.2"));
            plot.setForegroundAlpha(0.5f);
            plot.setBackgroundAlpha(0.5f);
            plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} = {2}"));
            plot.setToolTipGenerator(new StandardPieToolTipGenerator("{0} = {2}"));
            return new ChartPanel(jfchart);
        } catch (RuntimeException e) {
            Log.error(e);
            return null;
        }
    }

    /**
     * Device size pie.
     * 
     * @return the chart
     */
    private ChartPanel createDeviceRepartition() {
        try {
            DefaultPieDataset pdata = null;
            JFreeChart jfchart = null;
            // data
            pdata = new DefaultPieDataset();
            // prepare devices
            long lTotalSize = 0;
            double dOthers = 0;
            List<Device> devices = DeviceManager.getInstance().getDevices();
            long[] lSizes = new long[DeviceManager.getInstance().getElementCount()];
            ReadOnlyIterator<File> it = FileManager.getInstance().getFilesIterator();
            while (it.hasNext()) {
                File file = it.next();
                lTotalSize += file.getSize();
                lSizes[devices.indexOf(file.getDirectory().getDevice())] += file.getSize();
            }
            for (Device device : devices) {
                long lSize = lSizes[devices.indexOf(device)];
                if (lTotalSize > 0 && (double) lSize / lTotalSize < 0.05) {
                    // less than 5% -> go to others
                    dOthers += lSize;
                } else {
                    double dValue = Math.round((double) lSize / 1073741824);
                    pdata.setValue(device.getName(), dValue);
                }
            }
            if (dOthers > 0) {
                double dValue = Math.round((dOthers / 1073741824));
                pdata.setValue(Messages.getString("StatView.3"), dValue);
            }
            // chart
            jfchart = ChartFactory.createPieChart3D(Messages.getString("StatView.4"), pdata, true, true, true);
            // set the background color for the chart...
            PiePlot plot = (PiePlot) jfchart.getPlot();
            plot.setLabelFont(PiePlot.DEFAULT_LABEL_FONT);
            plot.setNoDataMessage(Messages.getString("StatView.5"));
            plot.setForegroundAlpha(0.5f);
            plot.setBackgroundAlpha(0.5f);
            plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} = {1} GB ({2})"));
            plot.setToolTipGenerator(new StandardPieToolTipGenerator("{0} = {1} GB ({2})"));
            return new ChartPanel(jfchart);
        } catch (RuntimeException e) {
            Log.error(e);
            return null;
        }
    }

    /**
     * Collection size bars.
     * 
     * @return the chart
     */
    private ChartPanel createCollectionSize() {
        try {
            final DateFormat additionFormatter = UtilString.getAdditionDateFormatter();
            CategoryDataset cdata = null;
            JFreeChart jfchart = null;
            int iMonthsNumber = 5; // number of mounts we show, mounts
            // before are set together in 'before'
            long lSizeByMonth[] = new long[iMonthsNumber + 1];
            // contains size ( in Go ) for each month, first cell is before
            // data
            int[] iMonths = getMonths(iMonthsNumber);
            ReadOnlyIterator<Track> tracks = TrackManager.getInstance().getTracksIterator();
            while (tracks.hasNext()) {
                Track track = tracks.next();
                int i = Integer.parseInt(additionFormatter.format(track.getDiscoveryDate())) / 100;
                for (int j = 0; j < iMonthsNumber + 1; j++) {
                    if (i <= iMonths[j]) {
                        lSizeByMonth[j] += track.getTotalSize();
                    }
                }
            }
            double[][] data = new double[1][iMonthsNumber + 1];
            for (int i = 0; i < iMonthsNumber + 1; i++) {
                data[0][i] = (double) lSizeByMonth[i] / 1073741824;
            }
            cdata = DatasetUtilities.createCategoryDataset(new String[] { "" }, getMonthsLabels(iMonthsNumber),
                    data);
            // chart, use local copy of method to use better format string for
            // tooltips
            jfchart = createBarChart3D(Messages.getString("StatView.7"), // chart
                    // title
                    Messages.getString("StatView.8"), // domain axis label
                    Messages.getString("StatView.9"), // range axis label
                    cdata, // data
                    PlotOrientation.VERTICAL, // orientation
                    false, // include legend
                    true, // tooltips
                    false, // urls
                    "{1} = {2} GB");
            CategoryPlot plot = jfchart.getCategoryPlot();
            CategoryAxis axis = plot.getDomainAxis();
            new CategoryLabelPosition(RectangleAnchor.TOP, TextBlockAnchor.TOP_RIGHT, TextAnchor.TOP_RIGHT,
                    -Math.PI / 8.0, CategoryLabelWidthType.CATEGORY, 0);
            axis.setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
            // set the background color for the chart...
            plot.setNoDataMessage(Messages.getString("StatView.10"));
            plot.setForegroundAlpha(0.5f);
            plot.setBackgroundAlpha(0.5f);
            // plot.setBackgroundImage(IconLoader.IMAGES_STAT_PAPER).getImage());
            return new ChartPanel(jfchart);
        } catch (Exception e) {
            Log.error(e);
            return null;
        }
    }

    // copied method from ChartFactory to overwrite format of tooltips which is
    // otherwise hardcoded in ChartFactory
    /**
     * Creates the bar chart3 d.
     * 
     * 
     * @param title 
     * @param categoryAxisLabel 
     * @param valueAxisLabel 
     * @param dataset 
     * @param orientation 
     * @param legend 
     * @param tooltips 
     * @param urls 
     * @param format 
     * 
     * @return the j free chart
     */
    public static JFreeChart createBarChart3D(String title, String categoryAxisLabel, String valueAxisLabel,
            CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls,
            String format) {
        if (orientation == null)
            throw new IllegalArgumentException("Null 'orientation' argument.");
        CategoryAxis categoryAxis = new CategoryAxis3D(categoryAxisLabel);
        ValueAxis valueAxis = new NumberAxis3D(valueAxisLabel);
        BarRenderer3D renderer = new BarRenderer3D();
        if (tooltips)
            renderer.setBaseToolTipGenerator(
                    new StandardCategoryToolTipGenerator(format, NumberFormat.getInstance()));
        if (urls)
            renderer.setBaseItemURLGenerator(new StandardCategoryURLGenerator());
        CategoryPlot plot = new CategoryPlot(dataset, categoryAxis, valueAxis, renderer);
        plot.setOrientation(orientation);
        if (orientation == PlotOrientation.HORIZONTAL) {
            plot.setRowRenderingOrder(SortOrder.DESCENDING);
            plot.setColumnRenderingOrder(SortOrder.DESCENDING);
        }
        plot.setForegroundAlpha(0.75F);
        JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, legend);
        ChartFactory.getChartTheme().apply(chart);
        return chart;
    }

    /**
     * Track number bars.
     * 
     * @return the chart
     */
    private ChartPanel createTrackNumber() {
        try {
            final DateFormat additionFormatter = UtilString.getAdditionDateFormatter();
            CategoryDataset cdata = null;
            JFreeChart jfchart = null;
            // number of months we show, mounts
            // before are set together in 'before'
            int iMonthsNumber = 5;
            // contains number of tracks for each month, first cell is 'before'
            // data
            int iTracksByMonth[] = new int[iMonthsNumber + 1];
            int[] iMounts = getMonths(iMonthsNumber);
            ReadOnlyIterator<Track> tracks = TrackManager.getInstance().getTracksIterator();
            while (tracks.hasNext()) {
                Track track = tracks.next();
                int i = Integer.parseInt(additionFormatter.format(track.getDiscoveryDate())) / 100;
                for (int j = 0; j < iMonthsNumber + 1; j++) {
                    if (i <= iMounts[j]) {
                        iTracksByMonth[j]++;
                    }
                }
            }
            double[][] data = new double[1][iMonthsNumber + 1];
            // cannot use System.arraycopy() here because we have different types in
            // the arrays...
            // System.arraycopy(iTracksByMonth, 0, data[0], 0, iMonthsNumber);
            for (int i = 0; i < iMonthsNumber + 1; i++) {
                data[0][i] = iTracksByMonth[i];
            }
            cdata = DatasetUtilities.createCategoryDataset(new String[] { "" }, getMonthsLabels(iMonthsNumber),
                    data);
            // chart, use local copy of method to use better format string for
            // tooltips
            jfchart = createBarChart3D(Messages.getString("StatView.12"), // chart
                    // title
                    Messages.getString("StatView.13"), // domain axis label
                    Messages.getString("StatView.14"), // range axis label
                    cdata, // data
                    PlotOrientation.VERTICAL, // orientation
                    false, // include legend
                    true, // tooltips
                    false, // urls
                    "{1} = {2}");
            CategoryPlot plot = jfchart.getCategoryPlot();
            CategoryAxis axis = plot.getDomainAxis();
            new CategoryLabelPosition(RectangleAnchor.TOP, TextBlockAnchor.TOP_RIGHT, TextAnchor.TOP_RIGHT,
                    -Math.PI / 8.0, CategoryLabelWidthType.CATEGORY, 0);
            axis.setCategoryLabelPositions(CategoryLabelPositions.STANDARD);
            // set the background color for the chart...
            plot.setNoDataMessage(Messages.getString("StatView.15"));
            plot.setForegroundAlpha(0.5f);
            plot.setBackgroundAlpha(0.5f);
            // plot.setBackgroundImage(IconLoader.IMAGES_STAT_PAPER).getImage());
            return new ChartPanel(jfchart);
        } catch (Exception e) {
            Log.error(e);
            return null;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.jajuk.ui.IView#getDesc()
     */
    @Override
    public String getDesc() {
        return Messages.getString("StatView.16");
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.jajuk.ui.Observer#update(java.lang.String)
     */
    @Override
    public void update(JajukEvent event) {
        JajukEvents subject = event.getSubject();
        if (JajukEvents.DEVICE_REFRESH.equals(subject) || JajukEvents.DEVICE_DELETE.equals(subject)) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UtilGUI.waiting();
                        if (getComponentCount() > 0) {
                            removeAll();
                        }
                        ChartPanel cp1 = createGenreRepartition();
                        if (cp1 != null) {
                            add(cp1);
                        }
                        ChartPanel cp2 = createCollectionSize();
                        if (cp2 != null) {
                            add(cp2, "wrap");
                        }
                        ChartPanel cp3 = createTrackNumber();
                        if (cp3 != null) {
                            add(cp3);
                        }
                        ChartPanel cp4 = createDeviceRepartition();
                        if (cp4 != null) {
                            add(cp4, "wrap");
                        }
                        revalidate();
                        repaint();
                    } finally {
                        UtilGUI.stopWaiting();
                    }
                }
            });
        }
    }

    /**
     * Computes mounts labels.
     * 
     * @param iMonthsNumber : number of mounts ( without 'before' ) you want
     * 
     * @return the mounts labels
     */
    private String[] getMonthsLabels(int iMonthsNumber) {
        int iNow = Integer.parseInt(new SimpleDateFormat(DATE_FILE, Locale.getDefault()).format(new Date())) / 100; // reference
        // month
        String sMonths[] = new String[iMonthsNumber + 1];
        // contains number of tracks for each month, first cell is 'before'
        int iYear = iNow / 100;
        int iMonth = Integer.parseInt(Integer.toString(iNow).substring(4, 6));
        for (int k = 0; k < iMonthsNumber; k++) {
            sMonths[iMonthsNumber - k] = new StringBuilder().append((iMonth / 10 == 0) ? "0" : "")
                    .append(Integer.toString(iMonth)).append('/').append(Integer.toString(iYear)).toString();
            iMonth--;
            if (iMonth == 0) {
                iMonth = 12;
                iYear--;
            }
        }
        sMonths[0] = Messages.getString("StatView.24");
        return sMonths;
    }

    /**
     * Get months as integers.
     * 
     * @param iMonthsNumber 
     * 
     * @return the months
     */
    private int[] getMonths(int iMonthsNumber) {
        int[] iMonths = new int[iMonthsNumber + 1];
        String[] sMonths = getMonthsLabels(iMonthsNumber + 1);
        for (int i = 0; i < iMonthsNumber + 1; i++) {
            iMonths[i] = Integer.parseInt(sMonths[i + 1].substring(3, 7) + sMonths[i + 1].substring(0, 2));
        }
        return iMonths;
    }
}