package org.geogebra.web.web.gui.view.data;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.gui.SetLabels;
import org.geogebra.common.gui.view.data.DataAnalysisModel;
import org.geogebra.common.gui.view.data.DataAnalysisModel.IDataAnalysisListener;
import org.geogebra.common.gui.view.data.DataDisplayModel;
import org.geogebra.common.gui.view.data.DataDisplayModel.PlotType;
import org.geogebra.common.gui.view.data.DataSource;
import org.geogebra.common.gui.view.data.DataVariable.GroupType;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.ModeSetter;
import org.geogebra.common.kernel.View;
import org.geogebra.common.kernel.geos.GProperty;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Feature;
import org.geogebra.common.main.GeoGebraColorConstants;
import org.geogebra.common.util.debug.Log;
import org.geogebra.web.html5.awt.PrintableW;
import org.geogebra.web.html5.main.AppW;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ProvidesResize;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
public class DataAnalysisViewW extends FlowPanel implements View,
ProvidesResize, RequiresResize, SetLabels, IDataAnalysisListener,
PrintableW {
// ggb
private AppW app;
private Kernel kernel;
private DataAnalysisModel model;
protected DataAnalysisControllerW daCtrl;
private DataAnalysisStyleBarW stylebar;
// colors
public static final GColor TABLE_GRID_COLOR = GeoGebraColorConstants.TABLE_GRID_COLOR;
public static final GColor TABLE_HEADER_COLOR = GColor.newColor(240, 240,
240);
public static final GColor HISTOGRAM_COLOR = GColor.BLUE;
public static final GColor BOXPLOT_COLOR = GeoGebraColorConstants.GGB_RED;
public static final GColor BARCHART_COLOR = GeoGebraColorConstants.GGB_GREEN;
public static final GColor DOTPLOT_COLOR = GeoGebraColorConstants.GRAY5;
public static final GColor NQPLOT_COLOR = GeoGebraColorConstants.GRAY5;
public static final GColor REGRESSION_COLOR = GColor.RED;
public static final GColor OVERLAY_COLOR = GeoGebraColorConstants.DARKBLUE;
private GColor[] colors = { TABLE_GRID_COLOR, TABLE_HEADER_COLOR,
HISTOGRAM_COLOR, BOXPLOT_COLOR, BARCHART_COLOR, DOTPLOT_COLOR,
NQPLOT_COLOR, REGRESSION_COLOR, OVERLAY_COLOR, GColor.BLACK,
GColor.WHITE };
// main GUI panels
private DataPanelW dataPanel;
private StatisticsPanelW statisticsPanel;
private RegressionPanelW regressionPanel;
private DataDisplayPanelW dataDisplayPanel1, dataDisplayPanel2;
private SplitLayoutPanel comboPanelSplit, mainSplit;
/**
* For calling the onResize method in a deferred way
*/
Scheduler.ScheduledCommand deferredOnRes = new Scheduler.ScheduledCommand() {
@Override
public void execute() {
onResize();
}
};
Scheduler.ScheduledCommand deferredDataPanelOnRes = new Scheduler.ScheduledCommand() {
@Override
public void execute() {
if (model.isMultiVar() && model.showStatPanel()) {
Log.debug("Showing MultiVar stat panel");
dataDisplayPanel1.resize(getOffsetWidth(), getOffsetHeight() - statisticsPanel.getOffsetHeight(), true);
} else {
dataDisplayPanel1.onResize();
dataDisplayPanel2.onResize();
}
if (model.showDataPanel()) {
dataPanel.onResize();
}
}
};
private DataSource dataSource;
/*************************************************
* Constructs the view.
*
* @param app
* @param mode
*/
public DataAnalysisViewW(AppW app, int mode) {
this.app = app;
this.kernel = app.getKernel();
daCtrl = new DataAnalysisControllerW(app, this);
model = new DataAnalysisModel(app, this, daCtrl);
dataSource = new DataSource(app);
daCtrl.loadDataLists(true);
setView(dataSource, mode, true);
model.setIniting(false);
}
/*************************************************
* END constructor
*/
public void changeMode(int mode) {
model = new DataAnalysisModel(app, this, daCtrl);
setView(dataSource, mode, true);
}
protected void setView(DataSource dataSource, int mode,
boolean forceModeUpdate) {
if (app.has(Feature.ONE_VAR_FREQUENCY_TABLE)) {
dataSource.setFrequencyFromColumn(true);
}
dataSource.setDataListFromSelection(mode);
dataDisplayPanel1 = new DataDisplayPanelW(this);
dataDisplayPanel2 = new DataDisplayPanelW(this);
comboPanelSplit = new SplitLayoutPanel();
comboPanelSplit.setStyleName("comboSplitLayout");
comboPanelSplit.add(dataDisplayPanel1);
mainSplit = new SplitLayoutPanel();
mainSplit.add(comboPanelSplit);
mainSplit.setWidgetMinSize(comboPanelSplit, 500);
mainSplit.setStyleName("daMainSplit");
add(mainSplit);
model.setView(dataSource, mode, forceModeUpdate);
// updateFonts();
setLabels();
updateGUI();
}
public Widget getStyleBar() {
if (stylebar == null) {
stylebar = new DataAnalysisStyleBarW(app, this);
}
return stylebar;
}
private void buildStatisticsPanel() {
if (statisticsPanel != null) {
// TODO handle any orphaned geo children of stat panel
statisticsPanel = null;
}
statisticsPanel = new StatisticsPanelW(app, this);
}
@Override
public void setPlotPanelOVNotNumeric(int mode) {
dataDisplayPanel1.setPanel(PlotType.BARCHART, mode);
dataDisplayPanel2.setPanel(PlotType.BARCHART, mode);
}
@Override
public void setPlotPanelOVRawData(int mode) {
dataDisplayPanel1.setPanel(PlotType.HISTOGRAM, mode);
dataDisplayPanel2.setPanel(PlotType.BOXPLOT, mode);
}
@Override
public void setPlotPanelOVFrequency(int mode) {
dataDisplayPanel1.setPanel(PlotType.BARCHART, mode);
dataDisplayPanel2.setPanel(PlotType.BOXPLOT, mode);
}
@Override
public void setPlotPanelOVClass(int mode) {
dataDisplayPanel1.setPanel(PlotType.HISTOGRAM, mode);
dataDisplayPanel2.setPanel(PlotType.HISTOGRAM, mode);
}
@Override
public void setPlotPanelRegression(int mode) {
dataDisplayPanel1.setPanel(PlotType.SCATTERPLOT, mode);
dataDisplayPanel2.setPanel(PlotType.RESIDUAL, mode);
}
@Override
public void setPlotPanelMultiVar(int mode) {
dataDisplayPanel1.setPanel(PlotType.MULTIBOXPLOT, mode);
}
/**
* set the data plot panels with default plots
*/
public void setDataPlotPanels() {
model.setDataPlotPanels();
}
// Create DataPanel to display the current data set(s) and allow
// temporary editing.
protected DataPanelW buildDataPanel() {
if (dataPanel != null) {
// TODO handle any orphaned data panel geos
dataPanel = null;
}
if (!model.isMultiVar()) {
dataPanel = new DataPanelW(app, this);
}
return dataPanel;
}
@Override
public void loadDataTable(ArrayList<GeoElement> dataArray) {
if (dataPanel == null) {
buildDataPanel();
}
// TODO: Implement!
// dataPanel.loadDataTable(dataArray);
}
protected DataPanelW getDataPanel() {
return dataPanel;
}
// =================================================
// GUI
// =================================================
private void updateLayout() {
clear();
int regressiodIdx = model.isRegressionMode() &&
regressionPanel != null ? regressionPanel.getRegressionIdx() :- 1;
mainSplit.clear();
boolean stat = model.showStatPanel();
boolean data = model.showDataPanel();
if (data && dataPanel == null) {
buildDataPanel();
}
if (model.isMultiVar()) {
comboPanelSplit.clear();
if (stat) {
// set the size of
comboPanelSplit.addSouth(statisticsPanel,
statisticsPanel
.estimateHeight(model.getDataTitles().length));
comboPanelSplit.add(dataDisplayPanel1);
} else {
comboPanelSplit.add(dataDisplayPanel1);
}
mainSplit.add(comboPanelSplit);
} else {
if (stat && data) {
mainSplit.addWest(statisticsPanel, 300);
mainSplit.addEast(comboPanelSplit, 300);
mainSplit.add(dataPanel);
} else
if (stat && !data) {
mainSplit.addWest(statisticsPanel, 300);
mainSplit.add(comboPanelSplit);
} else
if (!stat && data) {
mainSplit.addWest(dataPanel, 300);
mainSplit.add(comboPanelSplit);
} else {
mainSplit.add(comboPanelSplit);
}
mainSplit.setWidgetMinSize(comboPanelSplit, 500);
// ===========================================
// regression panel
}
add(mainSplit);
if (model.isRegressionMode()) {
regressionPanel = new RegressionPanelW(app, this);
add(regressionPanel);
if (regressiodIdx != -1) {
regressionPanel.setRegressionIdx(regressiodIdx);
}
mainSplit.setHeight("80%");
} else {
mainSplit.setHeight("100%");
}
deferredDataPanelOnResize();
}
// ======================================
// Getters/setters
// ======================================
public DataAnalysisControllerW getDaCtrl() {
return daCtrl;
}
public DataSource getDataSource() {
return model.getDataSource();
}
public GroupType groupType() {
return daCtrl.getDataSource().getGroupType();
}
public DataDisplayPanelW getDataDisplayPanel1() {
return dataDisplayPanel1;
}
public DataDisplayPanelW getDataDisplayPanel2() {
return dataDisplayPanel2;
}
public RegressionPanelW getRegressionPanel() {
return regressionPanel;
}
public StatisticsPanelW getStatisticsPanel() {
return statisticsPanel;
}
/**
* Component representation of this view
*
* @return reference to self
*/
public Widget getDataAnalysisViewComponent() {
return this;
// return statisticsPanel;
}
@Override
public DataAnalysisControllerW getController() {
return daCtrl;
}
public GeoElement getRegressionModel() {
return daCtrl.getRegressionModel();
}
public AppW getApp() {
return app;
}
// public int getMode() {
// return mode;
// }
// =================================================
// Handlers for Component Visibility
// =================================================
@Override
public void updateStatDataPanelVisibility() {
updateLayout();
}
public void doPrint() {
// List<Printable> l = new ArrayList<Printable>();
// l.add(this);
// PrintPreview.get(app, App.VIEW_DATA_ANALYSIS, PageFormat.LANDSCAPE)
// .setVisible(true);
}
// =================================================
// Event Handlers and Updates
// =================================================
@Override
public void updateGUI() {
if (stylebar != null) {
stylebar.updateGUI();
}
deferredOnResize();
}
@Override
public void setLabels() {
if (model.isIniting()) {
return;
}
if (model.isRegressionMode() && regressionPanel != null) {
regressionPanel.setLabels();
}
if (stylebar != null) {
stylebar.setLabels();
}
}
// =================================================
// Number Format
//
// (use GeoGebra rounding settings unless decimals < 4)
// =================================================
// =================================================
// View Implementation
// =================================================
@Override
public void remove(GeoElement geo) {
model.remove(geo);
}
@Override
public void update(GeoElement geo) {
model.update(geo);
}
@Override
final public void updateVisualStyle(GeoElement geo, GProperty prop) {
update(geo);
}
@Override
public void updatePreviewFromInputBar(GeoElement[] geos) {
// TODO
}
@Override
public void add(GeoElement geo) {
// do nothing
}
@Override
public void clearView() {
// do nothing
}
@Override
public void rename(GeoElement geo) {
// do nothing
}
@Override
public void repaintView() {
// do nothing
}
@Override
public void updateAuxiliaryObject(GeoElement geo) {
// do nothing
}
@Override
public void reset() {
// do nothing
}
@Override
public void setMode(int mode, ModeSetter m) {
// do nothing
}
public void attachView() {
model.updateFromSettings();
kernel.attach(this);
// attachView to plot panels
dataDisplayPanel1.attachView();
if (dataDisplayPanel2 != null) {
dataDisplayPanel2.attachView();
}
}
public void detachView() {
dataDisplayPanel1.detachView();
if (dataDisplayPanel2 != null) {
dataDisplayPanel2.detachView();
}
daCtrl.removeStatGeos();
kernel.detach(this);
}
public String[] getDataTitles() {
return daCtrl.getDataTitles();
}
// =================================================
// Printing
// =================================================
// public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
// if (pageIndex > 0)
// return (NO_SUCH_PAGE);
//
// Graphics2D g2d = (Graphics2D) g;
// g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
//
// // construction title
// int y = 0;
// Construction cons = kernel.getConstruction();
// String title = cons.getTitle();
// if (!"".equals(title)) {
// Font titleFont = app.getBoldFont().deriveFont(Font.BOLD,
// app.getBoldFont().getSize() + 2);
// g2d.setFont(titleFont);
// g2d.setColor(Color.black);
// // Font fn = g2d.getFont();
// FontMetrics fm = g2d.getFontMetrics();
// y += fm.getAscent();
// g2d.drawString(title, 0, y);
// }
//
// // construction author and date
// String author = cons.getAuthor();
// String date = cons.getDate();
// String line = null;
// if (!"".equals(author)) {
// line = author;
// }
// if (!"".equals(date)) {
// if (line == null)
// line = date;
// else
// line = line + " - " + date;
// }
//
// if (line != null) {
// g2d.setFont(app.getPlainFont());
// g2d.setColor(Color.black);
// // Font fn = g2d.getFont();
// FontMetrics fm = g2d.getFontMetrics();
// y += fm.getHeight();
// g2d.drawString(line, 0, y);
// }
// if (y > 0) {
// g2d.translate(0, y + 20); // space between title and drawing
// }
//
// // scale the dialog so that it fits on one page.
// double xScale = pageFormat.getImageableWidth() / this.getWidth();
// double yScale = (pageFormat.getImageableHeight() - (y + 20))
// / this.getHeight();
// double scale = Math.min(xScale, yScale);
//
// this.paint(g2d, scale);
//
// return (PAGE_EXISTS);
// }
//
// /**
// * Paint the dialog with given scale factor (used for printing).
// */
// public void paint(Graphics graphics, double scale) {
//
// Graphics2D g2 = (Graphics2D) graphics;
// g2.scale(scale, scale);
// super.paint(graphics);
//
// }
//
@Override
public int getViewID() {
return App.VIEW_DATA_ANALYSIS;
}
@Override
public void startBatchUpdate() {
// TODO Auto-generated method stub
}
@Override
public void endBatchUpdate() {
// TODO Auto-generated method stub
}
@Override
public boolean suggestRepaint() {
return false;
}
@Override
public DataAnalysisModel getModel() {
return model;
}
public void setModel(DataAnalysisModel model) {
this.model = model;
}
@Override
public void onModeChange() {
dataPanel = null;
buildStatisticsPanel();
setDataPlotPanels();
updateLayout();
}
@Override
public void showComboPanel2(boolean show) {
comboPanelSplit.clear();
int w = mainSplit.getOffsetWidth();
int h = mainSplit.getOffsetHeight();
if (show) {
dataDisplayPanel1.resize(w, h/2, true);
dataDisplayPanel1.resize(w, h/2, true);
comboPanelSplit.addNorth(dataDisplayPanel1, h / 2.0);
comboPanelSplit.add(dataDisplayPanel2);
} else {
dataDisplayPanel1.resize(w, h, true);
comboPanelSplit.add(dataDisplayPanel1);
}
updateGUI();
}
public String format(double value) {
return model.format(value);
}
@Override
public GColor createColor(int idx) {
return colors[idx];
}
@Override
public boolean hasFocus() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isShowing() {
return app.showView(App.VIEW_DATA_ANALYSIS);
}
@Override
public void onResize() {
for (Widget w: getChildren()) {
if (w instanceof RequiresResize) {
((RequiresResize)w).onResize();
}
}
}
/**
* For calling the onResize method in a deferred way
*/
public void deferredOnResize() {
Scheduler.get().scheduleDeferred(deferredOnRes);
}
public void deferredDataPanelOnResize() {
Scheduler.get().scheduleDeferred(deferredDataPanelOnRes);
}
public void updateOtherDataDisplay(DataDisplayPanelW display) {
if (!model.showDataDisplayPanel2()) {
return;
}
if (display == dataDisplayPanel1) {
dataDisplayPanel2.update();
} else {
dataDisplayPanel1.update();
}
}
public List<Widget> getPrintable() {
Widget[] printableList = { new Label("Data analysis View") };
return Arrays.asList(printableList);
}
@Override
public void getPrintable(FlowPanel pPanel, Button btPrint) {
// TODO Auto-generated method stub
}
@Override
public DataDisplayModel getDisplayModel(int index) {
return index == 0 ? this.dataDisplayPanel1.getModel()
: this.dataDisplayPanel2.getModel();
}
}