//***************************************************************************************************************************************************
//
// Copyright (C) 2020 Selim Temizer.
//
// This file is part of COVID-19.
//
// COVID-19 is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
//
// COVID-19 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with COVID-19. If not, see <http://www.gnu.org/licenses/>.
//
//***************************************************************************************************************************************************




//***************************************************************************************************************************************************

import java.io.File                                    ;
import java.io.IOException                             ;
import java.util.List                                  ;
import java.util.ArrayList                             ;
import java.net.URI                                    ;
import java.net.URISyntaxException                     ;
import java.awt.Color                                  ;
import java.awt.Desktop                                ;
import java.awt.Dimension                              ;
import javax.swing.JFrame                              ;
import javax.swing.JTable                              ;
import javax.swing.JLabel                              ;
import javax.swing.ImageIcon                           ;
import javax.swing.JFileChooser                        ;
import javax.swing.BorderFactory                       ;
import javax.swing.table.TableModel                    ;
import javax.swing.table.TableCellRenderer             ;
import javax.swing.event.RowSorterEvent                ;
import javax.swing.event.RowSorterListener             ;
import javax.swing.filechooser.FileFilter              ;
import javax.swing.filechooser.FileNameExtensionFilter ;

//***************************************************************************************************************************************************




//***************************************************************************************************************************************************

public class GuiTable extends JFrame
{
  //=================================================================================================================================================

  private static final long serialVersionUID = -7690607488246109365L ;

  //-------------------------------------------------------------------------------------------------------------------------------------------------

  private final Covid19      data        ;
  private final String       title       ;  // Window title
  private final String       caption     ;  // Table caption
  private final JFileChooser fileChooser ;

  private final int columnWidths [] = { /* Column  0 : Country                    */ 170 ,
                                        /* -------------------------------------- */
                                        /* Column  1 : Confirmed                  */  70 ,
                                        /* Column  2 : Active                     */  70 ,
                                        /* Column  3 : Recovered                  */  70 ,
                                        /* Column  4 : Deaths                     */  70 ,
                                        /* -------------------------------------- */
                                        /* Column  5 : % Active                   */  55 ,
                                        /* Column  6 : % Recovered                */  55 ,
                                        /* Column  7 : % Deaths                   */  55 ,
                                        /* -------------------------------------- */
                                        /* Column  8 : % Confirmed per Population */  55 ,
                                        /* Column  9 : % Active    per Population */  55 ,
                                        /* Column 10 : % Recovered per Population */  55 ,
                                        /* Column 11 : % Deaths    per Population */  55 ,
                                        /* -------------------------------------- */
                                        /* Column 12 : Confirmed per 1 Million    */  58 ,
                                        /* Column 13 : Active    per 1 Million    */  58 ,
                                        /* Column 14 : Recovered per 1 Million    */  58 ,
                                        /* Column 15 : Deaths    per 1 Million    */  58 ,
                                        /* -------------------------------------- */
                                        /* Column 16 : Re (day)                   */  50 ,
                                        /* Column 17 : Re (week)                  */  50 ,
                                        /* Column 18 : Re (fortnight)             */  50 ,
                                        /* -------------------------------------- */
                                        /* Column 19 : rC                         */  45 ,
                                        /* Column 20 : rR                         */  45 ,
                                        /* Column 21 : rD                         */  45 ,
                                        /* -------------------------------------- */
                                        /* Column 22 : Median Age                 */  35 ,
                                        /* Column 23 : Population                 */  85 ,
                                        /* Column 24 : % World Share              */  55 ,
                                        /* Column 25 : Land Area                  */  75 ,
                                        /* Column 26 : % Area Share               */  55 ,
                                        /* Column 27 : Density                    */  45 } ;

  //=================================================================================================================================================

  public GuiTable ( Covid19 data , String title , String caption , TableModel model , File currentDirectory /* Can be null */ )
  {
    //-----------------------------------------------------------------------------------------------------------------------------------------------

    if ( ( title   == null ) || ( title  .isEmpty() ) )  { title   = "Table" ; }
    if ( ( caption == null ) || ( caption.isEmpty() ) )  { caption = "Data"  ; }

    this.data        = data               ;
    this.title       = title              ;
    this.caption     = caption            ;
    this.fileChooser = new JFileChooser() ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    initComponents() ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    ImageIcon icon = new ImageIcon( GuiTable.class.getResource( "/media/favicon.png" ) ) ;    setIconImage( icon.getImage() ) ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    FileFilter fileFilter = new FileNameExtensionFilter( "Excel Files" , "xlsx" ) ;

    fileChooser.addChoosableFileFilter( fileFilter ) ;
    fileChooser.setFileFilter         ( fileFilter ) ;
    this       .setTitle              ( title      ) ;
    lCaption   .setText               ( caption    ) ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    if ( model            != null )  { tTable     .setModel           ( model            ) ; }
    if ( currentDirectory != null )  { fileChooser.setCurrentDirectory( currentDirectory ) ; }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    tfRows   .setText( "" + tTable.getModel().getRowCount   () ) ;
    tfColumns.setText( "" + tTable.getModel().getColumnCount() ) ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    RowSorterListener rowSorterListener = new RowSorterListener()
    {
      @Override public void sorterChanged ( RowSorterEvent event )
      {
        if ( event.getType() == RowSorterEvent.Type.SORTED )
        {
          tfSelectionRow   .setText( "" ) ;
          tfSelectionColumn.setText( "" ) ;
        }
      }
    } ;

    tTable.getRowSorter().addRowSorterListener( rowSorterListener ) ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    Utilities.setTableHeaderHorizontalAlignment( tTable , JLabel.CENTER ) ;

    tTable.getTableHeader().setBackground( Color.BLACK                                       ) ;
    tTable.getTableHeader().setBorder    ( BorderFactory.createLineBorder( Color.BLACK , 2 ) ) ;

    /*  "Column sorted" marks disappear if the code below runs:
    //
    for ( int i = 0 ; i < tTable.getColumnModel().getColumnCount() ; i++ )
    {
      DefaultTableCellRenderer r = new DefaultTableCellRenderer() ;
      JLabel                   l = (JLabel) r                     ;

      l.setBackground         ( new Color( 217 , 242 , 255 ) ) ;
      l.setHorizontalAlignment( JLabel.CENTER                ) ;

      tTable.getColumnModel().getColumn(i).setHeaderRenderer( r ) ;
    }
    */

    //-----------------------------------------------------------------------------------------------------------------------------------------------
    //                                    R     G     B
    int v = 170 ;    Color c = new Color( 0   , 0   , v   ) ;  // Blue
                     Color a = new Color( 255 , v   , 0   ) ;  // Yellow
                     Color r = new Color( 0   , v   , 0   ) ;  // Green
                     Color d = new Color( v   , 0   , 0   ) ;  // Red
                     Color p = new Color( 0   , v   , 255 ) ;  // Cyan
                     Color l = new Color( v   , 0   , 255 ) ;  // Magenta

    setColumnRenderer(  1 , new DecimalFormatRenderer( "###,###,###,###"        , c ) ) ;  // Confirmed
    setColumnRenderer(  2 , new DecimalFormatRenderer( "###,###,###,###"        , a ) ) ;  // Active
    setColumnRenderer(  3 , new DecimalFormatRenderer( "###,###,###,###"        , r ) ) ;  // Recovered
    setColumnRenderer(  4 , new DecimalFormatRenderer( "###,###,###,###"        , d ) ) ;  // Deaths

    setColumnRenderer(  5 , new DecimalFormatRenderer(             "##0.00 '%'" , a ) ) ;  // % Active
    setColumnRenderer(  6 , new DecimalFormatRenderer(             "##0.00 '%'" , r ) ) ;  // % Recovered
    setColumnRenderer(  7 , new DecimalFormatRenderer(             "##0.00 '%'" , d ) ) ;  // % Deaths

    setColumnRenderer(  8 , new DecimalFormatRenderer(             "##0.00 '%'" , c ) ) ;  // % Confirmed per Population
    setColumnRenderer(  9 , new DecimalFormatRenderer(             "##0.00 '%'" , a ) ) ;  // % Active    per Population
    setColumnRenderer( 10 , new DecimalFormatRenderer(             "##0.00 '%'" , r ) ) ;  // % Recovered per Population
    setColumnRenderer( 11 , new DecimalFormatRenderer(             "##0.00 '%'" , d ) ) ;  // % Deaths    per Population

    setColumnRenderer( 12 , new DecimalFormatRenderer(         "###,##0.0"      , c ) ) ;  // Confirmed per 1 Million
    setColumnRenderer( 13 , new DecimalFormatRenderer(         "###,##0.0"      , a ) ) ;  // Active    per 1 Million
    setColumnRenderer( 14 , new DecimalFormatRenderer(         "###,##0.0"      , r ) ) ;  // Recovered per 1 Million
    setColumnRenderer( 15 , new DecimalFormatRenderer(         "###,##0.0"      , d ) ) ;  // Deaths    per 1 Million

    setColumnRenderer( 16 , new DecimalFormatRenderer(             "##0.000"        ) ) ;  // Re (day)
    setColumnRenderer( 17 , new DecimalFormatRenderer(             "##0.000"        ) ) ;  // Re (week)
    setColumnRenderer( 18 , new DecimalFormatRenderer(             "##0.000"        ) ) ;  // Re (fortnight)

    setColumnRenderer( 19 , new DecimalFormatRenderer(             "##0.000"    , c ) ) ;  // rC
    setColumnRenderer( 20 , new DecimalFormatRenderer(             "##0.000"    , r ) ) ;  // rR
    setColumnRenderer( 21 , new DecimalFormatRenderer(             "##0.000"    , d ) ) ;  // rD

    setColumnRenderer( 22 , new DecimalFormatRenderer(             "###"            ) ) ;  // Median Age
    setColumnRenderer( 23 , new DecimalFormatRenderer( "###,###,###,###"        , p ) ) ;  // Population
    setColumnRenderer( 24 , new DecimalFormatRenderer(             "##0.00 '%'" , p ) ) ;  // % World Share
    setColumnRenderer( 25 , new DecimalFormatRenderer(     "###,###,###"        , l ) ) ;  // Land Area
    setColumnRenderer( 26 , new DecimalFormatRenderer(             "##0.00 '%'" , l ) ) ;  // % Area Share
    setColumnRenderer( 27 , new DecimalFormatRenderer(          "##,###"            ) ) ;  // Density

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    for ( int i = 0 ; i < tTable.getColumnModel().getColumnCount() ; i++ )
    {
      tTable.getColumnModel().getColumn( i ).setWidth         ( columnWidths[ i ] ) ;
      tTable.getColumnModel().getColumn( i ).setPreferredWidth( columnWidths[ i ] ) ;
    }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    List< String > countriesMissingDemographyData = new ArrayList<>() ;

    for ( CountryTimeSeries country : data.timeSeries.countries )
    {
      String sCountry = country.name ;

      if ( data.demography.getCountry( sCountry ) == null )  { countriesMissingDemographyData.add( sCountry ) ; }
    }

    if ( ! countriesMissingDemographyData.isEmpty() )
    {
      String message = "WARNING: Demography data missing for " ;

      for ( int i = 0 ; i < countriesMissingDemographyData.size() ; i++ )
      {
        message += countriesMissingDemographyData.get( i ) ;

        if ( i < countriesMissingDemographyData.size() - 1 )  { message += ", " ; }
      }

      tfStatus.setText( message ) ;
    }

    //-----------------------------------------------------------------------------------------------------------------------------------------------
  }

  //=================================================================================================================================================

  private void setColumnRenderer ( int column , TableCellRenderer renderer )
  {
    tTable.getColumnModel().getColumn( column ).setCellRenderer( renderer ) ;
  }

  //=================================================================================================================================================

  private void updateSelectionCoordinates ()
  {
    int rowIndex = tTable.getSelectedRow   () + 1 ;
    int colIndex = tTable.getSelectedColumn() + 1 ;

    if ( rowIndex >= 0 )  { tfSelectionRow   .setText( "" + rowIndex ) ; } else { tfSelectionRow   .setText( "" ) ; }
    if ( colIndex >= 0 )  { tfSelectionColumn.setText( "" + colIndex ) ; } else { tfSelectionColumn.setText( "" ) ; }
  }

  //=================================================================================================================================================

  public JTable getTable ()  { return tTable ; }

  //=================================================================================================================================================

  /**
   * This method is called from within the constructor to
   * initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is
   * always regenerated by the Form Editor.
   */
  @SuppressWarnings( "unchecked" )
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents()
  {
    bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

    bgNormalize = new javax.swing.ButtonGroup();
    lCaption = new javax.swing.JLabel();
    l1 = new javax.swing.JLabel();
    l2 = new javax.swing.JLabel();
    l3 = new javax.swing.JLabel();
    l4 = new javax.swing.JLabel();
    l5 = new javax.swing.JLabel();
    cbURLs = new javax.swing.JComboBox<>();
    bOpenURL = new javax.swing.JButton();
    bAbout = new javax.swing.JButton();
    bFitWidth = new javax.swing.JButton();
    sp1 = new javax.swing.JScrollPane();
    tTable = new javax.swing.JTable();
    tfRows = new javax.swing.JTextField();
    tfColumns = new javax.swing.JTextField();
    tfSelectionRow = new javax.swing.JTextField();
    tfSelectionColumn = new javax.swing.JTextField();
    cbHorizontalLines = new javax.swing.JCheckBox();
    cbVerticalLines = new javax.swing.JCheckBox();
    cbConfirmed = new javax.swing.JCheckBox();
    cbDeaths = new javax.swing.JCheckBox();
    cbRecovered = new javax.swing.JCheckBox();
    cbDerivative = new javax.swing.JComboBox<>();
    cbStartCount = new javax.swing.JCheckBox();
    tfStartCount = new javax.swing.JTextField();
    cbDots = new javax.swing.JCheckBox();
    cbValuesPositive = new javax.swing.JCheckBox();
    cbNormalize = new javax.swing.JCheckBox();
    cbNormalizeValue = new javax.swing.JComboBox<>();
    rbPeople = new javax.swing.JRadioButton();
    rbArea = new javax.swing.JRadioButton();
    bPlot = new javax.swing.JButton();
    tfStatus = new javax.swing.JTextField();
    bClear = new javax.swing.JButton();
    cbMA = new javax.swing.JComboBox<>();
    bRe = new javax.swing.JButton();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setTitle("Table");
    setLocationByPlatform(true);

    lCaption.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
    lCaption.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
    lCaption.setText("Table");

    l1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
    l1.setText("Rows :");

    l2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
    l2.setText("Columns :");

    l3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
    l3.setText("Status :");

    l4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
    l4.setText("Selection Row :");

    l5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
    l5.setText("Selection Column :");

    cbURLs.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "WHO Dashboard", "JHU Dashboard", "TR Dashboard", "Worldometer", "IndexMundi", "JHU GitHub" }));

    bOpenURL.setText("Open URL");
    bOpenURL.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        bOpenURLActionPerformed(evt);
      }
    });

    bAbout.setText("About");
    bAbout.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        bAboutActionPerformed(evt);
      }
    });

    bFitWidth.setText("Fit Width");
    bFitWidth.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        bFitWidthActionPerformed(evt);
      }
    });

    tTable.setAutoCreateRowSorter(true);
    tTable.setModel(new javax.swing.table.DefaultTableModel(
      new Object [][]
      {
        {null, null, null, null},
        {null, null, null, null},
        {null, null, null, null},
        {null, null, null, null}
      },
      new String []
      {
        "Title 1", "Title 2", "Title 3", "Title 4"
      }
    ));
    tTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);

    org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, cbHorizontalLines, org.jdesktop.beansbinding.ELProperty.create("${selected}"), tTable, org.jdesktop.beansbinding.BeanProperty.create("showHorizontalLines"));
    bindingGroup.addBinding(binding);
    binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, cbVerticalLines, org.jdesktop.beansbinding.ELProperty.create("${selected}"), tTable, org.jdesktop.beansbinding.BeanProperty.create("showVerticalLines"));
    bindingGroup.addBinding(binding);

    tTable.addMouseListener(new java.awt.event.MouseAdapter()
    {
      public void mouseClicked(java.awt.event.MouseEvent evt)
      {
        tTableMouseClicked(evt);
      }
    });
    sp1.setViewportView(tTable);

    tfRows.setEditable(false);

    tfColumns.setEditable(false);

    tfSelectionRow.setEditable(false);

    tfSelectionColumn.setEditable(false);

    cbHorizontalLines.setSelected(true);
    cbHorizontalLines.setText("Horizontal Lines");

    cbVerticalLines.setSelected(true);
    cbVerticalLines.setText("Vertical Lines");

    cbConfirmed.setSelected(true);
    cbConfirmed.setText("Confirmed");

    cbDeaths.setSelected(true);
    cbDeaths.setText("Deaths");

    cbRecovered.setSelected(true);
    cbRecovered.setText("Recovered");

    cbDerivative.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { " f", " f '", " f ''", " f '''" }));
    cbDerivative.setToolTipText("Plot function or derivative");

    cbStartCount.setForeground(new java.awt.Color(150, 0, 150));
    cbStartCount.setText("Start Count >=");

    tfStartCount.setForeground(new java.awt.Color(150, 0, 150));
    tfStartCount.setHorizontalAlignment(javax.swing.JTextField.CENTER);
    tfStartCount.setText("100.0");

    cbDots.setForeground(new java.awt.Color(150, 0, 0));
    cbDots.setSelected(true);
    cbDots.setText("Add Dots");
    cbDots.setToolTipText("Add day marks on line plots");

    cbValuesPositive.setForeground(new java.awt.Color(0, 150, 0));
    cbValuesPositive.setText("Values >= 1");
    cbValuesPositive.setToolTipText("All values less than 1 will be set to 1 (useful for generating logarithmic plots)");

    cbNormalize.setForeground(java.awt.Color.blue);
    cbNormalize.setText("Normalize per");

    cbNormalizeValue.setForeground(java.awt.Color.blue);
    cbNormalizeValue.setMaximumRowCount(10);
    cbNormalizeValue.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "1", "10", "100", "1,000", "10,000", "100,000", "1,000,000", "10,000,000", "100,000,000", "1,000,000,000" }));
    cbNormalizeValue.setSelectedIndex(3);

    bgNormalize.add(rbPeople);
    rbPeople.setForeground(java.awt.Color.blue);
    rbPeople.setSelected(true);
    rbPeople.setText("<html>People");

    bgNormalize.add(rbArea);
    rbArea.setForeground(java.awt.Color.blue);
    rbArea.setText("<html>Area (Km<small><sup>2 </sup></small>)");

    bPlot.setText("Plot");
    bPlot.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        bPlotActionPerformed(evt);
      }
    });

    tfStatus.setEditable(false);

    bClear.setText("Clear");
    bClear.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        bClearActionPerformed(evt);
      }
    });

    cbMA.setForeground(new java.awt.Color(0, 153, 153));
    cbMA.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "MA 1", "MA 2", "MA 3", "MA 4", "MA 5", "MA 6", "MA 7" }));

    bRe.setForeground(new java.awt.Color(0, 153, 153));
    bRe.setText("<html>R<small>e</small>");
    bRe.setMinimumSize(new java.awt.Dimension(45, 23));
    bRe.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        bReActionPerformed(evt);
      }
    });

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(sp1)
          .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
              .addGroup(layout.createSequentialGroup()
                .addComponent(l2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tfColumns))
              .addGroup(layout.createSequentialGroup()
                .addComponent(l1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tfRows, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
              .addGroup(layout.createSequentialGroup()
                .addComponent(l4)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tfSelectionRow, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
              .addGroup(layout.createSequentialGroup()
                .addComponent(l5)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tfSelectionColumn, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addComponent(cbHorizontalLines)
              .addComponent(cbVerticalLines))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 8, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
              .addComponent(bRe, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
              .addComponent(cbMA, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            .addGap(6, 6, 6)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
              .addComponent(cbConfirmed, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
              .addComponent(cbDots, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(cbValuesPositive)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))
              .addGroup(layout.createSequentialGroup()
                .addComponent(cbRecovered)
                .addGap(8, 8, 8)))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addComponent(cbDeaths, javax.swing.GroupLayout.PREFERRED_SIZE, 85, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addComponent(cbNormalize))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addGroup(layout.createSequentialGroup()
                .addComponent(cbNormalizeValue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(rbPeople, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(rbArea, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
              .addGroup(layout.createSequentialGroup()
                .addComponent(cbDerivative, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(cbStartCount)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(tfStartCount, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)))
            .addGap(10, 10, 10)
            .addComponent(bPlot))
          .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addComponent(l3)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(tfStatus)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(bClear))
          .addGroup(layout.createSequentialGroup()
            .addComponent(cbURLs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(bOpenURL)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(lCaption, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(bAbout)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(bFitWidth)))
        .addContainerGap())
    );

    layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {l1, l2, l3});

    layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cbHorizontalLines, cbVerticalLines});

    layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {l4, l5});

    layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bClear, bPlot});

    layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bAbout, bFitWidth});

    layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bRe, cbMA});

    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
          .addComponent(lCaption)
          .addComponent(bFitWidth)
          .addComponent(bAbout)
          .addComponent(cbURLs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
          .addComponent(bOpenURL, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(sp1, javax.swing.GroupLayout.DEFAULT_SIZE, 446, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
          .addGroup(layout.createSequentialGroup()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(l1)
                .addComponent(tfRows, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(cbHorizontalLines)
                .addComponent(l4)
                .addComponent(tfSelectionRow, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(cbConfirmed)
                .addComponent(cbMA, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
              .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(cbDerivative, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(cbStartCount)
                .addComponent(tfStartCount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(cbDeaths)
                .addComponent(cbRecovered)))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
              .addComponent(l2)
              .addComponent(tfColumns, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addComponent(cbVerticalLines)
              .addComponent(l5)
              .addComponent(tfSelectionColumn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addComponent(cbDots)
              .addComponent(cbValuesPositive)
              .addComponent(rbArea, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addComponent(cbNormalizeValue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addComponent(rbPeople, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addComponent(cbNormalize)
              .addComponent(bRe, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
          .addComponent(bPlot, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
          .addComponent(l3)
          .addComponent(tfStatus, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
          .addComponent(bClear))
        .addContainerGap())
    );

    bindingGroup.bind();

    pack();
  }// </editor-fold>//GEN-END:initComponents

  private void bPlotActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bPlotActionPerformed
  {//GEN-HEADEREND:event_bPlotActionPerformed
    //-----------------------------------------------------------------------------------------------------------------------------------------------

    int [] rows = tTable.getSelectedRows() ;

    if ( rows.length == 0 )  { tfStatus.setText( "No selection" ) ;  return ; }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    if ( ! ( cbConfirmed.isSelected() || cbDeaths.isSelected() || cbRecovered.isSelected() ) )
    {
      tfStatus.setText( "Choose at least one of: Confirmed, Recovered, Deaths" ) ;  return ;
    }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    List< CountryTimeSeries > countries = new ArrayList<>() ;

    for ( int row : rows )
    {
      String            sCountry = tTable.getValueAt( row , tTable.convertColumnIndexToView( 0 ) ).toString() ;
      CountryTimeSeries  country = data.timeSeries.getCountry( sCountry )                                     ;

      if ( country != null )  { countries.add( country ) ; }
    }

    if ( countries.isEmpty() )  { tfStatus.setText( "Time series data for selection(s) is not available" ) ;  return ; }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    String sNormalizeValue = (String) cbNormalizeValue.getSelectedItem()                  ;
    double normalizeValue  = Double.parseDouble( sNormalizeValue.replaceAll( "," , "" ) ) ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    boolean setMinimumStartCount = cbStartCount.isSelected() ;
    double  minimumStartCount    = 0.0                       ;

    try                    { minimumStartCount = Double.parseDouble( tfStartCount.getText().trim() ) ; }
    catch ( Exception e )  { setMinimumStartCount = false ;                                            }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    boolean status = Utilities.plot(
      /* List< CountryTimeSeries> countries                    */ countries                           ,
      /* TimeSeries               timeSeries                   */ data.timeSeries                     ,
      /* Demography               demography                   */ data.demography                     ,
      /* boolean                  includeConfirmed             */ cbConfirmed     .isSelected()       ,
      /* boolean                  includeDeaths                */ cbDeaths        .isSelected()       ,
      /* boolean                  includeRecovered             */ cbRecovered     .isSelected()       ,
      /* int                      numberOfTimesToDifferentiate */ cbDerivative    .getSelectedIndex() ,  // Zero or positive
      /* boolean                  setMinimumStartCount         */ setMinimumStartCount                ,
      /* double                   minimumStartCount            */ minimumStartCount                   ,
      /* boolean                  addDots                      */ cbDots          .isSelected()       ,
      /* boolean                  positiveValues               */ cbValuesPositive.isSelected()       ,
      /* boolean                  normalize                    */ cbNormalize     .isSelected()       ,
      /* double                   normalizeValue               */ normalizeValue                      ,
      /* boolean                  normalizeByPeople            */ rbPeople        .isSelected()       ,
      /* boolean                  normalizeByArea              */ rbArea          .isSelected()       ,
      /* ImageIcon                windowIcon                   */ null                                ,    // Can be null (for random virus icon            )
      /* String                   windowTitle                  */ null                                ,    // Can be null (will be assigned by this function)
      /* int                      windowWidth                  */ 700                                 ,    // Can be 0    (together with windowHeight       )
      /* int                      windowHeight                 */ 300                                 ,    // Can be 0    (together with windowWidth        )
      /* String                   xLabel                       */ null                                ,    // Can be null (will be assigned by this function)
      /* String                   yLabel                       */ null                                ) ;  // Can be null (will be assigned by this function)

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    if ( status == false )
    {
      tfStatus.setText( "Some problem(s) detected, try again" ) ;
    }
    else
    {
      if   ( countries.size() == 1 )  { tfStatus.setText( countries.get( 0 ).name + " time series displayed" ) ; }
      else                            { tfStatus.setText( "Selected"              + " time series displayed" ) ; }
    }

    //-----------------------------------------------------------------------------------------------------------------------------------------------
  }//GEN-LAST:event_bPlotActionPerformed

  private void bClearActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bClearActionPerformed
  {//GEN-HEADEREND:event_bClearActionPerformed
    tTable           .clearSelection() ;
    tfSelectionRow   .setText( "" )    ;
    tfSelectionColumn.setText( "" )    ;
    tfStatus         .setText( "" )    ;
  }//GEN-LAST:event_bClearActionPerformed

  private void tTableMouseClicked(java.awt.event.MouseEvent evt)//GEN-FIRST:event_tTableMouseClicked
  {//GEN-HEADEREND:event_tTableMouseClicked
    updateSelectionCoordinates() ;
  }//GEN-LAST:event_tTableMouseClicked

  private void bOpenURLActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bOpenURLActionPerformed
  {//GEN-HEADEREND:event_bOpenURLActionPerformed
    if ( ! Desktop.isDesktopSupported() )  { tfStatus.setText( "Desktop is not supported" ) ;  return ; }

    Desktop desktop = Desktop.getDesktop() ;

    if ( ! desktop.isSupported( Desktop.Action.BROWSE ) )  { tfStatus.setText( "Browse action is not supported" ) ;  return ; }

    String selection = (String) cbURLs.getSelectedItem() ;
    String url       = null                              ;

    switch ( selection )
    {
      case "WHO Dashboard" : url = "https://covid19.who.int"                                                                           ;  break ;
      case "JHU Dashboard" : url = "https://gisanddata.maps.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6" ;  break ;
      case "TR Dashboard"  : url = "https://corona.cbddo.gov.tr"                                                                       ;  break ;
      case "Worldometer"   : url = "https://www.worldometers.info/coronavirus"                                                         ;  break ;
      case "IndexMundi"    : url = "https://www.indexmundi.com"                                                                        ;  break ;
      case "JHU GitHub"    : url = "https://github.com/CSSEGISandData/COVID-19"                                                        ;  break ;
    }

    if ( url == null )  { tfStatus.setText( "No URL selection" ) ;  return ; }

    try
    {
      URI uri = new URI( url ) ;

      desktop.browse( uri ) ;

      tfStatus.setText( "URL opened" ) ;
    }
    catch ( URISyntaxException e )  { tfStatus.setText( "URL syntax exception" ) ; }
    catch ( IOException        e )  { tfStatus.setText( "IO exception"         ) ; }
  }//GEN-LAST:event_bOpenURLActionPerformed

  private void bFitWidthActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bFitWidthActionPerformed
  {//GEN-HEADEREND:event_bFitWidthActionPerformed
    int totalWidth = 55 ;

    for ( int i = 0 ; i < tTable.getColumnModel().getColumnCount() ; i++ )  { totalWidth += tTable.getColumnModel().getColumn( i ).getWidth() ; }

    Dimension windowSize = this.getSize() ;

    windowSize.width = totalWidth ;

    this.setSize( windowSize ) ;
  }//GEN-LAST:event_bFitWidthActionPerformed

  private void bAboutActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bAboutActionPerformed
  {//GEN-HEADEREND:event_bAboutActionPerformed
    GuiAbout aboutWindow = new GuiAbout( Covid19.version , data.demography.fileVersion ) ;

    aboutWindow.setLocationRelativeTo( null ) ;  // Center on screen
    aboutWindow.setVisible           ( true ) ;
  }//GEN-LAST:event_bAboutActionPerformed

  private void bReActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bReActionPerformed
  {//GEN-HEADEREND:event_bReActionPerformed
    //-----------------------------------------------------------------------------------------------------------------------------------------------

    int [] rows = tTable.getSelectedRows() ;

    if ( rows.length == 0 )  { tfStatus.setText( "No selection" ) ;  return ; }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    List< CountryTimeSeries > countries = new ArrayList<>() ;

    for ( int row : rows )
    {
      String            sCountry = tTable.getValueAt( row , tTable.convertColumnIndexToView( 0 ) ).toString() ;
      CountryTimeSeries  country = data.timeSeries.getCountry( sCountry )                                     ;

      if ( country != null )  { countries.add( country ) ; }
    }

    if ( countries.isEmpty() )  { tfStatus.setText( "Time series data for selection(s) is not available" ) ;  return ; }

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    int movingAverageLength = cbMA.getSelectedIndex() + 1 ;

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    boolean status = Utilities.plotRe(
      /* List< CountryTimeSeries> countries           */ countries                     ,
      /* int                      movingAverageLength */ movingAverageLength           ,
      /* boolean                  addDots             */ cbDots.isSelected()           ,
      /* boolean                  positiveValues      */ cbValuesPositive.isSelected() ,
      /* ImageIcon                windowIcon          */ null                          ,    // Can be null (for random virus icon            )
      /* String                   windowTitle         */ null                          ,    // Can be null (will be assigned by this function)
      /* int                      windowWidth         */ 700                           ,    // Can be 0    (together with windowHeight       )
      /* int                      windowHeight        */ 300                           ,    // Can be 0    (together with windowWidth        )
      /* String                   xLabel              */ null                          ,    // Can be null (will be assigned by this function)
      /* String                   yLabel              */ null                          ) ;  // Can be null (will be assigned by this function)

    //-----------------------------------------------------------------------------------------------------------------------------------------------

    if ( status == false )
    {
      tfStatus.setText( "Some problem(s) detected, try again" ) ;
    }
    else
    {
      if   ( countries.size() == 1 )  { tfStatus.setText( countries.get( 0 ).name + " effective reproduction numbers (Re) displayed" ) ; }
      else                            { tfStatus.setText( "Selected"              + " effective reproduction numbers (Re) displayed" ) ; }
    }

    //-----------------------------------------------------------------------------------------------------------------------------------------------
  }//GEN-LAST:event_bReActionPerformed

  /**
   * @param args the command line arguments
   */
  public static void test_main ( String args[] )
  {
    /* Set the Nimbus look and feel */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
     */
    try
    {
      for ( javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels() )
      {
        if ( "Windows".equals( info.getName() ) )
        {
          javax.swing.UIManager.setLookAndFeel( info.getClassName() );
          break;
        }
      }
    }
    catch ( ClassNotFoundException ex )
    {
      java.util.logging.Logger.getLogger( GuiTable.class.getName() ).log( java.util.logging.Level.SEVERE , null , ex );
    }
    catch ( InstantiationException ex )
    {
      java.util.logging.Logger.getLogger( GuiTable.class.getName() ).log( java.util.logging.Level.SEVERE , null , ex );
    }
    catch ( IllegalAccessException ex )
    {
      java.util.logging.Logger.getLogger( GuiTable.class.getName() ).log( java.util.logging.Level.SEVERE , null , ex );
    }
    catch ( javax.swing.UnsupportedLookAndFeelException ex )
    {
      java.util.logging.Logger.getLogger( GuiTable.class.getName() ).log( java.util.logging.Level.SEVERE , null , ex );
    }
    //</editor-fold>
    //</editor-fold>

    /* Create and display the form */
    java.awt.EventQueue.invokeLater( new Runnable()
    {
      @Override public void run ()
      {
        new GuiTable(null,null,null,null,null).setVisible( true ) ;
      }
    } ) ;
  }

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton bAbout;
  private javax.swing.JButton bClear;
  private javax.swing.JButton bFitWidth;
  private javax.swing.JButton bOpenURL;
  private javax.swing.JButton bPlot;
  private javax.swing.JButton bRe;
  private javax.swing.ButtonGroup bgNormalize;
  private javax.swing.JCheckBox cbConfirmed;
  private javax.swing.JCheckBox cbDeaths;
  private javax.swing.JComboBox<String> cbDerivative;
  private javax.swing.JCheckBox cbDots;
  private javax.swing.JCheckBox cbHorizontalLines;
  private javax.swing.JComboBox<String> cbMA;
  private javax.swing.JCheckBox cbNormalize;
  private javax.swing.JComboBox<String> cbNormalizeValue;
  private javax.swing.JCheckBox cbRecovered;
  private javax.swing.JCheckBox cbStartCount;
  private javax.swing.JComboBox<String> cbURLs;
  private javax.swing.JCheckBox cbValuesPositive;
  private javax.swing.JCheckBox cbVerticalLines;
  private javax.swing.JLabel l1;
  private javax.swing.JLabel l2;
  private javax.swing.JLabel l3;
  private javax.swing.JLabel l4;
  private javax.swing.JLabel l5;
  private javax.swing.JLabel lCaption;
  private javax.swing.JRadioButton rbArea;
  private javax.swing.JRadioButton rbPeople;
  private javax.swing.JScrollPane sp1;
  private javax.swing.JTable tTable;
  private javax.swing.JTextField tfColumns;
  private javax.swing.JTextField tfRows;
  private javax.swing.JTextField tfSelectionColumn;
  private javax.swing.JTextField tfSelectionRow;
  private javax.swing.JTextField tfStartCount;
  private javax.swing.JTextField tfStatus;
  private org.jdesktop.beansbinding.BindingGroup bindingGroup;
  // End of variables declaration//GEN-END:variables
}

//***************************************************************************************************************************************************