/*
 * WEPSDBViewer.java
 *
 * This is the main program for viewing WEPS data in spreadsheet form with multiple crops or operations
 * appearing in the tables.
 *
 * Jim Frankenberger
 * USDA-ARS, West Lafayette IN
 * jrf@purdue.edu
 *
 * Created on July 16, 2004, 8:47 AM
 *
 */
package ex1;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.swing.TFileChooser;
import ex1.database.DataType;
import ex1.database.DatabaseInformation;
import ex1.database.FileDatabaseInformation;
import ex1.database.StartupFrame;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import javax.help.HelpSet;
import javax.swing.ButtonGroup;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.MenuElement;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import usda.weru.util.AboutDialog;

/**
 * This is the main program for viewing WEPS data in spreadsheet form with multiple crops or
 * operations appearing in the tables.
 *
 * @author jrf
 */
public class WEPSDBViewer extends javax.swing.JFrame {

    private static final long serialVersionUID = 1L;

    private WepsTableModel wt;

    /**
     * true if user has selected to view crops
     */
    public boolean viewingCrops;
    private boolean altUnitsFlag; // true if user has selected to view in alt/English units
    private boolean allowEdits; // true if user has selected to allow edits
    private ArrayList<JTable> opTableLinks; // list of all detail tables used in operations
    private ArrayList<OpDetailTableModel> opModelLinks; // list of all detail models used in operations
    private ArrayList<JScrollPane> opScrollLinks; // List of all scroll panes used to host fixed operation tables
    private final CellRenderer myCellRenderer; // cell renderer for main operation and crop table
    private String dbMainDir; // directory where database files start
    private int currentPopRow; // row and column of table where user right-clicked for a popup menu
    private int currentPopCol;
    private int nameColWidth; // width of the name column
    private final int cropTableWidths[]; // initial column widths for crops, needed when we hide/unhide columns for grouping
    private JTable fixedTable; // the seperate table that holds the frozen columns because JTable needs 2 tables to implement this
    // the scrollable table is the jTable1 (either main crops or main operations).
    private FixedTableModel fixedModel;
    private boolean shortNames;
    private int rowHeight;
    private int pixRowHeight;
    private JTable curNameTable; // placeholder for doing promotes in detail tables
    private OpDetailTableModel curNameModel; // placeholder for doing promotes in detail tables
    private final boolean hasFocus;

    /**
     * Creates new form Application
     *
     * @param db
     * @param type
     */
    public WEPSDBViewer(FileDatabaseInformation db, DataType type) {
        initComponents();

        ButtonGroup group = new ButtonGroup();
        group.add(rightTabs);
        group.add(botTabs);

        wt = null;

        allowEdits = false;
        dbMainDir = null;
        currentPopRow = 0;
        shortNames = false;
        rowHeight = 1;
        hasFocus = false;

        Font x = jTable1.getFont();
        String fs = x.getName();
        int sz = x.getSize();

        Font theFont = new Font(fs, Font.PLAIN, sz);
        jTable1.setFont(theFont);
        myCellRenderer = new CellRenderer(theFont, "Main", -1);

        altUnitsFlag = false;

        setMenuItems();
        setPopupMenuItems();

        cropTableWidths = new int[300];

        /*
         * addWindowListener()
         * Handles checking if we should really exit
         */
        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                exit();
            }
        });

        // Set the initial window to be almost full screen
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        dim.height = dim.height - 100;
        dim.width = dim.width - 50;
        setSize(dim);

        viewingCrops = DataType.Crop.equals(type);

        dbMainDir = db.getFile().getAbsolutePath();

        /*
         * addMouseListener()
         * Handles getting the popup displayed if necessary
         */
        jTable1.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent me) {
                showPopup(me);
            }

            @Override
            public void mouseReleased(MouseEvent me) {
                showPopup(me);
            }
            
        });

        // Test where we are starting the program from, if it is in a jar subdirectory then we can
        // find the mcrew config files in ../mcrew_cfg
        // Set the variable needChooser if we need to display a file chooser dialog to locate the weps
        // data and config files. Normally this is not displayed if we start in the right jar directory
        TFile curDir = new TFile(".");
        String path = curDir.getAbsolutePath();
        String cfgpath = path;
        boolean needChooser = false;

        //test the directory, must have an mcrew_cfg directory
        TFile dir = null;
        if (needChooser == false) {
            dir = new TFile(cfgpath);
            TFile testdir = new TFile(dir.getAbsolutePath() + TFile.separator + "mcrew_cfg");
            if (testdir.exists() == false) {
                needChooser = true;
            }
        }
        // Check if the user chose a directory that is really weps and has the mcrew config files
        if (dir != null) {
            // Check that directory mcrew_cfg exists
            TFile testdir = new TFile(dir.getAbsolutePath() + TFile.separator + "mcrew_cfg");
            if (testdir.exists() == false) {
                JOptionPane.showMessageDialog(null,
                        "The subdirectory containing mcrew configuration files was not found at " + testdir.getAbsolutePath()
                        + "\n\nSelect the main install directory for WEPS that has mcrew_cfg as a subdirectory\n\n"
                        + "For example: c:/Program Files/USDA/WEPS/WEPS 1.0 (pre-release 13)",
                        "Error: Mcrew configuration files not found", JOptionPane.ERROR_MESSAGE);
                throw new RuntimeException();
            }

            // Setup the table models, these will read the mcrew config files
            switch(type)
            {
                case Crop:
                        wt = new CropTableModel(dir.getAbsolutePath() + TFile.separator + "mcrew_cfg", dbMainDir);
                        jTabbedPane1.setTitleAt(0, "Crops (All Parms)");
                        addCropTables();
                        break;
                case Operation:
                    wt = new OprnTableModel(dir.getAbsolutePath() + TFile.separator + "mcrew_cfg", dbMainDir);
                    jTabbedPane1.setTitleAt(0, "Operation Files");
                    //ops.dumpActionNames();
                    break;
                case UPGM:
                    wt = new UpgmTableModel(dir.getAbsolutePath() + TFile.separator + "mcrew_cfg", dbMainDir);
                    jTabbedPane1.setTitleAt(0, "UPGM Files");
                    break;
            }

            // attach online help
            setHelpSystem(dir.getAbsolutePath() + TFile.separatorChar + "jar");

            TFile dbDir = new TFile(dbMainDir);

            // this walks the direectory and loads all the data files
            walkDirectory(dbDir, type.getExtension());

            // operations tables are more complicated because some detail table rows are linked
            // to a single file. This occurs if the same process occurs several times in an operation
            if (viewingCrops == false) {
                computeRowMaps();
            }
        }

        if (viewingCrops) {
            // Use a seperate sorter table to handle sorting by clicking on the table header
            TableSorter2 tabSorter = new TableSorter2(wt);
            jTable1.setModel(tabSorter);
            tabSorter.setTableHeader(jTable1.getTableHeader());
            myCellRenderer.setModel(wt);
            setCropColumnWidths(jTable1, false);                 // set all the column widths

            // for a crop viewer turn off the 'check process' menu item on the options menu
            MenuElement items[] = menuBar.getSubElements();
            JMenu jm = (JMenu) items[1];
            JMenuItem jmi = jm.getItem(4);    // short process names
            jmi.setEnabled(false);
            jmi = jm.getItem(5);             // tabs on right
            jmi.setEnabled(false);
            jmi = jm.getItem(6);            // tabs on bottom
            jmi.setEnabled(false);
            jmi = jm.getItem(2);            // check process order
            jmi.setEnabled(false);
            setFixedTable1(wt);

            TableSorter2 tab2 = new TableSorter2(wt);
            tab2.setTableHeader(fixedTable.getTableHeader());
            setCropColumnWidths(fixedTable, true);
            setFixedTable2();
            tabSorter.setAuxModel(fixedModel);
            tab2.setAuxModel(fixedModel);
            tab2.setMainModel(wt);

        } else {
            opModelLinks = new ArrayList<OpDetailTableModel>();   // links to all process models
            opTableLinks = new ArrayList<JTable>();   // links to all process tables
            opScrollLinks = new ArrayList<JScrollPane>();  // scroll panes holding fixed tables
            TableSorter2 tabSorter = new TableSorter2(wt);  // sorter to handle clicking on table header
            jTable1.setModel(tabSorter);
            tabSorter.setTableHeader(jTable1.getTableHeader());
            setFixedTable1(wt);
            setOprnColumnWidths(jTable1, true, false);   // set column widths in main operations table
            setOprnColumnWidths(fixedTable, true, true);   // set column widths in main operations table
            setFixedTable2();

            TableSorter2 tab2 = new TableSorter2(wt);
            tab2.setTableHeader(fixedTable.getTableHeader());
            tabSorter.setAuxModel(fixedModel);
            tab2.setAuxModel(fixedModel);
            tab2.setMainModel(wt);

            myCellRenderer.setModel(wt);
            setupOtherTabs(theFont);   // set all the other detail tables and models for processes

            pixRowHeight = jTable1.getRowHeight();

            MenuElement items[] = menuBar.getSubElements();
            JMenu jm = (JMenu) items[1];
            JMenuItem jmi = jm.getItem(8);    // row height
            jmi.setEnabled(false);
        }

        fixedTable.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent me) {
                showPopup(me);
            }

            @Override
            public void mouseReleased(MouseEvent me) {
                showPopup(me);
            }
        });
        JTableHeader header = jTable1.getTableHeader();
        header.setReorderingAllowed(false);

        /*
         * componentResized()
         * Handles resize of the window, making sure the main table follows it
         */
        ComponentAdapter compAdap = new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent e) {
                Dimension thesize = getSize();
                int h = jScrollPane1.getHorizontalScrollBar().getMaximumSize().height;
                int w = jScrollPane1.getVerticalScrollBar().getMaximumSize().width;
                int m = menuBar.getHeight();

                jTabbedPane1.setSize(thesize.width - w, thesize.height - h - m - 25);
                jScrollPane1.setSize(thesize.width - w, thesize.height - h - m - 25);

                jTable1.setSize(thesize);
                jTable1.invalidate();
                jTable1.repaint();

            }
        };

        addComponentListener(compAdap);

        // If there were any error messages during startup they are archived in the ErrorSink class, this
        // just displays them in one dialog window if there are any. This would be things like mismatched parameter names
        ErrorSink.display();
    }

    private void addCropTables() {
        if (wt instanceof CropTableModel) {
            CropTableModel cropModel = (CropTableModel) wt;
            DispFileParser p = cropModel.getDispFileParser();

            for (int i = 0; i < p.getCategoryCount(); i++) {
                String s = p.getCategoryName(i);
                jTabbedPane1.addTab(s, null);
            }

            pixRowHeight = jTable1.getRowHeight();

            ChangeListener cl = new ChangeListener() {

                @Override
                public void stateChanged(ChangeEvent e) {
                    CropTableModel cropModel = (CropTableModel) wt;
                    JTabbedPane source = (JTabbedPane) e.getSource();
                    //System.out.println("Selected tab is: " + source.getSelectedIndex());
                    int inx = source.getSelectedIndex();
                    if (inx == 0) {
                        // show all the crops
                        for (int i = 3; i < cropModel.getColumnCount(); i++) {
                            unhideColumn(jTable1, i);
                        }
                    } else {
                        // Get lists of visible and hidden columns based on the tab
                        ArrayList<Integer> visible = new ArrayList<Integer>();
                        ArrayList<Integer> hidden = new ArrayList<Integer>();

                        cropModel.getVisibleList(visible, hidden, inx - 1);

                        for (Integer c : hidden) {
                            hideColumn(jTable1, c + 3);
                        }

                        for (Integer c : visible) {
                            unhideColumn(jTable1, c + 3);
                        }

                        System.out.println("Visible count: " + visible.size());
                    }
                    JTableHeader header = jTable1.getTableHeader();
                    if (header != null) {
                        header.invalidate();
                    }

                    jTable1.invalidate();
                    jTable1.repaint();
                    tabs();
                }
            };

            jTabbedPane1.addChangeListener(cl);

        } else {
            System.out.println("expected crop table, but got operations table");
        }
    }
    
    public int getCurrentRow()
    {
        return currentPopRow;
    }

    private void hideColumn(JTable table, int col) {
        TableColumn column = table.getColumnModel().getColumn(col);
        if (column.getMaxWidth() > 0) {
            column.setMinWidth(0);
            column.setMaxWidth(0);
            column.setResizable(false);
        }
    }

    private void unhideColumn(JTable table, int col) {
        TableColumn column = table.getColumnModel().getColumn(col);
        if (column.getMaxWidth() == 0) {
            column.setMaxWidth(cropTableWidths[col] + 500);
            column.setPreferredWidth(cropTableWidths[col]);
            column.setResizable(true);
        }
    }

    /*
     * This loads the approiate Help jar file and attaches an handler to the menu item.
     */
    private void setHelpSystem(String jarDir) {
        URL urls[];
        urls = new URL[1];
        try {
            urls[0] = new URL("file:///./wepsdbviewerhelp.jar");
        } catch (MalformedURLException me) {
            System.out.println("bad url: " + "");
            return;
        }
        URL hsURL;
        try {
            hsURL = new URL("jar:file:/" + jarDir + TFile.separatorChar + 
                    "wepsdbviewer.jar!/ex1/dbviewhelp/WEPSDBViewer.hs");
        } catch (MalformedURLException me) {
            System.out.println("bad url: " + "");
            return;
        }
        String helpHS = "WEPSDBViewer.hs";
        HelpSet hs;
        return;
//        try {
//            hs = new HelpSet(null, hsURL);
//        } catch (HelpSetException ex) {
//            System.out.println("HelpSet " + ex.getMessage());
//            System.out.println("HelpSet " + helpHS + " not found");
//            return;
//        }
//        HelpBroker hb = hs.createHelpBroker();
//        contentsMenuItem.addActionListener(new CSH.DisplayHelpFromSource(hb));
    }

    private boolean isColumnBlank(TableColumn tc) {
        if(tc.getHeaderValue() == null) {
            return true;
        }
        if(tc.getHeaderValue() instanceof String) {
            String header = (String)tc.getHeaderValue();
            if(header.equals("???") || header.equals("?") || header.equals("")) {
                return true;
            }
        }
        return false;
    }
    /*
     * gets the correct row, even if there are duplicate process creating blank rows in the fixed table
     */
    private int logicalRowSetUp( OprnTableModel ops){
        
        int [] rows = new int[1];
        rows[0] = currentPopRow;
         //uses tab table on the right to know which table for getLogicalRows to use
        int tabIndex = jTabbedPane1.getSelectedIndex() -1 ;
        if(tabIndex == -1) {tabIndex = 0;}
        return ops.getLogicalRow(tabIndex, rows[0]);
    }
    
    /*
     * Sets up handlers for all main menu items, except Help which is more complicated and done above
     */
    private void setMenuItems() {
        aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                AboutDialog JAboutDialog1 = new AboutDialog(WEPSDBViewer.this, usda.weru.util.Application.WEPSDBVIEWER);
                JAboutDialog1.setModal(true);
                JAboutDialog1.setVisible(true);
            }
        });

        rowHeightMenuItem.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Integer h = rowHeight;
                String rstr = JOptionPane.showInputDialog("Enter height(1-10) of each row:", h);
                try {
                    if (rstr != null) {
                        rowHeight = Integer.parseInt(rstr);
                    }
                } catch (NumberFormatException ne) {
                    rowHeight = -1;
                }
                if ((rowHeight <= 0) || (rowHeight > 10)) {
                    JOptionPane.showMessageDialog(null,
                            "Invalid row height, must be between 1 and 10.", "Set Row Height", JOptionPane.ERROR_MESSAGE);
                    rowHeight = 1;
                } else {
                    jTable1.setRowHeight(pixRowHeight * rowHeight);
                    fixedTable.setRowHeight(pixRowHeight * rowHeight);

                    computeRowMaps();

                    wt.fireTableDataChanged();

                    updateFixed(true);
                    forceTableUpdates();
                }
            }
        });

        saveMenuItem.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                saveFiles();
            }
        });

        rightTabs.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if ("Process Tabs on Right".equals(e.getActionCommand())) {
                    jTabbedPane1.setTabPlacement(JTabbedPane.RIGHT);
                    jTabbedPane1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
                    jTabbedPane1.revalidate();
                }
            }
        });

        botTabs.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if ("Process Tabs on Bottom".equals(e.getActionCommand())) {
                    jTabbedPane1.setTabPlacement(JTabbedPane.BOTTOM);
                    jTabbedPane1.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
                    jTabbedPane1.revalidate();
                }
            }
        });

        enableEdit.addItemListener(new java.awt.event.ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e != null) {
                    if (e.getStateChange() == ItemEvent.SELECTED) {
                        allowEdits = true;
                        JOptionPane.showMessageDialog(null,
                                "Parameters can now be changed.", "Changes Allowed", JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        allowEdits = false;
                    }

                    wt.setEdit(allowEdits);

                }
            }
        });

        CheckProcesses.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if ( (wt.getType() == WepsTableModel.TableEnum.Operation) || (wt.getType() == WepsTableModel.TableEnum.UPGM) ) {
                    JOptionPane.showMessageDialog(null,
                            "Operation names that have invalid process orders will be highlighted in red.\n",
                            "Check Process Order", JOptionPane.INFORMATION_MESSAGE);
                    wt.checkProcesses(false);
                    wt.fireTableDataChanged();
                    updateFixed(false);
                    forceTableUpdates();
                    WEPSDBViewer.this.revalidate();
                    WEPSDBViewer.this.repaint();
                }

            }
        });

        checkNames.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                String type = wt.getTypeString();
                JOptionPane.showMessageDialog(WEPSDBViewer.this,
                        type + " names that do not match their file names will be highlighted in pink.\n",
                        "Check " + type + " Names", JOptionPane.INFORMATION_MESSAGE);
                wt.checkNames();
                wt.fireTableDataChanged();
                updateFixed(false);
                forceTableUpdates();

                boolean someMismatched = false;
                for (int ix = 0; ix < wt.getRowCount(); ix++) {
                    WepsDBFile file = wt.getXmlFile(ix);
                    if (file != null && file.isNameMismatched()) {
                        someMismatched = true;
                        break;
                    }
                }

                if (someMismatched) {
                    int fix = JOptionPane.showConfirmDialog(WEPSDBViewer.this,
                            "Some " + type + " names do not match their file names.\nWould you like to fix them?",
                            "Fix " + type + " Names", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
                    if (fix == JOptionPane.YES_OPTION) {
                        try {
                            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                            for (int ix = 0; ix < wt.getRowCount(); ix++) {
                                WepsDBFile file = wt.getXmlFile(ix);
                                if (file != null && file.isNameMismatched()) {
                                    wt.rename(wt.getName(ix) + wt.getTypeFileExtension(), ix);
                                }
                            }
                            wt.fireTableDataChanged();
                            updateFixed(false);
                            forceTableUpdates();
                        } finally {
                            setCursor(Cursor.getDefaultCursor());
                        }
                    }
                } else {
                    JOptionPane.showMessageDialog(WEPSDBViewer.this,
                            "All " + type + " names match their files.\n",
                            "Check " + type + " Names", JOptionPane.INFORMATION_MESSAGE);
                }

            }
        });

        CheckData.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                wt.checkProcesses(false);
                wt.checkData = !wt.checkData;
                wt.fireTableDataChanged();
                tabs();
                updateFixed(false);
                forceTableUpdates();
            }
        });

        ShortProcessNames.addItemListener(new java.awt.event.ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e != null) {
                    if (e.getStateChange() == ItemEvent.SELECTED) {
                        shortNames = true;
                    } else {
                        shortNames = false;
                    }

                    if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                        OprnTableModel ops = (OprnTableModel) wt;
                        ops.setShortNames(shortNames);
                        setOprnColumnWidths(jTable1, true, false);
                        for (int i = 0; i < jTable1.getColumnCount(); i++) {

                            TableColumn tc = jTable1.getColumnModel().getColumn(i);

                            tc.setHeaderValue(ops.getColumnName(i));
                        }
                        setOprnColumnWidths(jTable1, true, false);

                        JTableHeader header = jTable1.getTableHeader();
                        if (header != null) {
                            header.invalidate();
                        }

                        jTable1.invalidate();
                        jTable1.repaint();
                        wt = ops;
                    } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                        UpgmTableModel upgm = (UpgmTableModel) wt;
                        upgm.setShortNames(shortNames);
                        setOprnColumnWidths(jTable1, true, false);
                        for (int i = 0; i < jTable1.getColumnCount(); i++) {

                            TableColumn tc = jTable1.getColumnModel().getColumn(i);

                            tc.setHeaderValue(upgm.getColumnName(i));
                        }
                        setOprnColumnWidths(jTable1, true, false);

                        JTableHeader header = jTable1.getTableHeader();
                        if (header != null) {
                            header.invalidate();
                        }

                        jTable1.invalidate();
                        jTable1.repaint();
                        wt = upgm;
                    }
                }
            }
        });

        // Display the process list in a separate window
        PromoteWin.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                NameDlg dlg = new NameDlg(null, true, jTable1.getRowCount());
                WepsDBFile wf;
                for (int i = 0; i < jTable1.getRowCount(); i++) {
                    wf = wt.getXmlFile(i);
                    dlg.addFile(wf);
                }

                dlg.setVisible(true);

                if (dlg.isSelected()) {
                    int rows[] = dlg.getSelected();
                    wt.promote(rows);
                    computeRowMaps();
                    wt.fireTableDataChanged();
                    updateFixed(false);
                    forceTableUpdates();
                    if(curNameModel != null) curNameModel.getFrozenTable().repaint();
                }

            }
        });
        altUnits.addItemListener(new java.awt.event.ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    altUnitsFlag = true;
                } else {
                    altUnitsFlag = false;
                }

                wt.setAltUnits(altUnitsFlag);

                if ( (wt.getType() == WepsTableModel.TableEnum.Operation) || (wt.getType() == WepsTableModel.TableEnum.UPGM) ){
                    // Need to propage this to the detail tables
                    for (int i = 0; i < opModelLinks.size(); i++) {
                        OpDetailTableModel curModel = opModelLinks.get(i);
                        JTable curTable = opTableLinks.get(i);
                        curModel.setAltUnits(altUnitsFlag);
                        int colCnt = curModel.getColumnCount();
                        for (int k = 0; k < colCnt; k++) {
                            TableColumn tc = curTable.getColumnModel().getColumn(k);
                            tc.setHeaderValue(curModel.getColumnName(k));
                        }
                    }
                }

                // This refreshed the current table so the headers match the selection
                if (viewingCrops) {
                    int colCnt = wt.getColumnCount();

                    for (int i = 0; i < colCnt; i++) {

                        TableColumn tc = jTable1.getColumnModel().getColumn(i);

                        tc.setHeaderValue(wt.getColumnName(i));
                    }
                    JTableHeader header = jTable1.getTableHeader();
                    if (header != null) {
                        header.invalidate();
                    }

                    jTable1.invalidate();
                    jTable1.repaint();
                } else {

                    int ind = jTabbedPane1.getSelectedIndex();
                    if (ind > 0) {   // can ignore pane 0 because it is only the process lists
                        // need to get the jtable that is in this view
                        JTable curTable = opTableLinks.get(ind - 1);

                        JTableHeader header = curTable.getTableHeader();
                        if (header != null) {
                            header.invalidate();
                        }

                        curTable.invalidate();
                        curTable.repaint();
                    }
                }
            }
        });
    }

    /**
     * Called to optionally save all the modified files
     *
     */
    public void saveFiles() {
        WepsDbSave wds = new WepsDbSave(wt, this);
        wds.setVisible(true);
    }
    
    public void saveFileSingle()
    {
        WepsDbSaveSingle wds = new WepsDbSaveSingle(wt, this);
        wds.setVisible(true);
    }

    public void scrollToCell(int row, int column) {
        jTable1.scrollRectToVisible(jTable1.getCellRect(row, column, true));
    }

    /*
     * Sets up handlers for the popup menu items. This function is long.
     */
    private void setPopupMenuItems() {

        // process column: delete a process
        DeleteAction.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    //JOptionPane.showMessageDialog(null,"Delete Action","Tag",JOptionPane.INFORMATION_MESSAGE);
                    int mi = currentPopRow;
                    String filename = ops.getFileName(mi);
                    String procName = (String) ops.getValueAt(mi, currentPopCol);
                    Integer it = currentPopCol - 2;
                    String msg = "Do you want to delete the following process from the operation?\n\n"
                            + "Operation: " + filename + "\nProcess: (" + it.toString() + ") " + procName;
                    if (JOptionPane.showConfirmDialog(null, msg,
                            "Delete Process", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                        return;
                    }
                    ops.deleteProcess(mi, currentPopCol - 3);

                    computeRowMaps();
                    ops.fireTableStructureChanged();
                    setOprnColumnWidths(jTable1, true, false);
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    //JOptionPane.showMessageDialog(null,"Delete Action","Tag",JOptionPane.INFORMATION_MESSAGE);
                    int mi = currentPopRow;
                    String filename = upgm.getFileName(mi);
                    String procName = (String) upgm.getValueAt(mi, currentPopCol);
                    Integer it = currentPopCol - 2;
                    String msg = "Do you want to delete the following process from the UPGM file?\n\n"
                            + "File: " + filename + "\nProcess: (" + it.toString() + ") " + procName;
                    if (JOptionPane.showConfirmDialog(null, msg,
                            "Delete Process", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                        return;
                    }
                    upgm.deleteProcess(mi, currentPopCol - 3);

                    computeRowMaps();
                    upgm.fireTableStructureChanged();
                    setOprnColumnWidths(jTable1, true, false);
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });

        // process column: subtitute a process
        ChangeAction.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    // Need to select the new process from a list
                    int count = ops.getActionNameCount();
                    String[] allActions = new String[count];
                    for (int i = 0; i < count; i++) {
                        allActions[i] = ops.getFullActionName(i);
                    }
                    Object selectedValue = JOptionPane.showInputDialog(null,
                            "Select a New Process:", "WEPS Processes",
                            JOptionPane.OK_CANCEL_OPTION, null, allActions, allActions[0]);
                    if (selectedValue != null) {
                        int mi = currentPopRow;
                        String filename = ops.getFileName(mi);
                        String procName = (String) ops.getValueAt(mi, currentPopCol);
                        if (procName.equals(selectedValue)) {
                            JOptionPane.showMessageDialog(null, "Processes are the same",
                                    "Nothing to do", JOptionPane.INFORMATION_MESSAGE);
                            return;
                        }

                        String msg = "Do you want to change the following process in the operation?\n\nOperation: "
                                + filename + "\nOld Process: "
                                + procName + "\nNew Process: " + (String) selectedValue;
                        if (JOptionPane.showConfirmDialog(null, msg,
                                "Change Process", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                            return;
                        }

                        int procIndex = 0;

                        for (int i = 0; i < count; i++) {
                            if (allActions[i].equals(selectedValue)) {
                                procIndex = i;
                            }
                        }

                        ops.changeProcess(mi, currentPopCol - 3, procIndex);
                        computeRowMaps();
                        ops.fireTableDataChanged();
                        forceTableUpdates();
                        wt = ops;
                    }
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    // Need to select the new process from a list
                    int count = upgm.getActionNameCount();
                    String[] allActions = new String[count];
                    for (int i = 0; i < count; i++) {
                        allActions[i] = upgm.getFullActionName(i);
                    }
                    Object selectedValue = JOptionPane.showInputDialog(null,
                            "Select a New Process:", "WEPS Processes",
                            JOptionPane.OK_CANCEL_OPTION, null, allActions, allActions[0]);
                    if (selectedValue != null) {
                        int mi = currentPopRow;
                        String filename = upgm.getFileName(mi);
                        String procName = (String) upgm.getValueAt(mi, currentPopCol);
                        if (procName.equals(selectedValue)) {
                            JOptionPane.showMessageDialog(null, "Processes are the same",
                                    "Nothing to do", JOptionPane.INFORMATION_MESSAGE);
                            return;
                        }

                        String msg = "Do you want to change the following process in the operation?\n\nOperation: "
                                + filename + "\nOld Process: "
                                + procName + "\nNew Process: " + (String) selectedValue;
                        if (JOptionPane.showConfirmDialog(null, msg,
                                "Change Process", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                            return;
                        }

                        int procIndex = 0;

                        for (int i = 0; i < count; i++) {
                            if (allActions[i].equals(selectedValue)) {
                                procIndex = i;
                            }
                        }

                        upgm.changeProcess(mi, currentPopCol - 3, procIndex);
                        computeRowMaps();
                        upgm.fireTableDataChanged();
                        forceTableUpdates();
                        wt = upgm;
                    }
                }
            }
        });

        // process column: insert a new process before selected one
        InsertBefore.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    insertAction(true);
                    computeRowMaps();
                    ops.fireTableStructureChanged();
                    setOprnColumnWidths(jTable1, true, false);
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    insertAction(true);
                    computeRowMaps();
                    upgm.fireTableStructureChanged();
                    setOprnColumnWidths(jTable1, true, false);
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });

        // process column: insert a new process after selected one
        InsertAfter.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    insertAction(false);
                    computeRowMaps();
                    ops.fireTableStructureChanged();
                    setOprnColumnWidths(jTable1, true, false);
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    insertAction(false);
                    computeRowMaps();
                    upgm.fireTableStructureChanged();
                    setOprnColumnWidths(jTable1, true, false);
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });

        // process column: move the selected process to the left
        Left1.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    ops.moveProcess(currentPopRow, currentPopCol - 3, false);

                    computeRowMaps();
                    ops.fireTableDataChanged();
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    upgm.moveProcess(currentPopRow, currentPopCol - 3, false);

                    computeRowMaps();
                    upgm.fireTableDataChanged();
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });

        // process column: move the selected process to the right
        Right1.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    ops.moveProcess(currentPopRow, currentPopCol - 3, true);

                    computeRowMaps();
                    ops.fireTableDataChanged();
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    upgm.moveProcess(currentPopRow, currentPopCol - 3, true);

                    computeRowMaps();
                    upgm.fireTableDataChanged();
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });

        // The following are for the operation name column popup
        // Add a new blank operation
        BlankOperation.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    String oname;
                    TFileChooser fileChooser = new TFileChooser();
                    fileChooser.setCurrentDirectory(new TFile(dbMainDir));
                    if (fileChooser.showOpenDialog(null) != TFileChooser.CANCEL_OPTION) {
                        oname = fileChooser.getSelectedFile().getAbsolutePath();
                        oname = checkName(oname, ".oprn");
                        ops.addBlankOperation(oname);
                        computeRowMaps();
                        ops.fireTableRowsInserted(ops.getRowCount(), ops.getRowCount());
                        updateFixed(true);
                        forceTableUpdates();
                    }
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    String oname;
                    TFileChooser fileChooser = new TFileChooser();
                    fileChooser.setCurrentDirectory(new TFile(dbMainDir));
                    if (fileChooser.showOpenDialog(null) != TFileChooser.CANCEL_OPTION) {
                        oname = fileChooser.getSelectedFile().getAbsolutePath();
                        oname = checkName(oname, ".upgm");

                        upgm.addBlankOperation(oname);
                        computeRowMaps();
                        upgm.fireTableRowsInserted(upgm.getRowCount(), upgm.getRowCount());
                        updateFixed(true);
                        forceTableUpdates();
                    }
                    wt = upgm;
                }
            }
        });

        // Display the process list in a separate window
        AltViewOperation.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    int logicalRow = logicalRowSetUp(ops);
                   
                    String name = ops.getFileName(logicalRow);
                    WepsDBFile wf = ops.getFile(logicalRow);
                    if (wf != null) {

                        AltView2Dlg dlg = new AltView2Dlg(null, false, name);

                        int count = wf.getActionCount();
                        for (int i = 0; i < count; i++) {
                            dlg.addItem(wf.getActionName(i));
                        }

                        dlg.setModel();
                        dlg.setVisible(true);
                    }
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    int mi = currentPopRow;
                    String name = upgm.getFileName(mi);
                    WepsDBFile wf = upgm.getFile(mi);
                    if (wf != null) {

                        AltView2Dlg dlg = new AltView2Dlg(null, false, name);

                        int count = wf.getActionCount();
                        for (int i = 0; i < count; i++) {
                            dlg.addItem(wf.getActionName(i));
                        }

                        dlg.setModel();
                        dlg.setVisible(true);
                    }
                    wt = upgm;
                }
            }
        });

        // make a copy of this operation
        CloneOperation.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    int logicalRow = logicalRowSetUp(ops);
                    String oname;
                    TFileChooser fileChooser = new TFileChooser();
                    fileChooser.setCurrentDirectory(new TFile(dbMainDir));
                    if (fileChooser.showOpenDialog(null) != TFileChooser.CANCEL_OPTION) {
                        oname = fileChooser.getSelectedFile().getAbsolutePath();
                        oname = checkName(oname, ".oprn");

                        ops.copy(oname, logicalRow);

                        computeRowMaps();
                        ops.fireTableDataChanged();
                        updateFixed(true);
                        forceTableUpdates();

                    }
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    String oname;
                    TFileChooser fileChooser = new TFileChooser();
                    fileChooser.setCurrentDirectory(new TFile(dbMainDir));
                    if (fileChooser.showOpenDialog(null) != TFileChooser.CANCEL_OPTION) {
                        oname = fileChooser.getSelectedFile().getAbsolutePath();
                        oname = checkName(oname, ".upgm");

                        upgm.copy(oname, currentPopRow);

                        computeRowMaps();
                        upgm.fireTableDataChanged();
                        updateFixed(true);
                        forceTableUpdates();

                    }
                    wt = upgm;
                }
            }
        });

        // Save this operation
        SaveOperation.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                saveFileSingle();
            }
        });

        // Rename this operation
        RenameOperation.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    int logicalRow = logicalRowSetUp(ops);
                    String oname;
                    oname = JOptionPane.showInputDialog("Enter a new name for this operation:                    ",
                            ops.getName(logicalRow));
                    if (oname != null) {
                        oname = checkName(oname, ".oprn");
                        ops.rename(oname, logicalRow);
                        computeRowMaps();
                        ops.fireTableDataChanged();
                        updateFixed(false);
                        forceTableUpdates();

                    }
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    String oname;
                    oname = JOptionPane.showInputDialog("Enter a new name for this operation:                    ",
                            upgm.getName(currentPopRow));
                    if (oname != null) {
                        oname = checkName(oname, ".upgm");

                        upgm.rename(oname, currentPopRow);

                        computeRowMaps();
                        upgm.fireTableDataChanged();
                        updateFixed(false);
                        forceTableUpdates();

                    }
                    wt = upgm;
                }
            }
        });

        // Delete this operation
        DeleteOperation.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    int logicalRow = logicalRowSetUp(ops);
                    String filename = ops.getFilePath(logicalRow);
                    String msg = "Do you want to delete the following file?\n\n" + filename;
                    if (JOptionPane.showConfirmDialog(null, msg, "Delete File?", JOptionPane.YES_NO_OPTION)
                            == JOptionPane.NO_OPTION) {
                        return;
                    }

                    if (ops.delete(logicalRow)) {
                        JOptionPane.showMessageDialog(null, "File Deleted", "File Deleted", JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(null,
                                "Could not delete file", "File not deleted", JOptionPane.ERROR_MESSAGE);
                    }

                    computeRowMaps();
                    ops.fireTableDataChanged();
                    updateFixed(true);
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    String filename = upgm.getFilePath(currentPopRow);
                    String msg = "Do you want to delete the following file?\n\n" + filename;
                    if (JOptionPane.showConfirmDialog(null, msg, "Delete File?", JOptionPane.YES_NO_OPTION)
                            == JOptionPane.NO_OPTION) {
                        return;
                    }

                    if (upgm.delete(currentPopRow)) {
                        JOptionPane.showMessageDialog(null, "File Deleted", "File Deleted", JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(null,
                                "Could not delete file", "File not deleted", JOptionPane.ERROR_MESSAGE);
                    }

                    computeRowMaps();
                    upgm.fireTableDataChanged();
                    updateFixed(true);
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });

        // Set the main type for this operation
        SetOperation.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    insertFirstAction();

                    computeRowMaps();
                    ops.fireTableDataChanged();
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    insertFirstAction();

                    computeRowMaps();
                    upgm.fireTableDataChanged();
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });

        // Check process order for this operation
        VerifyProcesses.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    if (ops.checkOneOperation(currentPopRow, true)) {
                        JOptionPane.showMessageDialog(null, "Process Order is Correct",
                                "Verify Process Order", JOptionPane.INFORMATION_MESSAGE);
                    }
                    ops.fireTableDataChanged();
                    updateFixed(false);
                    forceTableUpdates();
                    wt = ops;
                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    if (upgm.checkOneOperation(currentPopRow, true)) {
                        JOptionPane.showMessageDialog(null, "Process Order is Correct",
                                "Verify Process Order", JOptionPane.INFORMATION_MESSAGE);
                    }
                    upgm.fireTableDataChanged();
                    updateFixed(false);
                    forceTableUpdates();
                    wt = upgm;
                }
            }
        });
        // premote this operation
        PromoteOp.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (wt.getType() == WepsTableModel.TableEnum.Operation) {
                    OprnTableModel ops = (OprnTableModel) wt;
                    int [] rows = new int[1];
                    rows[0] = logicalRowSetUp(ops);
                    ops.promote(rows);
                    computeRowMaps();
                    ops.fireTableDataChanged();
                    updateFixed(false);
                    forceTableUpdates();
                    if(curNameModel != null) curNameModel.getFrozenTable().repaint();
                    wt = ops;

                } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
                    UpgmTableModel upgm = (UpgmTableModel) wt;
                    int rows[] = fixedTable.getSelectedRows();
                    if (curNameTable != fixedTable) {
                        // need to get "logical" rows
                        rows = curNameTable.getSelectedRows();
                        if (curNameModel != null) {
                            for (int i = 0; i < rows.length; i++) {
                                rows[i] = upgm.getLogicalRow(curNameModel.getModelTab(), rows[i]);
                            }
                        }
                    }
                    upgm.promote(rows);
                    computeRowMaps();
                    upgm.fireTableDataChanged();
                    updateFixed(false);
                    forceTableUpdates();
                    if(curNameModel != null) curNameModel.getFrozenTable().repaint();
                    wt = upgm;
                }
            }
        
        });
        // The following handlers are for the crop viewer

        // Make a copy of this crop
        CloneCrop.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                String oname;
                TFileChooser fileChooser = new TFileChooser();
                fileChooser.setCurrentDirectory(new TFile(dbMainDir));
                if (fileChooser.showOpenDialog(null) != TFileChooser.CANCEL_OPTION) {
                    oname = fileChooser.getSelectedFile().getAbsolutePath();
                    oname = checkName(oname, ".crop");

                    wt.copy(oname, currentPopRow);

                    computeRowMaps();
                    wt.fireTableDataChanged();
                    updateFixed(true);

                    forceTableUpdates();

                }
            }
        });

        // Save this crop file
        SaveCrop.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                saveFileSingle();
            }
        });
        Promote.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int rows[] = fixedTable.getSelectedRows();
                //JOptionPane.showMessageDialog(null,"Promote",Integer.toString(rows.length),JOptionPane.INFORMATION_MESSAGE);
                wt.promote(rows);
                computeRowMaps();
                wt.fireTableDataChanged();
                updateFixed(false);
                forceTableUpdates();
                if(curNameModel != null) curNameModel.getFrozenTable().repaint();

            }
        });

        /* Does not seem to work
         SetRowHeightCrop.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
         int crowHeight = 1;
         String rstr = JOptionPane.showInputDialog("Enter height(1-10) for row:");
         try {
         if (rstr != null)
         crowHeight = Integer.parseInt(rstr);
         } catch (NumberFormatException ne) {
         crowHeight = -1;
         }
         if (crowHeight != -1) {
         int rows[] = fixedTable.getSelectedRows();
         fixedTable.setRowHeight(rows[0],crowHeight*pixRowHeight);
         jTable1.setRowHeight(rows[0],crowHeight*pixRowHeight);
         computeRowMaps();
         ct.fireTableDataChanged();
         updateFixed(true);
         forceTableUpdates();
         }
         }
         });
         */
        // Rename this crop
        RenameCrop.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                String oname;
                oname = JOptionPane.showInputDialog("Enter a new name for this crop:", wt.getName(currentPopRow));
                if (oname != null) {
                    oname = checkName(oname, ".crop");

                    wt.rename(oname, currentPopRow);

                    computeRowMaps();
                    wt.fireTableDataChanged();
                    updateFixed(false);
                    forceTableUpdates();

                }
            }
        });

        // Delete this crop file
        DeleteCrop.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                String filename = wt.getFilePath(currentPopRow);
                String msg = "Do you want to delete the following file?\n\n" + filename;
                if (JOptionPane.showConfirmDialog(null, msg, "Delete File?",
                        JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                    return;
                }

                if (wt.delete(currentPopRow)) {
                    JOptionPane.showMessageDialog(null, "File Deleted", "File Deleted", JOptionPane.INFORMATION_MESSAGE);
                } else {
                    JOptionPane.showMessageDialog(null, "Could not delete file",
                            "File not deleted", JOptionPane.ERROR_MESSAGE);
                }

                computeRowMaps();
                wt.fireTableDataChanged();
                updateFixed(true);
                forceTableUpdates();
            }
        });
    }

    /**
     *
     * This function will check the ending part of the crop and operation names and prevent double
     * extensions or append an extension if one is not given.
     */
    private String checkName(String name, String extType) {
        if (name.length() > 5) {
            String ext = name.substring(name.length() - 5, name.length());
            if (ext.equalsIgnoreCase(extType) == false) {
                name = name + extType;
            }
        } else {
            name += extType;
        }

        return name;
    }

    /*
     * This only applies to the operation process tables. If anything changed on the main operations table the
     * one or more of the detail tables would probably change.
     */
    private void forceTableUpdates() {
        if (viewingCrops) {
            return;
        }
        for (OpDetailTableModel t : opModelLinks) {
            t.fireTableDataChanged();
            t.fireTableRowsUpdated(0, t.getRowCount());
        }
    }

    /*
     * Display a list of processes and allow the user to select one to insert either before or
     * after the current process.
     */
    private void insertAction(boolean before) {
        if (wt.getType() == WepsTableModel.TableEnum.Operation) {
            OprnTableModel ops = (OprnTableModel) wt;
            int count = ops.getActionNameCount();
            String[] allActions = new String[count];
            for (int i = 0; i < count; i++) {
                allActions[i] = ops.getFullActionName(i);
            }

            Object selectedValue = JOptionPane.showInputDialog(null,
                    "Select a New Process:", "WEPS Processes", JOptionPane.OK_CANCEL_OPTION,
                    null, allActions, allActions[0]);
            if (selectedValue != null) {
                int procIndex = 0;

                for (int i = 0; i < count; i++) {
                    if (allActions[i].equals(selectedValue)) {
                        procIndex = i;
                    }
                }

                ops.insertProcess(currentPopRow, currentPopCol - 3, procIndex, before);
            }
            wt = ops;
        } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
            UpgmTableModel upgm = (UpgmTableModel) wt;
            int count = upgm.getActionNameCount();
            String[] allActions = new String[count];
            for (int i = 0; i < count; i++) {
                allActions[i] = upgm.getFullActionName(i);
            }

            Object selectedValue = JOptionPane.showInputDialog(null,
                    "Select a New Process:", "WEPS Processes", JOptionPane.OK_CANCEL_OPTION,
                    null, allActions, allActions[0]);
            if (selectedValue != null) {
                int procIndex = 0;

                for (int i = 0; i < count; i++) {
                    if (allActions[i].equals(selectedValue)) {
                        procIndex = i;
                    }
                }

                upgm.insertProcess(currentPopRow, currentPopCol - 3, procIndex, before);
            }
            wt = upgm;
        }
    }

    /*
     * Displays a list of only the main operation types and allows the first process to be set to this
     */
    private void insertFirstAction() {
        if (wt.getType() == WepsTableModel.TableEnum.Operation) {
            OprnTableModel ops = (OprnTableModel) wt;
            int count = ops.getActionNameCount();
            int count2 = 0;
            String[] allActions = new String[count];
            for (int i = 0; i < count; i++) {
                String a = ops.getFullActionName(i);
                if (a.startsWith("O")) {
                    allActions[i] = a;
                    count2++;
                }
            }

            Object selectedValue = JOptionPane.showInputDialog(null,
                    "Select a New Operation Type:", "WEPS Operation Types", JOptionPane.OK_CANCEL_OPTION,
                    null, allActions, allActions[0]);
            if (selectedValue != null) {
                int procIndex = 0;

                for (int i = 0; i < count2; i++) {
                    if (allActions[i].equals(selectedValue)) {
                        procIndex = i;
                        break;
                    }
                }

                ops.insertFirstProcess(currentPopRow, 0, procIndex, true);
            }
            wt = ops;
        } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
            UpgmTableModel upgm = (UpgmTableModel) wt;
            int count = upgm.getActionNameCount();
            int count2 = 0;
            String[] allActions = new String[count];
            for (int i = 0; i < count; i++) {
                String a = upgm.getFullActionName(i);
                if ( a.startsWith("P100") ) {
                    allActions[i] = a;
                    count2++;
                }
            }

            Object selectedValue = JOptionPane.showInputDialog(null,
                    "Select a New Operation Type:", "WEPS Operation Types", JOptionPane.OK_CANCEL_OPTION,
                    null, allActions, allActions[0]);
            if (selectedValue != null) {
                int procIndex = 0;

                for (int i = 0; i < count2; i++) {
                    if (allActions[i].equals(selectedValue)) {
                        procIndex = i;
                        break;
                    }
                }

                upgm.insertFirstProcess(currentPopRow, 0, procIndex, true);
            }
            wt = upgm;
        }
    }

    /*
     * Any time the row order changes this should be called to make sure the detail operation tables
     * are in sync.
     */
    private void computeRowMaps() {
        if (viewingCrops) {
            return;
        }
        if (wt.getType() == WepsTableModel.TableEnum.Operation) {
            OprnTableModel ops = (OprnTableModel) wt;
            ops.computeRowMaps();
            wt = ops;
        } else if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
            UpgmTableModel upgm = (UpgmTableModel) wt;
            upgm.computeRowMaps();
            wt = upgm;
        }
    }

    /*
     * This function gets called when the user right-clicks. There are 3 menus that could be displayed:
     *    - crops - handled over the crop name
     *    - operations - handled over an operation name
     *    - process - handled over an operation process
     *
     */
    private void showPopup(MouseEvent me) {

        if (viewingCrops) {
            if ((JTable) me.getSource() == fixedTable) {

                curNameTable = fixedTable;
                curNameModel = null;

                if (cropNamePopup.isPopupTrigger(me)) {
                    // righ-click is over a crop name
                    Point p = me.getPoint();
                    int row = fixedTable.rowAtPoint(p);
                    int col = fixedTable.columnAtPoint(p);
                    currentPopRow = row;
                    currentPopCol = col;
                    MenuElement items[] = cropNamePopup.getSubElements();
                    if (row != -1 && col == 1) {
                        boolean enab;
                        enab = !wt.isReadOnly(row);
                        int rows[] = fixedTable.getSelectedRows();

                        // for readonly limit some of the choices
                        ((JMenuItem) items[1]).setEnabled(enab);
                        ((JMenuItem) items[2]).setEnabled(enab);
                        ((JMenuItem) items[3]).setEnabled(enab);

                        if (rows.length > 1) {
                            // multiple rows selected, some are not legal
                            ((JMenuItem) items[0]).setEnabled(false);
                            ((JMenuItem) items[1]).setEnabled(false);
                            ((JMenuItem) items[2]).setEnabled(false);
                            ((JMenuItem) items[3]).setEnabled(false);
                        } else {
                            ((JMenuItem) items[0]).setEnabled(true);
                            // force row to be selected
                            fixedTable.setRowSelectionInterval(row, row);
                        }

                        // display the menu
                        cropNamePopup.show(fixedTable, p.x, p.y);
                    }
                }
            } else { // not the fixed table, variable columns for parameters
                // notes field?
                if (me.isPopupTrigger()) {
                    Point p = me.getPoint();
                    int row = jTable1.rowAtPoint(p);
                    int col = jTable1.columnAtPoint(p);
                    if (wt.getColumnType(col) == ParamDef.ColumnType.STRING) {
                        String str = (String) wt.getValueAt(row, col);
                        // force row to be selected
                        jTable1.setRowSelectionInterval(row, row);
                        fixedTable.setRowSelectionInterval(row, row);
                        String nprompt = "";
                        String title = "";
                        String recName = wt.getFileName(row);
                        if (allowEdits) {
                            nprompt = "Enter new text";
                            title = "Notes Editor - [" + recName + "]";
                        } else {
                            title = "Notes Read Only - [" + recName + "]";
                        }

                        String nf = NotesJOptionPane.showInputDialog(
                                title, nprompt, str, allowEdits, viewingCrops, recName);
                        if ((allowEdits) && (nf != null)) {
                            wt.setValueAt(nf, row, col);

                            wt.fireTableDataChanged();
                        }
                    }
                }
            }

        } else {
            showPopupOperations(me);
        }

    }

    private void showPopupOperations(MouseEvent me) {
        //if (!oprnPopup.isPopupTrigger(me)) {
            //return;
        //}

        if (((JTable) me.getSource() == fixedTable) || ((JTable) me.getSource() == jTable1) || 
                ((JTable) me.getSource() instanceof OpDetailTableModel.FrozenTable)) {
            // fixed table is the main table on the first screen, jtable1 is process name table
            curNameTable = fixedTable;
            curNameModel = null;

            if (oprnPopup.isPopupTrigger(me)) {
                Point p = me.getPoint();
                int row, col;
                if ((JTable) me.getSource() == fixedTable) {
                    row = fixedTable.rowAtPoint(p);
                    col = fixedTable.columnAtPoint(p);
                } else if((JTable) me.getSource() == jTable1) {
                    row = jTable1.rowAtPoint(p);
                    col = jTable1.columnAtPoint(p);
                }
                else if(((JTable) me.getSource() instanceof OpDetailTableModel.FrozenTable))
                {
                    row = ((JTable) me.getSource()).rowAtPoint(p);
                    col = ((JTable) me.getSource()).columnAtPoint(p);
                }
                else
                {
                    row = col = 1;
                }
                currentPopRow = row;
                currentPopCol = col;

                String pstr = (String) wt.getValueAt(row, col);
                boolean enab;
                enab = !wt.isReadOnly(row);
                if (row != -1 && col >= 3) {
                    //for operation files page, open name pop up if cell is empty and process manipulator if it is populated
                    if (pstr.startsWith("--")) { 
                        // -- in process entry indicates nothing there
                    
                            //currentPopRow = row;
                            //currentPopCol = col;
                            
                            enab = !wt.isReadOnly(row);

                            int rows[] = jTable1.getSelectedRows();

                            // adjust some menu elements depending on readonly status
                            MenuElement items[] = oprnNamePopup.getSubElements();
                            if (rows.length > 1) {
                                // multiple rows selected, some are not legal
                                for (int i = 0; i < 7; i++) {
                                    ((JMenuItem) items[i]).setEnabled(false);
                                }

                            } else {
                                ((JMenuItem) items[2]).setEnabled(enab);
                                ((JMenuItem) items[3]).setEnabled(enab);
                                ((JMenuItem) items[5]).setEnabled(enab);
                                ((JMenuItem) items[6]).setEnabled(enab);
                                ((JMenuItem) items[0]).setEnabled(true);
                                ((JMenuItem) items[1]).setEnabled(true);
                                ((JMenuItem) items[4]).setEnabled(enab);
                                // force row to be selected
                                jTable1.setRowSelectionInterval(row, row);
                            }

                            ((JMenuItem) items[7]).setEnabled(true);
                            ((JMenuItem) items[8]).setEnabled(true);

                            oprnNamePopup.show(jTable1, p.x, p.y);
                        
                     
                    } else {
                        oprnPopup.show(jTable1, p.x, p.y);
                    }    // popup for process type
             } else {
                   
                    // popup for name column
                    if (row != -1 && col == 1) {
                        // adjust some menu elements depending on readonly status
                        MenuElement items[] = oprnNamePopup.getSubElements();

                        int rows[] = fixedTable.getSelectedRows();

                        if (rows.length > 1) {
                            // multiple rows selected, some are not legal
                            for (int i = 0; i < 7; i++) {
                                ((JMenuItem) items[i]).setEnabled(false);
                            }

                        } else {
                            ((JMenuItem) items[2]).setEnabled(enab);
                            ((JMenuItem) items[3]).setEnabled(enab);
                            ((JMenuItem) items[5]).setEnabled(enab);
                            ((JMenuItem) items[6]).setEnabled(enab);
                            ((JMenuItem) items[0]).setEnabled(true);
                            ((JMenuItem) items[1]).setEnabled(true);
                            ((JMenuItem) items[4]).setEnabled(enab);
                            // force row to be selected
                            //fixedTable.setRowSelectionInterval(row, row);
                        }
                        ((JMenuItem) items[7]).setEnabled(true);
                        ((JMenuItem) items[8]).setEnabled(true);
                        if ((JTable) me.getSource() == fixedTable) oprnNamePopup.show(fixedTable, p.x, p.y);   
                        else if(((JTable) me.getSource() instanceof OpDetailTableModel.FrozenTable)) 
                            oprnNamePopup.show(((JTable)me.getSource()), p.x, p.y);
                    }
               }
            } // endif ispopup
        } else {

            // not from a fixed table, must be from a parameter table, check if this is on the main screen
            JTable optable = (JTable) me.getSource();
            Point p = me.getPoint();
            int row = optable.rowAtPoint(p);
            int col = optable.columnAtPoint(p);
            TableSorter2 ts = (TableSorter2) optable.getModel();
            TableModel t = ts.getTableModel();
            OpDetailTableModel detail = (OpDetailTableModel) t;
            int lrow = wt.getLogicalRow(detail.getModelTab(), row);

            curNameTable = optable;
            curNameModel = detail;

//            if (row != -1 && col == 1) {
//                currentPopRow = lrow;
//                currentPopCol = col;
//                boolean enab;
//                enab = !wt.isReadOnly(lrow);
//
//                int rows[] = optable.getSelectedRows();
//
//                // adjust some menu elements depending on readonly status
//                MenuElement items[] = oprnNamePopup.getSubElements();
//                if (rows.length > 1) {
//                    // multiple rows selected, some are not legal
//                    for (int i = 0; i < 7; i++) {
//                        ((JMenuItem) items[i]).setEnabled(false);
//                    }
//
//                } else {
//                    ((JMenuItem) items[2]).setEnabled(enab);
//                    ((JMenuItem) items[3]).setEnabled(enab);
//                    ((JMenuItem) items[5]).setEnabled(enab);
//                    ((JMenuItem) items[6]).setEnabled(enab);
//                    ((JMenuItem) items[0]).setEnabled(true);
//                    ((JMenuItem) items[1]).setEnabled(true);
//                    ((JMenuItem) items[4]).setEnabled(enab);
//                    // force row to be selected
//                    optable.setRowSelectionInterval(row, row);
//                }
//
//                ((JMenuItem) items[7]).setEnabled(true);
//                ((JMenuItem) items[8]).setEnabled(true);
//
//                oprnNamePopup.show(optable, p.x, p.y);
//            }
            if ((detail.getColumnType(col) == ParamDef.ColumnType.STRING)) {

               // if (me.isPopupTrigger()) {
                    // force row to be selected
                    optable.setRowSelectionInterval(row, row);

                    String str = (String) detail.getValueAt(row, col);
                    String nprompt = "";
                    String title = "";
                    String recName = wt.getFileName(lrow);
                    if(str != "--"){
                        if (allowEdits) {
                            nprompt = "Enter new text";
                            title = "Notes Editor - [" + recName + "]";
                        } else {
                            title = "Notes Read Only - [" + recName + "]";
                        }
                    
                    //System.out.println("Column name: " + detail.getColumnName(col));
                        if(!detail.getColumnName(col).equals("Fuel")) {
                            String nf = NotesJOptionPane.showInputDialog(
                                    title, nprompt, str, allowEdits, viewingCrops, recName);
                            if ((allowEdits) && (nf != null)) {
                                detail.setValueAt(nf, row, col);
                                detail.fireTableDataChanged();
                            }
                        }
                    }
              // }
            } // end detail != null
        } // end is fixed table or jtable1

    }
    
 

    private void setFixedTable1(AbstractTableModel at) {
        fixedModel = new FixedTableModel(at);
        fixedTable = new JTable(fixedModel);
        ListSelectionModel lsm = fixedTable.getSelectionModel();
        fixedTable.getTableHeader().setResizingAllowed(true);

        lsm.addListSelectionListener(new SelectionListener(true));

        lsm = jTable1.getSelectionModel();
        lsm.addListSelectionListener(new SelectionListener(false));
        fixedTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        jTable1.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

    }

    private void setFixedTable2() {
        JViewport viewport = new JViewport();
        viewport.setView(fixedTable);
        Dimension d = fixedTable.getPreferredSize();
        viewport.setPreferredSize(d);
        jScrollPane1.setRowHeaderView(viewport);
        jScrollPane1.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
    }

    private void updateFixed(boolean needViewport) {
        if (needViewport) {
            setFixedTable2();
        }

        FixedTableModel ft = fixedModel;
        ft.fireTableDataChanged();
    }

    /*
     * This function sets up the other detail tables for the operation processes. For each process that
     * has parameters there is a table model, table and cell renderer allocated.
     *
     */
    private void setupOtherTabs(Font theFont) {
        if (wt.getType() == WepsTableModel.TableEnum.Operation) {
            OprnTableModel ops = (OprnTableModel) wt;
            String pName;
            JScrollPane jScrollPane1Op;
            JTable jTableOp;
            TableColumn column = null;
            Component comp = null;
            int headerWidth = 0;
            int cellWidth = 0;
            
            // for each possible process that has parameters set up the tables
            for (int k = 0; k < ops.getActionNameCount(); k++) {
                DefnFileParser p = ops.getParamDef();
                int cols = p.getOpParmCount(k);  // check how many parameters this action has
                if (cols > 0) {
                    // This action has parameters
                    jScrollPane1Op = new javax.swing.JScrollPane();
                    jTableOp = new javax.swing.JTable();
                    jTableOp.setName(ops.getActionName(k));

                    jScrollPane1Op.setBackground(new java.awt.Color(204, 204, 0));
//                    jScrollPane1Op.setHorizontalScrollBarPolicy(javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
                    jScrollPane1Op.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
                    OpDetailTableModel detailModel = new OpDetailTableModel(k, ops, p, fixedModel);
                    detailModel.setName(ops.getActionName(k));
                    jTableOp.setModel(detailModel);
                    jTableOp.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
                    jTableOp.setCellSelectionEnabled(true);
                    
                    //Sets the fixed table to the right.
                    //setFixedTable1(detailModel);
                    JTable frozTab = detailModel.getFrozenTable();
                    frozTab.addMouseListener(new MouseAdapter() {
                        @Override
                        public void mousePressed(MouseEvent me) {
                            showPopup(me);
                        }

                        @Override
                        public void mouseReleased(MouseEvent me) {
                            showPopup(me);
                        }
                    });
                    JViewport viewport = new JViewport();
                    viewport.setView(frozTab);
                    Dimension dim = frozTab.getPreferredSize();
                    viewport.setPreferredSize(dim);
                    jScrollPane1Op.setRowHeaderView(viewport);
                    jScrollPane1Op.setCorner(JScrollPane.UPPER_LEFT_CORNER, frozTab.getTableHeader());
                    
//setFixedTable1(detailModel);
//            JViewport viewport = new JViewport();
//        viewport.setView(fixedTable);
//        Dimension d = fixedTable.getPreferredSize();
//        viewport.setPreferredSize(d);
//        jScrollPane1Op.setRowHeaderView(viewport);
//        jScrollPane1Op.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
//                    // Attach a sorter to handle header clicks
                    TableSorter2 tabSorter = new TableSorter2(detailModel);
                    TableSorter2.MouseHandler sorter = tabSorter.extractSorter();
                    jTableOp.setModel(tabSorter);
                    tabSorter.setTableHeader(jTableOp.getTableHeader());
                    ((OpDetailTableModel.FrozenTable) frozTab).setSorter(sorter);

                    column = frozTab.getColumn(0);
                    column.setPreferredWidth(50); // this is width of widest name determined previously
                    column = frozTab.getColumn(1);
                    column.setPreferredWidth(547);
                    column = frozTab.getColumn(2);
                    column.setPreferredWidth(212);
                    jScrollPane1Op.setViewportView(jTableOp);
                    pName = ops.getFullActionName(k);
                    jTabbedPane1.addTab(pName, jScrollPane1Op);
                    opTableLinks.add(jTableOp); // add table to list of detail tables
                    opModelLinks.add(detailModel); // add model to list of detail models
                    opScrollLinks.add(jScrollPane1Op); // add reference to scroll pane
                    TableCellRenderer headerRenderer
                            = jTableOp.getTableHeader().getDefaultRenderer();


                    jTableOp.addMouseListener(new MouseAdapter() {

                        @Override
                        public void mousePressed(MouseEvent me) {
                            if(SwingUtilities.isRightMouseButton(me)){
                                showPopup(me);
                            }
                        }

                        @Override
                        public void mouseReleased(MouseEvent me) {
                            if(SwingUtilities.isRightMouseButton(me)){
                                showPopup(me);
                            }
                             
                        }
                    });

                    // for each column in the detail table setup the details, this could include choice lists elements
                    for (int m = 0; m < detailModel.getColumnCount(); m++) {
                        column = jTableOp.getColumnModel().getColumn(m);

                        column.setCellRenderer(myCellRenderer);

//                        if (m > 2) {
                            //------------
                            if (detailModel.getColumnType(m) == ParamDef.ColumnType.CHOICE) {
                                // choice list
                                JComboBox<String> combobox = new JComboBox<String>();
                                for (int n = 0; n < detailModel.getChoiceCount(m); n++) {
                                    String s = detailModel.getChoice(m, n);
                                    combobox.addItem(s);
                                }
                                DefaultCellEditor ed = new DefaultCellEditor(combobox);
                                column.setCellEditor(ed);
                            } else {
                                // fix to not have jtable process a double click in a cell with its default editor which
                                // does not keep formatting. 7-21-2005
                                if (detailModel.getColumnType(m) == ParamDef.ColumnType.STRING) {
                                    //CellEditor ed = new CellEditor();
                                    //column.setCellEditor(ed);
                                }
                            }

                            comp = headerRenderer.getTableCellRendererComponent(
                                    jTableOp, column.getHeaderValue(), false, false, 0, 0);

                            headerWidth = comp.getPreferredSize().width;

                            comp = jTableOp.getDefaultRenderer(detailModel.getColumnClass(m)).
                                    getTableCellRendererComponent(
                                            jTableOp, detailModel.getColumnName(m) + "   ",
                                            false, false, 0, m);

                            cellWidth = comp.getPreferredSize().width;

                            column.setPreferredWidth(Math.max(headerWidth, cellWidth));

                        if(isColumnBlank(column)) {
                            column.setMinWidth(0);
                            column.setMaxWidth(0);
                            column.setWidth(0);
                            //jTableOp.removeColumn(column);
                        }
                    }
                    setOprnColumnWidths(jTableOp, false, false);   // this sets the column widths on the table
                }
            }

            // on the main tabbed table set where the tabs are located
            jTabbedPane1.setTabPlacement(JTabbedPane.RIGHT);
            jTabbedPane1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
            wt = ops;
            tabDive();
        } else  if (wt.getType() == WepsTableModel.TableEnum.UPGM) {
            UpgmTableModel upgm = (UpgmTableModel) wt;
            String pName;
            JScrollPane jScrollPane1Op;
            JTable jTableOp;
            TableColumn column = null;
            Component comp = null;
            int headerWidth = 0;
            int cellWidth = 0;
            
            // for each possible process that has parameters set up the tables
            for (int k = 0; k < upgm.getActionNameCount(); k++) {
                DefnFileParser p = upgm.getParamDef();
                int cols = p.getOpParmCount(k);  // check how many parameters this action has
                if (cols > 0) {
                    // This action has parameters
                    jScrollPane1Op = new javax.swing.JScrollPane();
                    jTableOp = new javax.swing.JTable();
                    jTableOp.setName(upgm.getActionName(k));

                    jScrollPane1Op.setBackground(new java.awt.Color(204, 204, 0));
//                    jScrollPane1Op.setHorizontalScrollBarPolicy(javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
                    jScrollPane1Op.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
                    OpDetailTableModel detailModel = new OpDetailTableModel(k, upgm, p, fixedModel);
                    detailModel.setName(upgm.getActionName(k));
                    jTableOp.setModel(detailModel);
                    jTableOp.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
                    jTableOp.setCellSelectionEnabled(true);
                    
                    //Sets the fixed table to the right.
                    //setFixedTable1(detailModel);
                    JTable frozTab = detailModel.getFrozenTable();
                    frozTab.addMouseListener(new MouseAdapter() {
                        @Override
                        public void mousePressed(MouseEvent me) {
                            showPopup(me);
                        }

                        @Override
                        public void mouseReleased(MouseEvent me) {
                            showPopup(me);
                        }
                    });
                    JViewport viewport = new JViewport();
                    viewport.setView(frozTab);
                    Dimension dim = frozTab.getPreferredSize();
                    viewport.setPreferredSize(dim);
                    jScrollPane1Op.setRowHeaderView(viewport);
                    jScrollPane1Op.setCorner(JScrollPane.UPPER_LEFT_CORNER, frozTab.getTableHeader());
                    
//setFixedTable1(detailModel);
//            JViewport viewport = new JViewport();
//        viewport.setView(fixedTable);
//        Dimension d = fixedTable.getPreferredSize();
//        viewport.setPreferredSize(d);
//        jScrollPane1Op.setRowHeaderView(viewport);
//        jScrollPane1Op.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
//                    // Attach a sorter to handle header clicks
                    TableSorter2 tabSorter = new TableSorter2(detailModel);
                    TableSorter2.MouseHandler sorter = tabSorter.extractSorter();
                    jTableOp.setModel(tabSorter);
                    tabSorter.setTableHeader(jTableOp.getTableHeader());
                    ((OpDetailTableModel.FrozenTable) frozTab).setSorter(sorter);

                    column = frozTab.getColumn(0);
                    column.setPreferredWidth(50); // this is width of widest name determined previously
                    column = frozTab.getColumn(1);
                    column.setPreferredWidth(547);
                    column = frozTab.getColumn(2);
                    column.setPreferredWidth(212);
                    jScrollPane1Op.setViewportView(jTableOp);
                    pName = upgm.getFullActionName(k);
                    jTabbedPane1.addTab(pName, jScrollPane1Op);
                    opTableLinks.add(jTableOp); // add table to list of detail tables
                    opModelLinks.add(detailModel); // add model to list of detail models
                    opScrollLinks.add(jScrollPane1Op); // add reference to scroll pane
                    TableCellRenderer headerRenderer
                            = jTableOp.getTableHeader().getDefaultRenderer();


                    jTableOp.addMouseListener(new MouseAdapter() {

                        @Override
                        public void mousePressed(MouseEvent me) {
                            showPopup(me);
                        }

                        @Override
                        public void mouseReleased(MouseEvent me) {
                            showPopup(me);
                        }
                    });

                    // for each column in the detail table setup the details, this could include choice lists elements
                    for (int m = 0; m < detailModel.getColumnCount(); m++) {
                        column = jTableOp.getColumnModel().getColumn(m);

                        column.setCellRenderer(myCellRenderer);

//                        if (m > 2) {
                            //------------
                            if (detailModel.getColumnType(m) == ParamDef.ColumnType.CHOICE) {
                                // choice list
                                JComboBox<String> combobox = new JComboBox<String>();
                                for (int n = 0; n < detailModel.getChoiceCount(m); n++) {
                                    String s = detailModel.getChoice(m, n);
                                    combobox.addItem(s);
                                }
                                DefaultCellEditor ed = new DefaultCellEditor(combobox);
                                column.setCellEditor(ed);
                            } else {
                                // fix to not have jtable process a double click in a cell with its default editor which
                                // does not keep formatting. 7-21-2005
                                if (detailModel.getColumnType(m) == ParamDef.ColumnType.STRING) {
                                    CellEditor ed = new CellEditor();
                                    column.setCellEditor(ed);
                                }
                            }

                            comp = headerRenderer.getTableCellRendererComponent(
                                    jTableOp, column.getHeaderValue(), false, false, 0, 0);

                            headerWidth = comp.getPreferredSize().width;

                            comp = jTableOp.getDefaultRenderer(detailModel.getColumnClass(m)).
                                    getTableCellRendererComponent(
                                            jTableOp, detailModel.getColumnName(m) + "   ",
                                            false, false, 0, m);

                            cellWidth = comp.getPreferredSize().width;

                            column.setPreferredWidth(Math.max(headerWidth, cellWidth));

                        if(isColumnBlank(column)) {
                            column.setMinWidth(0);
                            column.setMaxWidth(0);
                            column.setWidth(0);
                            //jTableOp.removeColumn(column);
                        }
                    }
                    setOprnColumnWidths(jTableOp, false, false);   // this sets the column widths on the table
                }
            }

            // on the main tabbed table set where the tabs are located
            jTabbedPane1.setTabPlacement(JTabbedPane.RIGHT);
            jTabbedPane1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
            wt = upgm;
            tabDive();
        }
    }

    /*
     * This function finds all the xml files for crops or operations in a directory (and subdirectories)
     * and hands them to the table model to load.
     */
    private void walkDirectory(TFile dbDir, String ext) {
        if (dbDir.isDirectory()) {
            // need to make sure the two dtd files are here

            String[] children = dbDir.list();
            if (children != null) {
                for (String children1 : children) {
                    // Get filename of file or directory
                    String filename = dbDir.getAbsolutePath() + TFile.separator + children1;
                    TFile wf = new TFile(filename);
                    if (wf.isDirectory()) {
                        // recursive for subdirectories
                        walkDirectory(wf, ext);
                    } else {
                        String upName = filename.toUpperCase();
                        if (upName.endsWith(ext) && wf.isFile()) {
                            try
                            {
                                wt.addXmlFile(filename);
                            }
                            catch(NullPointerException npe)
                            {
                                ErrorSink.add("Invalid XML file:  " + filename);
                            }
                        } 
                    }
                }
            }
        }
    }

    /*
     * This sets the table column widths for the crop viewer
     */
    private void setCropColumnWidths(JTable table, boolean isFixed) {
        if (wt.getType() == WepsTableModel.TableEnum.Crop) {
            CropTableModel model = (CropTableModel) wt;
            TableColumn column = null;

            Component comp = null;
            int headerWidth = 0;
            int cellWidth = 0;
            int cols = 0;
            if (!isFixed) {
                cols = wt.getColumnCount();
            } else {
                cols = 3;
            }

            //TableCellRenderer headerRenderer = jTable1.getTableHeader().getDefaultRenderer();
            TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();

            for (int i = 0; i < cols; i++) {
                column = table.getColumnModel().getColumn(i);

                column.setHeaderRenderer(headerRenderer);
                if (!isFixed) {
                    if (model.getColumnType(i) == ParamDef.ColumnType.CHOICE) {
                        // choice list
                        JComboBox<String> combobox = new JComboBox<String>();
                        for (int k = 0; k < model.getChoiceCount(i); k++) {
                            combobox.addItem(model.getChoice(i, k));
                        }
                        DefaultCellEditor ed = new DefaultCellEditor(combobox);
                        column.setCellEditor(ed);
                    } else if (model.getColumnType(i) == ParamDef.ColumnType.STRING) {
                        CellEditor ed = new CellEditor();
                        column.setCellEditor(ed);
                    }

                }

                comp = headerRenderer.getTableCellRendererComponent(
                        table, column.getHeaderValue(),
                        false, false, 0, 0);
                headerWidth = comp.getPreferredSize().width;

                comp = table.getDefaultRenderer(model.getColumnClass(i)).
                        getTableCellRendererComponent(
                                table, model.getColumnName(i) + "   ",
                                false, false, 0, i);
                cellWidth = comp.getPreferredSize().width;

                column.setPreferredWidth(Math.max(headerWidth, cellWidth));
                column.setMinWidth(35);
                if (i >= 3) {
                    column.setMaxWidth(Math.max(headerWidth, cellWidth) + 500);
                }
                column.setCellRenderer(myCellRenderer);
                if (!isFixed) {
                    cropTableWidths[i] = Math.max(headerWidth, cellWidth);
                }
            } // end for

            // Make the name column wider to fit all the names
            int maxWidth = 0;
            for (int i = 0; i < model.getRowCount(); i++) {

                comp = table.getDefaultRenderer(model.getColumnClass(1)).
                        getTableCellRendererComponent(
                                table, model.getValueAt(i, 1),
                                false, hasFocus, i, 1);
                cellWidth = comp.getPreferredSize().width;
                if (cellWidth > maxWidth) {
                    maxWidth = cellWidth;
                }
            }
            if (!isFixed) {
                for (int i = 0; i < 3; i++) {
                    hideColumn(table, i);
                }
            } else {
                column = table.getColumnModel().getColumn(1);
                column.setPreferredWidth(maxWidth);
                column.setMaxWidth(maxWidth + 500);
            }
        }
    }

    /*
     * This function sets the column widths for any operation table.
     */
    private void setOprnColumnWidths(JTable table, boolean isMainModel, boolean isFixed) {
        TableColumn column = null;

        AbstractTableModel model = (AbstractTableModel) table.getModel();
        if ((isMainModel) && (!isFixed)) {
            model = wt;
        }
        Component comp = null;
        int headerWidth = 0;
        int cellWidth = 0;
        int cols = 0;
        //if (!isFixed)
        //   cols = model.getColumnCount();
        //else
        //    cols = 3;

        TableCellRenderer headerRenderer
                = table.getTableHeader().getDefaultRenderer();

        for (int i = 0; i < model.getColumnCount(); i++) {
            if(table.getColumnCount() > 0) {
                column = table.getColumnModel().getColumn(i);
            }
            if (column == null) {
                System.out.println("column is null");
                continue;
            }

            comp = headerRenderer.getTableCellRendererComponent(table, column.getHeaderValue(), false, false, 0, 0);
            headerWidth = comp.getPreferredSize().width;

            comp = table.getDefaultRenderer(model.getColumnClass(i)).
                        getTableCellRendererComponent(
                                table, model.getColumnName(i) + "   ",
                                false, false, 0, i);
            cellWidth = comp.getPreferredSize().width;

            column.setPreferredWidth(Math.max(headerWidth, cellWidth));
            column.setMinWidth(Math.max(headerWidth, cellWidth));
            if (isMainModel) {
                column.setCellRenderer(myCellRenderer);
            }

        } // end for

        // Make the name column wider to fit all the names
        int maxWidth = 0;
        for (int i = 0; i < model.getRowCount(); i++) {

            comp = jTable1.getDefaultRenderer(model.getColumnClass(1)).
                    getTableCellRendererComponent(
                            table, model.getValueAt(i, 1),
                            false, false, i, 1);
            cellWidth = comp.getPreferredSize().width;
            if (cellWidth > maxWidth) {
                maxWidth = cellWidth;
            }
        }
        
        if(model instanceof TableSorter2) 
            if(((TableSorter2) model).getTableModel() instanceof OpDetailTableModel)
                column = ((OpDetailTableModel) ((TableSorter2) model).getTableModel()).getFrozenTable().getColumn(0);
            else column = table.getColumnModel().getColumn(0);
        else column = table.getColumnModel().getColumn(0);
        column.setPreferredWidth(50);

        nameColWidth = maxWidth;
        if(model instanceof TableSorter2) 
            if(((TableSorter2) model).getTableModel() instanceof OpDetailTableModel)
                column = ((OpDetailTableModel) ((TableSorter2) model).getTableModel()).getFrozenTable().getColumn(1);
            else column = table.getColumnModel().getColumn(1);
        else column = table.getColumnModel().getColumn(1);
        column.setPreferredWidth(maxWidth);

        // Make the path column wider to fit all the names
        maxWidth = 0;
        for (int i = 0; i < model.getRowCount(); i++) {

            comp = table.getDefaultRenderer(model.getColumnClass(2)).
                    getTableCellRendererComponent(
                            table, model.getValueAt(i, 2),
                            false, false, i, 2);
            cellWidth = comp.getPreferredSize().width;
            if (cellWidth > maxWidth) {
                maxWidth = cellWidth;
            }
        }

        nameColWidth = maxWidth;
        if(model instanceof TableSorter2) 
            if(((TableSorter2) model).getTableModel() instanceof OpDetailTableModel)
                column = ((OpDetailTableModel) ((TableSorter2) model).getTableModel()).getFrozenTable().getColumn(2);
            else column = table.getColumnModel().getColumn(2);
        else column = table.getColumnModel().getColumn(2);
        column.setPreferredWidth(maxWidth);

        // Need to set all the column widths beyond the name column to the same value which is the
        // widest dropdown
        if ((isMainModel) && (!isFixed)) {
            maxWidth = 0;
            OprnTableModel omodel = (OprnTableModel) model;
            for (int k = 0; k < omodel.getChoiceCount(); k++) {
                comp = table.getDefaultRenderer(model.getColumnClass(3)).
                        getTableCellRendererComponent(
                                table, omodel.getChoice(k),
                                false, false, 0, 1);
                cellWidth = comp.getPreferredSize().width;
                if (cellWidth > maxWidth) {
                    maxWidth = cellWidth;
                }
            }

            if (shortNames) {
                maxWidth = 30;
            }

            for (int k = 3; k < model.getColumnCount(); k++) {
                column = table.getColumnModel().getColumn(k);
                column.setPreferredWidth(maxWidth);
            }

            for (int i = 0; i < 3; i++) {
                hideColumn(table, i);
            }
        }

        int wid = table.getTableHeader().getWidth();
        
        if(model instanceof TableSorter2) 
            if(((TableSorter2) model).getTableModel() instanceof OpDetailTableModel)
                column = ((OpDetailTableModel) ((TableSorter2) model).getTableModel()).getFrozenTable().getColumn(0);
            else column = table.getColumnModel().getColumn(0);
        else column = table.getColumnModel().getColumn(0);
        column.setPreferredWidth(50);
        
        if(model instanceof TableSorter2) 
            if(((TableSorter2) model).getTableModel() instanceof OpDetailTableModel)
                column = ((OpDetailTableModel) ((TableSorter2) model).getTableModel()).getFrozenTable().getColumn(1);
            else column = table.getColumnModel().getColumn(1);
        else column = table.getColumnModel().getColumn(1);
        column.setPreferredWidth(547);
        
        if(model instanceof TableSorter2) 
            if(((TableSorter2) model).getTableModel() instanceof OpDetailTableModel)
                column = ((OpDetailTableModel) ((TableSorter2) model).getTableModel()).getFrozenTable().getColumn(2);
            else column = table.getColumnModel().getColumn(2);
        else column = table.getColumnModel().getColumn(2);
        column.setPreferredWidth(212);

    }

    class SelectionListener implements ListSelectionListener {

        boolean isFixedTable = true;

        public SelectionListener(boolean isFixedTable) {
            this.isFixedTable = isFixedTable;
        }

        @Override
        public void valueChanged(ListSelectionEvent e) {
            int selectedIndex = -1;
            if (isFixedTable) {
                selectedIndex = fixedTable.getSelectedRow();
                if (selectedIndex >= 0) {
                    jTable1.setRowSelectionInterval(selectedIndex, selectedIndex);
                }
            } else {
                selectedIndex = jTable1.getSelectedRow();
                if (selectedIndex >= 0) {
                    fixedTable.setRowSelectionInterval(selectedIndex, selectedIndex);
                }
            }

            if ( ( (wt.getType() == WepsTableModel.TableEnum.Operation) || (wt.getType() == WepsTableModel.TableEnum.UPGM) ) && (selectedIndex >= 0)) {

                for (int i = 0; i < opModelLinks.size(); i++) {
                    JTable curTable = opTableLinks.get(i);
                    if (curTable != null) {
                        curTable.setRowSelectionInterval(selectedIndex, selectedIndex);
                    }
                }
            }
        }
    }

    /**
     * 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.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        oprnPopup = new javax.swing.JPopupMenu();
        DeleteAction = new javax.swing.JMenuItem();
        ChangeAction = new javax.swing.JMenuItem();
        InsertBefore = new javax.swing.JMenuItem();
        InsertAfter = new javax.swing.JMenuItem();
        Left1 = new javax.swing.JMenuItem();
        Right1 = new javax.swing.JMenuItem();
        oprnNamePopup = new javax.swing.JPopupMenu();
        BlankOperation = new javax.swing.JMenuItem();
        CloneOperation = new javax.swing.JMenuItem();
        RenameOperation = new javax.swing.JMenuItem();
        DeleteOperation = new javax.swing.JMenuItem();
        AltViewOperation = new javax.swing.JMenuItem();
        SetOperation = new javax.swing.JMenuItem();
        SaveOperation = new javax.swing.JMenuItem();
        VerifyProcesses = new javax.swing.JMenuItem();
        PromoteOp = new javax.swing.JMenuItem();
        sorterPopup = new javax.swing.JPopupMenu();
        ascendingMenu = new javax.swing.JMenuItem();
        descendingMenu = new javax.swing.JMenuItem();
        cropNamePopup = new javax.swing.JPopupMenu();
        CloneCrop = new javax.swing.JMenuItem();
        RenameCrop = new javax.swing.JMenuItem();
        DeleteCrop = new javax.swing.JMenuItem();
        SaveCrop = new javax.swing.JMenuItem();
        Promote = new javax.swing.JMenuItem();
        jToolBar1 = new javax.swing.JToolBar();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        menuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        saveMenuItem = new javax.swing.JMenuItem();
        exitMenuItem = new javax.swing.JMenuItem();
        Options = new javax.swing.JMenu();
        altUnits = new javax.swing.JCheckBoxMenuItem();
        enableEdit = new javax.swing.JCheckBoxMenuItem();
        CheckProcesses = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JSeparator();
        ShortProcessNames = new javax.swing.JCheckBoxMenuItem();
        rightTabs = new javax.swing.JRadioButtonMenuItem();
        botTabs = new javax.swing.JRadioButtonMenuItem();
        PromoteWin = new javax.swing.JMenuItem();
        rowHeightMenuItem = new javax.swing.JMenuItem();
        checkNames = new javax.swing.JMenuItem();
        CheckData = new javax.swing.JCheckBoxMenuItem();
        helpMenu = new javax.swing.JMenu();
        contentsMenuItem = new javax.swing.JMenuItem();
        aboutMenuItem = new javax.swing.JMenuItem();

        DeleteAction.setText("Delete Process");
        oprnPopup.add(DeleteAction);

        ChangeAction.setText("Select a different process");
        oprnPopup.add(ChangeAction);

        InsertBefore.setText("Insert new process before");
        oprnPopup.add(InsertBefore);

        InsertAfter.setText("Insert new process after");
        oprnPopup.add(InsertAfter);

        Left1.setText("<< Move Process Left <<");
        oprnPopup.add(Left1);

        Right1.setText(">> Move Process Right >>");
        oprnPopup.add(Right1);

        BlankOperation.setText("Create new empty operation");
        oprnNamePopup.add(BlankOperation);

        CloneOperation.setText("Create a copy of this operation");
        oprnNamePopup.add(CloneOperation);

        RenameOperation.setText("Rename Operation");
        oprnNamePopup.add(RenameOperation);

        DeleteOperation.setText("Delete Operation");
        oprnNamePopup.add(DeleteOperation);

        AltViewOperation.setText("View List of Processes");
        oprnNamePopup.add(AltViewOperation);

        SetOperation.setText("Set New Operation Type");
        oprnNamePopup.add(SetOperation);

        SaveOperation.setText("Save This Operation");
        oprnNamePopup.add(SaveOperation);

        VerifyProcesses.setText("Check Process Order");
        oprnNamePopup.add(VerifyProcesses);

        PromoteOp.setText("Promote to top");
        oprnNamePopup.add(PromoteOp);

        ascendingMenu.setText("Sort Ascending");
        sorterPopup.add(ascendingMenu);

        descendingMenu.setText("Sort Descending");
        sorterPopup.add(descendingMenu);

        CloneCrop.setText("Create a copy of this crop");
        cropNamePopup.add(CloneCrop);

        RenameCrop.setText("Rename Crop");
        cropNamePopup.add(RenameCrop);

        DeleteCrop.setText("Delete Crop");
        cropNamePopup.add(DeleteCrop);

        SaveCrop.setText("Save Crop");
        cropNamePopup.add(SaveCrop);

        Promote.setText("Promote to top");
        cropNamePopup.add(Promote);

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("WEPS DB Viewer");
        getContentPane().add(jToolBar1, java.awt.BorderLayout.NORTH);

        jTabbedPane1.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e)
            {
                tabs();
            }
        });

        jScrollPane1.setBackground(new java.awt.Color(204, 204, 0));
        jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        jTable1.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"
            }
        ));
        jTable1.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
        jTable1.setCellSelectionEnabled(true);
        jScrollPane1.setViewportView(jTable1);
        jTable1.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);

        jTabbedPane1.addTab("tab2", jScrollPane1);

        getContentPane().add(jTabbedPane1, java.awt.BorderLayout.CENTER);

        fileMenu.setText("File");

        saveMenuItem.setText("Save All");
        saveMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveMenuItem);

        exitMenuItem.setText("Exit");
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        Options.setText("Options");

        altUnits.setText("Alternate (English) Units");
        Options.add(altUnits);

        enableEdit.setText("Allow Changes");
        Options.add(enableEdit);

        CheckProcesses.setText("Check Process Order (All)");
        Options.add(CheckProcesses);
        Options.add(jSeparator1);

        ShortProcessNames.setText("Short Process Names");
        Options.add(ShortProcessNames);

        rightTabs.setSelected(true);
        rightTabs.setText("Process Tabs on Right");
        Options.add(rightTabs);

        botTabs.setText("Process Tabs on Bottom");
        Options.add(botTabs);

        PromoteWin.setText("Promote Group to Top");
        Options.add(PromoteWin);

        rowHeightMenuItem.setText("Set Row Height");
        Options.add(rowHeightMenuItem);

        checkNames.setText("Check Names");
        Options.add(checkNames);

        CheckData.setText("CheckData");
        CheckData.setSelected(true);
        Options.add(CheckData);

        menuBar.add(Options);

        helpMenu.setText("Help");

        contentsMenuItem.setText("Contents");
        helpMenu.add(contentsMenuItem);

        aboutMenuItem.setText("About");
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        setJMenuBar(menuBar);

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

    private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed

    }//GEN-LAST:event_saveMenuItemActionPerformed

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        exit();
    }//GEN-LAST:event_exitMenuItemActionPerformed

    private void exit() {
        WepsDbExit wde = new WepsDbExit(wt, this);
        wde.setVisible(true);
    }

    /**
     * @param args the command line arguments
     * @throws java.lang.Exception
     */
    public static void main(String args[]) throws Exception {

        final StartupFrame suf = new StartupFrame();

        EventQueue.invokeAndWait(new Runnable() {

            @Override
            public void run() {
                suf.setVisible(true);
            }
        });

        while (suf.isVisible()) {
            Thread.yield();
        }

        final DatabaseInformation info = suf.getDatabaseInformation();
        final DataType type = suf.getDataType();

        if (info == null || type == null) {

            return;
        }

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                WEPSDBViewer viewer = new WEPSDBViewer((FileDatabaseInformation) info, type);
                viewer.setVisible(true);
            }
        });
        
    }
    /**
     * This method polls the Operation Detail methods to see which have out
     * of bounds data.  It then highlights the corresponding tab.
     */
    private void tabs()
    {
        if(opModelLinks != null)
        {
            for(int index = 0; index < opModelLinks.size(); index ++)
            {
                if(opModelLinks.get(index).getColor()) 
                {
                    jTabbedPane1.setBackgroundAt(index + 1, CellRenderer.outsideAbsolute);
                }
                else jTabbedPane1.setBackgroundAt(index + 1, null);
            }
            wt.clearRowStatus();
            if(!wt.checkData)
            {
                for(int index = 0; index < opModelLinks.size(); index ++)
                {
                    jTabbedPane1.setBackgroundAt(index + 1, null);
                }
            }
        }
    }
    
    /**
     * This method initializes the tab color;  It looks through each xml file 
     * and triggers the tab coloring based on the values contained within.
     */
    private void tabDive()
    {
        if(opModelLinks != null && wt.checkData)
        {
            ArrayList<String> values = wt.dive();
            for(int index = 0; index < opModelLinks.size(); index ++)
            {
                if(values.contains(opModelLinks.get(index).getName())) 
                {
                    opModelLinks.get(index).setOverrideStatus(InputLimits.TableStatus.NOSAVE);
                }
            }
            tabs();
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem AltViewOperation;
    private javax.swing.JMenuItem BlankOperation;
    private javax.swing.JMenuItem ChangeAction;
    private javax.swing.JCheckBoxMenuItem CheckData;
    private javax.swing.JMenuItem CheckProcesses;
    private javax.swing.JMenuItem CloneCrop;
    private javax.swing.JMenuItem CloneOperation;
    private javax.swing.JMenuItem DeleteAction;
    private javax.swing.JMenuItem DeleteCrop;
    private javax.swing.JMenuItem DeleteOperation;
    private javax.swing.JMenuItem InsertAfter;
    private javax.swing.JMenuItem InsertBefore;
    private javax.swing.JMenuItem Left1;
    private javax.swing.JMenu Options;
    private javax.swing.JMenuItem Promote;
    private javax.swing.JMenuItem PromoteOp;
    private javax.swing.JMenuItem PromoteWin;
    private javax.swing.JMenuItem RenameCrop;
    private javax.swing.JMenuItem RenameOperation;
    private javax.swing.JMenuItem Right1;
    private javax.swing.JMenuItem SaveCrop;
    private javax.swing.JMenuItem SaveOperation;
    private javax.swing.JMenuItem SetOperation;
    private javax.swing.JCheckBoxMenuItem ShortProcessNames;
    private javax.swing.JMenuItem VerifyProcesses;
    private javax.swing.JMenuItem aboutMenuItem;
    private javax.swing.JCheckBoxMenuItem altUnits;
    private javax.swing.JMenuItem ascendingMenu;
    private javax.swing.JRadioButtonMenuItem botTabs;
    private javax.swing.JMenuItem checkNames;
    private javax.swing.JMenuItem contentsMenuItem;
    private javax.swing.JPopupMenu cropNamePopup;
    private javax.swing.JMenuItem descendingMenu;
    private javax.swing.JCheckBoxMenuItem enableEdit;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JTable jTable1;
    private javax.swing.JToolBar jToolBar1;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JPopupMenu oprnNamePopup;
    private javax.swing.JPopupMenu oprnPopup;
    private javax.swing.JRadioButtonMenuItem rightTabs;
    private javax.swing.JMenuItem rowHeightMenuItem;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JPopupMenu sorterPopup;
    // End of variables declaration//GEN-END:variables
}
