/*
 * 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 turgen.tapeimageextractor;

import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ItemEvent;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import turgen.DialogManager;
import turgen.UIPersistor;
import turgen.Utils;

/**
 *
 * @author michael
 */
public class ExtractorDialog extends javax.swing.JDialog implements UIPersistor,ListSelectionListener,ExtractionReporter {

    /**
     * Creates new form ExtractorFrame
     */
    public ExtractorDialog() {
        
        normalFont = new Font("Monospaced",Font.PLAIN,12);
        biggerFont = new Font("Monospaced",Font.PLAIN,14);
                
        setModal(true);
        tapeImageModel = new TapeImageModel();
        initComponents();
        jtbChunks.getSelectionModel().addListSelectionListener(this);
        setSelectionSensitiveControlsEnabled(false);
    }

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

        fcOpenTapeImage = new javax.swing.JFileChooser();
        fcSaveData = new javax.swing.JFileChooser();
        jtbTools = new javax.swing.JToolBar();
        jbtOpen = new javax.swing.JButton();
        jSeparator3 = new javax.swing.JToolBar.Separator();
        jbtSelectAll = new javax.swing.JButton();
        jSeparator4 = new javax.swing.JToolBar.Separator();
        jbtSetExtractionHint = new javax.swing.JButton();
        jbtExtractAsIs = new javax.swing.JButton();
        jSeparator5 = new javax.swing.JToolBar.Separator();
        jtgbMagnify = new javax.swing.JToggleButton();
        tabTabs = new javax.swing.JTabbedPane();
        jspChunks = new javax.swing.JScrollPane();
        jtbChunks = new javax.swing.JTable();
        pReport = new javax.swing.JPanel();
        jspReport = new javax.swing.JScrollPane();
        jtaReport = new javax.swing.JTextArea();
        pReportButtons = new javax.swing.JPanel();
        jbtClearReport = new javax.swing.JButton();
        jmbMainMenu = new javax.swing.JMenuBar();
        jmFile = new javax.swing.JMenu();
        jmiOpen = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
        jmiExit = new javax.swing.JMenuItem();
        jmSelect = new javax.swing.JMenu();
        jmiSelectAll = new javax.swing.JMenuItem();
        jmiSelectNone = new javax.swing.JMenuItem();
        jmChunk = new javax.swing.JMenu();
        jmiSetExtractionHint = new javax.swing.JMenuItem();
        jSeparator2 = new javax.swing.JPopupMenu.Separator();
        jmiExtractAsIs = new javax.swing.JMenuItem();
        jmiExtractToBinaryFile = new javax.swing.JMenuItem();

        setTitle("Tape Image Extractor");

        jtbTools.setFloatable(false);
        jtbTools.setRollover(true);

        jbtOpen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/action_edit.png"))); // NOI18N
        jbtOpen.setText("Open");
        jbtOpen.setFocusable(false);
        jbtOpen.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jbtOpen.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jbtOpen.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onToolOpen(evt);
            }
        });
        jtbTools.add(jbtOpen);
        jtbTools.add(jSeparator3);

        jbtSelectAll.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/action_all.png"))); // NOI18N
        jbtSelectAll.setText("Select all");
        jbtSelectAll.setFocusable(false);
        jbtSelectAll.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jbtSelectAll.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jbtSelectAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onToolSelectAll(evt);
            }
        });
        jtbTools.add(jbtSelectAll);
        jtbTools.add(jSeparator4);

        jbtSetExtractionHint.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/action_instructions.png"))); // NOI18N
        jbtSetExtractionHint.setText("Set hint");
        jbtSetExtractionHint.setFocusable(false);
        jbtSetExtractionHint.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jbtSetExtractionHint.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jbtSetExtractionHint.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onToolSetExtractionHint(evt);
            }
        });
        jtbTools.add(jbtSetExtractionHint);

        jbtExtractAsIs.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/action_image.png"))); // NOI18N
        jbtExtractAsIs.setText("Extract");
        jbtExtractAsIs.setFocusable(false);
        jbtExtractAsIs.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jbtExtractAsIs.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jbtExtractAsIs.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onToolExtractAsIs(evt);
            }
        });
        jtbTools.add(jbtExtractAsIs);
        jtbTools.add(jSeparator5);

        jtgbMagnify.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/action_magnify.png"))); // NOI18N
        jtgbMagnify.setText("Magnify");
        jtgbMagnify.setFocusable(false);
        jtgbMagnify.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jtgbMagnify.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jtgbMagnify.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                onMagnifyToggled(evt);
            }
        });
        jtbTools.add(jtgbMagnify);

        getContentPane().add(jtbTools, java.awt.BorderLayout.NORTH);

        jspChunks.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N

        jtbChunks.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
        jtbChunks.setModel(tapeImageModel);
        jtbChunks.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
        jtbChunks.setSelectionMode(javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        jspChunks.setViewportView(jtbChunks);

        tabTabs.addTab("Tape image", jspChunks);

        pReport.setLayout(new java.awt.BorderLayout());

        jtaReport.setEditable(false);
        jtaReport.setColumns(20);
        jtaReport.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
        jtaReport.setRows(10);
        jspReport.setViewportView(jtaReport);

        pReport.add(jspReport, java.awt.BorderLayout.CENTER);

        jbtClearReport.setText("Clear");
        jbtClearReport.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onClearReport(evt);
            }
        });
        pReportButtons.add(jbtClearReport);

        pReport.add(pReportButtons, java.awt.BorderLayout.SOUTH);

        tabTabs.addTab("Report", pReport);

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

        jmFile.setMnemonic('F');
        jmFile.setText("File");

        jmiOpen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        jmiOpen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/document-open.png"))); // NOI18N
        jmiOpen.setMnemonic('O');
        jmiOpen.setText("Open tape image...");
        jmiOpen.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onMenuOpen(evt);
            }
        });
        jmFile.add(jmiOpen);
        jmFile.add(jSeparator1);

        jmiExit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/system-log-out.png"))); // NOI18N
        jmiExit.setMnemonic('x');
        jmiExit.setText("Exit");
        jmiExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onMenuExit(evt);
            }
        });
        jmFile.add(jmiExit);

        jmbMainMenu.add(jmFile);

        jmSelect.setMnemonic('S');
        jmSelect.setText("Select");

        jmiSelectAll.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK));
        jmiSelectAll.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/action_all_small.png"))); // NOI18N
        jmiSelectAll.setMnemonic('A');
        jmiSelectAll.setText("All chunks");
        jmiSelectAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onMenuSelectAll(evt);
            }
        });
        jmSelect.add(jmiSelectAll);

        jmiSelectNone.setMnemonic('N');
        jmiSelectNone.setText("No chunks");
        jmiSelectNone.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onMenuSelectNone(evt);
            }
        });
        jmSelect.add(jmiSelectNone);

        jmbMainMenu.add(jmSelect);

        jmChunk.setMnemonic('C');
        jmChunk.setText("Chunks");

        jmiSetExtractionHint.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_H, java.awt.event.InputEvent.CTRL_MASK));
        jmiSetExtractionHint.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/action_instructions_small.png"))); // NOI18N
        jmiSetExtractionHint.setMnemonic('S');
        jmiSetExtractionHint.setText("Set extraction hint...");
        jmiSetExtractionHint.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onMenuSetExtractionHint(evt);
            }
        });
        jmChunk.add(jmiSetExtractionHint);
        jmChunk.add(jSeparator2);

        jmiExtractAsIs.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E, java.awt.event.InputEvent.CTRL_MASK));
        jmiExtractAsIs.setIcon(new javax.swing.ImageIcon(getClass().getResource("/turgen/resources/document-save.png"))); // NOI18N
        jmiExtractAsIs.setMnemonic('E');
        jmiExtractAsIs.setText("Extract...");
        jmiExtractAsIs.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                OnMenuExtractAsIs(evt);
            }
        });
        jmChunk.add(jmiExtractAsIs);

        jmiExtractToBinaryFile.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_B, java.awt.event.InputEvent.CTRL_MASK));
        jmiExtractToBinaryFile.setText("Extract and embed to binary file...");
        jmiExtractToBinaryFile.setEnabled(false);
        jmChunk.add(jmiExtractToBinaryFile);

        jmbMainMenu.add(jmChunk);

        setJMenuBar(jmbMainMenu);

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

    private void onMenuOpen(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onMenuOpen
        
        int result = fcOpenTapeImage.showOpenDialog(this);
        if (result!=JFileChooser.APPROVE_OPTION) return;
        
        File f = fcOpenTapeImage.getSelectedFile();
        if (f==null) return;
        try {
            tapeImageModel.openTapeImage(f.getAbsolutePath());
        }
        catch (Exception e) {
            
            String msg = Utils.getTitledExceptionMessage("Unable to open tape image", e);
            JOptionPane.showMessageDialog(this, msg);
            e.printStackTrace();
        }
        
    }//GEN-LAST:event_onMenuOpen

    private void onToolOpen(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onToolOpen
        onMenuOpen(evt);
    }//GEN-LAST:event_onToolOpen

    private void onMenuSelectAll(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onMenuSelectAll
        jtbChunks.selectAll();
    }//GEN-LAST:event_onMenuSelectAll

    private void onToolSelectAll(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onToolSelectAll
        onMenuSelectAll(evt);
    }//GEN-LAST:event_onToolSelectAll

    private void onMenuExit(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onMenuExit
        tapeImageModel.clear();
        setVisible(false);
        dispose();
    }//GEN-LAST:event_onMenuExit

    private void onMenuSelectNone(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onMenuSelectNone
        jtbChunks.clearSelection();
    }//GEN-LAST:event_onMenuSelectNone

    private void onMenuSetExtractionHint(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onMenuSetExtractionHint
        
        /*Are there any chunks selected ?*/
        ListSelectionModel lsm = jtbChunks.getSelectionModel();
        if (lsm.isSelectionEmpty()==true) return;
        
        int[] indexes = jtbChunks.getSelectedRows();
        
        int lastFirst=-2;
        int lastLast=-2;
        int lastLengthOffset=-2;
        int last16BitLength=-2;
        
        int numFirstChanges=0;
        int numLastChanges=0;
        int numLengthOffsetChanges=0;
        int num16BitLengthChanges=0;
        
        int extractibleCount=0;
        
        
        for (int i=0;i<indexes.length;i++) {
            ExtractorChunk chunk = tapeImageModel.elementAt(indexes[i]);
            
            if (!chunk.isExtractible()) {
                continue;
            }
            extractibleCount++;
            
            int cf,cl,clo,cl16;
            cf=chunk.getSkipFirst();
            cl=chunk.getSkipLast();
            clo=chunk.getLengthOffset();
            cl16=chunk.isLength16Bit()?1:0;
            
            if (cf!=lastFirst) {
                numFirstChanges++;
                lastFirst=cf;
            }
            if (cl!=lastLast) {
                numLastChanges++;
                lastLast=cl;
            }
            if (clo!=lastLengthOffset) {
                numLengthOffsetChanges++;
                lastLengthOffset=clo;
            }
            if (cl16!=last16BitLength) {
                num16BitLengthChanges++;
                last16BitLength=cl16;
            }
            
        }
        
        /*No extractible chunks... nothing to do*/
        if (extractibleCount==0) return;
        
        /*Now check the common values*/
        if (numFirstChanges!=1) {
            lastFirst=0;
        }
        if (numLastChanges!=1) {
            lastLast=0;
        }
        if (numLengthOffsetChanges!=1) {
            lastLengthOffset=-1;
        }
        if (num16BitLengthChanges!=1) {
            last16BitLength=0;
        }
        
        /*Create the dialog*/
        if (setHintDialog==null) {
            setHintDialog = new SetHintDialog();
            setHintDialog.pack();
            DialogManager.centerContainer(setHintDialog);
        }
        setHintDialog.fillValues(lastFirst,lastLast,lastLengthOffset,(last16BitLength==1));
        setHintDialog.setVisible(true);
        
        HintsCrate crate = setHintDialog.getHintsCrate();
        if (crate!=null) {
            tapeImageModel.updateExtractionHints(indexes,crate);
        }
        /*Restore selection*/
        for(int i=0;i<indexes.length;i++) {
            jtbChunks.getSelectionModel().addSelectionInterval(indexes[i],indexes[i]);
        }
        
    }//GEN-LAST:event_onMenuSetExtractionHint

    private void onToolSetExtractionHint(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onToolSetExtractionHint
        onMenuSetExtractionHint(evt);
    }//GEN-LAST:event_onToolSetExtractionHint

    private void onMagnifyToggled(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_onMagnifyToggled
        if (evt.getStateChange()==ItemEvent.SELECTED) {
            jtbChunks.setFont(biggerFont);
            jtaReport.setFont(biggerFont);
        }
        else {
            jtbChunks.setFont(normalFont);
            jtaReport.setFont(normalFont);
        }
    }//GEN-LAST:event_onMagnifyToggled

    private void OnMenuExtractAsIs(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OnMenuExtractAsIs
        /*Are there any chunks selected ?*/
        ListSelectionModel lsm = jtbChunks.getSelectionModel();
        if (lsm.isSelectionEmpty()==true) return;
        
        /*Now we have indexes*/
        int[] indexes = jtbChunks.getSelectedRows();
        
        /*Display file chooser*/
        int result = fcSaveData.showSaveDialog(this);
        if (result!=JFileChooser.APPROVE_OPTION) return;
        
        File f = fcSaveData.getSelectedFile();
        if (f==null) return;
        try {
            jtaReport.setText("");
            ExtractionReportCrate erc = tapeImageModel.extractChunks(indexes, f.getAbsolutePath(),this);
            JOptionPane.showMessageDialog(this, erc.getFormattedMessage());
            
        }
        catch (Exception e) {
            String msg = Utils.getTitledExceptionMessage("Unable to extract chunks", e);
            JOptionPane.showMessageDialog(this, msg);
            e.printStackTrace();
            return;
        }
        
        
        
    }//GEN-LAST:event_OnMenuExtractAsIs

    private void onToolExtractAsIs(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onToolExtractAsIs
        OnMenuExtractAsIs(evt);
    }//GEN-LAST:event_onToolExtractAsIs

    private void onClearReport(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onClearReport
        jtaReport.setText("");
    }//GEN-LAST:event_onClearReport

    /**
     * @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(ExtractorDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(ExtractorDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(ExtractorDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ExtractorDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

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

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JFileChooser fcOpenTapeImage;
    private javax.swing.JFileChooser fcSaveData;
    private javax.swing.JPopupMenu.Separator jSeparator1;
    private javax.swing.JPopupMenu.Separator jSeparator2;
    private javax.swing.JToolBar.Separator jSeparator3;
    private javax.swing.JToolBar.Separator jSeparator4;
    private javax.swing.JToolBar.Separator jSeparator5;
    private javax.swing.JButton jbtClearReport;
    private javax.swing.JButton jbtExtractAsIs;
    private javax.swing.JButton jbtOpen;
    private javax.swing.JButton jbtSelectAll;
    private javax.swing.JButton jbtSetExtractionHint;
    private javax.swing.JMenu jmChunk;
    private javax.swing.JMenu jmFile;
    private javax.swing.JMenu jmSelect;
    private javax.swing.JMenuBar jmbMainMenu;
    private javax.swing.JMenuItem jmiExit;
    private javax.swing.JMenuItem jmiExtractAsIs;
    private javax.swing.JMenuItem jmiExtractToBinaryFile;
    private javax.swing.JMenuItem jmiOpen;
    private javax.swing.JMenuItem jmiSelectAll;
    private javax.swing.JMenuItem jmiSelectNone;
    private javax.swing.JMenuItem jmiSetExtractionHint;
    private javax.swing.JScrollPane jspChunks;
    private javax.swing.JScrollPane jspReport;
    private javax.swing.JTextArea jtaReport;
    private javax.swing.JTable jtbChunks;
    private javax.swing.JToolBar jtbTools;
    private javax.swing.JToggleButton jtgbMagnify;
    private javax.swing.JPanel pReport;
    private javax.swing.JPanel pReportButtons;
    private javax.swing.JTabbedPane tabTabs;
    // End of variables declaration//GEN-END:variables

    
    private final TapeImageModel tapeImageModel;
    private SetHintDialog setHintDialog;
    private final Font normalFont;
    private final Font biggerFont;
    
    public Object[] getPersistenceData() {
        Rectangle r = getBounds();
        Object[] persistenceData = new Object[5];
        persistenceData[0]=r;
        persistenceData[1]=fcOpenTapeImage.getCurrentDirectory().getAbsolutePath();
        
        /*Column sizes in playlist*/
        int cc = jtbChunks.getColumnCount();
        int[] colSizes = new int[cc];
        for(int i=0;i<cc;i++) {
            colSizes[i]=jtbChunks.getColumn(jtbChunks.getColumnName(i)).getWidth();
        }
        persistenceData[2]=colSizes;
        persistenceData[3]=fcSaveData.getCurrentDirectory().getAbsolutePath();
        persistenceData[4]=Boolean.valueOf(jtgbMagnify.isSelected());
        return persistenceData;
    }

    public void setPersistenceData(Object[] data) throws Exception {
        Rectangle r = (Rectangle)data[0];
        String path1 = (String)data[1];
        int[] colSizes = (int[])data[2];
        String path2 = (String)data[3];
        Boolean magnify = (Boolean)data[4];
        
        setBounds(r);
        fcOpenTapeImage.setCurrentDirectory(new File(path1));
        fcSaveData.setCurrentDirectory(new File(path2));
        jtgbMagnify.setSelected(magnify.booleanValue());
        
        for(int i=0;i<colSizes.length;i++) {
            jtbChunks.getColumn(jtbChunks.getColumnName(i)).setWidth(colSizes[i]);
            jtbChunks.getColumn(jtbChunks.getColumnName(i)).setPreferredWidth(colSizes[i]);
        }
        
    }

    public String getPersistenceId() {
        return getClass().getName();
    }

    public void setPersistenceDefaults() {
        pack();
    }

    public void updateFileDialogUI() {
        fcOpenTapeImage.updateUI();
        fcSaveData.updateUI();
    }
    
    private void setSelectionSensitiveControlsEnabled(boolean b) {
        jmiExtractAsIs.setEnabled(b);
        jmiSetExtractionHint.setEnabled(b);
        jbtExtractAsIs.setEnabled(b);
        jbtSetExtractionHint.setEnabled(b);
    }

    public void valueChanged(ListSelectionEvent e) {
        
        if (e.getValueIsAdjusting()) return;
        
        if (jtbChunks.getSelectionModel().isSelectionEmpty()) {
            setSelectionSensitiveControlsEnabled(false);
        }
        else {
            setSelectionSensitiveControlsEnabled(true);
        }
    }

    public void addMessage(String s) {
        jtaReport.append(s);
        jtaReport.append(System.getProperty("line.separator"));
    }
   
    
}
