java/fiji-Pombe_Analyzer_jar_1.0.0-SNAPSHOT_1/src/main/java/pombeAnalyzer/JFrame.java
package pombeAnalyzer;

import ij.IJ;
import ij.ImagePlus;
import org.scijava.command.Command;
import org.scijava.plugin.Plugin;
import ij.gui.GenericDialog;
import ij.io.DirectoryChooser;
import ij.io.Opener;
import ij.plugin.frame.RoiManager;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;



/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JFrame.java to edit this template
 */

/**
 *
 * @author nakaokahidenori
 */

@Plugin(type = Command.class, headless = true, menuPath = "MyPlugin>Pombe Analyzer")
public class JFrame extends javax.swing.JFrame implements Command {
    
    // Private fields
    Binarizer binarizer_;
    
    /**
     * Creates new form NewJFrame
     */
    public JFrame() {
        initComponents();
    }

    /**
     * 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() {

        jLabel13 = new javax.swing.JLabel();
        open = new javax.swing.JButton();
        rootdirectory = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        postable = new javax.swing.JTable();
        includeall = new javax.swing.JCheckBox();
        excludeall = new javax.swing.JCheckBox();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        objective = new javax.swing.JComboBox<>();
        jLabel3 = new javax.swing.JLabel();
        binning = new javax.swing.JComboBox<>();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        scale1 = new javax.swing.JTextField();
        scale2 = new javax.swing.JTextField();
        aux_magnification = new javax.swing.JCheckBox();
        jLabel7 = new javax.swing.JLabel();
        interval = new javax.swing.JTextField();
        timeunit = new javax.swing.JComboBox<>();
        jPanel2 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        keychannel = new javax.swing.JComboBox<>();
        jLabel9 = new javax.swing.JLabel();
        customkey = new javax.swing.JTextField();
        testimage = new javax.swing.JTextField();
        jLabel16 = new javax.swing.JLabel();
        modeslider = new javax.swing.JSlider();
        modevalue = new javax.swing.JTextField();
        jLabel10 = new javax.swing.JLabel();
        jLabel11 = new javax.swing.JLabel();
        mexicanhatslider = new javax.swing.JSlider();
        binarize = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JSeparator();
        processall = new javax.swing.JButton();
        progressbar = new javax.swing.JProgressBar();
        progresslabel = new javax.swing.JLabel();
        jPanel3 = new javax.swing.JPanel();

        jLabel13.setText("jLabel13");

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Pombe Analyzer");

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

        rootdirectory.setText("/path/to/root/directory");

        jLabel1.setText("Root Directory:");

        postable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Directory", "Images", "Include"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.Integer.class, java.lang.Boolean.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, true
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jScrollPane2.setViewportView(postable);

        includeall.setText("Include All");
        includeall.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                includeallActionPerformed(evt);
            }
        });

        excludeall.setText("Exclude All");
        excludeall.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                excludeallActionPerformed(evt);
            }
        });

        jLabel2.setText("Objective magnification:");

        objective.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "4", "10", "20", "40", "60", "100" }));
        objective.setSelectedIndex(3);
        objective.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                objectiveActionPerformed(evt);
            }
        });

        jLabel3.setText("Binning:");

        binning.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "1", "2", "4" }));
        binning.setToolTipText("");
        binning.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                binningActionPerformed(evt);
            }
        });

        jLabel4.setText("Scale:");

        jLabel5.setText("µm/pxl");

        jLabel6.setText("pxl/µm");

        scale1.setEditable(false);
        scale1.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        scale1.setText("6.192");
        scale1.setToolTipText("");

        scale2.setEditable(false);
        scale2.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        scale2.setText("0.161");

        aux_magnification.setLabel("Aux. Magnification (x1.5)");
        aux_magnification.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aux_magnificationActionPerformed(evt);
            }
        });

        jLabel7.setText("Time-lapse interval:");

        interval.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        interval.setText("5");

        timeunit.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "min", "h" }));

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(jLabel4))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                                    .addComponent(scale1, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(binning, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(objective, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(aux_magnification)
                                    .addComponent(jLabel6)))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(scale2, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(jLabel5))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(interval, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(timeunit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
                    .addComponent(jLabel3)
                    .addComponent(jLabel7))
                .addContainerGap(122, Short.MAX_VALUE))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(objective, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(aux_magnification))
                .addGap(18, 18, 18)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(binning, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(scale1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel4)
                    .addComponent(jLabel6))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(scale2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel5))
                .addGap(29, 29, 29)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel7)
                    .addComponent(interval, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(timeunit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(176, Short.MAX_VALUE))
        );

        jTabbedPane1.addTab("Parameters", null, jPanel1, "");
        jPanel1.getAccessibleContext().setAccessibleName("");

        jButton1.setText("Open Test Image");
        jButton1.setToolTipText("Randomly open a single image for testing binarization");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        keychannel.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "CFP", "GFP", "YFP", "RFP", "mCherry", "mVenus", "mNeonGreen", "channel000", "channel001", "channel002", "channel003", "Custom" }));
        keychannel.setSelectedIndex(3);
        keychannel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                keychannelActionPerformed(evt);
            }
        });

        jLabel9.setText("Key for images used for binarization:");

        customkey.setEditable(false);
        customkey.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        customkey.setText("Put Custom Key Here");

        testimage.setEditable(false);
        testimage.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        testimage.setText("Image to be tested");

        jLabel16.setText("Mode:");
        jLabel16.setToolTipText("Mode value of a test image");

        modeslider.setMajorTickSpacing(5);
        modeslider.setMaximum(10);
        modeslider.setMinorTickSpacing(1);
        modeslider.setPaintLabels(true);
        modeslider.setPaintTicks(true);
        modeslider.setSnapToTicks(true);
        modeslider.setToolTipText("");
        modeslider.setValue(1);
        modeslider.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                JFrame.this.mouseReleased(evt);
            }
        });

        modevalue.setEditable(false);
        modevalue.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        modevalue.setText("---");

        jLabel10.setText("Subtraction level:");
        jLabel10.setToolTipText("Mode value of an image is used to determine the background intensity. [Background] = [Mode]*[1+level/10]");

        jLabel11.setText("Mexican Hat Radious:");

        mexicanhatslider.setMajorTickSpacing(5);
        mexicanhatslider.setMaximum(10);
        mexicanhatslider.setMinorTickSpacing(1);
        mexicanhatslider.setPaintLabels(true);
        mexicanhatslider.setPaintTicks(true);
        mexicanhatslider.setSnapToTicks(true);
        mexicanhatslider.setToolTipText("");
        mexicanhatslider.setValue(7);
        mexicanhatslider.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                mouseReleased2(evt);
            }
        });

        binarize.setText("Test Run");
        binarize.setToolTipText("Run a binarizer for testing.");
        binarize.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                binarizeActionPerformed(evt);
            }
        });

        processall.setText("Process All & Save");
        processall.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                processallActionPerformed(evt);
            }
        });

        progressbar.setToolTipText("");

        progresslabel.setText("Processing ------ images out of ------");
        progresslabel.setToolTipText("");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING)
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
                                    .addGap(0, 0, Short.MAX_VALUE)
                                    .addComponent(testimage, javax.swing.GroupLayout.PREFERRED_SIZE, 547, javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addGroup(jPanel2Layout.createSequentialGroup()
                                    .addComponent(progressbar, javax.swing.GroupLayout.PREFERRED_SIZE, 266, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addGap(0, 0, Short.MAX_VALUE))
                                .addGroup(jPanel2Layout.createSequentialGroup()
                                    .addComponent(progresslabel, javax.swing.GroupLayout.PREFERRED_SIZE, 266, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(processall)))
                            .addGroup(jPanel2Layout.createSequentialGroup()
                                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jButton1)
                                    .addGroup(jPanel2Layout.createSequentialGroup()
                                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addGroup(jPanel2Layout.createSequentialGroup()
                                                .addGap(6, 6, 6)
                                                .addComponent(jLabel16)
                                                .addGap(18, 18, 18)
                                                .addComponent(modevalue, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE))
                                            .addComponent(binarize, javax.swing.GroupLayout.PREFERRED_SIZE, 150, javax.swing.GroupLayout.PREFERRED_SIZE))
                                        .addGap(18, 18, 18)
                                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addComponent(jLabel10)
                                            .addComponent(jLabel11))
                                        .addGap(18, 18, 18)
                                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addComponent(mexicanhatslider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                            .addComponent(modeslider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
                                .addGap(0, 0, Short.MAX_VALUE))))
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGap(15, 15, 15)
                        .addComponent(jLabel9)
                        .addGap(18, 18, 18)
                        .addComponent(keychannel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(customkey, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addGap(20, 20, 20))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGap(19, 19, 19)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(keychannel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel9)
                    .addComponent(customkey, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addComponent(jButton1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(testimage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(jLabel16)
                        .addComponent(modevalue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(jLabel10))
                    .addComponent(modeslider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(21, 21, 21)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(jLabel11)
                        .addComponent(binarize))
                    .addComponent(mexicanhatslider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(progressbar, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(progresslabel)
                    .addComponent(processall))
                .addContainerGap(26, Short.MAX_VALUE))
        );

        jTabbedPane1.addTab("Binarization", null, jPanel2, "");

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 579, Short.MAX_VALUE)
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 387, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("ROI refinement", jPanel3);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(open)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jLabel1))
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(includeall)
                    .addComponent(excludeall))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(rootdirectory, javax.swing.GroupLayout.PREFERRED_SIZE, 600, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jTabbedPane1))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(open)
                    .addComponent(jLabel1)
                    .addComponent(rootdirectory, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(18, 18, 18)
                        .addComponent(jScrollPane2))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(12, 12, 12)
                        .addComponent(jTabbedPane1)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(includeall)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(excludeall)
                .addGap(18, 18, 18))
        );

        jTabbedPane1.getAccessibleContext().setAccessibleName("");
        jTabbedPane1.getAccessibleContext().setAccessibleDescription("");

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

    private void openActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openActionPerformed
        // Choose a root directory where Pos folders are located.
        ij.io.DirectoryChooser dc = new DirectoryChooser("Choose a root directory");
        String rootdir = dc.getDirectory();
        rootdirectory.setText(rootdir);
        // Get a list of Pos folders
        File file = new File(rootdir);
        String[] directories = file.list(new FilenameFilter() {
            @Override
            public boolean accept(File f, String str) {
                if(f.isDirectory() && str.matches("Pos[0-9]{1,}")){
                    return true;
                }else return false;
            }
        });
        
        TableModel model = postable.getModel();
        DefaultTableModel new_model = new DefaultTableModel(){
            
            // Make The table non-editable, except Column2
            @Override
            public boolean isCellEditable(int row, int column)
            {
                // make read only fields except column 2
                return column == 2;
            }
            
            // This is to display checkbox in the JTable
            @Override
            public Class<?> getColumnClass(int column)
            {
                switch (column){
                    case 0:
                        return String.class;
                    case 1:
                        return Integer.class;
                    case 2:
                        return Boolean.class;
                }return null;
            }
            
        };
        
        for(int i=0; i<model.getColumnCount(); i++){
            new_model.addColumn(model.getColumnName(i)); 
        }
        new_model.setRowCount(directories.length);
        
        for(int i=0; i<directories.length; i++){
            new_model.setValueAt(directories[i], i, 0);
            new_model.setValueAt(false, i, 2);
            File posdir = new File(rootdir+directories[i]);
            File[] imageFiles = posdir.listFiles();
            int imageNum = 0;
            for(int j=0; j<imageFiles.length; j++){
                if(imageFiles[j].isFile() && !imageFiles[j].isHidden()) imageNum++;
            }
            new_model.setValueAt(imageNum, i, 1);
        }
        
        postable.setModel(new_model);
        
        
    }//GEN-LAST:event_openActionPerformed

    private void includeallActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_includeallActionPerformed
        if(includeall.isSelected()){
            excludeall.setSelected(false);
            for(int i=0; i<postable.getRowCount(); i++){
                postable.setValueAt(true, i, 2);
            }
        }
    }//GEN-LAST:event_includeallActionPerformed

    private void excludeallActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_excludeallActionPerformed
        if(excludeall.isSelected()){
            includeall.setSelected(false);
            for(int i=0; i<postable.getRowCount(); i++){
                postable.setValueAt(false, i, 2);
            }
        }
    }//GEN-LAST:event_excludeallActionPerformed

    private void objectiveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_objectiveActionPerformed
        setScale();     
    }//GEN-LAST:event_objectiveActionPerformed

    private void binningActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binningActionPerformed
        setScale(); 
    }//GEN-LAST:event_binningActionPerformed

    private void aux_magnificationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aux_magnificationActionPerformed
        setScale();
    }//GEN-LAST:event_aux_magnificationActionPerformed

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

        ArrayList<Integer> included_list = new ArrayList<>();
        for(int i=0; i<postable.getRowCount(); i++){
            if(postable.getValueAt(i, 2).equals(true)){
                included_list.add(i);
            }
        }
        if(included_list.size()==0){
            IJ.showMessage("No Position is included in the analysis list!");
            return;
        }else{
            // Randomly choose a position to be analyzed
            int test_pos_index = (int)Math.ceil(Math.random() * (included_list.size()-1));
            File test_pos_dir = new File(rootdirectory.getText()+postable.getValueAt(test_pos_index, 0));
            File[] test_image_list = test_pos_dir.listFiles();// This might includes Directories and hidden files.
            ArrayList<File> key_images = new ArrayList<>();
            String key = keychannel.getSelectedItem().toString();
            for(File f : test_image_list){
                if(f.getName().contains(key) && f.isFile() && !f.isHidden()) key_images.add(f);
            }
            if(key_images.size()==0){
                IJ.showMessage("No image matches with the specified key!!");
                return;
            }
            // Randomly choose an image to be analyzed
            int test_image_index = (int)Math.ceil(Math.random() * (key_images.size()-1));
            testimage.setText(key_images.get(test_image_index).getAbsolutePath());
            
            // Open a test image, copy, and show it
            Opener op = new Opener();
            ImagePlus imp = op.openImage(testimage.getText());
            ImagePlus imp_copy = (ImagePlus)imp.clone();
            imp_copy.show();
            IJ.run(imp_copy, "Enhance Contrast", "saturated=0.35");
            
            int mode = (int)(imp.getAllStatistics().dmode);
            modevalue.setText(Integer.valueOf(mode).toString());
            
        }
        
    }//GEN-LAST:event_jButton1ActionPerformed

    private void keychannelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keychannelActionPerformed
        if(keychannel.getSelectedItem().toString().equals("Custom")){
            customkey.setEditable(true);
        }else{
            customkey.setText("Put Custom Key Here");
            customkey.setEditable(false);
        }
    }//GEN-LAST:event_keychannelActionPerformed

    private void binarizeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binarizeActionPerformed
  
        // Get active image information. Changes will be made on the active image
        ImagePlus imp_active = IJ.getImage();
        ImagePlus imp_dup = imp_active.duplicate();// Use this for binarization
        imp_dup.show();
        int mode_level = modeslider.getValue();
        int mexican_radious = mexicanhatslider.getValue();
        binarizer_ = new Binarizer(imp_dup, mode_level, mexican_radious);
        binarizer_.run();
        
        // Find Cells
        CellFinder cf = new CellFinder(imp_dup, Double.parseDouble(scale2.getText()));
        cf.run();
        
        // Update a binarized image
        imp_dup.updateAndDraw();
    }//GEN-LAST:event_binarizeActionPerformed

    private void mouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mouseReleased
        if(binarizer_==null) return;
                
        int[] ids = ij.WindowManager.getIDList();
        if(ids.length<2) return; // There must be two images: the original and binarizee=d
        
        // Identify the original test image and shown binary image
        int index_original = 0;
        int index_bin = 0;
        for(int i : ids){
            if(ij.WindowManager.getImage(i).getTitle().startsWith("DUP")){
                index_bin = i;
            }else if(ij.WindowManager.getImage(i).getTitle().contains(keychannel.getSelectedItem().toString())){
                index_original = i;
            }
        }
        binarizer_ = new Binarizer(ij.WindowManager.getImage(index_original).duplicate(), modeslider.getValue(), mexicanhatslider.getValue());
        binarizer_.run();
        ij.WindowManager.getImage(index_bin).setProcessor(binarizer_.getImageProcessor());
        CellFinder cf = new CellFinder(ij.WindowManager.getImage(index_bin), Double.parseDouble(scale2.getText()));
        cf.run();
        ij.WindowManager.getImage(index_bin).updateAndDraw();
        
    }//GEN-LAST:event_mouseReleased

    private void mouseReleased2(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mouseReleased2
        mouseReleased(evt);
    }//GEN-LAST:event_mouseReleased2

    private void processallActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_processallActionPerformed
        
        GenericDialog gd = new GenericDialog("Process All Images in the Selected Directories...");
        gd.showDialog();
        if(gd.wasCanceled()) return;
        
        // Close all windows and create a file opener
        ij.WindowManager.closeAllWindows();
        Opener op = new Opener();
        
        // Process all images
        int mode_level = modeslider.getValue();
        int mexican_radious = mexicanhatslider.getValue();
        String key = keychannel.getSelectedItem().toString();
        double scale = Double.parseDouble(scale2.getText());
        int max = getNumberOfKeyImages();
        
        // Make directories for saveing binarized images
        for(int i=0; i<postable.getRowCount(); i++){
            if(postable.getValueAt(i, 2).equals(true)){
                String path = rootdirectory.getText()+postable.getValueAt(i, 0)+"/bin";
                File bindir = new File(path);    
                bindir.mkdir();
            }
        }
        
        // Swing worker
        // SwingWorker<Void, Integer>()
        // In this case, Void is the type of final result, and Integer is the type of published variable during the process.
        // We will publish the number of processed images, whose type is int
        SwingWorker sw = new SwingWorker<Void, Integer>(){
            @Override
            protected Void doInBackground() throws Exception {
                int processed = 0;// the number of processed images
                for(int i=0; i<postable.getRowCount(); i++){
                    if(postable.getValueAt(i, 2).equals(true)){
                        // Get key image list
                        File PosFolder = new File(rootdirectory.getText()+postable.getValueAt(i, 0));
                        File[] all_list = PosFolder.listFiles();// This includes everything like Directories and hidden files.
                        for(File f : all_list){
                            if(f.getName().contains(key) && f.isFile() && !f.isHidden()){
                                ImagePlus imp = op.openImage(f.getAbsolutePath());
                                binarizer_ = new Binarizer(imp, mode_level, mexican_radious);
                                binarizer_.run();
                                // For unknown reasons, imp.show() is required here to reflect the changes
                                // In order to avoid showing the images, roiManager was used
                                CellFinder cf = new CellFinder(imp, scale);
                                RoiManager rm = cf.run_with_roiManager();
                                imp.getProcessor().multiply(0); // Erase everything, then re-fill using roiManager
                                imp.updateAndDraw();
                                IJ.setForegroundColor(255, 255, 255);
                                rm.runCommand(imp,"Deselect");
                                rm.runCommand(imp,"Fill");
                                String path = rootdirectory.getText()+postable.getValueAt(i, 0)+"/bin";
                                IJ.saveAs(imp, "Tiff", path+"/"+f.getName());
                                processed++;
                                
                                // publish is a function of SwingWorker that publishes the transient result (# of proccessed images)
                                // The value is probably handed to List<Integer> chunks.
                                publish(processed);
                                Thread.sleep(100);// This is to update GUI?
                            }
                        }
                    }
                }
                return null;
            }
            @Override
            protected void process(List<Integer> chunks) {
                int i = chunks.get(chunks.size()-1);
                progressbar.setValue(100*i/max); // The last value in this array is all we care about.
                progresslabel.setText("Processing " + i + " of " + max);
            }            
        };
        sw.execute();
    }//GEN-LAST:event_processallActionPerformed

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

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

    @Override
    public void run() {
        //throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
        new JFrame().setVisible(true);
    }
    
    private void setScale(){
        int obj = Integer.parseInt(objective.getSelectedItem().toString());
        int bin = Integer.parseInt(binning.getSelectedItem().toString());
        boolean aux = aux_magnification.isSelected();
        
        ScaleCalculator sc = new ScaleCalculator(obj, bin, aux);
        scale2.setText(String.format("%.3f", sc.getScale_um_per_pxl()));
        scale1.setText(String.format("%.3f", sc.getScale_pxl_per_um()));
    }
    
    private int getNumberOfKeyImages(){
        int num = 0;
        String key = keychannel.getSelectedItem().toString();
        for(int i=0; i<postable.getRowCount(); i++){
            if(postable.getValueAt(i, 2).equals(true)){
                // Get image list
                File PosFolder = new File(rootdirectory.getText()+postable.getValueAt(i, 0));
                File[] all_list = PosFolder.listFiles();// This includes everything like Directories and hidden files.
                for(File f : all_list){
                    if(f.getName().contains(key) && f.isFile() && !f.isHidden()) num++;
                }
            }
        }
        return num;
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox aux_magnification;
    private javax.swing.JButton binarize;
    private javax.swing.JComboBox<String> binning;
    private javax.swing.JTextField customkey;
    private javax.swing.JCheckBox excludeall;
    private javax.swing.JCheckBox includeall;
    private javax.swing.JTextField interval;
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JLabel jLabel16;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JComboBox<String> keychannel;
    private javax.swing.JSlider mexicanhatslider;
    private javax.swing.JSlider modeslider;
    private javax.swing.JTextField modevalue;
    private javax.swing.JComboBox<String> objective;
    private javax.swing.JButton open;
    private javax.swing.JTable postable;
    private javax.swing.JButton processall;
    private javax.swing.JProgressBar progressbar;
    private javax.swing.JLabel progresslabel;
    private javax.swing.JTextField rootdirectory;
    private javax.swing.JTextField scale1;
    private javax.swing.JTextField scale2;
    private javax.swing.JTextField testimage;
    private javax.swing.JComboBox<String> timeunit;
    // End of variables declaration//GEN-END:variables
}
