com.github.dougkelly88.FLIMPlateReaderGUI.SequencingClasses.GUIComponents.XYSequencing.java Source code

Java tutorial

Introduction

Here is the source code for com.github.dougkelly88.FLIMPlateReaderGUI.SequencingClasses.GUIComponents.XYSequencing.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.github.dougkelly88.FLIMPlateReaderGUI.SequencingClasses.GUIComponents;

import com.github.dougkelly88.FLIMPlateReaderGUI.GeneralClasses.Insert_object;
import com.github.dougkelly88.FLIMPlateReaderGUI.GeneralClasses.PlateProperties;
import com.github.dougkelly88.FLIMPlateReaderGUI.GeneralClasses.SeqAcqProps;
import com.github.dougkelly88.FLIMPlateReaderGUI.GeneralClasses.Variable;
import com.github.dougkelly88.FLIMPlateReaderGUI.GeneralGUIComponents.HCAFLIMPluginFrame;
import com.github.dougkelly88.FLIMPlateReaderGUI.InstrumentInterfaceClasses.XYZMotionInterface;
import com.github.dougkelly88.FLIMPlateReaderGUI.SequencingClasses.Classes.FOV;
import com.github.dougkelly88.FLIMPlateReaderGUI.SequencingClasses.Classes.FOVTableModel;
import com.google.gson.Gson;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import static java.lang.Math.abs;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Locale;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.text.NumberFormatter;

// This lot are for attempts at handling filenames - to get the list of macros
import java.io.File;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

//import javax.swing.filechooser.FileNameExtensionFilter;
//import org.apache.commons.io.FileUtils;
//import org.apache.commons.io.filefilter.WildcardFileFilter;

/**
 *
 * @author dk1109
 */
public class XYSequencing extends javax.swing.JPanel {

    PlateProperties pp_;
    PlateMapDrawPanel pmdp_;
    public FOVTableModel tableModel_;
    public FOVTableModel searchFOVtableModel_;
    private static final XYSequencing fINSTANCE = new XYSequencing();
    JTable fovTable_;
    SeqAcqProps sap_;
    public HCAFLIMPluginFrame parent_;
    //final static String um = "(" + "\u00B5" + "m)";
    final static String um = "(" + "micro" + "m)";
    boolean zAsOffset_ = true;
    double[] zStackParams = { 0.0, 0.0, 1.0 };
    XYZMotionInterface xyzmi_;
    public boolean sendEmailBoolean = false;
    String emailString;
    private Variable var_;
    private ArrayList<FOV> spiralFOVs = new ArrayList<FOV>();
    private double[] insertOffsets;
    private String[][] insertOffsetInfo;
    public boolean InsertOffsetsloaded;

    /**
     * Creates new form XYSequencing
     */
    public XYSequencing() {
        initComponents();
        setControlDefaults();
        var_ = Variable.getInstance();
        insertOffsets = new double[] { 0.0, 0.0, 0.0 }; // X, Y, Z
    }

    public static XYSequencing getInstance() {
        return fINSTANCE;
    }

    private void setupInsertComboBox() {
        Gson gsonInserts = new Gson();
        //Load the file with the stored offsets
        String directoryName = ij.IJ.getDirectory("ImageJ");
        String objectFilepath = directoryName.concat("OPENFLIMHCA_JSONInsertOffsets.txt");
        String JSONInString = "";
        try {
            JSONInString = new String(Files.readAllBytes(FileSystems.getDefault().getPath(objectFilepath)));
        } catch (Exception e) {
        }
        insertType.removeAllItems();
        Insert_object[] inserts = gsonInserts.fromJson(JSONInString, Insert_object[].class);
        insertOffsetInfo = new String[inserts.length][inserts[0].getClass().getDeclaredFields().length];
        //System.out.println(inserts[0].getClass().getDeclaredFields().length);
        for (int i = 0; i < inserts.length; i++) {
            insertOffsetInfo[i][0] = inserts[i].getInsertName();
            insertOffsetInfo[i][1] = inserts[i].getInsertOffsets()[0].toString();
            insertOffsetInfo[i][2] = inserts[i].getInsertOffsets()[1].toString();
            insertOffsetInfo[i][3] = inserts[i].getInsertOffsets()[2].toString();
            insertType.addItem(inserts[i].getInsertName());
        }
        InsertOffsetsloaded = true;
    }

    public void addaFOV(FOV FOVtoadd) {
        tableModel_.addRow(FOVtoadd);
        pmdp_.addSelectedWell(FOVtoadd.getWell());
    }

    private void setControlDefaults() {

        pmdp_ = new PlateMapDrawPanel(this);
        sap_ = SeqAcqProps.getInstance();
        plateMapBasePanel.setLayout(new BorderLayout());
        plateMapBasePanel.add(pmdp_, BorderLayout.CENTER);

        tableModel_ = new FOVTableModel(pp_);
        searchFOVtableModel_ = new FOVTableModel(pp_); //Not sure if this is the best way, but try it for now.
        tableModel_.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {

            }
        });

        fovTable_ = new JTable();
        fovTable_.setModel(tableModel_);
        fovTable_.setSurrendersFocusOnKeystroke(true);
        fovTable_.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

        JScrollPane scroller = new javax.swing.JScrollPane(fovTable_);
        fovTable_.setPreferredScrollableViewportSize(new java.awt.Dimension(190, 130));
        fovTablePanel.setLayout(new BorderLayout());
        fovTablePanel.add(scroller, BorderLayout.CENTER);

        final JPopupMenu popupMenu = new JPopupMenu();
        JMenuItem deleteItem = new JMenuItem("Delete FOV");
        deleteItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int r = fovTable_.getSelectedRow();
                tableModel_.removeRow(r);
            }
        });
        JMenuItem addItem = new JMenuItem("Add FOV");
        addItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int r = fovTable_.getSelectedRow();
                tableModel_.insertRow(r, new FOV("A1", pp_, 6000));
            }
        });
        JMenuItem goToFOVItem = new JMenuItem("Go to FOV");
        goToFOVItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int r = fovTable_.getSelectedRow();
                //                FOV fov = tableModel_.getData().get(r);
                xyzmi_.gotoFOV(tableModel_.getData().get(r));
                if (!zAsOffset_) {
                    double zval = tableModel_.getData().get(r).getZ();
                    xyzmi_.moveZAbsolute(zval);
                } else {
                    // obviously, this isn't quite right - we want to get
                    // the offset of the CURRENT FOV (perhaps from parent in 
                    // later implementations?) and subtract from that of the 
                    // NEWLY SELECTED FOV. 
                    // TODO: fix for proper zAsOffset behaviour. 
                    // Wait for move completion
                    while (xyzmi_.isStageBusy()) {
                        System.out.println("Stage moving...");
                    }
                    ;

                    if (parent_.checkifAFenabled()) {
                        // If we have gone to the FOV, and have AF, do AF
                        xyzmi_.customAutofocus(parent_.getAFOffset());
                    } else {
                        // If we don't have AF, go to the 'good offset position'
                        xyzmi_.moveZAbsolute(parent_.getFixedAFDefault());
                    }
                    //Now do the relative shift
                    xyzmi_.moveZRelative(tableModel_.getData().get(r).getZ());
                    System.out.println("Z value" + tableModel_.getData().get(r).getZ());
                }
            }
        });

        popupMenu.add(addItem);
        popupMenu.add(deleteItem);
        popupMenu.add(goToFOVItem);

        fovTable_.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                //                System.out.println("pressed");
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    JTable source = (JTable) e.getSource();
                    int row = source.rowAtPoint(e.getPoint());
                    int column = source.columnAtPoint(e.getPoint());

                    if (!source.isRowSelected(row)) {
                        source.changeSelection(row, column, false, false);
                    }
                    popupMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });

        //        fovTable_.setDefaultRenderer(FOV.class, new TableRenderer());
        setupInsertComboBox();
    }

    public void onPlateConfigLoaded(boolean enable, PlateProperties pp) {
        pmdp_.setEnabled(enable, pp);
        pp_ = pp;
    }

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

        storedXYZPanel = new javax.swing.JPanel();
        clearXYZButton = new javax.swing.JButton();
        storeXYZButton = new javax.swing.JButton();
        fovTablePanel = new javax.swing.JPanel();
        genZStackButton = new javax.swing.JButton();
        zModeCombo = new javax.swing.JComboBox();
        clearZButton = new javax.swing.JButton();
        SaveXYZ = new javax.swing.JButton();
        LoadXYZ = new javax.swing.JButton();
        FOVNudgeCheckbox = new javax.swing.JCheckBox();
        prefindPanel = new javax.swing.JPanel();
        quickPFButton = new javax.swing.JButton();
        advancedPFButton = new javax.swing.JToggleButton();
        testPrefind = new javax.swing.JButton();
        prefindMacroname = new javax.swing.JComboBox<String>();
        plateMapBasePanel = new javax.swing.JPanel();
        autoFOVPanel = new javax.swing.JPanel();
        autoGenerateFOVsCheck = new javax.swing.JCheckBox();
        noFOVLabel = new javax.swing.JLabel();
        noFOVsField = new javax.swing.JFormattedTextField();
        FOVPatternCombo = new javax.swing.JComboBox();
        ringRadiusField = new javax.swing.JFormattedTextField();
        ringRadiusLabel = new javax.swing.JLabel();
        groupDescLabel = new javax.swing.JLabel();
        groupDescField = new javax.swing.JTextField();
        snakeType = new javax.swing.JComboBox();
        snaketypelabel = new javax.swing.JLabel();
        insertType = new javax.swing.JComboBox<String>();
        jLabel2 = new javax.swing.JLabel();

        storedXYZPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Stored XYZ positions"));

        clearXYZButton.setText("Clear stored XYZ");
        clearXYZButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearXYZButtonActionPerformed(evt);
            }
        });

        storeXYZButton.setText("Store current XYZ");
        storeXYZButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                storeXYZButtonActionPerformed(evt);
            }
        });

        fovTablePanel.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                fovTablePanelMouseClicked(evt);
            }
        });

        javax.swing.GroupLayout fovTablePanelLayout = new javax.swing.GroupLayout(fovTablePanel);
        fovTablePanel.setLayout(fovTablePanelLayout);
        fovTablePanelLayout.setHorizontalGroup(fovTablePanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 0, Short.MAX_VALUE));
        fovTablePanelLayout.setVerticalGroup(fovTablePanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 0, Short.MAX_VALUE));

        genZStackButton.setText("Generate Z stack...");
        genZStackButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                genZStackButtonActionPerformed(evt);
            }
        });

        zModeCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Z as offset", "Absolute Z" }));
        zModeCombo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                zModeComboActionPerformed(evt);
            }
        });

        clearZButton.setText("Clear Z stack");
        clearZButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearZButtonActionPerformed(evt);
            }
        });

        SaveXYZ.setText("Save XYZ");
        SaveXYZ.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                SaveXYZActionPerformed(evt);
            }
        });

        LoadXYZ.setText("Load XYZ");
        LoadXYZ.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                LoadXYZActionPerformed(evt);
            }
        });

        FOVNudgeCheckbox.setText("Nudge mode");
        FOVNudgeCheckbox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                FOVNudgeCheckboxActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout storedXYZPanelLayout = new javax.swing.GroupLayout(storedXYZPanel);
        storedXYZPanel.setLayout(storedXYZPanelLayout);
        storedXYZPanelLayout.setHorizontalGroup(storedXYZPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, storedXYZPanelLayout.createSequentialGroup()
                        .addComponent(fovTablePanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(storedXYZPanelLayout
                                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(storeXYZButton, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(genZStackButton, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(clearZButton, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addGroup(storedXYZPanelLayout.createSequentialGroup().addComponent(SaveXYZ)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(LoadXYZ))
                                .addComponent(clearXYZButton, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(zModeCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addContainerGap())
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, storedXYZPanelLayout.createSequentialGroup()
                        .addGap(0, 0, Short.MAX_VALUE).addComponent(FOVNudgeCheckbox).addGap(52, 52, 52)));
        storedXYZPanelLayout.setVerticalGroup(storedXYZPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                        storedXYZPanelLayout.createSequentialGroup().addContainerGap()
                                .addComponent(fovTablePanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addGap(37, 37, 37))
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, storedXYZPanelLayout.createSequentialGroup()
                        .addComponent(zModeCombo, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(genZStackButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(clearZButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(storeXYZButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(clearXYZButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(
                                storedXYZPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                        .addComponent(SaveXYZ).addComponent(LoadXYZ))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(FOVNudgeCheckbox)));

        prefindPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Prefind"));

        quickPFButton.setText("Quick prefind");
        quickPFButton.setFocusCycleRoot(true);
        quickPFButton.setMargin(new java.awt.Insets(2, 8, 2, 8));
        quickPFButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                quickPFButtonActionPerformed(evt);
            }
        });

        advancedPFButton.setText("Update list of macros");
        advancedPFButton.setMargin(new java.awt.Insets(2, 4, 2, 4));
        advancedPFButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                advancedPFButtonActionPerformed(evt);
            }
        });

        testPrefind.setText("Test prefind on current FOV");
        testPrefind.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                testPrefindActionPerformed(evt);
            }
        });

        prefindMacroname.setModel(
                new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        prefindMacroname.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                prefindMacronameActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout prefindPanelLayout = new javax.swing.GroupLayout(prefindPanel);
        prefindPanel.setLayout(prefindPanelLayout);
        prefindPanelLayout.setHorizontalGroup(prefindPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(prefindPanelLayout.createSequentialGroup().addGroup(prefindPanelLayout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                prefindPanelLayout.createSequentialGroup().addContainerGap().addComponent(
                                        prefindMacroname, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                prefindPanelLayout.createSequentialGroup().addContainerGap().addComponent(
                                        testPrefind, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addGroup(prefindPanelLayout.createSequentialGroup().addGap(10, 10, 10)
                                .addComponent(quickPFButton)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(advancedPFButton, javax.swing.GroupLayout.DEFAULT_SIZE, 121,
                                        Short.MAX_VALUE)))
                        .addContainerGap()));
        prefindPanelLayout.setVerticalGroup(prefindPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, prefindPanelLayout.createSequentialGroup()
                        .addGap(112, 112, 112).addComponent(testPrefind)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(prefindMacroname, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(prefindPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(quickPFButton).addComponent(advancedPFButton))));

        javax.swing.GroupLayout plateMapBasePanelLayout = new javax.swing.GroupLayout(plateMapBasePanel);
        plateMapBasePanel.setLayout(plateMapBasePanelLayout);
        plateMapBasePanelLayout.setHorizontalGroup(plateMapBasePanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 470, Short.MAX_VALUE));
        plateMapBasePanelLayout.setVerticalGroup(plateMapBasePanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 320, Short.MAX_VALUE));

        autoGenerateFOVsCheck.setText("Auto-generate FOVs?");
        autoGenerateFOVsCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                autoGenerateFOVsCheckActionPerformed(evt);
            }
        });

        noFOVLabel.setText("# FOVs ");

        noFOVsField.setText("4");
        noFOVsField.setEnabled(false);
        noFOVsField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                noFOVsFieldActionPerformed(evt);
            }
        });

        FOVPatternCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Spiral", "Ring", "ZFish" }));
        FOVPatternCombo.setEnabled(false);
        FOVPatternCombo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                FOVPatternComboActionPerformed(evt);
            }
        });

        ringRadiusField.setText("3000");
        ringRadiusField.setEnabled(false);
        ringRadiusField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ringRadiusFieldActionPerformed(evt);
            }
        });

        ringRadiusLabel.setText("Ring radius um:");

        groupDescLabel.setText("Group description:");

        groupDescField.setText("Experiment");
        groupDescField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                groupDescFieldActionPerformed(evt);
            }
        });

        snakeType.setModel(new javax.swing.DefaultComboBoxModel(
                new String[] { "Horizontal snake", "Vertical snake", "No sorting" }));
        snakeType.setToolTipText("Type of motion pattern for stage during acquisition sequence");
        snakeType.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                snakeTypeActionPerformed(evt);
            }
        });

        snaketypelabel.setText("Snake type");

        insertType.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "No insert", "Normal", "CO2" }));
        insertType.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                insertTypeActionPerformed(evt);
            }
        });

        jLabel2.setText("Insert type");

        javax.swing.GroupLayout autoFOVPanelLayout = new javax.swing.GroupLayout(autoFOVPanel);
        autoFOVPanel.setLayout(autoFOVPanelLayout);
        autoFOVPanelLayout.setHorizontalGroup(autoFOVPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(autoFOVPanelLayout.createSequentialGroup().addContainerGap().addGroup(autoFOVPanelLayout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(autoFOVPanelLayout
                                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addGroup(autoFOVPanelLayout.createSequentialGroup().addComponent(ringRadiusLabel)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(ringRadiusField, javax.swing.GroupLayout.PREFERRED_SIZE, 53,
                                                javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addComponent(autoGenerateFOVsCheck, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                        autoFOVPanelLayout.createSequentialGroup().addComponent(noFOVLabel)
                                                .addPreferredGap(
                                                        javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                                .addComponent(noFOVsField, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                        43, javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addComponent(FOVPatternCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        Short.MAX_VALUE)
                                .addComponent(groupDescLabel).addComponent(groupDescField)
                                .addComponent(snakeType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(snaketypelabel)
                                .addComponent(insertType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addComponent(jLabel2)).addContainerGap(52, Short.MAX_VALUE)));
        autoFOVPanelLayout.setVerticalGroup(autoFOVPanelLayout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(autoFOVPanelLayout.createSequentialGroup().addContainerGap()
                        .addComponent(autoGenerateFOVsCheck)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(autoFOVPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(noFOVLabel).addComponent(noFOVsField,
                                        javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(FOVPatternCombo, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(autoFOVPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(ringRadiusField, javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(ringRadiusLabel))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(groupDescLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(groupDescField, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(snaketypelabel).addGap(4, 4, 4)
                        .addComponent(snakeType, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(insertType, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addGroup(layout.createSequentialGroup()
                                        .addComponent(prefindPanel, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(storedXYZPanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                .addGroup(layout.createSequentialGroup()
                                        .addComponent(plateMapBasePanel, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(autoFOVPanel, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)))));
        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                javax.swing.GroupLayout.Alignment.TRAILING,
                layout.createSequentialGroup().addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(storedXYZPanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(prefindPanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(plateMapBasePanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(autoFOVPanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addContainerGap()));
    }// </editor-fold>//GEN-END:initComponents

    private void autoGenerateFOVsCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_autoGenerateFOVsCheckActionPerformed
        boolean autoFOV = autoGenerateFOVsCheck.isSelected();
        noFOVsField.setEnabled(autoFOV);
        FOVPatternCombo.setEnabled(autoFOV);
        ringRadiusField.setEnabled(autoFOV);
        if (autoFOV) {
            generateFOVs();
        }
    }//GEN-LAST:event_autoGenerateFOVsCheckActionPerformed

    public boolean reportAutogenerateFOVstatus() {
        return autoGenerateFOVsCheck.isSelected();
    }

    public void checkAutogenerateFOVs() {
        autoGenerateFOVsCheck.setSelected(true);
    }

    public void uncheckAutogenerateFOVs() {
        autoGenerateFOVsCheck.setSelected(false);
    }

    public void generateFOVs() {
        if (autoGenerateFOVsCheck.isSelected()) {

            ArrayList<FOV> fovs = new ArrayList<FOV>();
            ArrayList<FOV> preexisting = new ArrayList<FOV>(tableModel_.getData());
            tableModel_.clearAllData();

            for (int cols = 0; cols < pp_.getPlateColumns(); cols++) {
                ArrayList<Boolean> temp = pmdp_.wellsSelected_.get(cols);
                for (int rows = 0; rows < pp_.getPlateRows(); rows++) {
                    if (temp.get(rows)) {

                        String wellString = Character.toString((char) (65 + rows)) + Integer.toString(cols + 1);
                        if (FOVPatternCombo.getSelectedIndex() == 0) { // spiral pattern
                            fovs = generateSpiral(Integer.parseInt(noFOVsField.getText()), wellString);
                        } else {
                            fovs = generateRing(Integer.parseInt(noFOVsField.getText()), wellString);
                        }

                        for (FOV fov : fovs) {
                            if (preexisting.contains(fov)) {
                                //                                int ind = preexisting.indexOf(fov);
                                fov.setGroup(preexisting.get(preexisting.indexOf(fov)).getGroup());
                            } else {
                                fov.setGroup(groupDescField.getText());
                            }

                            tableModel_.addRow(fov);
                            //                            xyzmi_.fovXYtoStageXY(fov);
                        }

                        doZStackGeneration(getZStackParams());
                        //                        tableModel_.addRow(new FOV(wellString, pp_, 0));
                    }
                }
            }
        }
    }

    public void generatesearchFOVs() { // Copied from generateFOVs()
        ArrayList<FOV> searchfovs = new ArrayList<FOV>();
        //Use the display table to 
        ArrayList<FOV> preexisting = new ArrayList<FOV>(tableModel_.getData());
        searchFOVtableModel_.clearAllData();
        tableModel_.clearAllData();
        //Clear pre-existing FOV table? Not sure yet, so comment out
        //tableModel_.clearAllData();

        for (int cols = 0; cols < pp_.getPlateColumns(); cols++) {
            ArrayList<Boolean> temp = pmdp_.wellsSelected_.get(cols);
            for (int rows = 0; rows < pp_.getPlateRows(); rows++) {
                if (temp.get(rows)) {

                    //Always do spiral for now...

                    String wellString = Character.toString((char) (65 + rows)) + Integer.toString(cols + 1);
                    //Max # of times to search = #of FOVs desired * #to try before giving up
                    searchfovs = generateSpiral(
                            parent_.getPrefind_NoOfAttempts() * parent_.getPrefind_NoOfFOVToFind(), wellString);
                    //searchfovs = generateSpiral(Integer.parseInt(FOVToFindField.getText())*(Integer.parseInt(attemptsField.getText())),wellString);

                    for (FOV fov : searchfovs) {
                        //Do we need this part?
                        if (preexisting.contains(fov)) {
                            fov.setGroup(preexisting.get(preexisting.indexOf(fov)).getGroup());
                        } else {
                            fov.setGroup(groupDescField.getText());
                        }

                        searchFOVtableModel_.addRow(fov);
                    }
                    //Can ignore the Z stuff?
                    //doZStackGeneration(getZStackParams());
                }
            }
        }
    }

    public String getSelectedAnalyser() {
        //System.out.println(prefindMacroname.getSelectedItem().toString());
        String selected_analyser = "default.ijm";
        System.out.print(prefindMacroname.getSelectedItem().toString());
        if (prefindMacroname.getSelectedItem().toString().length() > 0) {
            selected_analyser = prefindMacroname.getSelectedItem().toString();
        }
        return selected_analyser;
    }

    private ArrayList<FOV> generateSpiral1(int noFOV, String wellString) {

        // cover whole well in a rectangle; remove those outwith well bounds;
        // finally trim to #fov. Deals with asymmetric FOV
        ArrayList<FOV> spiralFOVs = new ArrayList<FOV>();
        FOV fov = new FOV(wellString, pp_, 0);
        double[] centrexy = { fov.getX(), fov.getY() };
        //        double[] DXY = {sap_.getFLIMFOVSize()[0], sap_.getFLIMFOVSize()[1]};
        double[] DXY = { parent_.globalFOVset_.getWidth_(), parent_.globalFOVset_.getHeight_() };
        int[][] dir = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };
        double[] dxy = new double[2];
        int stepsInCurrentDir;

        spiralFOVs.add(fov);
        int fovind = 1;
        int dirind = 0;
        while (fovind < noFOV & dirind < 100) { // just in case we have a runaway case...

            stepsInCurrentDir = (int) Math.ceil((double) (dirind) / 2);

            dxy[0] = dir[dirind % 4][0] * DXY[0];
            dxy[1] = dir[dirind % 4][1] * DXY[1];
            for (int j = 0; j < stepsInCurrentDir; j++) {
                centrexy[0] += dxy[0];
                centrexy[1] += dxy[1];
                fov = new FOV(centrexy[0], centrexy[1], 0, wellString, pp_);
                if (fov.isValid()) {
                    spiralFOVs.add(fov);
                    fovind++;
                }
            }
            dirind++;
            //    System.out.print("Dirind = " + dirind + "\n");
        }
        // trim, a bit hacky but works
        int currsize = spiralFOVs.size();
        for (int j = currsize - 1; j > noFOV - 1; j--) {
            spiralFOVs.remove(j);
        }
        return spiralFOVs;
    }

    private ArrayList<FOV> generateSpiral11(int noFOV, String wellString) {

        // cover whole well in a rectangle; remove those outwith well bounds;
        // finally trim to #fov. Deals with asymmetric FOV
        ArrayList<FOV> spiralFOVs = new ArrayList<FOV>();
        FOV fov = new FOV(wellString, pp_, 0);
        double[] centrexy = { fov.getX(), fov.getY() };
        //        double[] DXY = {sap_.getFLIMFOVSize()[0], sap_.getFLIMFOVSize()[1]};
        double[] DXY = { parent_.globalFOVset_.getWidth_(), parent_.globalFOVset_.getHeight_() };

        /*int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
        double[] dxy = new double[2];
        int stepsInCurrentDir;*/

        spiralFOVs.add(fov);
        int fovind = 1;
        int dirind = 0;
        double nx = 1;
        double nxCount = 0;
        double ny = 1;
        double nyCount = 0;

        while (fovind < noFOV & dirind < 100) { // just in case we have a runaway case...
            //stepsInCurrentDir = (int) Math.ceil((double) (dirind) / 2);
            if (fovind % 2 == 0) {

                while (nyCount < abs(ny)) {
                    centrexy[1] = centrexy[1] + (ny + nyCount) * DXY[1];
                    nyCount++;

                }
                ny = -(abs(ny) + 1);
            } else {

                while (nxCount < abs(nx)) {
                    centrexy[0] = centrexy[0] + (nx + nyCount) * DXY[0];
                    nxCount++;

                }
                nx = -(abs(nx) + 1);
            }

            fovind++;
            fov = new FOV(centrexy[0], centrexy[1], 0, wellString, pp_);

            if (fov.isValid()) {
                spiralFOVs.add(fov);
            }

            System.out.println(fov.toString());
            dirind++;
            //    System.out.print("Dirind = " + dirind + "\n");
        }
        // trim, a bit hacky but works
        int currsize = spiralFOVs.size();
        for (int j = currsize - 1; j > noFOV - 1; j--) {
            spiralFOVs.remove(j);
        }
        return spiralFOVs;
    }

    private ArrayList<FOV> generateSpiral(int noFOV, String wellString) {
        spiralFOVs.clear();
        // cover whole well in a rectangle; remove those outwith well bounds;
        // finally trim to #fov. Deals with asymmetric FOV

        FOV fov = new FOV(wellString, pp_, 0);
        double[] centrexy = { fov.getX(), fov.getY() };
        //        double[] DXY = {sap_.getFLIMFOVSize()[0], sap_.getFLIMFOVSize()[1]};
        double[] DXY = { parent_.globalFOVset_.getWidth_um(), parent_.globalFOVset_.getHeight_um() };

        /*int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
        double[] dxy = new double[2];
        int stepsInCurrentDir;*/
        spiralFOVs.add(fov);
        int fovind = 1;
        int dirind = 0;
        double nx = 0;
        double ny = 0;

        //        System.out.println("Start");
        //        System.out.println("y: "+fov.getY()+"    x: "+fov.getX()+"           ny: "+ny+"    nx: "+nx);
        // 
        while (fovind < noFOV & dirind < 1000) { // just in case we have a runaway case...
            ny++;
            for (int iy = 0; iy < ny; iy++) {
                if (fovind < noFOV) {
                    centrexy = mysteriousSpiralProducer(ny, nx, wellString, centrexy, spiralFOVs);
                    fovind++;
                }
            }
            nx++;
            for (int ix = 0; ix < nx; ix++) {
                if (fovind < noFOV) {
                    centrexy = mysteriousSpiralProducer(ny, nx, wellString, centrexy, spiralFOVs);
                    fovind++;
                }
            }
            dirind++;
        }
        // trim, a bit hacky but works
        int currsize = spiralFOVs.size();
        for (int j = currsize - 1; j > noFOV - 1; j--) {
            spiralFOVs.remove(j);
        }
        //        System.out.println("END");
        return spiralFOVs;
    }

    private double[] mysteriousSpiralProducer(double ny, double nx, String wellString, double[] centrexy,
            ArrayList<FOV> spiralFgOVs) {
        FOV fov = new FOV(wellString, pp_, 0);
        double[] DXY = { parent_.globalFOVset_.getWidth_um(), parent_.globalFOVset_.getHeight_um() };
        if (nx == 0 & ny == 1) {
            centrexy[1] = centrexy[1] + DXY[1];
            fov = new FOV(centrexy[0], centrexy[1], 0, wellString, pp_);
            spiralFOVs.add(fov);
        } else if (nx == ny) {
            if (nx % 2 == 0) {
                centrexy[0] = centrexy[0] - DXY[0];
                fov = new FOV(centrexy[0], centrexy[1], 0, wellString, pp_);
                spiralFOVs.add(fov);

            } else {
                centrexy[0] = centrexy[0] + DXY[0];
                fov = new FOV(centrexy[0], centrexy[1], 0, wellString, pp_);
                spiralFOVs.add(fov);
            }
        } else if (nx != ny) {
            if (ny % 2 == 0) {
                centrexy[1] = centrexy[1] - DXY[1];
                fov = new FOV(centrexy[0], centrexy[1], 0, wellString, pp_);
                spiralFOVs.add(fov);

            } else {
                centrexy[1] = centrexy[1] + DXY[1];
                fov = new FOV(centrexy[0], centrexy[1], 0, wellString, pp_);
                spiralFOVs.add(fov);
            }
        } else {
            System.out.println("Couldn't identify Spiral operator!");
        }
        //        System.out.println("y: "+fov.getY()+"    x: "+fov.getX()+"           ny: "+ny+"    nx: "+nx);
        return centrexy;
    }

    private ArrayList<FOV> generateRing(int noFOV, String wellString) {
        //  generate FOV in a ring with specific diameter 
        ArrayList<FOV> ringFOVs = new ArrayList<FOV>();
        FOV fov = new FOV(wellString, pp_, 0);

        //  Get all values (master offset, center of FOV, radius of ring, noFOV) and estimate the stepsize
        double[] centrexy = { fov.getX() + var_.xOffset, fov.getY() + var_.yOffset };
        double stepSize = (double) (2 * Math.PI) / noFOV;
        double ringRadius = Double.parseDouble(ringRadiusField.getText());

        for (int j = 0; j < noFOV; j++) {
            // doing a circle step for every j
            double xRing = Math.round(Math.cos(stepSize * j) * ringRadius);
            double yRing = Math.round(Math.sin(stepSize * j) * ringRadius);
            double xt = centrexy[0] + xRing;
            double yt = centrexy[1] + yRing;
            double[] centrexyNew = { xt, yt };

            // add to FOV
            fov = new FOV(centrexyNew[0], centrexyNew[1], 0, wellString, pp_);

            ringFOVs.add(fov);
        }
        return ringFOVs;
    }

    private void noFOVsFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_noFOVsFieldActionPerformed
        generateFOVs();
    }//GEN-LAST:event_noFOVsFieldActionPerformed

    private void FOVPatternComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_FOVPatternComboActionPerformed
        generateFOVs();
    }//GEN-LAST:event_FOVPatternComboActionPerformed

    private void ringRadiusFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ringRadiusFieldActionPerformed
        generateFOVs();
    }//GEN-LAST:event_ringRadiusFieldActionPerformed

    private void clearXYZButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearXYZButtonActionPerformed
        tableModel_.clearAllData();
        pmdp_.clearAllWells();
    }//GEN-LAST:event_clearXYZButtonActionPerformed

    private void genZStackButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_genZStackButtonActionPerformed
        //TODO: generate new FOV in current position if FOV table is empty. 
        //TODO: 

        double startUm = -1.0;
        double endUm = -1.0;
        double stepUm = 1.0;

        String um = "(" + "\u00B5" + "m)";
        JLabel messageLabel = new JLabel("<html>Please enter start, end and delta values for Z stack: </html>");
        JLabel startLabel = new JLabel("Start Z position " + um + ":");
        JLabel endLabel = new JLabel("End Z position " + um + ":");
        JLabel stepLabel = new JLabel("Step size " + um + ":");

        // Uses a custom NumberFormat.
        NumberFormat customFormat = NumberFormat.getInstance(new Locale("en_US"));
        JFormattedTextField customFormatField = new JFormattedTextField(new NumberFormatter(customFormat));

        JFormattedTextField startField = new JFormattedTextField(customFormat);
        startField.setValue(-3.0);
        JFormattedTextField endField = new JFormattedTextField(customFormat);
        endField.setValue(3.0);
        JFormattedTextField stepField = new JFormattedTextField(customFormat);
        stepField.setValue(1.0);

        JPanel zStackDialog = new JPanel();
        zStackDialog.setLayout(new BorderLayout(50, 100));

        JPanel controlsPanel = new JPanel();
        controlsPanel.setLayout(new GridLayout(3, 2, 50, 10));

        controlsPanel.add(startLabel);
        controlsPanel.add(startField);
        controlsPanel.add(endLabel);
        controlsPanel.add(endField);
        controlsPanel.add(stepLabel);
        controlsPanel.add(stepField);

        zStackDialog.add(messageLabel, BorderLayout.PAGE_START);
        zStackDialog.add(controlsPanel, BorderLayout.CENTER);

        int result = JOptionPane.showConfirmDialog(this, zStackDialog, "Z stack setup",
                JOptionPane.OK_CANCEL_OPTION);
        if (result == JOptionPane.OK_OPTION) {

            // must be a better way to achieve this...?
            if (startField.getValue().getClass() == Double.class) {
                startUm = (Double) (startField.getValue());
            } else {
                startUm = ((Long) startField.getValue()).doubleValue();
            }

            if (endField.getValue().getClass() == Double.class) {
                endUm = (Double) (endField.getValue());
            } else {
                endUm = ((Long) endField.getValue()).doubleValue();
            }

            if (stepField.getValue().getClass() == Double.class) {
                stepUm = (Double) (stepField.getValue());
            } else {
                stepUm = ((Long) stepField.getValue()).doubleValue();
            }

            setZStackParams(startUm, endUm, stepUm);

            doZStackGeneration(getZStackParams());
        }

    }//GEN-LAST:event_genZStackButtonActionPerformed

    //    public double getPrefindThreshold(){
    //        return Double.parseDouble(intensityThresoldField.getText().toString());
    //    }
    //    
    //    public double getPercentCoverage(){
    //        return Double.parseDouble(percentCoverage.getText().toString());
    //    }

    private void doZStackGeneration(double[] z) {
        double startUm = z[0];
        double endUm = z[1];
        double stepUm = z[2];

        ArrayList<FOV> temp = tableModel_.getData();
        ArrayList<FOV> newtemp = new ArrayList<FOV>();
        ArrayList<FOV> unique = new ArrayList<FOV>();

        for (FOV fov : temp) {
            if (!unique.contains(fov)) {
                fov.setZ(0);
                unique.add(fov);
            }
        }

        int Nz = (int) ((endUm - startUm) / stepUm + 1);

        for (FOV fov : unique) {

            for (int zpos = 0; zpos < Nz; zpos++) {

                double zed = startUm + zpos * stepUm;

                newtemp.add(new FOV(fov.getX(), fov.getY(), fov.getZ() + zed, fov.getWell(), fov.getPlateProps()));
            }
        }

        tableModel_.addWholeData(newtemp);
    }

    private void zModeComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zModeComboActionPerformed
        zAsOffset_ = (String) zModeCombo.getSelectedItem() == "Z as offset";
    }//GEN-LAST:event_zModeComboActionPerformed

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

        FOV newfov = xyzmi_.getCurrentFOV();
        tableModel_.addRow(newfov);
        //        doZStackGeneration(getZStackParams());
        // deal with ZFish case (tile FOVS)
        if (((String) FOVPatternCombo.getSelectedItem()).equals("ZFish") & autoGenerateFOVsCheck.isSelected()) {
            // currently hardcode fov size for 10 x objective...
            // adds 4 FOVs centred on current xy
            // boilerplate - tidy up!
            double fovx = 1256;
            double fovy = 920;
            FOV q1 = new FOV(newfov.getX() - fovx / 2, newfov.getY() - fovy / 2, newfov.getZ(), pp_);
            FOV q2 = new FOV(newfov.getX() + fovx / 2, newfov.getY() - fovy / 2, newfov.getZ(), pp_);
            FOV q3 = new FOV(newfov.getX() + fovx / 2, newfov.getY() + fovy / 2, newfov.getZ(), pp_);
            FOV q4 = new FOV(newfov.getX() - fovx / 2, newfov.getY() + fovy / 2, newfov.getZ(), pp_);
            tableModel_.addRow(q1);
            tableModel_.addRow(q2);
            tableModel_.addRow(q3);
            tableModel_.addRow(q4);

        }
        pmdp_.addSelectedWell(newfov.getWell());
    }//GEN-LAST:event_storeXYZButtonActionPerformed

    private void groupDescFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupDescFieldActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_groupDescFieldActionPerformed

    private void clearZButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearZButtonActionPerformed
        setZStackParams(0.0, 0.0, 1);
        doZStackGeneration(getZStackParams());
    }//GEN-LAST:event_clearZButtonActionPerformed

    private void fovTablePanelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_fovTablePanelMouseClicked
        // TODO add your handling code here:
    }//GEN-LAST:event_fovTablePanelMouseClicked

    private void prefindMacronameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prefindMacronameActionPerformed
        // TODO add your handling code here:
        parent_.updatePrefindPanel();
    }//GEN-LAST:event_prefindMacronameActionPerformed

    private void testPrefindActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_testPrefindActionPerformed
        parent_.testPrefind(); // TODO add your handling code here:
    }//GEN-LAST:event_testPrefindActionPerformed

    private void advancedPFButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_advancedPFButtonActionPerformed
        // Update the list of macros in the combobox nextdoor

        // http://rsb.info.nih.gov/ij/developer/api/ij/io/DirectoryChooser.html
        String directoryName = ij.IJ.getDirectory("macros");
        System.out.println(directoryName);
        // http://alvinalexander.com/java/list-files-directory-match-filename-extension-pattern
        java.util.Collection macrofiles;
        String[] filefilter = { "ijm" };
        File directory = new File(directoryName);

        //remove existing items
        //prefindMacroname.removeAllItems();
        prefindMacroname.removeItemAt(0);
        prefindMacroname.removeItemAt(0);
        prefindMacroname.removeItemAt(0);

        //New way

        File[] listOfFiles = directory.listFiles();
        for (int i = 0; i < listOfFiles.length; i++) {
            if (listOfFiles[i].isFile()) {
                prefindMacroname.addItem(listOfFiles[i].getName());
                System.out.println(listOfFiles[i].getName());
            } else if (listOfFiles[i].isDirectory()) {
            }
        }
        prefindMacroname.setSelectedIndex(1);
        //      //Old way...
        //        macrofiles = org.apache.commons.io.FileUtils.listFiles(directory, filefilter, false);
        // Unholy hybrid of: http://stackoverflow.com/questions/3293946/the-easiest-way-to-transform-collection-to-array
        //                 : http://stackoverflow.com/questions/1018750/how-to-convert-object-array-to-string-array-in-java
        //        String[] macros = new String[macrofiles.size()];
        //        Object[] macrofilesarray = macrofiles.toArray(new java.io.File[macrofiles.size()]);      
        //        for (int i=0;i<macrofiles.size();i++){
        //            // Just want the name, not the whole path...
        //            java.io.File filepath = new java.io.File(macrofilesarray[i].toString());
        //            macros[i] = filepath.getName();
        //        }
        //        // http://stackoverflow.com/questions/4620295/dynamically-change-jcombobox
        //        // http://stackoverflow.com/questions/2812850/how-to-use-map-element-as-text-of-a-jcombobox/2813094#2813094
        //        prefindMacroname.setModel(new javax.swing.DefaultComboBoxModel(macros));

    }//GEN-LAST:event_advancedPFButtonActionPerformed

    private void quickPFButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_quickPFButtonActionPerformed
        // Generate a spiral search pattern in each well - always spiral for now?
        generatesearchFOVs(); // does this need any other arguments?
        // Call the search function in the parent (HCAFLIMPluginFrame())
        try {
            parent_.prefindButtonPressed();
        } catch (Exception e) {
            System.out.println(e);
        }
    }//GEN-LAST:event_quickPFButtonActionPerformed

    private void snakeTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_snakeTypeActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_snakeTypeActionPerformed

    private void SaveXYZActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SaveXYZActionPerformed
        parent_.saveXYZ();
    }//GEN-LAST:event_SaveXYZActionPerformed

    private void LoadXYZActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_LoadXYZActionPerformed
        parent_.loadXYZ();
    }//GEN-LAST:event_LoadXYZActionPerformed

    private void FOVNudgeCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_FOVNudgeCheckboxActionPerformed
        parent_.FOVNudgeMode = FOVNudgeCheckbox.isSelected();
    }//GEN-LAST:event_FOVNudgeCheckboxActionPerformed

    private void insertTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_insertTypeActionPerformed
        double[] OldOffsets = getInsertOffsets();

        //setByLabel(objectiveComboBox, "Objective"); - don't need to perform checking function?
        if (InsertOffsetsloaded == true) {
            //get the offsets here...
            int whichinsert = insertType.getSelectedIndex();
            double[] NewOffsets = { Double.parseDouble(insertOffsetInfo[whichinsert][1]),
                    Double.parseDouble(insertOffsetInfo[whichinsert][2]),
                    Double.parseDouble(insertOffsetInfo[whichinsert][3]) }; // placeholder
            setInsertOffsets(NewOffsets);

            //Shift the stage to account for the objetive change
            double[] Shifts = { 0, 0, 0 };
            for (int i = 0; i <= 2; i++) {
                Shifts[i] = NewOffsets[i] - OldOffsets[i];
            }
            parent_.xyzmi_.moveXYRelative(Shifts[0], Shifts[1]); // ignoring Z for now
        }
    }//GEN-LAST:event_insertTypeActionPerformed

    public String getSnakeType() {
        return snakeType.getSelectedItem().toString();
    }

    public void setPlateProperties(PlateProperties pp) {
        pp_ = pp;
    }

    public double[] getInsertOffsets() {
        return insertOffsets;
    }

    public void setInsertOffsets(double[] newOffsets) {
        insertOffsets = newOffsets;
    }

    public void setParent(Object o) {
        parent_ = (HCAFLIMPluginFrame) o;
    }

    public double[] getZStackParams() {
        if (zAsOffset_)
            return zStackParams;
        else {
            try {
                double z1 = xyzmi_.getZAbsolute();
                double[] zs = { z1, z1, z1 };
                for (int ind = 1; ind < 3; ind++) {
                    zs[ind] = zs[ind] + zStackParams[ind];
                }
                return zs;
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        return zStackParams;
    }

    //    public int getNoOfAttempts(){
    //        return Integer.parseInt(this.attemptsField.getText());
    //    }
    //    
    //    public int getNoOfFOVToFind(){
    //        return Integer.parseInt(FOVToFindField.getText());
    //    }  

    public int getSearchRowCount() {
        return searchFOVtableModel_.getRowCount();
    }

    public ArrayList<FOV> getFOVTable() {
        return tableModel_.getData();
    }

    public void setZStackParams(double start, double end, double step) {
        this.zStackParams[0] = start;
        this.zStackParams[1] = end;
        this.zStackParams[2] = step;
    }

    public XYZMotionInterface getXYZMotionInterface() {
        return xyzmi_;
    }

    public void setXYZMotionInterface(XYZMotionInterface xyzmi_) {
        this.xyzmi_ = xyzmi_;
    }

    public void sendEmail(String subject, String text, String toEmail) {

        // Recipient's email ID needs to be mentioned.
        String to = toEmail;

        // Sender's email ID needs to be mentioned
        String from = "flimplatereader@gmail.com";

        // Assuming you are sending email from localhost
        String host = "localhost";

        // Get system properties
        //  Properties properties = System.getProperties();
        Properties properties = System.getProperties();

        // Setup mail server
        //properties.setProperty("mail.smtp.host", "10.101.3.229");
        properties.setProperty("mail.smtp.host", "smtp.gmail.com");
        properties.put("mail.smtp.port", "587");
        properties.setProperty("mail.user", "flimplatereader");
        properties.setProperty("mail.password", "flimimages");
        properties.put("mail.smtp.starttls.enable", "true");
        properties.put("mail.smtp.auth", "true"); //enable authentication

        final String pww = "flimimages";
        Session session;
        session = Session.getDefaultInstance(properties, new javax.mail.Authenticator() {
            protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
                return new javax.mail.PasswordAuthentication("flimplatereader@gmail.com", pww);
            }
        });

        try {
            // Create a default MimeMessage object.
            MimeMessage message = new MimeMessage(session);

            // Set From: header field of the header.
            message.setFrom(new InternetAddress(from));

            // Set To: header field of the header.
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

            // Set Subject: header field
            message.setSubject(subject);

            // Now set the actual message
            message.setText(text);

            // Send message
            Transport.send(message);
            System.out.println("Sent message successfully....");
        } catch (MessagingException mex) {
            mex.printStackTrace();
        }
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox FOVNudgeCheckbox;
    private javax.swing.JComboBox FOVPatternCombo;
    private javax.swing.JButton LoadXYZ;
    private javax.swing.JButton SaveXYZ;
    private javax.swing.JToggleButton advancedPFButton;
    private javax.swing.JPanel autoFOVPanel;
    private javax.swing.JCheckBox autoGenerateFOVsCheck;
    private javax.swing.JButton clearXYZButton;
    private javax.swing.JButton clearZButton;
    private javax.swing.JPanel fovTablePanel;
    private javax.swing.JButton genZStackButton;
    private javax.swing.JTextField groupDescField;
    private javax.swing.JLabel groupDescLabel;
    private javax.swing.JComboBox<String> insertType;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel noFOVLabel;
    private javax.swing.JFormattedTextField noFOVsField;
    private javax.swing.JPanel plateMapBasePanel;
    private javax.swing.JComboBox<String> prefindMacroname;
    private javax.swing.JPanel prefindPanel;
    private javax.swing.JButton quickPFButton;
    private javax.swing.JFormattedTextField ringRadiusField;
    private javax.swing.JLabel ringRadiusLabel;
    private javax.swing.JComboBox snakeType;
    private javax.swing.JLabel snaketypelabel;
    private javax.swing.JButton storeXYZButton;
    private javax.swing.JPanel storedXYZPanel;
    private javax.swing.JButton testPrefind;
    private javax.swing.JComboBox zModeCombo;
    // End of variables declaration//GEN-END:variables

}