/**
   * Updates the histogram.
   *
   * @param oLegend Legend for this chart.
   * @throws ModelException Passing through an underlying exception.
   */
  void updateChart(Legend oLegend) throws ModelException {

    // If there are no series in the dataset, add them now (in case the
    // file was re-parsed while this chart was open)
    if (m_oDataset.getSeriesCount() == 0) {
      addSeriesToDataset();
    }

    ModelHistogramDataset oAdjustedDataset = updateForVisible(oLegend);

    DataGrapher.updateHistogram(oAdjustedDataset, m_oChartFrame, oLegend, this);

    // Update bin information, if we're updating
    if (m_bRecalcBinsOnUpdate) {
      JTextField jNumBins =
          (JTextField)
              DataGrapher.findNamedComponent(m_oChartFrame.getContentPane(), NUMBER_BINS_NAME);
      JTextField jBinSize =
          (JTextField)
              DataGrapher.findNamedComponent(m_oChartFrame.getContentPane(), BIN_SIZE_NAME);
      jNumBins.setText(String.valueOf(m_iNumBins));
      jBinSize.setText(m_jFormat.format(m_fBinSize));
    }

    if (m_bIsInt) m_jMinDatasetValue.setText(String.valueOf((int) m_fDatasetMin));
    else m_jMinDatasetValue.setText(String.valueOf(m_jFormat.format(m_fDatasetMin)));
    if (m_bIsInt) m_jMaxDatasetValue.setText(String.valueOf((int) m_fDatasetMax));
    else m_jMaxDatasetValue.setText(String.valueOf(m_jFormat.format(m_fDatasetMax)));
  }
  /**
   * Extracts information needed by the data request from the controls panel displayed to the user.
   *
   * @param oInfo Object which contains the chart information.
   */
  public void extractBatchSetupInfo(ChartInfo oInfo) throws ModelException {
    super.extractBatchSetupInfo(oInfo);

    int iNumBins = 0;
    float fSizeBins = 0;
    try {
      JTextField jField =
          (JTextField) DataGrapher.findNamedComponent(oInfo.m_jExtraOptions, NUMBER_BINS_NAME);
      Integer oNumBins = new Integer(jField.getText());
      jField = (JTextField) DataGrapher.findNamedComponent(oInfo.m_jExtraOptions, BIN_SIZE_NAME);
      Float oBinSize = new Float(jField.getText());
      iNumBins = oNumBins.intValue();
      fSizeBins = oBinSize.floatValue();
    } catch (java.lang.NumberFormatException oErr) {
      throw (new ModelException(
          ErrorGUI.BAD_DATA,
          "Histogram Request",
          "The value for number " + "of bins or bin size is not a recognized number."));
    }

    if (iNumBins <= 0 || fSizeBins < 0) {
      throw (new ModelException(
          ErrorGUI.BAD_DATA,
          "Stand Table Request",
          "The values for number"
              + " of size classes or size class size must be greater than zero."));
    }

    m_iNumBins = iNumBins;
    m_fBinSize = fSizeBins;

    if (m_fBinSize == 0) {
      m_bRecalcBinsOnUpdate = true;
    } else {
      m_bRecalcBinsOnUpdate = false;
    }
  }
  /**
   * Creates the histogram using data accumulated thus far.
   *
   * @param oLegend Legend for this chart.
   * @param sChartTitle Title for this chart.
   * @return The new chart window.
   * @throws sortie.data.simpletypes.ModelException Passing through underlying exceptions.
   */
  ModelInternalFrame drawChart(Legend oLegend, String sChartTitle) throws ModelException {
    int i;

    ModelHistogramDataset oAdjustedDataset = updateForVisible(oLegend);

    // Make the chart
    m_oChartFrame =
        DataGrapher.drawHistogram(
            oAdjustedDataset, m_sLabel, "Total Number", sChartTitle, oLegend, this);

    // Add the extra controls to the top of the histogram window
    JPanel jLine1Controls = new JPanel(new FlowLayout(FlowLayout.LEFT));

    // Bins boxes
    JLabel jTemp = new JLabel("Number of bins:");
    jTemp.setFont(new sortie.gui.components.SortieFont());
    jLine1Controls.add(jTemp);

    JTextField jNumBins = new JTextField(String.valueOf(m_iNumBins));
    jNumBins.setFont(new SortieFont());
    jNumBins.setPreferredSize(
        new java.awt.Dimension(50, (int) jNumBins.getPreferredSize().getHeight()));
    jNumBins.setName(NUMBER_BINS_NAME);
    jLine1Controls.add(jNumBins);

    jTemp = new JLabel("Bin size:");
    jTemp.setFont(new sortie.gui.components.SortieFont());
    jLine1Controls.add(jTemp);

    JTextField jBinSize = new JTextField(m_jFormat.format(m_fBinSize));
    jBinSize.setFont(new SortieFont());
    jBinSize.setPreferredSize(
        new java.awt.Dimension(50, (int) jBinSize.getPreferredSize().getHeight()));
    jBinSize.setName(BIN_SIZE_NAME);
    jLine1Controls.add(jBinSize);

    // Button to change
    JButton jButton = new JButton("Change");
    jButton.setFont(new sortie.gui.components.SortieFont());
    jButton.setActionCommand("UpdateBins");
    jButton.addActionListener(this);
    jLine1Controls.add(jButton);

    // Checkbox for logarithmic axis
    JCheckBox jCheckBox = new JCheckBox("Use Logarithmic Axis", getUseLogarithmicAxis());
    jCheckBox.setFont(new SortieFont());
    jCheckBox.setName("log_checkbox");
    jCheckBox.addActionListener(this);
    jLine1Controls.add(jCheckBox);

    // Checkbox for showing total bars
    jCheckBox = new JCheckBox("Show Totals", m_bShowTotal);
    jCheckBox.setFont(new sortie.gui.components.SortieFont());
    jCheckBox.setName("total_checkbox");
    jCheckBox.addActionListener(this);
    jLine1Controls.add(jCheckBox);

    JPanel jLine2Controls = new JPanel(new FlowLayout(FlowLayout.LEFT));
    jTemp = new JLabel("Min value:");
    jTemp.setFont(new sortie.gui.components.SortieFont());
    jLine2Controls.add(jTemp);
    m_jMinDatasetValue.setFont(new sortie.gui.components.SortieFont());
    if (m_bIsInt) m_jMinDatasetValue.setText(String.valueOf((int) m_fDatasetMin));
    else m_jMinDatasetValue.setText(String.valueOf(m_jFormat.format(m_fDatasetMin)));
    jLine2Controls.add(m_jMinDatasetValue);
    jTemp = new JLabel("Max value:");
    jTemp.setFont(new sortie.gui.components.SortieFont());
    jLine2Controls.add(jTemp);
    m_jMaxDatasetValue.setFont(new sortie.gui.components.SortieFont());
    if (m_bIsInt) m_jMaxDatasetValue.setText(String.valueOf((int) m_fDatasetMax));
    else m_jMaxDatasetValue.setText(String.valueOf(m_jFormat.format(m_fDatasetMax)));
    jLine2Controls.add(m_jMaxDatasetValue);

    // Remove the chart, which is the content panel
    org.jfree.chart.ChartPanel jChart = null;
    for (i = 0; i < m_oChartFrame.getContentPane().getComponentCount(); i++) {
      if (m_oChartFrame.getContentPane().getComponent(i) instanceof org.jfree.chart.ChartPanel) {
        jChart = (org.jfree.chart.ChartPanel) m_oChartFrame.getContentPane().getComponent(i);
      }
    }

    JPanel jControls = new JPanel();
    jControls.setLayout(new BoxLayout(jControls, BoxLayout.PAGE_AXIS));
    jControls.add(jLine1Controls);
    jControls.add(jLine2Controls);

    // Recreate the content pane with the controls and the chart
    JPanel jContentPanel = new JPanel(new java.awt.BorderLayout());
    jContentPanel.setLayout(new java.awt.BorderLayout());
    jContentPanel.add(jControls, java.awt.BorderLayout.NORTH);
    jContentPanel.add(jChart, java.awt.BorderLayout.CENTER);

    m_oChartFrame.setContentPane(jContentPanel);

    return m_oChartFrame;
  }
  /**
   * Performs actions for the controls in the Histogram window.
   *
   * @param oEvent Event triggered.
   */
  public void actionPerformed(ActionEvent oEvent) {
    try {
      if (oEvent.getSource() instanceof JCheckBox) {
        JCheckBox jBox = (JCheckBox) oEvent.getSource();
        if (jBox.getName().equals("log_checkbox")) {
          if (jBox.isSelected() != m_bUseLogarithmicAxis) {
            m_bUseLogarithmicAxis = jBox.isSelected();
            updateChart(m_oManager.getLegend());
          }
        } else if (jBox.getName().equals("total_checkbox")) {
          if (jBox.isSelected() != m_bShowTotal) {
            m_bShowTotal = jBox.isSelected();

            // If the dataset already exists, simply calling an update will
            // have no effect; so either remove or add the series, as
            // requested
            if (m_oDataset != null && m_oDataset.getSeriesCount() > 0) {
              if (m_bShowTotal == true) {
                m_oDataset.addTotalSeries();
              } else {
                for (int i = 0; i < m_oDataset.getSeriesCount(); i++) {
                  if (((String) m_oDataset.getSeriesKey(i)).equalsIgnoreCase("total")) {
                    m_oDataset.removeSeries(i);
                    break;
                  }
                }
              }
            }
            updateChart(m_oManager.getLegend());
          }
        }
      } else if (oEvent.getActionCommand().equals("UpdateBins")) {

        // Make sure the values in the bins are recognizable, greater-than-zero numbers
        int iNumBins = 0;
        float fBinSize = 0;
        JTextField jNumBins =
            (JTextField)
                DataGrapher.findNamedComponent(m_oChartFrame.getContentPane(), NUMBER_BINS_NAME);
        JTextField jBinSize =
            (JTextField)
                DataGrapher.findNamedComponent(m_oChartFrame.getContentPane(), BIN_SIZE_NAME);
        try {
          Integer oNumBins = new Integer(jNumBins.getText());
          Float oBinSize = new Float(jBinSize.getText());
          iNumBins = oNumBins.intValue();
          fBinSize = oBinSize.floatValue();
        } catch (java.lang.NumberFormatException oErr) {
          JOptionPane.showMessageDialog(
              m_oChartFrame,
              "The value for number of bins or bin size is not a recognized number.");
          jNumBins.setText(String.valueOf(m_iNumBins));
          jBinSize.setText(String.valueOf(m_fBinSize));
          return;
        }

        if (iNumBins <= 0 || fBinSize <= 0) {
          JOptionPane.showMessageDialog(
              m_oChartFrame,
              "The values for number of bins and bin size must be greater than zero.");
          jNumBins.setText(String.valueOf(m_iNumBins));
          jBinSize.setText(String.valueOf(m_fBinSize));
          return;
        }

        if (iNumBins != m_iNumBins || fBinSize != m_fBinSize) {
          m_iNumBins = iNumBins;
          m_fBinSize = fBinSize;

          // Clear the dataset to force a reconstruction
          m_oDataset = null;
          m_oDataset = new ModelHistogramDataset();

          m_bRecalcBinsOnUpdate = false;
          updateChart(m_oManager.getLegend());
        }
      }
      super.actionPerformed(oEvent);
    } catch (sortie.data.simpletypes.ModelException oErr) {
      ErrorGUI oHandler = new ErrorGUI(m_oChartFrame);
      oHandler.writeErrorMessage(oErr);
    }
  }