Package org.eobjects.datacleaner.widgets.result

Source Code of org.eobjects.datacleaner.widgets.result.DateGapAnalyzerResultSwingRenderer

/**
* eobjects.org DataCleaner
* Copyright (C) 2010 eobjects.org
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.eobjects.datacleaner.widgets.result;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.io.File;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollBar;
import javax.swing.JSplitPane;
import javax.swing.border.EmptyBorder;

import org.eobjects.analyzer.beans.DateGapAnalyzer;
import org.eobjects.analyzer.beans.api.RendererBean;
import org.eobjects.analyzer.beans.convert.ConvertToStringTransformer;
import org.eobjects.analyzer.configuration.AnalyzerBeansConfiguration;
import org.eobjects.analyzer.configuration.JaxbConfigurationReader;
import org.eobjects.analyzer.connection.DataContextProvider;
import org.eobjects.analyzer.connection.Datastore;
import org.eobjects.analyzer.data.InputColumn;
import org.eobjects.analyzer.data.MutableInputColumn;
import org.eobjects.analyzer.job.builder.AnalysisJobBuilder;
import org.eobjects.analyzer.job.runner.AnalysisResultFuture;
import org.eobjects.analyzer.job.runner.AnalysisRunner;
import org.eobjects.analyzer.job.runner.AnalysisRunnerImpl;
import org.eobjects.analyzer.result.AnalyzerResult;
import org.eobjects.analyzer.result.DateGapAnalyzerResult;
import org.eobjects.analyzer.result.renderer.AbstractRenderer;
import org.eobjects.analyzer.result.renderer.RendererFactory;
import org.eobjects.analyzer.result.renderer.SwingRenderingFormat;
import org.eobjects.analyzer.util.TimeInterval;
import org.eobjects.datacleaner.bootstrap.DCWindowContext;
import org.eobjects.datacleaner.panels.DCPanel;
import org.eobjects.datacleaner.user.DataCleanerHome;
import org.eobjects.datacleaner.user.UserPreferences;
import org.eobjects.datacleaner.util.ChartUtils;
import org.eobjects.datacleaner.util.LabelUtils;
import org.eobjects.datacleaner.util.LookAndFeelManager;
import org.eobjects.datacleaner.util.WidgetUtils;
import org.eobjects.datacleaner.windows.DetailsResultWindow;
import org.eobjects.metamodel.schema.Table;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.PlotEntity;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.data.gantt.SlidingGanttCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.data.time.SimpleTimePeriod;
import org.jfree.data.time.TimePeriod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RendererBean(SwingRenderingFormat.class)
public class DateGapAnalyzerResultSwingRenderer extends AbstractRenderer<DateGapAnalyzerResult, JComponent> {

  private static final Logger logger = LoggerFactory.getLogger(DateGapAnalyzerResultSwingRenderer.class);

  private static final String LABEL_OVERLAPS = "Overlaps";
  private static final String LABEL_GAPS = "Gaps";
  private static final String LABEL_COMPLETE_DURATION = "Complete duration";
  private static final int GROUPS_VISIBLE = 6;

  @Override
  public JComponent render(DateGapAnalyzerResult result) {

    final TaskSeriesCollection dataset = new TaskSeriesCollection();
    final Set<String> groupNames = result.getGroupNames();
    final TaskSeries completeDurationTaskSeries = new TaskSeries(LABEL_COMPLETE_DURATION);
    final TaskSeries gapsTaskSeries = new TaskSeries(LABEL_GAPS);
    final TaskSeries overlapsTaskSeries = new TaskSeries(LABEL_OVERLAPS);
    for (final String groupName : groupNames) {
      final String groupDisplayName;

      if (groupName == null) {
        if (groupNames.size() == 1) {
          groupDisplayName = "All";
        } else {
          groupDisplayName = LabelUtils.NULL_LABEL;
        }
      } else {
        groupDisplayName = groupName;
      }

      final TimeInterval completeDuration = result.getCompleteDuration(groupName);
      final Task completeDurationTask = new Task(groupDisplayName, createTimePeriod(completeDuration.getFrom(),
          completeDuration.getTo()));
      completeDurationTaskSeries.add(completeDurationTask);

      // plot gaps
      {
        final SortedSet<TimeInterval> gaps = result.getGaps(groupName);

        int i = 1;
        Task rootTask = null;
        for (TimeInterval interval : gaps) {
          final TimePeriod timePeriod = createTimePeriod(interval.getFrom(), interval.getTo());

          if (rootTask == null) {
            rootTask = new Task(groupDisplayName, timePeriod);
            gapsTaskSeries.add(rootTask);
          } else {
            Task task = new Task(groupDisplayName + " gap" + i, timePeriod);
            rootTask.addSubtask(task);
          }

          i++;
        }
      }

      // plot overlaps
      {
        final SortedSet<TimeInterval> overlaps = result.getOverlaps(groupName);

        int i = 1;
        Task rootTask = null;
        for (TimeInterval interval : overlaps) {
          final TimePeriod timePeriod = createTimePeriod(interval.getFrom(), interval.getTo());

          if (rootTask == null) {
            rootTask = new Task(groupDisplayName, timePeriod);
            overlapsTaskSeries.add(rootTask);
          } else {
            Task task = new Task(groupDisplayName + " overlap" + i, timePeriod);
            rootTask.addSubtask(task);
          }

          i++;
        }
      }
    }
    dataset.add(overlapsTaskSeries);
    dataset.add(gapsTaskSeries);
    dataset.add(completeDurationTaskSeries);

    final SlidingGanttCategoryDataset slidingDataset = new SlidingGanttCategoryDataset(dataset, 0, GROUPS_VISIBLE);

    final JFreeChart chart = ChartFactory.createGanttChart("Date gaps and overlaps in " + result.getFromColumnName()
        + " / " + result.getToColumnName(), result.getGroupColumnName(), "Time", slidingDataset, true, true, false);
    ChartUtils.applyStyles(chart);

    // make sure the 3 timeline types have correct coloring
    {
      final CategoryPlot plot = (CategoryPlot) chart.getPlot();

      plot.setDrawingSupplier(new DCDrawingSupplier(WidgetUtils.ADDITIONAL_COLOR_GREEN_BRIGHT,
          WidgetUtils.ADDITIONAL_COLOR_RED_BRIGHT, WidgetUtils.BG_COLOR_BLUE_BRIGHT));
    }

    final ChartPanel chartPanel = new ChartPanel(chart);

    chartPanel.addChartMouseListener(new ChartMouseListener() {
      @Override
      public void chartMouseMoved(ChartMouseEvent event) {
        Cursor cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
        ChartEntity entity = event.getEntity();
        if (entity instanceof PlotEntity) {
          cursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
        }
        chartPanel.setCursor(cursor);
      }

      @Override
      public void chartMouseClicked(ChartMouseEvent event) {
        // do nothing
      }
    });

    final int visibleLines = Math.min(GROUPS_VISIBLE, groupNames.size());

    chartPanel.setPreferredSize(new Dimension(0, visibleLines * 50 + 200));

    final JComponent decoratedChartPanel;

    StringBuilder chartDescription = new StringBuilder();
    chartDescription.append("<html><p>The chart displays the recorded timeline based on FROM and TO dates.<br/><br/>");
    chartDescription
        .append("The <b>red items</b> represent gaps in the timeline and the <b>green items</b> represent points in the timeline where more than one record show activity.<br/><br/>");
    chartDescription
        .append("You can <b>zoom in</b> by clicking and dragging the area that you want to examine in further detail.");

    if (groupNames.size() > GROUPS_VISIBLE) {
      final JScrollBar scroll = new JScrollBar(JScrollBar.VERTICAL);
      scroll.setMinimum(0);
      scroll.setMaximum(groupNames.size());
      scroll.addAdjustmentListener(new AdjustmentListener() {

        @Override
        public void adjustmentValueChanged(AdjustmentEvent e) {
          int value = e.getAdjustable().getValue();
          slidingDataset.setFirstCategoryIndex(value);
        }
      });

      chartPanel.addMouseWheelListener(new MouseWheelListener() {

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
          int scrollType = e.getScrollType();
          if (scrollType == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
            int wheelRotation = e.getWheelRotation();
            scroll.setValue(scroll.getValue() + wheelRotation);
          }
        }
      });

      final DCPanel outerPanel = new DCPanel();
      outerPanel.setLayout(new BorderLayout());
      outerPanel.add(chartPanel, BorderLayout.CENTER);
      outerPanel.add(scroll, BorderLayout.EAST);
      chartDescription.append("<br/><br/>Use the right <b>scrollbar</b> to scroll up and down on the chart.");
      decoratedChartPanel = outerPanel;

    } else {
      decoratedChartPanel = chartPanel;
    }

    chartDescription.append("</p></html>");

    final JLabel chartDescriptionLabel = new JLabel(chartDescription.toString());

    chartDescriptionLabel.setBorder(new EmptyBorder(4, 10, 4, 10));

    final JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
    split.add(decoratedChartPanel);
    split.add(chartDescriptionLabel);
    split.setDividerLocation(550);

    return split;
  }

  private TimePeriod createTimePeriod(long from, long to) {
    if (from > to) {
      logger.warn("An illegal from/to combination occurred: {}, {}", from, to);
    }
    return new SimpleTimePeriod(from, to);
  }

  /**
   * A main method that will display the results of a few example value
   * distributions. Useful for tweaking the charts and UI.
   *
   * @param args
   * @throws Throwable
   */
  public static void main(String[] args) throws Throwable {
    LookAndFeelManager.getInstance().init();

    // run a small job
    AnalyzerBeansConfiguration conf = new JaxbConfigurationReader().create(new File(DataCleanerHome.get(), "conf.xml"));
    AnalysisRunner runner = new AnalysisRunnerImpl(conf);
    AnalysisJobBuilder ajb = new AnalysisJobBuilder(conf);

    Datastore ds = conf.getDatastoreCatalog().getDatastore("orderdb");
    ajb.setDatastore(ds);

    DataContextProvider dcp = ds.getDataContextProvider();
    Table table = dcp.getSchemaNavigator().convertToTable("PUBLIC.ORDERS");

    ajb.addSourceColumn(table.getColumnByName("ORDERDATE"));
    ajb.addSourceColumn(table.getColumnByName("SHIPPEDDATE"));
    ajb.addSourceColumn(table.getColumnByName("CUSTOMERNUMBER"));

    @SuppressWarnings("unchecked")
    InputColumn<Date> orderDateColumn = (InputColumn<Date>) ajb.getSourceColumnByName("ORDERDATE");
    @SuppressWarnings("unchecked")
    InputColumn<Date> shippedDateColumn = (InputColumn<Date>) ajb.getSourceColumnByName("SHIPPEDDATE");
    @SuppressWarnings("unchecked")
    InputColumn<Integer> customerNumberColumn = (InputColumn<Integer>) ajb.getSourceColumnByName("CUSTOMERNUMBER");
    @SuppressWarnings("unchecked")
    MutableInputColumn<String> customerNumberAsStringColumn = (MutableInputColumn<String>) ajb
        .addTransformer(ConvertToStringTransformer.class).addInputColumn(customerNumberColumn).getOutputColumns()
        .get(0);

    DateGapAnalyzer dga = ajb.addRowProcessingAnalyzer(DateGapAnalyzer.class).getConfigurableBean();
    dga.setFromColumn(orderDateColumn);
    dga.setToColumn(shippedDateColumn);
    dga.setGroupColumn(customerNumberAsStringColumn);

    AnalysisResultFuture resultFuture = runner.run(ajb.toAnalysisJob());

    if (resultFuture.isErrornous()) {
      throw resultFuture.getErrors().get(0);
    }

    List<AnalyzerResult> list = Collections.emptyList();
    RendererFactory rendererFactory = new RendererFactory(conf.getDescriptorProvider(), null);
    DetailsResultWindow window = new DetailsResultWindow("Example", list, new DCWindowContext(conf,
        UserPreferences.getInstance()), rendererFactory);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    List<AnalyzerResult> results = resultFuture.getResults();
    for (AnalyzerResult analyzerResult : results) {
      JComponent renderedResult = new DateGapAnalyzerResultSwingRenderer()
          .render((DateGapAnalyzerResult) analyzerResult);
      window.addRenderedResult(renderedResult);
    }
    window.repaint();

    window.setPreferredSize(new Dimension(800, 600));

    window.setVisible(true);
  }
}
TOP

Related Classes of org.eobjects.datacleaner.widgets.result.DateGapAnalyzerResultSwingRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.