package org.geogebra.web.web.gui.view.data; import org.geogebra.common.euclidian.event.KeyEvent; import org.geogebra.common.euclidian.event.KeyHandler; import org.geogebra.common.gui.view.data.DataAnalysisModel; import org.geogebra.common.gui.view.data.DataDisplayModel; import org.geogebra.common.gui.view.data.DataDisplayModel.PlotType; import org.geogebra.common.gui.view.data.DataVariable.GroupType; import org.geogebra.common.gui.view.data.StatPanelSettings; import org.geogebra.common.kernel.arithmetic.NumberValue; import org.geogebra.common.main.Feature; import org.geogebra.common.main.Localization; import org.geogebra.web.html5.gui.inputfield.AutoCompleteTextFieldW; import org.geogebra.web.html5.gui.util.LayoutUtilW; import org.geogebra.web.html5.main.AppW; import org.geogebra.web.web.gui.view.algebra.InputPanelW; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.RadioButton; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.TabPanel; /** * JPanel to display settings options for a ComboStatPanel * * @author G. Sturr * */ public class OptionsPanelW extends FlowPanel implements ClickHandler, BlurHandler, StatPanelInterfaceW { private AppW app; private StatPanelSettings settings; // histogram panel GUI private CheckBox ckCumulative, ckManual, ckOverlayNormal, ckOverlayPolygon, ckShowFrequencyTable, ckShowHistogram; private RadioButton rbRelative, rbNormalized, rbFreq, rbLeftRule, rbRightRule; private Label lblFreqType, lblOverlay, lblClassRule; private FlowPanel freqPanel, showPanel; private Label lbClassTitle, lbFreqTitle, lbShowTitle, lbDimTitle; // graph panel GUI private CheckBox ckAutoWindow, ckShowGrid; private Label lblXMin, lblXMax, lblYMin, lblYMax, lblXInterval, lblYInterval; AutoCompleteTextFieldW fldXMin, fldXMax; private AutoCompleteTextFieldW fldYMin, fldYMax, fldXInterval, fldYInterval; private boolean showYAxisSettings = true; // bar chart panel GUI private Label lblBarWidth; private AutoCompleteTextFieldW fldBarWidth; private CheckBox ckAutoBarWidth; private FlowPanel barChartWidthPanel; // box plot panel GUI private CheckBox ckShowOutliers; // scatterplot panel GUI private CheckBox ckShowLines; // panels private FlowPanel histogramPanel, graphPanel, classesPanel, scatterplotPanel, barChartPanel, boxPlotPanel; private FlowPanel mainPanel; private TabPanel tabPanel; private boolean isUpdating = false; private DataAnalysisModel daModel; private DataDisplayModel dyModel; private ScrollPanel spHistogram; private ScrollPanel spGraph; private ListBox cbLogAxes; private Localization loc; private final static int fieldWidth = 8; private class PropertyChangeHandler implements ClickHandler { @Override public void onClick(ClickEvent event) { actionPerformed(event.getSource()); } } private class PropertyKeyHandler implements KeyHandler { private Object source; public PropertyKeyHandler(Object source) { this.source = source; } @Override public void keyReleased(KeyEvent e) { if (e.isEnterKey()) { actionPerformed(source); } } } /************************************************************ * Constructs an OptionPanel * * @param app * App * @param settings * @param statDialog * statDialog * @param settings * settings */ public OptionsPanelW(AppW app, DataAnalysisModel model, DataDisplayModel dyModel) { this.app = app; this.loc = app.getLocalization(); this.daModel = model; this.dyModel = dyModel; this.settings = dyModel.getSettings(); // create option panels createHistogramPanel(); createGraphPanel(); createScatterplotPanel(); createBarChartPanel(); createBoxPlotPanel(); mainPanel = new FlowPanel(); mainPanel.add(histogramPanel); mainPanel.add(scatterplotPanel); mainPanel.add(barChartPanel); mainPanel.add(boxPlotPanel); tabPanel = new TabPanel(); tabPanel.setStyleName("daOptionsTabPanel"); add(tabPanel); // update setLabels(); updateGUI(); } public void setPanel(PlotType plotType) { tabPanel.clear(); this.setVisible(true); // add plot-specific tab String tabTitle = plotType.getTranslatedKey(loc); spHistogram = new ScrollPanel(); mainPanel.setStyleName("daScrollPanel"); spHistogram.add(mainPanel); tabPanel.add(spHistogram, tabTitle); classesPanel.setVisible(false); histogramPanel.setVisible(false); scatterplotPanel.setVisible(false); barChartPanel.setVisible(false); boxPlotPanel.setVisible(false); rbNormalized.setVisible(false); ckOverlayNormal.setVisible(false); ckShowHistogram.setVisible(false); ckCumulative.setVisible(false); ckOverlayPolygon.setVisible(false); // add graph tab spGraph = new ScrollPanel(); spGraph.setStyleName("daScrollPanel"); spGraph.add(graphPanel); tabPanel.add(spGraph, loc.getMenu("Graph")); graphPanel.setVisible(true); showYAxisSettings = true; // set visibility for plot-specific panels switch (plotType) { case HISTOGRAM: classesPanel.setVisible(true); histogramPanel.setVisible(true); rbNormalized.setVisible(true); ckOverlayNormal.setVisible(true); ckShowHistogram.setVisible(true); ckCumulative.setVisible(true); ckOverlayPolygon.setVisible(true); layoutHistogramPanel(); break; case BOXPLOT: case MULTIBOXPLOT: boxPlotPanel.setVisible(true); break; case BARCHART: barChartPanel.setVisible(true); layoutBarChartPanel(); break; case SCATTERPLOT: scatterplotPanel.setVisible(true); break; // graph tab only case DOTPLOT: case NORMALQUANTILE: case RESIDUAL: tabPanel.remove(0); break; case STEMPLOT: this.setVisible(false); break; } tabPanel.selectTab(0); setLabels(); updateGUI(); } private void createHistogramPanel() { histogramPanel = new FlowPanel(); // create components ckCumulative = new CheckBox(); lblFreqType = new Label(); lbClassTitle = new Label(); lbClassTitle.setStyleName("panelTitle"); lbFreqTitle = new Label(); lbFreqTitle.setStyleName("panelTitle"); lbShowTitle = new Label(); lbShowTitle.setStyleName("panelTitle"); lbDimTitle = new Label(); lbDimTitle.setStyleName("panelTitle"); rbFreq = new RadioButton("group1"); rbNormalized = new RadioButton("group1"); rbRelative = new RadioButton("group1"); lblOverlay = new Label(); ckOverlayNormal = new CheckBox(); ckOverlayPolygon = new CheckBox(); ckShowFrequencyTable = new CheckBox(); ckShowHistogram = new CheckBox(); ckManual = new CheckBox(); lblClassRule = new Label(); rbLeftRule = new RadioButton("rule"); rbRightRule = new RadioButton("rule"); // create frequency type panel freqPanel = new FlowPanel(); freqPanel.add(lbFreqTitle); freqPanel.add(ckCumulative); freqPanel.add(LayoutUtilW.panelRowIndent(rbFreq)); freqPanel.add(LayoutUtilW.panelRowIndent(rbRelative)); freqPanel.add(LayoutUtilW.panelRowIndent(rbNormalized)); // create show panel showPanel = new FlowPanel(); showPanel.add(lbShowTitle); showPanel.add(LayoutUtilW.panelRowIndent(ckShowHistogram)); showPanel.add(LayoutUtilW.panelRowIndent(ckShowFrequencyTable)); showPanel.add(LayoutUtilW.panelRowIndent(ckOverlayPolygon)); showPanel.add(LayoutUtilW.panelRowIndent(ckOverlayNormal)); // create classes panel classesPanel = new FlowPanel(); classesPanel.setStyleName("daOptionsGroup"); classesPanel.add(lbClassTitle); classesPanel.add(LayoutUtilW.panelRowIndent(ckManual)); classesPanel.add(lblClassRule); classesPanel.add(LayoutUtilW.panelRowIndent(rbLeftRule)); classesPanel.add(LayoutUtilW.panelRowIndent(rbRightRule)); layoutHistogramPanel(); PropertyChangeHandler handler = new PropertyChangeHandler(); ckManual.addClickHandler(handler); ckCumulative.addClickHandler(handler); ckShowHistogram.addClickHandler(handler); ckOverlayPolygon.addClickHandler(handler); ckOverlayNormal.addClickHandler(handler); ckShowFrequencyTable.addClickHandler(handler); rbFreq.addClickHandler(handler); rbRelative.addClickHandler(handler); rbNormalized.addClickHandler(handler); rbLeftRule.addClickHandler(handler); rbRightRule.addClickHandler(handler); } private void layoutHistogramPanel() { if (histogramPanel == null) { histogramPanel = new FlowPanel(); } FlowPanel p = new FlowPanel(); p.add(classesPanel); p.add(freqPanel); p.add(showPanel); histogramPanel.add(p); } private void layoutBarChartPanel() { if (barChartPanel == null) { barChartPanel = new FlowPanel(); } barChartPanel.clear(); barChartPanel.add(barChartWidthPanel); // barChartPanel.add(freqPanel); barChartPanel.add(showPanel); } private void createBarChartPanel() { // create components ckAutoBarWidth = new CheckBox(); ckAutoBarWidth.addClickHandler(this); lblBarWidth = new Label(); fldBarWidth = new AutoCompleteTextFieldW(fieldWidth, app); fldBarWidth.setEditable(true); fldBarWidth.addKeyHandler(new PropertyKeyHandler(fldBarWidth)); fldBarWidth.addBlurHandler(this); // barChartWidthPanel barChartWidthPanel = new FlowPanel(); barChartWidthPanel.add(ckAutoBarWidth); barChartWidthPanel.add(LayoutUtilW.panelRow(lblBarWidth, fldBarWidth)); layoutBarChartPanel(); } private void createBoxPlotPanel() { // create components ckShowOutliers = new CheckBox(); ckShowOutliers.addClickHandler(this); // layout boxPlotPanel = new FlowPanel(); boxPlotPanel.add(ckShowOutliers); } private void createScatterplotPanel() { // create components ckShowLines = new CheckBox(); ckShowLines.addClickHandler(this); scatterplotPanel = new FlowPanel(); scatterplotPanel.add(ckShowLines); } private void createGraphPanel() { // create components ckAutoWindow = new CheckBox(); ckAutoWindow.addClickHandler(this); ckShowGrid = new CheckBox(); ckShowGrid.addClickHandler(this); lblXMin = new Label(); fldXMin = InputPanelW.newTextComponent(app); fldXMin.setEditable(true); fldXMin.addKeyHandler(new KeyHandler() { @Override public void keyReleased(KeyEvent e) { if (e.isEnterKey()) { actionPerformed(fldXMin); } } }); fldXMin.addBlurHandler(new BlurHandler() { @Override public void onBlur(BlurEvent event) { actionPerformed(fldXMin); } }); lblXMax = new Label(); fldXMax = InputPanelW.newTextComponent(app); fldXMax.addKeyHandler(new KeyHandler() { @Override public void keyReleased(KeyEvent e) { if (e.isEnterKey()) { actionPerformed(fldXMax); } } }); fldXMax.addBlurHandler(new BlurHandler() { @Override public void onBlur(BlurEvent event) { actionPerformed(fldXMax); } }); lblYMin = new Label(); fldYMin = InputPanelW.newTextComponent(app); fldYMin.addKeyHandler(new PropertyKeyHandler(fldYMin)); fldYMin.addBlurHandler(this); lblYMax = new Label(); fldYMax = InputPanelW.newTextComponent(app); fldYMax.addKeyHandler(new PropertyKeyHandler(fldYMax)); fldYMax.addBlurHandler(this); lblXInterval = new Label(); fldXInterval = new AutoCompleteTextFieldW(fieldWidth, app); fldXInterval.addKeyHandler(new PropertyKeyHandler(fldXInterval)); fldXInterval.addBlurHandler(this); lblYInterval = new Label(); fldYInterval = new AutoCompleteTextFieldW(fieldWidth, app); fldYInterval.addKeyHandler(new PropertyKeyHandler(fldYInterval)); fldYInterval.addBlurHandler(this); // create graph options panel FlowPanel graphOptionsPanel = new FlowPanel(); graphOptionsPanel.add(ckShowGrid); graphOptionsPanel.add(ckAutoWindow); // create window dimensions panel FlowPanel dimPanel = new FlowPanel(); dimPanel.add(LayoutUtilW.panelRow(lblXMin, fldXMin)); dimPanel.add(LayoutUtilW.panelRow(lblXMax, fldXMax)); dimPanel.add(LayoutUtilW.panelRow(lblXInterval, fldXInterval)); // y dimensions dimPanel.add(LayoutUtilW.panelRow(lblYMin, fldYMin)); dimPanel.add(LayoutUtilW.panelRow(lblYMax, fldYMax)); dimPanel.add(LayoutUtilW.panelRow(lblYInterval, fldYInterval)); cbLogAxes = new ListBox(); ckAutoWindow.addClickHandler(this); // put the sub-panels together graphPanel = new FlowPanel(); graphPanel.add(graphOptionsPanel); graphPanel.add(dimPanel); if (app.has(Feature.LOG_AXES)) { cbLogAxes.addItem("Standard To Standard"); cbLogAxes.addItem("Logarithmic To Standard"); cbLogAxes.addItem("Standard To Logarithmic"); cbLogAxes.addItem("Logarithmic To Logarithmic"); cbLogAxes.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { onComboBoxChange(); } }); FlowPanel modePanel = new FlowPanel(); modePanel.add(cbLogAxes); graphPanel.add(modePanel); } } protected void onComboBoxChange() { int index = cbLogAxes.getSelectedIndex(); settings.setCoordMode(StatPanelSettings.CoordMode.values()[index]); this.firePropertyChange(); updateGUI(); } @Override public void setLabels() { // titled borders lbClassTitle.setText(loc.getMenu("Classes")); lbShowTitle.setText(loc.getMenu("Show")); lbFreqTitle.setText(loc.getMenu("FrequencyType")); lbDimTitle.setText(loc.getMenu("Dimensions")); // histogram options ckManual.setText(loc.getMenu("SetClasssesManually")); lblFreqType.setText(loc.getMenu("FrequencyType") + ":"); rbFreq.setText(loc.getMenu("Count")); rbNormalized.setText(loc.getMenu("Normalized")); rbRelative.setText(loc.getMenu("Relative")); ckCumulative.setText(loc.getMenu("Cumulative")); lblOverlay.setText(loc.getMenu("Overlay")); ckOverlayNormal.setText(loc.getMenu("NormalCurve")); ckOverlayPolygon.setText(loc.getMenu("FrequencyPolygon")); ckShowFrequencyTable.setText(loc.getMenu("FrequencyTable")); ckShowHistogram.setText(loc.getMenu("Histogram")); lblClassRule.setText(loc.getMenu("ClassRule") + ":"); rbRightRule.setText(loc.getMenu("RightClassRule")); rbLeftRule.setText(loc.getMenu("LeftClassRule")); // bar chart lblBarWidth.setText(loc.getMenu("Width")); ckAutoBarWidth.setText(loc.getMenu("AutoDimension")); // graph options ckAutoWindow.setText(loc.getMenu("AutoDimension")); ckShowGrid.setText(loc.getMenu("ShowGrid")); lblXMin.setText(loc.getMenu("xmin") + ":"); lblXMax.setText(loc.getMenu("xmax") + ":"); lblYMin.setText(loc.getMenu("ymin") + ":"); lblYMax.setText(loc.getMenu("ymax") + ":"); lblXInterval.setText(loc.getMenu("xstep") + ":"); lblYInterval.setText(loc.getMenu("ystep") + ":"); // scatterplot options ckShowLines.setText(loc.getMenu("LineGraph")); // boxplot options ckShowOutliers.setText(loc.getMenu("ShowOutliers")); } private void updateGUI() { // set updating flag so we don't have to add/remove action listeners isUpdating = true; // histogram/barchart ckManual.setValue(settings.isUseManualClasses()); rbFreq.setValue(settings.getFrequencyType() == StatPanelSettings.TYPE_COUNT); rbRelative .setValue(settings.getFrequencyType() == StatPanelSettings.TYPE_RELATIVE); rbNormalized .setValue(settings.getFrequencyType() == StatPanelSettings.TYPE_NORMALIZED); rbLeftRule.setValue(settings.isLeftRule()); ckCumulative.setValue(settings.isCumulative()); ckOverlayNormal.setValue(settings.isHasOverlayNormal()); ckOverlayPolygon.setValue(settings.isHasOverlayPolygon()); ckShowGrid.setValue(settings.showGrid); ckAutoWindow.setValue(settings.isAutomaticWindow()); ckShowFrequencyTable.setValue(settings.isShowFrequencyTable()); ckShowHistogram.setValue(settings.isShowHistogram()); if (settings.dataSource != null) { ckManual.setVisible(settings.getDataSource().getGroupType() != GroupType.CLASS); freqPanel .setVisible(settings.getDataSource().getGroupType() == GroupType.RAWDATA); } // normal overlay ckOverlayNormal .setEnabled(settings.getFrequencyType() == StatPanelSettings.TYPE_NORMALIZED); // bar chart width ckAutoBarWidth.setValue(settings.isAutomaticBarWidth()); fldBarWidth.setText("" + settings.getBarWidth()); fldBarWidth.setEditable(!ckAutoBarWidth.getValue()); // window dimension lblYMin.setVisible(showYAxisSettings); fldYMin.setVisible(showYAxisSettings); lblYMax.setVisible(showYAxisSettings); fldYMax.setVisible(showYAxisSettings); lblYInterval.setVisible(showYAxisSettings); fldYInterval.setVisible(showYAxisSettings); fldXMin.setEditable(!ckAutoWindow.getValue()); fldXMax.setEditable(!ckAutoWindow.getValue()); fldXInterval.setEditable(!ckAutoWindow.getValue()); fldYMin.setEditable(!ckAutoWindow.getValue()); fldYMax.setEditable(!ckAutoWindow.getValue()); fldYInterval.setEditable(!ckAutoWindow.getValue()); // update automatic dimensions fldXMin.setText("" + daModel.format(settings.xMin)); fldXMax.setText("" + daModel.format(settings.xMax)); fldXInterval.setText("" + daModel.format(settings.xAxesInterval)); fldYMin.setText("" + daModel.format(settings.yMin)); fldYMax.setText("" + daModel.format(settings.yMax)); fldYInterval.setText("" + daModel.format(settings.yAxesInterval)); // show outliers ckShowOutliers.setValue(settings.isShowOutliers()); isUpdating = false; } public void actionPerformed(Object source) { if (isUpdating) { return; } if (source instanceof AutoCompleteTextFieldW) { doTextFieldActionPerformed((AutoCompleteTextFieldW) source); } else if (source == ckManual) { settings.setUseManualClasses(ckManual.getValue()); firePropertyChange(); } else if (source == ckCumulative) { settings.setCumulative(ckCumulative.getValue()); firePropertyChange(); } else if (source == rbFreq) { settings.setFrequencyType(StatPanelSettings.TYPE_COUNT); firePropertyChange(); } else if (source == rbRelative) { settings.setFrequencyType(StatPanelSettings.TYPE_RELATIVE); firePropertyChange(); } else if (source == rbNormalized) { settings.setFrequencyType(StatPanelSettings.TYPE_NORMALIZED); firePropertyChange(); } else if (source == ckOverlayNormal) { settings.setHasOverlayNormal(ckOverlayNormal.getValue()); firePropertyChange(); } else if (source == ckOverlayPolygon) { settings.setHasOverlayPolygon(ckOverlayPolygon.getValue()); firePropertyChange(); } else if (source == ckShowGrid) { settings.showGrid = ckShowGrid.getValue(); firePropertyChange(); } else if (source == ckAutoWindow) { settings.setAutomaticWindow(ckAutoWindow.getValue()); settings.xAxesIntervalAuto = ckAutoWindow.getValue(); settings.yAxesIntervalAuto = ckAutoWindow.getValue(); firePropertyChange(); } else if (source == ckShowFrequencyTable) { settings.setShowFrequencyTable(ckShowFrequencyTable.getValue()); firePropertyChange(); } else if (source == ckShowHistogram) { settings.setShowHistogram(ckShowHistogram.getValue()); firePropertyChange(); } else if (source == rbLeftRule || source == rbRightRule) { settings.setLeftRule(rbLeftRule.getValue()); firePropertyChange(); } else if (source == ckShowLines) { settings.setShowScatterplotLine(ckShowLines.getValue()); firePropertyChange(); } else if (source == ckShowOutliers) { settings.setShowOutliers(ckShowOutliers.getValue()); firePropertyChange(); } else if (source == ckAutoBarWidth) { settings.setAutomaticBarWidth(ckAutoBarWidth.getValue()); firePropertyChange(); } else { firePropertyChange(); } updateGUI(); } private void doTextFieldActionPerformed(AutoCompleteTextFieldW source) { if (isUpdating) { return; } try { String inputText = source.getText().trim(); NumberValue nv; nv = app.getKernel().getAlgebraProcessor() .evaluateToNumeric(inputText, false); double value = nv.getDouble(); // TODO better validation if (source == fldXMin) { settings.xMin = value; firePropertyChange(); } else if (source == fldXMax) { settings.xMax = value; firePropertyChange(); } else if (source == fldYMax) { settings.yMax = value; firePropertyChange(); } else if (source == fldYMin) { settings.yMin = value; firePropertyChange(); } else if (source == fldXInterval && value >= 0) { settings.xAxesInterval = value; firePropertyChange(); } else if (source == fldYInterval && value >= 0) { settings.yAxesInterval = value; firePropertyChange(); } else if (source == fldBarWidth && value >= 0) { settings.setBarWidth(value); firePropertyChange(); } updateGUI(); } catch (NumberFormatException e) { e.printStackTrace(); } } private void firePropertyChange() { dyModel.updatePlot(true); } @Override public void updatePanel() { // TODO Auto-generated method stub } @Override public void onBlur(BlurEvent event) { actionPerformed(event.getSource()); } @Override public void onClick(ClickEvent event) { actionPerformed(event.getSource()); } public void resize(int height) { spHistogram.setHeight(height + "px"); spGraph.setHeight(height + "px"); } }