/* AWE - Amanzi Wireless Explorer
* http://awe.amanzi.org
* (C) 2008-2009, AmanziTel AB
*
* This library is provided under the terms of the Eclipse Public License
* as described at http://www.eclipse.org/legal/epl-v10.html. Any use,
* reproduction or distribution of the library constitutes recipient's
* acceptance of this agreement.
*
* This library is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.amanzi.awe.charts.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.amanzi.awe.charts.builder.dataset.dto.ICategoryRow;
import org.amanzi.awe.charts.builder.dataset.dto.IColumn;
import org.amanzi.awe.charts.builder.dataset.dto.ITimeRow;
import org.amanzi.awe.charts.impl.ChartModelPlugin;
import org.amanzi.awe.charts.manger.ChartsManager;
import org.amanzi.awe.charts.model.ChartType;
import org.amanzi.awe.charts.model.IChartDataFilter;
import org.amanzi.awe.charts.model.IChartModel;
import org.amanzi.awe.charts.model.IRangeAxis;
import org.amanzi.awe.charts.model.provider.IChartModelProvider;
import org.amanzi.awe.charts.ui.widget.ItemsSelectorWidget;
import org.amanzi.awe.charts.ui.widget.ItemsSelectorWidget.ItemSelectedListener;
import org.amanzi.awe.statistics.dto.IStatisticsGroup;
import org.amanzi.awe.statistics.filter.IStatisticsFilter;
import org.amanzi.awe.statistics.model.DimensionType;
import org.amanzi.awe.statistics.model.IStatisticsModel;
import org.amanzi.awe.statistics.ui.filter.impl.StatisticsFilter;
import org.amanzi.awe.ui.manager.AWEEventManager;
import org.amanzi.neo.models.exceptions.ModelException;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.entity.CategoryItemEntity;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.experimental.chart.swt.ChartComposite;
/**
* TODO Purpose of
* <p>
* </p>
*
* @author Vladislav_Kondratenko
* @since 1.0.0
*/
public class ChartsView extends ViewPart implements ItemSelectedListener, ChartMouseListener {
private static final Logger LOGGER = Logger.getLogger(ChartsView.class);
public static final String VIEW_ID = "org.amanzi.awe.views.ChartsView";
private static final String GROUPS_LABEL = "Group(s)";
private static final String CELLS_LABEL = "Column(s)";
private static final String CHART_NAME_FORMAT = "%s, %s";
private Composite controlsComposite;
private ItemsSelectorWidget groupSelectorWidget;
private ItemsSelectorWidget columnsSelectorWidget;
private ChartComposite chartComposite;
private ChartType type = ChartType.TIME_CHART;
private final Map<ChartsCahceId, JFreeChart> chartsCache = new HashMap<ChartsCahceId, JFreeChart>();
private IStatisticsModel model;
private IStatisticsFilter container;
@Override
public void createPartControl(final Composite parent) {
parent.setLayout(new GridLayout(1, false));
controlsComposite = new Composite(parent, SWT.NONE);
controlsComposite.setLayout(new GridLayout(1, false));
controlsComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Composite buttonsContainer = new Composite(controlsComposite, SWT.NONE);
buttonsContainer.setLayout(new GridLayout(4, true));
buttonsContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
createRadioButton(buttonsContainer, "Line", true, ChartType.TIME_CHART);
createRadioButton(buttonsContainer, "Bar", false, ChartType.BAR_CHART);
createRadioButton(buttonsContainer, "Stacked", false, ChartType.STACKED_CHART);
createRadioButton(buttonsContainer, "Pie", false, ChartType.PIE_CHART);
Composite filteringContainer = new Composite(controlsComposite, SWT.BORDER);
filteringContainer.setLayout(new GridLayout(2, true));
filteringContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
groupSelectorWidget = new ItemsSelectorWidget(filteringContainer, this, GROUPS_LABEL);
columnsSelectorWidget = new ItemsSelectorWidget(filteringContainer, this, CELLS_LABEL);
groupSelectorWidget.initializeWidget();
columnsSelectorWidget.initializeWidget();
int width = parent.getShell().getSize().x;
chartComposite = new ChartComposite(parent, SWT.FILL, null, ChartComposite.DEFAULT_WIDTH, ChartComposite.DEFAULT_HEIGHT,
ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH, ChartComposite.DEFAULT_MINIMUM_DRAW_HEIGHT, width,
ChartComposite.DEFAULT_MAXIMUM_DRAW_HEIGHT, true, true, true, true, true, true);
chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
chartComposite.setVisible(false);
chartComposite.addChartMouseListener(this);
}
/**
* @param allStatisticsGroups
* @return
*/
private List<String> getStatisticsGroups(final Iterable<IStatisticsGroup> allStatisticsGroups) {
List<String> groups = new ArrayList<String>();
for (IStatisticsGroup group : allStatisticsGroups) {
groups.add(group.getPropertyValue());
}
return groups;
}
/**
* Creates radio button with the text specified and assigns the layout data
*
* @param parent parent composite
* @param chartType TODO
*/
private Button createRadioButton(final Composite parent, final String text, final boolean selected, final ChartType chartType) {
Button radioButton = new Button(parent, SWT.RADIO);
radioButton.setText(text);
radioButton.setSelection(selected);
GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
radioButton.setLayoutData(layoutData);
radioButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
type = chartType;
onItemSelected();
}
});
return radioButton;
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
@Override
public void onItemSelected() {
if (container == null) {
return;
}
IChartModel chartModel = createChartModel(model, container);
updateChart(chartModel);
}
/**
* @param model
* @param container
*/
public void fireStatisticsChanged(final IStatisticsModel model, final IStatisticsFilter container) {
this.model = model;
this.container = container;
List<String> groups;
try {
groups = getStatisticsGroups(model.getAllStatisticsGroups(DimensionType.TIME, container.getPeriod().getId()));
groupSelectorWidget.setItems(groups);
columnsSelectorWidget.setItems(model.getColumns());
IChartModel chartModel = createChartModel(model, container);
updateChart(chartModel);
} catch (ModelException e) {
LOGGER.error("can't init necessary field with statistics model " + model + " and period" + container);
}
}
/**
* firstly trying to find chart in cache. if not exists - create new one
*
* @param chartModel
*/
private void updateChart(final IChartModel chartModel) {
LOGGER.info("Chart updating begin, for model " + chartModel);
Long startTime = System.currentTimeMillis();
ChartsCahceId ID = new ChartsCahceId(chartModel, container);
JFreeChart chart = chartsCache.get(ID);
if (chart == null) {
chart = ChartsManager.getInstance().buildChart(chartModel);
chartsCache.put(ID, chart);
}
LOGGER.info("Chart updated in : " + (System.currentTimeMillis() - startTime) + " ms");
chartComposite.setChart(chart);
chartComposite.forceRedraw();
chartComposite.setVisible(true);
}
/**
* @param model
* @param container
*/
private IChartModel createChartModel(final IStatisticsModel model, final IStatisticsFilter container) {
IChartModelProvider chartProvider = ChartModelPlugin.getDefault().getChartModelProvider();
IChartDataFilter filter = chartProvider.getChartDataFilter(container.getStartTime(), container.getEndTime(),
groupSelectorWidget.getSelected());
IRangeAxis axis = chartProvider.getRangeAxisContainer("value", columnsSelectorWidget.getSelected());
String chartName = String.format(CHART_NAME_FORMAT, model.getName(), container.getPeriod().getId());
return chartProvider.getChartModel(chartName, "cells", type, model, container.getPeriod(), filter, axis);
}
/**
* <p>
* ID of charts in cache
* </p>
*
* @author Vladislav_Kondratenko
* @since 1.0.0
*/
private static class ChartsCahceId {
private final IChartModel model;
private final IStatisticsFilter container;
/**
* @param model
* @param container
*/
public ChartsCahceId(final IChartModel model, final IStatisticsFilter container) {
super();
this.model = model;
this.container = container;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (container == null ? 0 : container.hashCode());
result = prime * result + (model == null ? 0 : model.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ChartsCahceId other = (ChartsCahceId)obj;
if (container == null) {
if (other.container != null) {
return false;
}
} else if (!container.equals(other.container)) {
return false;
}
if (model == null) {
if (other.model != null) {
return false;
}
} else if (!model.equals(other.model)) {
return false;
}
return true;
}
}
@Override
public void dispose() {
chartsCache.clear();
super.dispose();
}
@Override
public void chartMouseClicked(final ChartMouseEvent event) {
if (event == null) {
return;
}
Collection<String> groups = null;
long startDate = Long.MIN_VALUE;
long endDate = Long.MAX_VALUE;
String cellName = StringUtils.EMPTY;
if (event.getEntity() instanceof CategoryItemEntity) {
CategoryItemEntity entity = (CategoryItemEntity)event.getEntity();
IColumn period = (IColumn)entity.getColumnKey();
ICategoryRow column = period.getItemByName((String)entity.getRowKey());
groups = column.getGroupsNames();
startDate = period.getStartDate();
endDate = period.getEndDate();
cellName = column.getName();
} else if (event.getEntity() instanceof XYItemEntity) {
XYItemEntity entity = (XYItemEntity)event.getEntity();
TimeSeriesCollection dataset = (TimeSeriesCollection)entity.getDataset();
TimeSeries ts = dataset.getSeries(entity.getSeriesIndex());
ITimeRow row = (ITimeRow)ts.getKey();
RegularTimePeriod period = ts.getTimePeriod(entity.getItem());
startDate = period.getStart().getTime();
endDate = container.getPeriod().addPeriod(startDate);
groups = row.getGroupsForTime(startDate);
cellName = row.getName();
} else {
return;
}
AWEEventManager.getManager().fireShowInViewEvent(model,
new StatisticsFilter(container.getPeriod(), startDate, endDate, groups, cellName), this);
}
@Override
public void chartMouseMoved(final ChartMouseEvent arg0) {
// TODO Auto-generated method stub
}
}