package org.geogebra.desktop.gui.view.probcalculator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.gui.view.probcalculator.ChiSquareCell;
import org.geogebra.common.gui.view.probcalculator.ChiSquarePanel;
import org.geogebra.common.gui.view.probcalculator.StatisticsCalculator;
import org.geogebra.common.gui.view.probcalculator.StatisticsCalculator.Procedure;
import org.geogebra.common.gui.view.probcalculator.StatisticsCollection;
import org.geogebra.common.main.GeoGebraColorConstants;
import org.geogebra.common.main.Localization;
import org.geogebra.desktop.awt.GColorD;
import org.geogebra.desktop.gui.inputfield.MyTextFieldD;
import org.geogebra.desktop.gui.util.LayoutUtil;
import org.geogebra.desktop.main.AppD;
/**
* Panel for Chi Square and Goodness of Fit Tests
*
* @author G. Sturr
*
*/
public class ChiSquarePanelD extends ChiSquarePanel
implements ActionListener, FocusListener {
// ======================================
// GUI components
// ======================================
private JPanel pnlCount, pnlControl;
private JComboBox cbRows, cbColumns;
private ChiSquareCellD[][] cell;
private JCheckBox ckExpected, ckChiDiff, ckRowPercent, ckColPercent;
private JLabel lblRows, lblColumns;
private boolean showColumnMargin;
private JPanel wrappedPanel;
/**
* @param loc
* @param statCalc
*/
public ChiSquarePanelD(Localization loc, StatisticsCalculator statCalc) {
super(loc, statCalc);
createGUI();
setLabels();
}
public void setLabels() {
lblRows.setText(getMenu("Rows"));
lblColumns.setText(getMenu("Columns"));
ckExpected.setText(getMenu("ExpectedCount"));
ckChiDiff.setText(getMenu("ChiSquaredContribution"));
ckRowPercent.setText(getMenu("RowPercent"));
ckColPercent.setText(getMenu("ColumnPercent"));
if (getStatCalc().getSelectedProcedure() == Procedure.GOF_TEST) {
cell[0][1].setLabelText(0, getMenu("ObservedCount"));
cell[0][2].setLabelText(0, getMenu("ExpectedCount"));
}
}
private void createGUI() {
this.wrappedPanel = new JPanel();
createGUIElements();
createCountPanel();
createControlPanel();
JPanel p = new JPanel(new BorderLayout());
p.add(pnlCount, BorderLayout.NORTH);
p.setBackground(null);
wrappedPanel.setLayout(new BorderLayout());
wrappedPanel.add(pnlControl, BorderLayout.NORTH);
wrappedPanel.add(p, BorderLayout.CENTER);
wrappedPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
}
private void createGUIElements() {
lblRows = new JLabel();
lblColumns = new JLabel();
ckExpected = new JCheckBox();
ckChiDiff = new JCheckBox();
ckRowPercent = new JCheckBox();
ckColPercent = new JCheckBox();
ckExpected.addActionListener(this);
ckChiDiff.addActionListener(this);
ckRowPercent.addActionListener(this);
ckColPercent.addActionListener(this);
// drop down menu for rows/columns 2-12
String[] num = new String[11];
for (int i = 0; i < num.length; i++) {
num[i] = "" + (i + 2);
}
cbRows = new JComboBox(num);
cbRows.setSelectedItem("" + getSc().rows);
cbRows.addActionListener(this);
cbRows.setMaximumRowCount(12);
cbColumns = new JComboBox(num);
cbColumns.setSelectedItem("" + getSc().columns);
cbColumns.addActionListener(this);
cbColumns.setMaximumRowCount(12);
}
private void createControlPanel() {
pnlControl = new JPanel();
pnlControl.setLayout(new BoxLayout(pnlControl, BoxLayout.Y_AXIS));
pnlControl.add(wrappedPanel.add(
LayoutUtil.flowPanel(lblRows, cbRows, lblColumns, cbColumns)));
pnlControl.add(wrappedPanel.add(LayoutUtil.flowPanel(ckRowPercent,
ckColPercent, ckExpected, ckChiDiff)));
}
private void createCountPanel() {
if (pnlCount == null) {
pnlCount = new JPanel();
}
pnlCount.removeAll();
pnlCount.setLayout(new BoxLayout(pnlCount, BoxLayout.Y_AXIS));
cell = new ChiSquareCellD[getSc().rows + 2][getSc().columns + 2];
// create grid of cells
for (int r = 0; r < getSc().rows + 2; r++) {
JPanel row = new JPanel(new FlowLayout(FlowLayout.LEFT, 1, 1));
for (int c = 0; c < getSc().columns + 2; c++) {
cell[r][c] = new ChiSquareCellD(getSc(), r, c);
cell[r][c].getInputField().addActionListener(this);
cell[r][c].getInputField().addFocusListener(this);
// wider fields for the GOF test
if (getStatCalc().getSelectedProcedure() == Procedure.GOF_TEST) {
cell[r][c].setColumns(10);
}
row.add(cell[r][c].getWrappedPanel());
}
pnlCount.add(row);
}
// upper-right corner cell
cell[0][0].setMarginCell(true);
// column headers and margins
for (int c = 1; c < getSc().columns + 2; c++) {
cell[0][c].setHeaderCell(true);
cell[getSc().rows + 1][c].setMarginCell(true);
}
// row headers and margins
for (int r = 1; r < getSc().rows + 1; r++) {
cell[r][0].setHeaderCell(true);
cell[r][getSc().columns + 1].setMarginCell(true);
}
// clear other corners
cell[getSc().rows + 1][0].hideAll();
cell[0][getSc().columns + 1].hideAll();
if (getStatCalc().getSelectedProcedure() == Procedure.GOF_TEST) {
cell[0][1].setMarginCell(true);
cell[0][2].setMarginCell(true);
}
}
// ==========================================
// Event handlers
// ==========================================
public void updateGUI() {
if (getStatCalc().getSelectedProcedure() == Procedure.CHISQ_TEST) {
cbColumns.setVisible(true);
lblColumns.setVisible(true);
ckRowPercent.setVisible(true);
ckExpected.setVisible(true);
ckChiDiff.setVisible(true);
} else if (getStatCalc().getSelectedProcedure() == Procedure.GOF_TEST) {
cbColumns.setVisible(false);
lblColumns.setVisible(false);
ckRowPercent.setVisible(false);
ckExpected.setVisible(false);
ckChiDiff.setVisible(false);
// only two columns for GOF
cbColumns.removeActionListener(this);
cbColumns.setSelectedItem("2");
cbColumns.addActionListener(this);
}
getSc().setChiSqData(Integer.parseInt((String) cbRows.getSelectedItem()),
Integer.parseInt((String) cbColumns.getSelectedItem()));
createCountPanel();
setLabels();
wrappedPanel.revalidate();
wrappedPanel.repaint();
}
private void updateVisibility() {
for (int i = 1; i < getSc().rows + 1; i++) {
for (int j = 1; j < getSc().columns + 1; j++) {
cell[i][j].setLabelVisible(1, ckExpected.isSelected());
cell[i][j].setLabelVisible(2, ckChiDiff.isSelected());
cell[i][j].setLabelVisible(3, ckRowPercent.isSelected());
cell[i][j].setLabelVisible(4, ckColPercent.isSelected());
}
}
// column percent for bottom margin
for (int r = 0; r < getSc().rows; r++) {
cell[r + 1][getSc().columns + 1].setLabelVisible(3,
ckColPercent.isSelected());
}
// row percent for right margin
for (int c = 0; c < getSc().columns; c++) {
cell[getSc().rows + 1][c + 1].setLabelVisible(4,
ckRowPercent.isSelected());
}
updateCellContent();
}
private void updateCellContent() {
getStatProcessor().doCalculate();
for (int r = 0; r < getSc().rows; r++) {
for (int c = 0; c < getSc().columns; c++) {
if (ckExpected.isSelected()) {
cell[r + 1][c + 1].setLabelText(1,
getStatCalc().format(getSc().expected[r][c]));
}
if (ckChiDiff.isSelected()) {
cell[r + 1][c + 1].setLabelText(2,
getStatCalc().format(getSc().diff[r][c]));
}
if (ckRowPercent.isSelected()) {
cell[r + 1][c + 1].setLabelText(3, getStatCalc()
.format(100 * getSc().observed[r][c] / getSc().rowSum[r]));
}
if (ckColPercent.isSelected()) {
cell[r + 1][c + 1].setLabelText(4, getStatCalc()
.format(100 * getSc().observed[r][c] / getSc().columnSum[c]));
}
}
}
// column margin
if (showColumnMargin) {
for (int r = 0; r < getSc().rows; r++) {
cell[r + 1][getSc().columns + 1].setLabelText(0,
getStatCalc().format(getSc().rowSum[r]));
if (ckRowPercent.isSelected()) {
cell[r + 1][getSc().columns + 1].setLabelText(3,
getStatCalc().format(100 * getSc().rowSum[r] / getSc().total));
}
}
}
// bottom margin
for (int c = 0; c < getSc().columns; c++) {
cell[getSc().rows + 1][c + 1].setLabelText(0,
getStatCalc().format(getSc().columnSum[c]));
if (ckColPercent.isSelected()) {
cell[getSc().rows + 1][c + 1].setLabelText(4,
getStatCalc().format(100 * getSc().columnSum[c] / getSc().total));
}
}
// bottom right corner
if (showColumnMargin) {
cell[getSc().rows + 1][getSc().columns + 1].setLabelText(0,
getStatCalc().format(getSc().total));
}
}
@Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof JTextField) {
doTextFieldActionPerformed((JTextField) source);
}
if (source == cbRows || source == cbColumns) {
updateGUI();
}
if (source == ckExpected || source == ckChiDiff
|| source == ckRowPercent || source == ckColPercent) {
updateVisibility();
}
}
public void doTextFieldActionPerformed(JTextField source) {
updateCellContent();
}
@Override
public void focusGained(FocusEvent e) {
if (e.getSource() instanceof MyTextFieldD) {
((MyTextFieldD) e.getSource()).selectAll();
}
}
@Override
public void focusLost(FocusEvent e) {
if (e.getSource() instanceof MyTextFieldD) {
doTextFieldActionPerformed((MyTextFieldD) e.getSource());
}
}
/*****************************************************************
*
* Class ChiSquareCell: extended JPanel to hold cell components
*
*****************************************************************
*/
public class ChiSquareCellD extends ChiSquareCell
implements ActionListener, FocusListener {
private JPanel wrappedPanel;
private MyTextFieldD fldInput;
private JLabel[] label;
/**
* Construct ChiSquareCell with given row, column
*/
public ChiSquareCellD(StatisticsCollection sc, int row, int column) {
this(sc);
init(row, column);
}
/**
* Construct ChiSquareCell
*/
public ChiSquareCellD(StatisticsCollection sc) {
super(sc);
this.wrappedPanel = new JPanel();
wrappedPanel.setOpaque(true);
wrappedPanel.setLayout(
new BoxLayout(this.wrappedPanel, BoxLayout.Y_AXIS));
fldInput = new MyTextFieldD((AppD) statCalc.getApp());
fldInput.addActionListener(this);
fldInput.addFocusListener(this);
wrappedPanel.add(LayoutUtil.flowPanelCenter(0, 0, 0, fldInput));
label = new JLabel[5];
for (int i = 0; i < label.length; i++) {
label[i] = new JLabel();
label[i].setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
wrappedPanel.add(LayoutUtil.flowPanelCenter(0, 0, 0, label[i]));
}
setColumns(4);
setVisualStyle();
hideAllLabels();
}
public void setColumns(int columns) {
fldInput.setColumns(columns);
// force a minimum width for margin cells
wrappedPanel.add(Box
.createHorizontalStrut(fldInput.getPreferredSize().width));
}
/**
* hide all labels
*/
public void hideAllLabels() {
for (int i = 0; i < label.length; i++) {
label[i].setVisible(false);
}
}
/**
* hide all
*/
public void hideAll() {
hideAllLabels();
fldInput.setVisible(false);
wrappedPanel.setBorder(BorderFactory.createEmptyBorder());
}
/**
* @return input field
*/
public MyTextFieldD getInputField() {
return fldInput;
}
/**
* @return label array
*/
public JLabel[] getLabel() {
return label;
}
public void setLabelText(int index, String s) {
label[index].setText(s);
}
public void setLabelVisible(int index, boolean isVisible) {
label[index].setVisible(isVisible);
}
@Override
protected void setVisualStyle() {
wrappedPanel.setBackground(null);
fldInput.setVisible(false);
if (isMarginCell()) {
wrappedPanel
.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
setLabelVisible(0, true);
} else if (isHeaderCell()) {
wrappedPanel
.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
fldInput.setVisible(true);
fldInput.setBackground(GColorD.getAwtColor(
GeoGebraColorConstants.TABLE_BACKGROUND_COLOR_HEADER));
} else {
fldInput.setVisible(true);
wrappedPanel.setBorder(
BorderFactory.createLineBorder(Color.GRAY, 1));
fldInput.setBackground(GColorD.getAwtColor(GColor.WHITE));
}
}
private void updateCellData() {
updateCellData(fldInput.getText());
}
@Override
public void focusGained(FocusEvent e) {
if (e.getSource() instanceof MyTextFieldD) {
((MyTextFieldD) e.getSource()).selectAll();
}
}
@Override
public void focusLost(FocusEvent e) {
updateCellData();
getStatCalc().updateResult();
}
@Override
public void actionPerformed(ActionEvent e) {
updateCellData();
getStatCalc().updateResult();
}
public JPanel getWrappedPanel() {
return wrappedPanel;
}
}
/**
* @return the GUI wrapper panel
*/
public JPanel getWrappedPanel() {
return wrappedPanel;
}
}