Package uk.co.nimp.scardterminalmanager

Source Code of uk.co.nimp.scardterminalmanager.CardReaderManagerView$CardWarmConnectActionTask

/*
* CardReaderManagerView.java
*/
/**
*
* @author Sebastien Riou
*/
package uk.co.nimp.scardterminalmanager;

import java.util.EventObject;
import javax.smartcardio.CardNotPresentException;
import org.jdesktop.application.Application;
import uk.co.nimp.scard.log.StarScriptLogHandler;
import uk.co.nimp.scard.log.ScardPrintStreamLogHandler;
import uk.co.nimp.scard.log.MpScopeSequenceLogHandler;
import com.atolsystems.atolutilities.InputFileFormatException;
import code.from.internet.CloseableTabbedPaneListener;
import code.from.internet.JListUtility;
import code.from.internet.JarClassLoader;
import com.atolsystems.atolutilities.*;
import com.atolsystems.atolutilities.ACommandLineUtilities.Arg;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.smartcardio.CardException;
import javax.swing.event.DocumentEvent;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.Task;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.jdesktop.application.Application.ExitListener;
import uk.co.nimp.scard.*;
import uk.co.nimp.scard.Main.StdParams;
import uk.co.nimp.scard.log.MpManagerScriptLogHandler;
import uk.co.nimp.scard.log.VerilogStimuliLogHandler;
import uk.co.nimp.smartcard.Apdu;

/**
* The application's main frame.
*/
public final class CardReaderManagerView extends FrameView implements SmartCardTaskProcessor {

    public static final String LAST_TASK_PATH_KEY = "CardReaderManagerViewLastTaskPath";
    public static final String LAST_LOG_PATH_KEY = "CardReaderManagerViewLastLogPath";
    LoggingWindow appLoggingWindow;
    private ActiveTerminalPropertyListener activeTerminalPropertyListener;
    private boolean initCompleted;
    private List<GenericTerminalManager> terminalManagers;

    //needed for RMI scheme
    public boolean exist() throws Exception {
        return true;
    }
    protected HashMap<String, TerminalInfo> terminals;//this contain all terminals seen since startup. terminals are never removed from it

    protected class ConnectReaderAction extends javax.swing.AbstractAction {

        public void actionPerformed(ActionEvent e) {
            try {
                if (terminalsListSelection != LIST_AVAILABLE_TERMINALS) {
                    return;//terminal already connected
                }
                JList list = (JList) e.getSource();
                if (false == list.isSelectionEmpty()) {
                    String name = list.getSelectedValue().toString();
                    TerminalInfo tI = terminals.get(name);
                    StatusDisplayerLabel sdl = new StatusDisplayerLabel();
                    sdl.setText(name);
                    tI.setStatusDisplayer(sdl);
                    int index = loggingTabbedPane.getTabCount();
                    TerminalLoggingWindow logWindow = new TerminalLoggingWindow(tI);
                    loggingTabbedPane.addTab(name, logWindow);
                    tI.setTopComponentInTab(loggingTabbedPane.getComponentAt(index));
                    /*must be done before changing the list because the list update will trigger
                    update of status label, which is based on the selected tab in this case*/
                    loggingTabbedPane.setSelectedIndex(index);
                    DefaultListModel model = (DefaultListModel) list.getModel();
                    model.remove(list.getSelectedIndex());
                    if (0 == model.getSize()) {
                        terminalsListButtonGroup.setSelected(openedRadioButton.getModel(), true);
                        openedAction().run();
                    }
                    controlTabbedPane.add(logControlPanel);
                    enableConnectedTerminalsLists(true);
                }
            } catch (IOException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    protected TerminalInfo[] getSelectedTerminalInfo(boolean throwExceptionIfNoSelection) {
        int selected[] = readersList.getSelectedIndices();
        TerminalInfo out[] = null;
        TerminalLoggingWindow tLog = loggingTabbedPane.getSelectedTerminalLoggingWindow();

        if (selected.length > 0) {
            out = new TerminalInfo[selected.length];
            for (int i = 0; i < selected.length; i++) {
                NamedObject o = (NamedObject) readersList.getModel().getElementAt(selected[i]);
                out[i] = (TerminalInfo) o.getObject();
            }
        } else {
            if (null == tLog) {
                if (throwExceptionIfNoSelection) {
                    throw new RuntimeException("No terminal selected");
                }
            } else {
                out = new TerminalInfo[1];
                out[0] = tLog.gettI();
            }
        }
        return out;
    }

    protected void selectTerminalInReadersList(TerminalInfo tI) {
        NamedObject o = getNamedObjectInReadersList(tI);
        if (null != o) {
            readersList.setSelectedValue(o, true);
        }
    }

    protected NamedObject getNamedObjectInReadersList(TerminalInfo tI) {
        NamedObject out = null;
        for (int i = 0; i < readersList.getModel().getSize(); i++) {
            NamedObject trial = (NamedObject) readersList.getModel().getElementAt(i);
            if (trial.getObject() == tI) {
                out = trial;
                break;
            }
        }
        return out;
    }

    class ActiveLogHandler {

        final ScardLogHandler logHandler;
        final GenericTerminal terminal;

        public ActiveLogHandler(ScardLogHandler logHandler, GenericTerminal terminal) {
            this.logHandler = logHandler;
            this.terminal = terminal;
        }

        public ScardLogHandler getLogHandler() {
            return logHandler;
        }

        public GenericTerminal getTerminal() {
            return terminal;
        }
    }

    protected void addLogHandler() {
        try {
            DefaultListModel model = (DefaultListModel) availableLoggersList.getModel();
            int selectedIndexes[] = availableLoggersList.getSelectedIndices();
            if (selectedIndexes.length < 1) {
                return;//nothing to do
            }
            Class loggerClass = (Class) ((NamedObject) availableLoggersList.getSelectedValue()).getObject();
            Class[] args = new Class[1];
            args[0] = File.class;
            Constructor c = loggerClass.getConstructor(args);
            AFileChooser fileChooser;
            fileChooser = new AFileChooser((java.awt.Frame) null, true, LAST_LOG_PATH_KEY);
            fileChooser.setDialogTitle("Output file for " + loggerClass.getSimpleName());
            fileChooser.setAcceptAllFileFilterUsed(true);
            int option = fileChooser.showOpenDialog(null);
            if (option != JFileChooser.APPROVE_OPTION) {
                return;
            }
            fileChooser.saveCurrentPath();
            File out = fileChooser.getSelectedFile();
            fileChooser.dispose();
            TerminalInfo[] selectedTerminalInfo = getSelectedTerminalInfo(true);
            File targetFile = out;
            String extension = AFileUtilities.extractFileExtension(out.getCanonicalPath());
            String path = out.getCanonicalPath();
            String baseName;
            if (extension.isEmpty()) {
                baseName = path;
            } else {
                baseName = path.substring(0, path.length() - extension.length() - 1);
            }
            model = (DefaultListModel) registeredLoggersList.getModel();
            for (int i = 0; i < selectedTerminalInfo.length; i++) {
                if (selectedTerminalInfo.length > 1) {
                    targetFile = new File(baseName + " - " + selectedTerminalInfo[i].getTerminal().getName() + "." + extension);
                }
                ScardLogHandler logger = (ScardLogHandler) c.newInstance(targetFile);
                selectedTerminalInfo[i].getTerminal().addLogHandler(logger);
                String name = logger.getClass().getSimpleName() + " - " + selectedTerminalInfo[i].getTerminal().getName();
                name += " - " + targetFile.getName() + " (" + targetFile.getParent() + ")";
                NamedObject o = new NamedObject(name, new ActiveLogHandler(logger, selectedTerminalInfo[i].getTerminal()));
                model.addElement(o);
            }
        } catch (Exception ex) {
            Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    protected void removeLogHandler() {
        try {
            DefaultListModel model = (DefaultListModel) registeredLoggersList.getModel();
            int selectedIndexes[] = registeredLoggersList.getSelectedIndices();
            if (selectedIndexes.length < 1) {
                return;//nothing to do
            }
            NamedObject o = (NamedObject) model.getElementAt(registeredLoggersList.getSelectedIndex());
            model.removeElementAt(registeredLoggersList.getSelectedIndex());
            ActiveLogHandler alh = (ActiveLogHandler) o.getObject();
            alh.getTerminal().closeLog(alh.getLogHandler());
            alh.getTerminal().removeLog(alh.getLogHandler());
        } catch (Exception ex) {
            Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    protected class AddLogAction extends javax.swing.AbstractAction {

        public void actionPerformed(ActionEvent e) {
            addLogHandler();
        }
    }

    protected class RemoveLogAction extends javax.swing.AbstractAction {

        public void actionPerformed(ActionEvent e) {
            removeLogHandler();
        }
    }
    Apdu manualApdu;

    protected Apdu makeManualApdu(boolean includeLc, boolean includeLe, boolean showErrorMessages) {
        //try to make an apdu
        Apdu out = null;
        try {
            String header = (String) apduHeaderTextField.getText();
            header = header.replaceAll("\\s", "");
            header = header.replaceAll("-", "");
            Apdu apdu = new Apdu();
            apdu.setHeader(header);
            apdu.setLcData(CardReaderManagerView.this.lcDataEditor.getText().replaceAll("\\s", "").replaceAll("-", ""));
            String le = CardReaderManagerView.this.leTextField.getText().replaceAll("\\s", "").replaceAll("-", "");
            if (!le.isEmpty()) {
                apdu.setExpectedLe(Integer.parseInt(le, 16));

            }
            out = apdu;
        } catch (Throwable ex) {
            if (showErrorMessages) {
                String msg = "Cannot parse the APDU, action cancelled:\n" + ex;
                JOptionPane.showMessageDialog(null, msg, "Incorrect input", JOptionPane.INFORMATION_MESSAGE);
            }
        }
        manualApdu = out;
        if (null == out) {
            if (this.isActiveTerminalReady()) {
                enableSendApduButtons(false);
            }
            this.sendApduButton.setToolTipText("APDU not recognized");
            this.sendApduNoLeButton.setToolTipText("APDU not recognized");
            this.sendApduNoLcButton.setToolTipText("APDU not recognized");
            return out;
        }
        String toolTip = out.toString().replace("\n", "<br>");
        toolTip = "<html>" + toolTip + "</html>";
        this.sendApduButton.setToolTipText(toolTip);
        Apdu outNoLe = out.clone();
        outNoLe.setExpectedLe(0);
        toolTip = outNoLe.toString().replace("\n", "<br>");
        toolTip = "<html>" + toolTip + "</html>";
        this.sendApduNoLeButton.setToolTipText(toolTip);
        Apdu outNoLc = out.clone();
        outNoLc.setLcData(new byte[0]);
        toolTip = outNoLc.toString().replace("\n", "<br>");
        toolTip = "<html>" + toolTip + "</html>";
        this.sendApduNoLcButton.setToolTipText(toolTip);
        if (this.isActiveTerminalReady()) {
            enableSendApduButtons(true);
        }

        if (!includeLc) {
            out = outNoLc;
        }
        if (!includeLe) {
            out = outNoLe;
        }
        return out;
    }

    void enableSendApduButtons(boolean enable) {
        this.sendApduButton.setEnabled(enable);
        this.sendApduNoLeButton.setEnabled(enable);
        this.sendApduNoLcButton.setEnabled(enable);
    }

    class ApduHeaderActionListener extends javax.swing.AbstractAction {

        public void actionPerformed(ActionEvent e) {
            //comboBoxChanged: fired selection changed or string has been edited
            //comboBoxEdited: fired when press enter, or when loosing focus and string has been edited
            if (false == e.getActionCommand().equals("comboBoxChanged")) {
                return;

            }
            loadApduFromApduComboBoxToTextFields();
        }
    }

    void loadApduFromApduComboBoxToTextFields(){
        String apduString = (String) CardReaderManagerView.this.apduComboBox.getSelectedItem();
        if ((null == apduString) || apduString.isEmpty()) {
            return;

        }
        Apdu apdu = new Apdu(apduString);
        CardReaderManagerView.this.lcDataEditor.setText(apdu.getLcDataAsString());
        String header = apdu.getClaAsString() + " ";
        header += apdu.getInsAsString() + " ";
        header += apdu.getP1AsString() + " ";
        header += apdu.getP2AsString();
        CardReaderManagerView.this.apduHeaderTextField.setText(header);
        CardReaderManagerView.this.leTextField.setText(apdu.getExpectedLeAsHexString());
    }

    class LcDataDocumentListener implements DocumentListener {

        void refreshLc() {
            String lcData = CardReaderManagerView.this.lcDataEditor.getText();
            lcData = lcData.replaceAll("\\s", "").replaceAll("-", "");
            int len = lcData.length();
            if ((1 == (len & 1)) || ((len / 2) > 255)) {
                CardReaderManagerView.this.lcTextField.setText("xx");
            } else {
                CardReaderManagerView.this.lcTextField.setText(AStringUtilities.byteToHex(len / 2));
            }
            CardReaderManagerView.this.makeManualApdu(true, true, false);
        }

        public void insertUpdate(DocumentEvent e) {
            refreshLc();
        }

        public void removeUpdate(DocumentEvent e) {
            refreshLc();
        }

        public void changedUpdate(DocumentEvent e) {
            refreshLc();
        }
    }

    class ApduPartDocumentListener implements DocumentListener {

        public void insertUpdate(DocumentEvent e) {
            CardReaderManagerView.this.makeManualApdu(true, true, false);
        }

        public void removeUpdate(DocumentEvent e) {
            CardReaderManagerView.this.makeManualApdu(true, true, false);
        }

        public void changedUpdate(DocumentEvent e) {
            CardReaderManagerView.this.makeManualApdu(true, true, false);
        }
    }

    protected class CloseTabListener implements CloseableTabbedPaneListener {

        /**
         * Informs all <code>CloseableTabbedPaneListener</code>s when a tab should be
         * closed
         * @param tabIndexToClose the index of the tab which should be closed
         * @return true if the tab can be closed, false otherwise
         */
        public boolean closeTab(int tabIndexToClose) {
            TerminalLoggingWindow log = (TerminalLoggingWindow) loggingTabbedPane.getTerminalLoggingWindowAt(tabIndexToClose);
            if (null == log) {
                return false;//never close the default log window
            }
            TerminalInfo tI = log.gettI();
            if (null != tI) {
                tI.setTopComponentInTab(null);
                tI.getStatusDisplayer().setText("");
            }
            if (2 == loggingTabbedPane.getTabCount())//if no terminal connected, (compare to 2 because the terminal tab is not removed yet)
            {
                terminalsListButtonGroup.setSelected(availableRadioButton.getModel(), true);
                availableAction().run();//force terminal list to show available terminals
                controlTabbedPane.remove(logControlPanel);//remove the logging tab
                enableConnectedTerminalsLists(false);//disable buttons to show coldConnect terminals
            }
            return true;//always close terminal logging windows
        }
    }

    class ActiveTerminalPropertyListener implements PropertyChangeListener {

        public void propertyChange(PropertyChangeEvent evt) {
            TerminalInfo tI = (TerminalInfo) evt.getNewValue();
            setStatusLabel(tI);
            if (null != tI) {
                Object selected[] = readersList.getSelectedValues();
                NamedObject toSelect = getNamedObjectInReadersList(tI);
                boolean found = false;
                for (int i = 0; i < selected.length; i++) {
                    if (selected[i] == toSelect) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    selectTerminalInReadersList(tI);
                }
            }
            enableCardRelatedComponents();
        }
    }

    boolean isActiveTerminalReady() {
        boolean enable = false;
        if (null != this.loggingTabbedPane.activeTerminal) {
            enable = this.loggingTabbedPane.activeTerminal.isPresent() & !this.loggingTabbedPane.activeTerminal.isBusy();

        }
        return enable;
    }

    void enableCardRelatedComponents() {
        boolean enable = isActiveTerminalReady();
        Component[] comps;
        comps = terminalConnectedPanel.getComponents();
        for (int i = 0; i < comps.length; i++) {
            comps[i].setEnabled(enable);
        }

        comps = this.scriptPanel.getComponents();
        for (int i = 0; i < comps.length; i++) {
            if (!comps[i].equals(this.startScriptButton)) {
                comps[i].setEnabled(enable);
            }
        }
        if (enable) {
            if (null != script) {
                startScriptButton.setEnabled(true);
            }
        } else {
            startScriptButton.setEnabled(false);
        }

        comps = this.taskPanel.getComponents();
        for (int i = 0; i < comps.length; i++) {
            comps[i].setEnabled(enable);
        }
        if (enable) {
            if (null != manualApdu) {
                this.enableSendApduButtons(true);
            }
        } else {
            this.enableSendApduButtons(false);
        }
    }

    void enableConnectedTerminalsLists(boolean enable) {
        this.openedRadioButton.setEnabled(enable);
        this.noCardRadioButton.setEnabled(enable);
        this.idleRadioButton.setEnabled(enable);
        this.busyRadioButton.setEnabled(enable);
    }

    protected void initLogControlPanel() {
        DefaultListModel model = new DefaultListModel();
        //Constructor c=new Constructor();
        model.addElement(new NamedObject(ScardPrintStreamLogHandler.class.getSimpleName(), ScardPrintStreamLogHandler.class));
        model.addElement(new NamedObject(StarScriptLogHandler.class.getSimpleName(), StarScriptLogHandler.class));
        model.addElement(new NamedObject(MpManagerScriptLogHandler.class.getSimpleName(), MpManagerScriptLogHandler.class));
        model.addElement(new NamedObject(MpScopeSequenceLogHandler.class.getSimpleName(), MpScopeSequenceLogHandler.class));
        model.addElement(new NamedObject(VerilogStimuliLogHandler.class.getSimpleName(), VerilogStimuliLogHandler.class));

        availableLoggersList.setModel(model);
        JListUtility.addAction(availableLoggersList, new AddLogAction());//add double click action
        model = new DefaultListModel();
        registeredLoggersList.setModel(model);
        JListUtility.addAction(registeredLoggersList, new RemoveLogAction());//add double click action

    }
    private static final KeyStroke DELETE = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);

    public static void addAction(JComboBox source, javax.swing.Action action) {
        //  Handle enter key
        InputMap im = source.getInputMap();
        im.put(DELETE, DELETE);
        source.getActionMap().put(DELETE, action);
    }

    void deleteApdu() {
        DefaultComboBoxModel model = (DefaultComboBoxModel) this.apduComboBox.getModel();
        int sel = this.apduComboBox.getSelectedIndex();
        model.removeElementAt(sel);
    }

    class deleteAction implements javax.swing.Action {

        public Object getValue(String key) {
            return this;
        }

        public void putValue(String key, Object value) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void setEnabled(boolean b) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public boolean isEnabled() {
            return true;
        }

        public void addPropertyChangeListener(PropertyChangeListener listener) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void actionPerformed(ActionEvent e) {
            deleteApdu();
        }
    }

    public static class MyOwnFocusTraversalPolicy
            extends FocusTraversalPolicy {

        Vector<Component> order;

        public MyOwnFocusTraversalPolicy(Vector<Component> order) {
            this.order = new Vector<Component>(order.size());
            this.order.addAll(order);
        }

        public Component getComponentAfter(Container focusCycleRoot,
                Component aComponent) {
            int idx = (order.indexOf(aComponent) + 1) % order.size();
            return order.get(idx);
        }

        public Component getComponentBefore(Container focusCycleRoot,
                Component aComponent) {
            int idx = order.indexOf(aComponent) - 1;
            if (idx < 0) {
                idx = order.size() - 1;
            }
            return order.get(idx);
        }

        public Component getDefaultComponent(Container focusCycleRoot) {
            return order.get(0);
        }

        public Component getLastComponent(Container focusCycleRoot) {
            return order.lastElement();
        }

        public Component getFirstComponent(Container focusCycleRoot) {
            return order.get(0);
        }
    }

    protected void initManualControlPanel() {
        this.enableSendApduButtons(false);
        apduComboBox.addActionListener(new ApduHeaderActionListener());
        addAction(apduComboBox, new deleteAction());
        ApduPartDocumentListener apduPartDocumentListener = new ApduPartDocumentListener();
        this.apduHeaderTextField.getDocument().addDocumentListener(apduPartDocumentListener);
        this.lcDataEditor.getDocument().addDocumentListener(new LcDataDocumentListener());
        this.leTextField.getDocument().addDocumentListener(apduPartDocumentListener);
        MyOwnFocusTraversalPolicy newPolicy;
        Vector<Component> order = new Vector<Component>(5);
        order.add(this.apduHeaderTextField);
        order.add(this.lcDataEditor);
        order.add(this.leTextField);
        order.add(this.sendApduButton);
        order.add(this.sendApduNoLeButton);
        order.add(this.sendApduNoLcButton);
        order.add(this.apduComboBox);
        newPolicy = new MyOwnFocusTraversalPolicy(order);
        manualControlPanel.setFocusTraversalPolicyProvider(true);
        manualControlPanel.setFocusTraversalPolicy(newPolicy);
        loadApduFromApduComboBoxToTextFields();
    }
    static final String ARG_HELP = "-help";
    static final int ARG_HELP_ID = 0;
    static final String ARG_SET_CONF_FOLDER = "-confFolder:";
    static final int ARG_SET_CONF_FOLDER_ID = 1;
    static final String ARG_ADD_JAR_FILE = "-addJarFile:";
    static final int ARG_ADD_JAR_FILE_ID = 2;
    static final String ARG_ADD_TERMINAL_MANAGER = "-addTerminalManager:";
    static final int ARG_ADD_TERMINAL_MANAGER_ID = 3;

    protected void initClass(SingleFrameApplication app) {
        debugMenu.setVisible(false);

        sharedPanelPlaceHolder = new JPanel();
        taskLastSharedPanelPlaceHolder = dummySharedPanel;
        manualLastSharedPanelPlaceHolder = manualSharedPanel;
        scriptLastSharedPanelPlaceHolder = sharedPanel;

        visibleStatusLabel = statusMessageLabel;
        enableCardRelatedComponents();

        appLoggingWindow = new LoggingWindow();
        appLoggingWindow.putClientProperty("isClosable", false);
        loggingTabbedPane.addTab("App log", appLoggingWindow);
        loggingTabbedPane.enableHighlightOnChange(0, Color.orange, true, false, false);

        initLogControlPanel();
        initManualControlPanel();

        PipedOutputStream pos = new PipedOutputStream();
        PrintStream outStream = new PrintStream(pos);
        try {
            appLoggingWindow.monitorStream(pos);
            System.setOut(outStream);
            System.setErr(outStream);
        } catch (IOException ex) {
            Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
        }

        terminals = new HashMap<String, TerminalInfo>();
        loggingTabbedPane.addCloseableTabbedPaneListener(new CloseTabListener());


        readersList.setModel(new DefaultListModel());
        JListUtility.addAction(readersList, new ConnectReaderAction());//add double click action

        activeTerminalPropertyListener = new ActiveTerminalPropertyListener();
        loggingTabbedPane.addPropertyChangeListener(LogTabbedPane.SELECTED_TERMINAL_PROPERTY, activeTerminalPropertyListener);

        loadTerminalManagers();
        terminalListRefreshTimer = new Timer(1000, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                org.jdesktop.application.Task refreshTask = new RefreshReadersListTask(getApplication());
                refreshTask.run();
            }
        });
        if (null != terminalManagers) {
            LinkedList<GenericTerminal> availableTerminals = new LinkedList<GenericTerminal>();
            try {
                Main.getAvailableTerminals(terminalManagers, availableTerminals);
            } catch (ScardException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            }
            if (availableTerminals.isEmpty()) {
                Main.printNoTerminalMessage(terminalManagers);
            }

            terminalListRefreshTimer.setInitialDelay(0);
            terminalListRefreshTimer.start();
        } else {
            System.out.println("No terminal manager succesfully loaded: please check command line and \".conf\" files\n");
        }

        this.getFrame().addWindowFocusListener(new java.awt.event.WindowFocusListener() {

            public void windowGainedFocus(WindowEvent e) {
                if (null != terminalManagers) {
                    terminalListRefreshTimer.start();
                }
            }

            public void windowLostFocus(WindowEvent e) {
                terminalListRefreshTimer.stop();
            }
        });

        this.controlTabbedPane.remove(logControlPanel);

    }

    protected void loadTerminalManagers() {
        try {
            ArgSpec[] argSpecs = {};
            StdParams p = Main.processStdArgs(ScardTerminalManagerApp.args, argSpecs, this.getClass(), "ScardTerminalManager");
            terminalManagers = p.getTerminalManagers();
        } catch (Throwable ex) {
            Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public CardReaderManagerView(SingleFrameApplication app) {
        super(app);

        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action actionStarters to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String) (evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer) (evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
        initClass(app);
    }

    public class ViewExitListener implements ExitListener {

        public boolean canExit(EventObject event) {
            return true;
        }

        public void willExit(EventObject event) {
            //we restore the original state of tabs to avoid a warning from
            CardReaderManagerView.this.controlTabbedPane.setSelectedComponent(scriptPanel);
            CardReaderManagerView.this.controlTabbedPaneStateChanged(null);
            //JOptionPane.showConfirmDialog(null, "bye", "Bye", JOptionPane.OK_OPTION);
        }
    }

    public void endOfStartupHook() {
        this.controlTabbedPane.setSelectedComponent(scriptPanel);
        this.getApplication().addExitListener(new ViewExitListener());
        statusMessageLabel.setText("Ready");
        initCompleted = true;
    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = ScardTerminalManagerApp.getApplication().getMainFrame();
            aboutBox = new ScardTerminalManagerAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        ScardTerminalManagerApp.getApplication().show(aboutBox);
    }

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

        mainPanel = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        readersList = new javax.swing.JList();
        availableRadioButton = new javax.swing.JRadioButton();
        openedRadioButton = new javax.swing.JRadioButton();
        noCardRadioButton = new javax.swing.JRadioButton();
        idleRadioButton = new javax.swing.JRadioButton();
        busyRadioButton = new javax.swing.JRadioButton();
        jLabel1 = new javax.swing.JLabel();
        controlTabbedPane = new javax.swing.JTabbedPane();
        manualControlPanel = new javax.swing.JPanel();
        apduComboBox = new javax.swing.JComboBox();
        sendApduButton = new javax.swing.JButton();
        manualSharedPanel = new javax.swing.JPanel();
        jScrollPane4 = new javax.swing.JScrollPane();
        lcDataEditor = new javax.swing.JEditorPane();
        lcTextField = new javax.swing.JTextField();
        jLabel5 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        leTextField = new javax.swing.JTextField();
        apduHeaderTextField = new javax.swing.JTextField();
        clearApduButton = new javax.swing.JButton();
        sendApduNoLcButton = new javax.swing.JButton();
        sendApduNoLeButton = new javax.swing.JButton();
        scriptPanel = new javax.swing.JPanel();
        browseScriptButton = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        nRunTextField = new javax.swing.JTextField();
        sharedPanel = new javax.swing.JPanel();
        terminalConnectedPanel = new javax.swing.JPanel();
        cardConnectButton = new javax.swing.JButton();
        cardConnectButton1 = new javax.swing.JButton();
        cardDisconnectButton = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JSeparator();
        loggingTabbedPane = new uk.co.nimp.scardterminalmanager.LogTabbedPane();
        clearLogButton = new javax.swing.JButton();
        scriptFileTextField = new javax.swing.JTextField();
        startScriptButton = new javax.swing.JButton();
        taskPanel = new javax.swing.JPanel();
        startTaskButton = new javax.swing.JButton();
        dummySharedPanel = new javax.swing.JPanel();
        logControlPanel = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        availableLoggersList = new javax.swing.JList();
        jLabel3 = new javax.swing.JLabel();
        jScrollPane3 = new javax.swing.JScrollPane();
        registeredLoggersList = new javax.swing.JList();
        moveLoggersButton = new javax.swing.JButton();
        jLabel4 = new javax.swing.JLabel();
        openAllTerminalsButton = new javax.swing.JButton();
        openAllTerminalsWithCardButton = new javax.swing.JButton();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        debugModeMenuItem = new javax.swing.JMenuItem();
        debugMenu = new javax.swing.JMenu();
        debugMenuItem = new javax.swing.JMenuItem();
        debugBackGroundMenuItem = new javax.swing.JMenuItem();
        garbageCollectorMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();
        terminalsListButtonGroup = new javax.swing.ButtonGroup();

        mainPanel.setName("mainPanel"); // NOI18N

        jScrollPane1.setEnabled(false);
        jScrollPane1.setName("jScrollPane1"); // NOI18N
        jScrollPane1.setPreferredSize(new java.awt.Dimension(23, 23));

        readersList.setDoubleBuffered(true);
        readersList.setName("readersList"); // NOI18N
        readersList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                readersListValueChanged(evt);
            }
        });
        jScrollPane1.setViewportView(readersList);

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(uk.co.nimp.scardterminalmanager.ScardTerminalManagerApp.class).getContext().getActionMap(CardReaderManagerView.class, this);
        availableRadioButton.setAction(actionMap.get("availableAction")); // NOI18N
        terminalsListButtonGroup.add(availableRadioButton);
        availableRadioButton.setSelected(true);
        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(uk.co.nimp.scardterminalmanager.ScardTerminalManagerApp.class).getContext().getResourceMap(CardReaderManagerView.class);
        availableRadioButton.setText(resourceMap.getString("availableRadioButton.text")); // NOI18N
        availableRadioButton.setName("availableRadioButton"); // NOI18N

        openedRadioButton.setAction(actionMap.get("openedAction")); // NOI18N
        terminalsListButtonGroup.add(openedRadioButton);
        openedRadioButton.setText(resourceMap.getString("openedRadioButton.text")); // NOI18N
        openedRadioButton.setName("openedRadioButton"); // NOI18N

        noCardRadioButton.setAction(actionMap.get("noCardAction")); // NOI18N
        terminalsListButtonGroup.add(noCardRadioButton);
        noCardRadioButton.setText(resourceMap.getString("noCardRadioButton.text")); // NOI18N
        noCardRadioButton.setName("noCardRadioButton"); // NOI18N

        idleRadioButton.setAction(actionMap.get("idleAction")); // NOI18N
        terminalsListButtonGroup.add(idleRadioButton);
        idleRadioButton.setText(resourceMap.getString("idleRadioButton.text")); // NOI18N
        idleRadioButton.setName("idleRadioButton"); // NOI18N

        busyRadioButton.setAction(actionMap.get("busyAction")); // NOI18N
        terminalsListButtonGroup.add(busyRadioButton);
        busyRadioButton.setText(resourceMap.getString("busyRadioButton.text")); // NOI18N
        busyRadioButton.setName("busyRadioButton"); // NOI18N

        jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
        jLabel1.setName("jLabel1"); // NOI18N

        controlTabbedPane.setName("controlTabbedPane"); // NOI18N
        controlTabbedPane.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                controlTabbedPaneStateChanged(evt);
            }
        });

        manualControlPanel.setName("manualControlPanel"); // NOI18N

        apduComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "0084000010" }));
        apduComboBox.setToolTipText(resourceMap.getString("apduComboBox.toolTipText")); // NOI18N
        apduComboBox.setName("apduComboBox"); // NOI18N

        sendApduButton.setAction(actionMap.get("sendApduAction")); // NOI18N
        sendApduButton.setText(resourceMap.getString("sendApduButton.text")); // NOI18N
        sendApduButton.setName("sendApduButton"); // NOI18N

        manualSharedPanel.setName("manualSharedPanel"); // NOI18N

        javax.swing.GroupLayout manualSharedPanelLayout = new javax.swing.GroupLayout(manualSharedPanel);
        manualSharedPanel.setLayout(manualSharedPanelLayout);
        manualSharedPanelLayout.setHorizontalGroup(
            manualSharedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 546, Short.MAX_VALUE)
        );
        manualSharedPanelLayout.setVerticalGroup(
            manualSharedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 144, Short.MAX_VALUE)
        );

        jScrollPane4.setName("jScrollPane4"); // NOI18N

        lcDataEditor.setToolTipText(resourceMap.getString("lcDataEditor.toolTipText")); // NOI18N
        lcDataEditor.setName("lcDataEditor"); // NOI18N
        jScrollPane4.setViewportView(lcDataEditor);

        lcTextField.setEditable(false);
        lcTextField.setText(resourceMap.getString("lcTextField.text")); // NOI18N
        lcTextField.setFocusable(false);
        lcTextField.setName("lcTextField"); // NOI18N

        jLabel5.setText(resourceMap.getString("jLabel5.text")); // NOI18N
        jLabel5.setName("jLabel5"); // NOI18N

        jLabel6.setText(resourceMap.getString("jLabel6.text")); // NOI18N
        jLabel6.setName("jLabel6"); // NOI18N

        leTextField.setText(resourceMap.getString("leTextField.text")); // NOI18N
        leTextField.setName("leTextField"); // NOI18N

        apduHeaderTextField.setText(resourceMap.getString("apduHeaderTextField.text")); // NOI18N
        apduHeaderTextField.setToolTipText(resourceMap.getString("apduHeaderTextField.toolTipText")); // NOI18N
        apduHeaderTextField.setName("apduHeaderTextField"); // NOI18N

        clearApduButton.setAction(actionMap.get("clearApduButton")); // NOI18N
        clearApduButton.setText(resourceMap.getString("clearApduButton.text")); // NOI18N
        clearApduButton.setName("clearApduButton"); // NOI18N

        sendApduNoLcButton.setAction(actionMap.get("sendApduNoLcAction")); // NOI18N
        sendApduNoLcButton.setText(resourceMap.getString("sendApduNoLcButton.text")); // NOI18N
        sendApduNoLcButton.setName("sendApduNoLcButton"); // NOI18N

        sendApduNoLeButton.setAction(actionMap.get("sendApduNoLe")); // NOI18N
        sendApduNoLeButton.setText(resourceMap.getString("sendApduNoLeButton.text")); // NOI18N
        sendApduNoLeButton.setName("sendApduNoLeButton"); // NOI18N

        javax.swing.GroupLayout manualControlPanelLayout = new javax.swing.GroupLayout(manualControlPanel);
        manualControlPanel.setLayout(manualControlPanelLayout);
        manualControlPanelLayout.setHorizontalGroup(
            manualControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, manualControlPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(manualControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(manualSharedPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, manualControlPanelLayout.createSequentialGroup()
                        .addComponent(apduHeaderTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(jLabel5)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(lcTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(jLabel6)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(leTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(sendApduButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sendApduNoLeButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sendApduNoLcButton))
                    .addComponent(jScrollPane4, javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(manualControlPanelLayout.createSequentialGroup()
                        .addComponent(apduComboBox, 0, 462, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(clearApduButton)))
                .addContainerGap())
        );
        manualControlPanelLayout.setVerticalGroup(
            manualControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(manualControlPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(manualControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5)
                    .addComponent(lcTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel6)
                    .addComponent(leTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(sendApduButton)
                    .addComponent(apduHeaderTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(sendApduNoLeButton)
                    .addComponent(sendApduNoLcButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(manualControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(apduComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(clearApduButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(manualSharedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        controlTabbedPane.addTab(resourceMap.getString("manualControlPanel.TabConstraints.tabTitle"), manualControlPanel); // NOI18N

        scriptPanel.setName("scriptPanel"); // NOI18N

        browseScriptButton.setAction(actionMap.get("browseScriptAction")); // NOI18N
        browseScriptButton.setText(resourceMap.getString("browseScriptButton.text")); // NOI18N
        browseScriptButton.setFocusable(false);
        browseScriptButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        browseScriptButton.setName("browseScriptButton"); // NOI18N
        browseScriptButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);

        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
        jLabel2.setName("jLabel2"); // NOI18N

        nRunTextField.setText(resourceMap.getString("nRunTextField.text")); // NOI18N
        nRunTextField.setAutoscrolls(false);
        nRunTextField.setMaximumSize(new java.awt.Dimension(100, 20));
        nRunTextField.setName("nRunTextField"); // NOI18N

        sharedPanel.setMaximumSize(new java.awt.Dimension(0, 0));
        sharedPanel.setName("sharedPanel"); // NOI18N
        sharedPanel.setPreferredSize(new java.awt.Dimension(0, 0));

        terminalConnectedPanel.setName("terminalConnectedPanel"); // NOI18N

        cardConnectButton.setAction(actionMap.get("cardConnectAction")); // NOI18N
        cardConnectButton.setText(resourceMap.getString("cardConnectButton.text")); // NOI18N
        cardConnectButton.setFocusable(false);
        cardConnectButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        cardConnectButton.setName("cardConnectButton"); // NOI18N
        cardConnectButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);

        cardConnectButton1.setAction(actionMap.get("cardWarmConnectAction")); // NOI18N
        cardConnectButton1.setText(resourceMap.getString("cardConnectButton1.text")); // NOI18N
        cardConnectButton1.setFocusable(false);
        cardConnectButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        cardConnectButton1.setName("cardConnectButton1"); // NOI18N
        cardConnectButton1.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);

        cardDisconnectButton.setAction(actionMap.get("powerOffCardAction")); // NOI18N
        cardDisconnectButton.setText(resourceMap.getString("cardDisconnectButton.text")); // NOI18N
        cardDisconnectButton.setFocusable(false);
        cardDisconnectButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        cardDisconnectButton.setName("cardDisconnectButton"); // NOI18N
        cardDisconnectButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);

        jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL);
        jSeparator1.setName("jSeparator1"); // NOI18N

        javax.swing.GroupLayout terminalConnectedPanelLayout = new javax.swing.GroupLayout(terminalConnectedPanel);
        terminalConnectedPanel.setLayout(terminalConnectedPanelLayout);
        terminalConnectedPanelLayout.setHorizontalGroup(
            terminalConnectedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(terminalConnectedPanelLayout.createSequentialGroup()
                .addComponent(cardConnectButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(cardConnectButton1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(cardDisconnectButton, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        terminalConnectedPanelLayout.setVerticalGroup(
            terminalConnectedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(terminalConnectedPanelLayout.createSequentialGroup()
                .addGroup(terminalConnectedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(cardConnectButton)
                    .addComponent(cardConnectButton1)
                    .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(cardDisconnectButton))
                .addContainerGap())
        );

        terminalConnectedPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {cardConnectButton1, jSeparator1});

        loggingTabbedPane.setName("loggingTabbedPane"); // NOI18N
        loggingTabbedPane.setPreferredSize(new java.awt.Dimension(32767, 32767));

        clearLogButton.setAction(actionMap.get("clearLogAction")); // NOI18N
        clearLogButton.setText(resourceMap.getString("clearLogButton.text")); // NOI18N
        clearLogButton.setFocusable(false);
        clearLogButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        clearLogButton.setName("clearLogButton"); // NOI18N
        clearLogButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);

        javax.swing.GroupLayout sharedPanelLayout = new javax.swing.GroupLayout(sharedPanel);
        sharedPanel.setLayout(sharedPanelLayout);
        sharedPanelLayout.setHorizontalGroup(
            sharedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(sharedPanelLayout.createSequentialGroup()
                .addComponent(terminalConnectedPanel, 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)
                .addComponent(clearLogButton))
            .addComponent(loggingTabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 568, Short.MAX_VALUE)
        );
        sharedPanelLayout.setVerticalGroup(
            sharedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(sharedPanelLayout.createSequentialGroup()
                .addGroup(sharedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(terminalConnectedPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(clearLogButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(loggingTabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE))
        );

        scriptFileTextField.setEditable(false);
        scriptFileTextField.setText(resourceMap.getString("scriptFileTextField.text")); // NOI18N
        scriptFileTextField.setName("scriptFileTextField"); // NOI18N

        startScriptButton.setAction(actionMap.get("startScriptAction")); // NOI18N
        startScriptButton.setText(resourceMap.getString("startScriptButton.text")); // NOI18N
        startScriptButton.setName("startScriptButton"); // NOI18N

        javax.swing.GroupLayout scriptPanelLayout = new javax.swing.GroupLayout(scriptPanel);
        scriptPanel.setLayout(scriptPanelLayout);
        scriptPanelLayout.setHorizontalGroup(
            scriptPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(scriptPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(scriptPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(sharedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 546, Short.MAX_VALUE)
                    .addGroup(scriptPanelLayout.createSequentialGroup()
                        .addComponent(browseScriptButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(scriptFileTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(startScriptButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(nRunTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        scriptPanelLayout.setVerticalGroup(
            scriptPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(scriptPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(scriptPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(browseScriptButton)
                    .addGroup(scriptPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(nRunTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(jLabel2)
                        .addComponent(scriptFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(startScriptButton)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(sharedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 275, Short.MAX_VALUE))
        );

        controlTabbedPane.addTab(resourceMap.getString("scriptPanel.TabConstraints.tabTitle"), scriptPanel); // NOI18N

        taskPanel.setName("taskPanel"); // NOI18N

        startTaskButton.setAction(actionMap.get("addTaskAction")); // NOI18N
        startTaskButton.setText(resourceMap.getString("startTaskButton.text")); // NOI18N
        startTaskButton.setFocusable(false);
        startTaskButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        startTaskButton.setName("startTaskButton"); // NOI18N
        startTaskButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);

        dummySharedPanel.setMaximumSize(new java.awt.Dimension(0, 0));
        dummySharedPanel.setName("dummySharedPanel"); // NOI18N

        javax.swing.GroupLayout dummySharedPanelLayout = new javax.swing.GroupLayout(dummySharedPanel);
        dummySharedPanel.setLayout(dummySharedPanelLayout);
        dummySharedPanelLayout.setHorizontalGroup(
            dummySharedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 546, Short.MAX_VALUE)
        );
        dummySharedPanelLayout.setVerticalGroup(
            dummySharedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 275, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout taskPanelLayout = new javax.swing.GroupLayout(taskPanel);
        taskPanel.setLayout(taskPanelLayout);
        taskPanelLayout.setHorizontalGroup(
            taskPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(taskPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(taskPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(dummySharedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(startTaskButton))
                .addContainerGap())
        );
        taskPanelLayout.setVerticalGroup(
            taskPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(taskPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(startTaskButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(dummySharedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        controlTabbedPane.addTab(resourceMap.getString("taskPanel.TabConstraints.tabTitle"), taskPanel); // NOI18N

        logControlPanel.setEnabled(false);
        logControlPanel.setName("logControlPanel"); // NOI18N

        jScrollPane2.setName("jScrollPane2"); // NOI18N

        availableLoggersList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        availableLoggersList.setName("availableLoggersList"); // NOI18N
        availableLoggersList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                availableLoggersListMouseClicked(evt);
            }
        });
        jScrollPane2.setViewportView(availableLoggersList);

        jLabel3.setText(resourceMap.getString("jLabel3.text")); // NOI18N
        jLabel3.setName("jLabel3"); // NOI18N

        jScrollPane3.setName("jScrollPane3"); // NOI18N

        registeredLoggersList.setName("registeredLoggersList"); // NOI18N
        registeredLoggersList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                registeredLoggersListMouseClicked(evt);
            }
        });
        jScrollPane3.setViewportView(registeredLoggersList);

        moveLoggersButton.setAction(actionMap.get("moveLoggers")); // NOI18N
        moveLoggersButton.setText(resourceMap.getString("moveLoggersButton.text")); // NOI18N
        moveLoggersButton.setName("moveLoggersButton"); // NOI18N

        jLabel4.setText(resourceMap.getString("jLabel4.text")); // NOI18N
        jLabel4.setName("jLabel4"); // NOI18N

        javax.swing.GroupLayout logControlPanelLayout = new javax.swing.GroupLayout(logControlPanel);
        logControlPanel.setLayout(logControlPanelLayout);
        logControlPanelLayout.setHorizontalGroup(
            logControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(logControlPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(logControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel3)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 238, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(moveLoggersButton, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(logControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jLabel4)
                    .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE))
                .addContainerGap())
        );
        logControlPanelLayout.setVerticalGroup(
            logControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(logControlPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(logControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(jLabel4))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(logControlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 277, Short.MAX_VALUE)
                    .addComponent(jScrollPane3, 0, 0, Short.MAX_VALUE)
                    .addComponent(moveLoggersButton))
                .addContainerGap())
        );

        controlTabbedPane.addTab(resourceMap.getString("logControlPanel.TabConstraints.tabTitle"), logControlPanel); // NOI18N

        openAllTerminalsButton.setAction(actionMap.get("openAllTerminalsAction")); // NOI18N
        openAllTerminalsButton.setText(resourceMap.getString("openAllTerminalsButton.text")); // NOI18N
        openAllTerminalsButton.setName("openAllTerminalsButton"); // NOI18N

        openAllTerminalsWithCardButton.setAction(actionMap.get("openAllTerminalsWithCardAction")); // NOI18N
        openAllTerminalsWithCardButton.setText(resourceMap.getString("openAllTerminalsWithCardButton.text")); // NOI18N
        openAllTerminalsWithCardButton.setName("openAllTerminalsWithCardButton"); // NOI18N

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, mainPanelLayout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(availableRadioButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(openedRadioButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(noCardRadioButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(idleRadioButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(busyRadioButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(openAllTerminalsButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(openAllTerminalsWithCardButton))
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(controlTabbedPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 575, Short.MAX_VALUE))
                .addContainerGap())
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(availableRadioButton)
                    .addComponent(openedRadioButton)
                    .addComponent(noCardRadioButton)
                    .addComponent(idleRadioButton)
                    .addComponent(busyRadioButton)
                    .addComponent(openAllTerminalsButton)
                    .addComponent(openAllTerminalsWithCardButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(controlTabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 347, Short.MAX_VALUE)
                .addContainerGap())
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        debugModeMenuItem.setAction(actionMap.get("debugModeAction")); // NOI18N
        debugModeMenuItem.setText(resourceMap.getString("debugModeMenuItem.text")); // NOI18N
        debugModeMenuItem.setName("debugModeMenuItem"); // NOI18N
        helpMenu.add(debugModeMenuItem);

        menuBar.add(helpMenu);

        debugMenu.setText(resourceMap.getString("debugMenu.text")); // NOI18N
        debugMenu.setName("debugMenu"); // NOI18N

        debugMenuItem.setAction(actionMap.get("debugButtonAction")); // NOI18N
        debugMenuItem.setText(resourceMap.getString("debugMenuItem.text")); // NOI18N
        debugMenuItem.setName("debugMenuItem"); // NOI18N
        debugMenu.add(debugMenuItem);

        debugBackGroundMenuItem.setAction(actionMap.get("debugBackgroundAction")); // NOI18N
        debugBackGroundMenuItem.setText(resourceMap.getString("debugBackGroundMenuItem.text")); // NOI18N
        debugBackGroundMenuItem.setName("debugBackGroundMenuItem"); // NOI18N
        debugMenu.add(debugBackGroundMenuItem);

        garbageCollectorMenuItem.setAction(actionMap.get("garbageCollectorAction")); // NOI18N
        garbageCollectorMenuItem.setText(resourceMap.getString("garbageCollectorMenuItem.text")); // NOI18N
        garbageCollectorMenuItem.setName("garbageCollectorMenuItem"); // NOI18N
        debugMenu.add(garbageCollectorMenuItem);

        menuBar.add(debugMenu);

        statusPanel.setName("statusPanel"); // NOI18N
        statusPanel.setPreferredSize(new java.awt.Dimension(521, 35));

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 599, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 424, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 16, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents
    JPanel sharedPanelPlaceHolder;
    JPanel taskLastSharedPanelPlaceHolder;
    JPanel manualLastSharedPanelPlaceHolder;
    JPanel scriptLastSharedPanelPlaceHolder;

    private void controlTabbedPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_controlTabbedPaneStateChanged
        if (!initCompleted) {
            return;//we just return if this happen during tab construction
        }
        JPanel p = (JPanel) controlTabbedPane.getSelectedComponent();
        if ((logControlPanel == p)) {
            this.terminalsListButtonGroup.setSelected(openedRadioButton.getModel(), true);
            openedAction().run();
            //();
        } else {
            if (sharedPanel.getParent() != p) {
                /*here we should move the sharedPanel from its current container to the new one (p)
                problem is, it is not as simple as calling "p.add(sharedPanel);"
                that would basically works but it loose the resizing property
                so what is needed is a clean code which play with the layout manager
                well, not in the mood today, so here is my quick and dirty trick:
                - have a fake panel in other tabs
                - have a spare panel not placed anywhere
                - use the replace method of GroupManager to move the sharedPanel
                probably not very efficient, but that does the trick !*/
                JPanel toReplace = null;
                if ((taskPanel == p)) {
                    toReplace = taskLastSharedPanelPlaceHolder;
                } else if ((manualControlPanel == p)) {
                    toReplace = manualLastSharedPanelPlaceHolder;
                } else if ((scriptPanel == p)) {
                    toReplace = scriptLastSharedPanelPlaceHolder;
                } else {
                    throw new RuntimeException("Unknown target JPanel");
                }
                GroupLayout oldLayout = (GroupLayout) sharedPanel.getParent().getLayout();
                oldLayout.replace(sharedPanel, sharedPanelPlaceHolder);
                GroupLayout newLayout = (GroupLayout) p.getLayout();
                newLayout.replace(toReplace, sharedPanel);
                oldLayout.replace(sharedPanelPlaceHolder, toReplace);
                if ((toReplace.getParent() == taskPanel)) {
                    taskLastSharedPanelPlaceHolder = toReplace;
                } else if ((toReplace.getParent() == manualControlPanel)) {
                    manualLastSharedPanelPlaceHolder = toReplace;
                } else if ((toReplace.getParent() == scriptPanel)) {
                    scriptLastSharedPanelPlaceHolder = toReplace;
                } else {
                    throw new RuntimeException("Unknown parent JPanel");
                }

            }
            if (1 == loggingTabbedPane.getTabCount()) {//if no terminal connected, don't change terminal list
                return;
            }
            this.terminalsListButtonGroup.setSelected(openedRadioButton.getModel(), true);
            openedAction().run();
        }
    }//GEN-LAST:event_controlTabbedPaneStateChanged
    JLabel visibleStatusLabel;

    protected void updateVisibleStatusLabel() {
        JPanel p = (JPanel) controlTabbedPane.getSelectedComponent();
        if (logControlPanel == p) {
            return;
        }
        if ((LIST_AVAILABLE_TERMINALS != terminalsListSelection) && (1 == readersList.getSelectedValues().length)) {
            //update according to readersList
            NamedObject o = (NamedObject) readersList.getSelectedValue();
            TerminalInfo tI = (TerminalInfo) o.getObject();

            loggingTabbedPane.setSelectedComponent(tI.getTopComponentInTab());
            setStatusLabel(tI);
        } else if ((LIST_AVAILABLE_TERMINALS == terminalsListSelection) || (0 == readersList.getSelectedValues().length)) {
            //update according to loggingTabbedPane
            setStatusLabel(loggingTabbedPane.getSelectedTerminalLoggingWindow());
        }
    }

    protected void setStatusLabel(TerminalLoggingWindow terminalLoggingWindow) {
        if (null == terminalLoggingWindow) {
            setStatusLabel((TerminalInfo) null);
        } else {
            setStatusLabel(terminalLoggingWindow.gettI());
        }
    }

    protected void setStatusLabel(TerminalInfo tI) {
        JLabel label;
        if (null == tI) {
            label = statusMessageLabel;
        } else {
            label = tI.getStatusDisplayer();
        }
        GroupLayout layout = (GroupLayout) visibleStatusLabel.getParent().getLayout();
        layout.replace(visibleStatusLabel, label);
        visibleStatusLabel = label;
    }

    private void readersListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_readersListValueChanged
        if (terminalsListRefreshing) {
            return;
        }
        if (!initCompleted) {
            return;
        }

        JPanel p = (JPanel) controlTabbedPane.getSelectedComponent();
        if (logControlPanel == p) {
            manageLogControlPanelGui();
        } else {
            updateVisibleStatusLabel();
        }
    }//GEN-LAST:event_readersListValueChanged

    private void registeredLoggersListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_registeredLoggersListMouseClicked
        this.availableLoggersList.clearSelection();
        this.moveLoggersButton.setText("<");
    }//GEN-LAST:event_registeredLoggersListMouseClicked

    private void availableLoggersListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_availableLoggersListMouseClicked
        this.registeredLoggersList.clearSelection();
        this.moveLoggersButton.setText(">");
    }//GEN-LAST:event_availableLoggersListMouseClicked

    void manageLogControlPanelGuiWithGuards() {
        if (terminalsListRefreshing) {
            return;
        }
        if (!initCompleted) {
            return;
        }
        JPanel p = (JPanel) controlTabbedPane.getSelectedComponent();
        if (logControlPanel != p) {
            return;
        }
        manageLogControlPanelGui();
    }

    void manageLogControlPanelGui() {
        if ((LIST_AVAILABLE_TERMINALS != terminalsListSelection) && (1 == readersList.getModel().getSize())) {
            readersList.setSelectedIndex(0);//if only one terminal, select it
        }
        int selected[] = readersList.getSelectedIndices();
        if ((0 == selected.length) || (LIST_AVAILABLE_TERMINALS == terminalsListSelection)) {
            this.availableLoggersList.setEnabled(false);
            this.availableLoggersList.clearSelection();
            this.registeredLoggersList.setVisible(false);
            this.registeredLoggersList.clearSelection();
        } else {
            this.availableLoggersList.setEnabled(true);
            this.registeredLoggersList.setVisible(true);
        }
        //this.logControlPanel.invalidate();
    }

    List<TerminalInfo> getListOfTerminalsToUpdate() throws ScardException {
        // Your Task's code here.  This method runs
        // on a background thread, so don't reference
        // the Swing GUI from here.
        List<GenericTerminal> allTerminals = new LinkedList<GenericTerminal>();
        List<TerminalInfo> terminalsToUpdate = new LinkedList<TerminalInfo>();
        HashMap<String, TerminalInfo> newTerminals = new HashMap<String, TerminalInfo>();

        for (GenericTerminalManager terminalManager : terminalManagers) {
            List<GenericTerminal> trial = terminalManager.list();
            if (null != trial) {
                allTerminals.addAll(trial);
            }
        }

        for (GenericTerminal t : allTerminals) {
            String name = t.getName();
            TerminalInfo tI = terminals.get(name);
            if (null == tI) {
                //add to general list
                tI = new TerminalInfo(t, null, null);
                newTerminals.put(name, tI);
            }
            terminalsToUpdate.add(tI);//add to the list
        }
        for (Map.Entry<String, TerminalInfo> e : terminals.entrySet()) {
            if (allTerminals.contains(e.getValue().getTerminal())) {
                //terminal is present, update its state if necessary
                if (false == e.getValue().isPresent()) {
                    //was in "absent" state, update it
                    e.getValue().setPresent(true);
                    //terminalsToUpdate.add(e.getValue());
                }
            } else {//terminal not present anymore
                if (e.getValue().isPresent()) {
                    //was in "present" state, update it
                    e.getValue().setPresent(false);
                    terminalsToUpdate.add(e.getValue());
                }
            }
        }
        terminals.putAll(newTerminals);
        return terminalsToUpdate;
    }
    protected int terminalsListSelection = LIST_AVAILABLE_TERMINALS;
    protected static final int LIST_AVAILABLE_TERMINALS = 0;
    protected static final int LIST_OPENED_TERMINALS = 1;
    protected static final int LIST_NOCARD_TERMINALS = 2;
    protected static final int LIST_IDLE_TERMINALS = 3;
    protected static final int LIST_BUSY_TERMINALS = 4;
    protected boolean terminalsListRefreshing;

    void updateTerminalListAndTabs(List<TerminalInfo> terminals) {
        // Runs on the EDT.  Update the GUI based on
        // the result computed by doInBackground().
        terminalsListRefreshing = true;
        try {
            DefaultListModel model = (DefaultListModel) readersList.getModel();
            Object selection[] = readersList.getSelectedValues();
            model.clear();
            for (TerminalInfo tI : terminals) {

                if (tI.isInTab()) {
                    //update tab title
                    loggingTabbedPane.updateTab(tI);
                }
                switch (terminalsListSelection) {
                    case CardReaderManagerView.LIST_AVAILABLE_TERMINALS: {
                        if (false == tI.isInTab()) {
                            //update available terminals list
                            if (tI.isPresent()) {
                                model.addElement(new NamedObject(tI.getTerminal().getName(), tI));
                            }
                        }
                        break;
                    }
                    case CardReaderManagerView.LIST_OPENED_TERMINALS: {
                        if (tI.isInTab()) {
                            //update opened terminals list
                            model.addElement(new NamedObject(tI.getTerminal().getName(), tI));
                        }
                        break;
                    }
                    case CardReaderManagerView.LIST_NOCARD_TERMINALS: {
                        if (tI.isInTab()) {
                            //update opened terminals list without card
                            if (false == tI.getTerminal().isCardPresent()) {
                                model.addElement(new NamedObject(tI.getTerminal().getName(), tI));
                            }
                        }
                        break;
                    }
                    case CardReaderManagerView.LIST_IDLE_TERMINALS: {
                        if (tI.isInTab()) {
                            if (tI.getTerminal().isCardPresent()) {
                                if (!tI.isBusy()) {
                                    model.addElement(new NamedObject(tI.getTerminal().getName(), tI));
                                }
                            }
                        }
                        break;
                    }
                    case CardReaderManagerView.LIST_BUSY_TERMINALS: {
                        if (tI.isInTab()) {
                            if (tI.isBusy()) {
                                model.addElement(new NamedObject(tI.getTerminal().getName(), tI));
                            }
                        }
                        break;
                    }
                    default:
                        throw new RuntimeException("terminalsListSelection as an invalid value:" + terminalsListSelection);
                }
            }
            if (null != selection) {
                for (int i = 0; i < selection.length; i++) {
                    int j = model.indexOf(selection[i]);
                    if (-1 != j) {
                        readersList.addSelectionInterval(j, j);
                    }
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            terminalsListRefreshing = false;
            manageLogControlPanelGuiWithGuards();
            enableCardRelatedComponents();
        }
    }

    private class RefreshReadersListTask extends org.jdesktop.application.Task<Object, Void> {

        RefreshReadersListTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to RefreshReadersListTask fields, here.
            super(app);
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.
            List<TerminalInfo> terminalsToUpdate;
            try {
                terminalsToUpdate = getListOfTerminalsToUpdate();
            } catch (ScardException ex) {
                return ex;
            }
            return terminalsToUpdate;  // return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
            if (result instanceof ScardException) {
                ScardException ex = (ScardException) result;
                System.out.println(ex.getMessage() + " " + ex.getCode());
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                return;
            }
            updateTerminalListAndTabs((List<TerminalInfo>) result);
        }
    }

    @Action
    public Task refreshReadersListAction() {
        return new RefreshReadersListTask(getApplication());
    }

    @Action
    public Task availableAction() {
        terminalsListSelection = CardReaderManagerView.LIST_AVAILABLE_TERMINALS;
        return new RefreshReadersListTask(getApplication());
    }

    @Action
    public Task openedAction() {
        terminalsListSelection = CardReaderManagerView.LIST_OPENED_TERMINALS;
        return new RefreshReadersListTask(getApplication());
    }

    @Action
    public Task noCardAction() {
        terminalsListSelection = CardReaderManagerView.LIST_NOCARD_TERMINALS;
        return new RefreshReadersListTask(getApplication());
    }

    @Action
    public Task idleAction() {
        terminalsListSelection = CardReaderManagerView.LIST_IDLE_TERMINALS;
        return new RefreshReadersListTask(getApplication());
    }

    @Action
    public Task busyAction() {
        terminalsListSelection = CardReaderManagerView.LIST_BUSY_TERMINALS;
        return new RefreshReadersListTask(getApplication());
    }

    @Action
    public Task cardConnectAction() {
        return new CardConnectActionStarterTask(getApplication());
    }

        class CardConnectActionTask extends MultiTerminalActionTask {

        CardConnectActionTask(TerminalLoggingWindow log) {
            super(log);
        }

        @Override
        void doAction() throws InterruptedException, StopRequestFromUserException, ScardException, CardNotPresentException {
            log.getTerminal().coldConnect();
        }
    }

    class CardConnectActionStarterTask extends MultiTerminalActionStarterTask {

        CardConnectActionStarterTask(Application application) {
            super(application);
        }

        @Override
        void commonInit() {
            //nothing to do
        }

        @Override
        MultiTerminalActionTask getNewActionTask(TerminalLoggingWindow log) {
            return new CardConnectActionTask(log);
        }
    }

/*    private class CardConnectActionStarterTask extends org.jdesktop.application.Task<Object, Void> {

        TerminalLoggingWindow log;

        CardConnectActionStarterTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to CardConnectActionStarterTask fields, here.
            super(app);
            log = loggingTabbedPane.getSelectedTerminalLoggingWindow();
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.

            if (null == log) {
                System.out.println("no terminal selected");
                return new Boolean(false);
            }
            GenericTerminal terminal = log.getTerminal();
            try {
                terminal.coldConnect();
                return new Boolean(true);  // return your result
            } catch (CardException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                return new Boolean(false);
            }
        }

        @Override
        protected void succeeded(Object result) {
        }
    }*/

    @Action
    public Task cardWarmConnectAction() {
        return new CardWarmConnectActionStarterTask(getApplication());
    }

    class CardWarmConnectActionTask extends MultiTerminalActionTask {

        CardWarmConnectActionTask(TerminalLoggingWindow log) {
            super(log);
        }

        @Override
        void doAction() throws InterruptedException, StopRequestFromUserException, ScardException, CardNotPresentException {
            GenericTerminal terminal=log.getTerminal();
            if(false==terminal.isConnected())
                terminal.coldConnect();
            terminal.warmConnect();

        }
    }

    class CardWarmConnectActionStarterTask extends MultiTerminalActionStarterTask {

        CardWarmConnectActionStarterTask(Application application) {
            super(application);
        }

        @Override
        void commonInit() {
            //nothing to do
        }

        @Override
        MultiTerminalActionTask getNewActionTask(TerminalLoggingWindow log) {
            return new CardWarmConnectActionTask(log);
        }
    }

    @Action
    public Task powerOffCardAction() {
        return new PowerOffCardActionStarterTask(getApplication());
    }

    class PowerOffActionTask extends MultiTerminalActionTask {

        PowerOffActionTask(TerminalLoggingWindow log) {
            super(log);
        }

        @Override
        void doAction() throws InterruptedException, StopRequestFromUserException, ScardException, CardNotPresentException {
            log.getTerminal().disconnect();
        }
    }

    class PowerOffCardActionStarterTask extends MultiTerminalActionStarterTask {

        PowerOffCardActionStarterTask(Application application) {
            super(application);
        }

        @Override
        void commonInit() {
            //nothing to do
        }

        @Override
        MultiTerminalActionTask getNewActionTask(TerminalLoggingWindow log) {
            return new PowerOffActionTask(log);
        }
    }

    @Action
    public Task sendApduAction() {
        return sendApduAction(true, true);
    }

    @Action
    public Task sendApduNoLe() {
        return sendApduAction(true, false);
    }

    @Action
    public Task sendApduNoLcAction() {
        return sendApduAction(false, true);
    }

    Task sendApduAction(boolean sendLc, boolean sendLe) {
        TerminalLoggingWindow log = loggingTabbedPane.getSelectedTerminalLoggingWindow();
        if (null == log) {
            throw new RuntimeException("sendApduAction invoked but loggingTabbedPane.getSelectedTerminalLoggingWindow() return null");
        }
        if (log.gettI().isBusy()) {
            throw new RuntimeException("sendApduAction invoked but log.gettI().isBusy() return true");
        }

        log.gettI().setReserved(true);
        this.enableCardRelatedComponents();
        Apdu apdu = makeManualApdu(sendLc, sendLe, true);
        if (null == apdu) {
            log.gettI().setReserved(false);
            this.enableCardRelatedComponents();
            return null;
        }
        DefaultComboBoxModel model = (DefaultComboBoxModel) this.apduComboBox.getModel();
        String header = AStringUtilities.bytesToHex(apdu.getCommandAPDU().getBytes());

        boolean present = false;
        for (int i = 0; i < model.getSize(); i++) {
            if (header.equals((String) model.getElementAt(i))) {
                present = true;
            }
        }
        if (false == present) {
            model.addElement(header);
        }
        return new SendApduActionStarterTask(getApplication(), log, apdu);
    }

    class SendApduActionTask extends MultiTerminalActionTask {
        Apdu apdu;
        SendApduActionTask(TerminalLoggingWindow log) {
            super(log);
        }

        public void setApdu(Apdu apdu) {
            this.apdu = apdu;
        }

        @Override
        void doAction() throws InterruptedException, StopRequestFromUserException, ScardException, CardNotPresentException {
            log.getTerminal().checkConnection();
            log.getTerminal().sendApdu(apdu);
        }
    }

    class SendApduActionStarterTask extends MultiTerminalActionStarterTask {
        LinkedList<SendApduActionTask> actionTasks;
        SendApduActionStarterTask(Application application, TerminalLoggingWindow log, Apdu apdu) {
            super(application);
            if(null!=actionTasks){
                for(SendApduActionTask actionTask:actionTasks)
                    actionTask.setApdu(apdu);
            }
        }

        @Override
        void commonInit() {
            actionTasks=new LinkedList<SendApduActionTask>();
        }

        @Override
        MultiTerminalActionTask getNewActionTask(TerminalLoggingWindow log) {
            /*if(null==actionTasks)
                actionTasks=new LinkedList<SendApduActionTask>();*/
            actionTasks.add( new SendApduActionTask(log));
            return actionTasks.getLast();
        }
    }


    /*private class SendApduActionTask extends org.jdesktop.application.Task<Object, Void> {

        TerminalLoggingWindow log;
        Apdu apdu;

        SendApduActionTask(org.jdesktop.application.Application app, TerminalLoggingWindow log, Apdu apdu) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to SendApduActionTask fields, here.
            super(app);
            this.log = log;
            this.apdu = apdu;
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.
            if (null == log) {
                System.out.println("no terminal selected");
                return null;
            }
            GenericTerminal terminal = log.getTerminal();
            try {
                terminal.checkConnection();
                terminal.sendApdu(apdu);
            } catch (CardException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            } catch (StopRequestFromUserException e) {
                //nothing to do
            }
            return null;  // return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
            //CardReaderManagerView.this.sendApduButton.setEnabled(true);
            //CardReaderManagerView.this.enableCardRelatedComponents(true);
            log.gettI().setReserved(false);
            CardReaderManagerView.this.enableCardRelatedComponents();
        }
    }*/

    @Action
    public void debugButtonAction() {
        RmiServerThread rmiServer = new RmiServerThread(this);
        Thread rmiServerThread = new Thread(rmiServer);
        rmiServerThread.setName("RmiServerThread");
        rmiServerThread.setDaemon(true);
        rmiServerThread.start();
    }

    @Action
    public void clearLogAction() {
        //check if user wanted to clear the app log pane
        if (loggingTabbedPane.getSelectedLoggingWindow() == appLoggingWindow) {
            loggingTabbedPane.clearHighlightOfSelectedTab();
            appLoggingWindow.clear();
        } else {
            TerminalInfo tIs[] = getSelectedTerminalInfo(false);
            if (null != tIs) {
                for (int i = 0; i < tIs.length; i++) {
                    int index = loggingTabbedPane.indexOfComponent(tIs[i].getTopComponentInTab());
                    loggingTabbedPane.getTerminalLoggingWindowAt(index).clear();
                }
            } else {
                throw new RuntimeException("Could not determine the log to clear");
            }
        }
    }

    public int executeTask(SmartCardTask t) throws Exception {
        int out = SmartCardTask.SYSTEM_ERROR;
        this.getFrame().requestFocusInWindow();
        this.getApplication().show(this);
        TerminalLoggingWindow log = loggingTabbedPane.getSelectedTerminalLoggingWindow();
        if (null == log) {
            System.out.println("No connected terminal selected");
            return out;
        }
        TerminalInfo tI = log.gettI();
        tI.setWorkingThread(Thread.currentThread());
        GenericTerminal terminal = log.getTerminal();
        PipedOutputStream pos = log.getStream();

        BasicCardReaderTaskExecutor executor = new BasicCardReaderTaskExecutor(false, false, new PrintStream(pos), terminal, log);
        try {
            out = executor.executeTask(t);
        } catch (InterruptedException e) {
            //nothing to do
        } catch (StopRequestFromUserException e) {
            //nothing to do
        } catch (Throwable ex) {
            PrintStream ps = new PrintStream(pos);
            ps.println();
            ex.printStackTrace(ps);
            System.err.println("ERROR: " + log.getTerminalName());
            Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            //executor.closeMonitoringWindow(false);
            executor = null;
            log = null;
            terminal = null;
            pos = null;
            tI.setWorkingThread(null);
        }
        return out;
    }

    public int executeScript(List<? extends Object> cmds, long nRun, TerminalLoggingWindow log) throws Exception {
        int out = SmartCardTask.SYSTEM_ERROR;

        TerminalInfo tI = log.gettI();
        tI.setWorkingThread(Thread.currentThread());
        GenericTerminal terminal = log.getTerminal();
        PipedOutputStream pos = log.getStream();

        ScriptPlayer player = new ScriptPlayer(tI.getStatusDisplayer());
        player.setnRun(nRun);
        try {
            player.play(terminal, cmds);
        } catch (StopRequestFromUserException e) {
            //nothing to do
        } catch (Throwable ex) {
            PrintStream ps = new PrintStream(pos);
            ps.println();
            ex.printStackTrace(ps);
            System.err.println("ERROR: " + log.getTerminalName());
            Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            player = null;
            log = null;
            terminal = null;
            pos = null;
            tI.setWorkingThread(null);
        }
        return out;
    }

    public class TaskStarter implements Runnable {

        File out;

        TaskStarter() {
            AFileChooser fileChooser;
            fileChooser = new AFileChooser((java.awt.Frame) null, true, LAST_TASK_PATH_KEY);
            fileChooser.setDialogTitle("Start task");
            FileNameExtensionFilter filter = new FileNameExtensionFilter("all jar files", "jar");
            fileChooser.addChoosableFileFilter(filter);
            filter = new FileNameExtensionFilter("smart card task files", "scardtask");
            fileChooser.addChoosableFileFilter(filter);
            fileChooser.setAcceptAllFileFilterUsed(true);
            int option = fileChooser.showOpenDialog(null);
            if (option != JFileChooser.APPROVE_OPTION) {
                return;
            }
            fileChooser.saveCurrentPath();
            out = fileChooser.getSelectedFile();
            fileChooser.dispose();
        }

        public void run() {
            try {
                SmartCardTask task = null;
                JarClassLoader cl = null;
                try {
                    if (null == out) {
                        return;
                    }
                    cl = new JarClassLoader(out.toURI().toURL());
                    InputStream reg = cl.getResourceAsStream("SmartCardTaskRegistrator");
                    InputStreamReader isr = new InputStreamReader(reg);
                    BufferedReader in = new BufferedReader(isr);
                    String className = in.readLine();
                    String methodName = in.readLine();
                    in.close();
                    task = (SmartCardTask) cl.invokeClassStaticMethod(className, methodName);
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                } catch (NoSuchMethodException ex) {
                    Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                }
                try {
                    executeTask(task);
                } catch (InterruptedException ex) {
                    //do nothing
                } catch (StopRequestFromUserException ex) {
                    //do nothing
                } catch (Exception ex) {
                    Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                } finally {
                    cl = null;
                    task = null;
                    System.gc();
                    System.gc();//attempt to unload the task to allow replacement of the jar file when debugging
                    //does not really work :-S
                }
            } catch (MalformedURLException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    File scriptFile=null;

    protected File getScriptFile() {
        return scriptFile;
    }

    protected void browseScriptFile() {
        AFileChooser fileChooser;
        fileChooser = new AFileChooser((java.awt.Frame) null, true, LAST_TASK_PATH_KEY);
        fileChooser.setDialogTitle("Start script");
        FileNameExtensionFilter filter = new FileNameExtensionFilter("starScript files", "starScript");
        fileChooser.addChoosableFileFilter(filter);
        filter = new FileNameExtensionFilter("text files", "txt");
        fileChooser.setAcceptAllFileFilterUsed(true);
        int option = fileChooser.showOpenDialog(null);
        if (option != JFileChooser.APPROVE_OPTION) {
            //scriptFile = null;//keep previous file
        }
        fileChooser.saveCurrentPath();
        scriptFile = fileChooser.getSelectedFile();
        fileChooser.dispose();
    }

    public class ScriptStarter implements Runnable {

        final File in;
        final long nRun;
        final TerminalLoggingWindow log;

        ScriptStarter(long nRun, TerminalLoggingWindow log) {
            in = getScriptFile();
            if (null == in) {
                this.nRun = 0;
                this.log = null;
                return;
            }
            this.nRun = nRun;
            this.log = log;
        }

        ScriptStarter(long nRun, TerminalLoggingWindow log, File in) {
            this.log = log;
            this.in = in;
            this.nRun = nRun;
        }

        public void run() {
            try {
                List<? extends Object> cmds;
                StarScriptReader script = new StarScriptReader(in);
                cmds = script.getCmds();
                try {
                    executeScript(cmds, nRun, log);
                } catch (InterruptedException ex) {
                    //do nothing
                } catch (StopRequestFromUserException ex) {
                    //do nothing
                } catch (Throwable ex) {
                    Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (IOException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    @Action
    public Task addTaskAction() {
        return new AddTaskActionTask(getApplication());
    }

    private class AddTaskActionTask extends org.jdesktop.application.Task<Object, Void> {

        TaskStarter startTask;

        AddTaskActionTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to AddTaskActionTask fields, here.
            super(app);
            startTask = new TaskStarter();
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.

            Thread startTaskThread = new Thread(startTask);
            startTaskThread.setName("startTaskThread");

            startTaskThread.start();
            return null// return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
        }
    }

    protected long getNRun() {
        long out = -2;
        try {
            out = Long.decode(nRunTextField.getText());
            if (-1 > out) {
                String msg = "Number of iteration must be >= -1 and <= " + Long.MAX_VALUE + ".\n(-1 means infinte number of iterations)\n\n";
                JOptionPane.showMessageDialog(null, msg, "Incorrect input", JOptionPane.INFORMATION_MESSAGE);
                out = -2;
            }
        } catch (RuntimeException e) {
            String msg = "Cannot decode the number of iteration, action cancelled.\n\n";
            JOptionPane.showMessageDialog(null, msg, "Incorrect input", JOptionPane.INFORMATION_MESSAGE);
        }

        return out;
    }

    @Action
    public Task startScriptAction() {

        if (this.START_SCRIPT_BUTTON_TEXT.equals(this.startScriptButton.getText())) {
            return new StartScriptActionTask(getApplication());
        }
        TerminalLoggingWindow log = loggingTabbedPane.getSelectedTerminalLoggingWindow();
        if (null == log) {
            throw new RuntimeException("sendApduAction invoked but loggingTabbedPane.getSelectedTerminalLoggingWindow() return null");
        }
        if (log.gettI().isBusy()) {
            throw new RuntimeException("sendApduAction invoked but log.gettI().isBusy() return true");
        }

        log.gettI().setReserved(true);
        this.enableCardRelatedComponents();

        return new CheckScriptActionTask(getApplication(), log, false);
    }
    StarScriptReader script = null;

    private class StartScriptActionTask extends org.jdesktop.application.Task<Object, Void> {

        ScriptStarter startScript[];
        long nRun;

        StartScriptActionTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to StartScriptActionTask fields, here.
            super(app);

            nRun = getNRun();
            if (-2 != nRun) {
                int selected[] = readersList.getSelectedIndices();
                TerminalLoggingWindow logs[] = null;
                if (0 == selected.length) {//CardReaderManagerView.LIST_IDLE_TERMINALS!=terminalsListSelection){
                    //in this case, only single terminal is possible
                    //the terminal is the current one in the log tabs
                    TerminalLoggingWindow log = loggingTabbedPane.getSelectedTerminalLoggingWindow();
                    if (null != log) {
                        logs = new TerminalLoggingWindow[1];
                        logs[0] = log;
                        selected = new int[1];
                    }
                } else {
                    logs = new TerminalLoggingWindow[selected.length];
                    for (int i = 0; i < selected.length; i++) {
                        NamedObject o = (NamedObject) readersList.getModel().getElementAt(selected[i]);
                        TerminalInfo tI = (TerminalInfo) o.getObject();
                        logs[i] = loggingTabbedPane.getTerminalTab(tI.getTerminal().getName());
                    }
                }
                if ((null != logs) && (0 < logs.length)) {
                    startScript = new ScriptStarter[logs.length];
                    File in = getScriptFile();
                    if (null == in) {
                        nRun = -2;
                        return;
                    }
                    for (int i = 0; i < logs.length; i++) {
                        logs[i].gettI().setReserved(true);
                        startScript[i] = new ScriptStarter(nRun, logs[i], in);
                    }
                } else {
                    System.out.println("No connected terminal selected");
                    this.nRun = -2;
                    return;
                }

                CardReaderManagerView.this.enableCardRelatedComponents();
            }
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.
            if (-2 != nRun) {
                Thread startScriptThread[] = new Thread[startScript.length];
                for (int i = 0; i < startScript.length; i++) {
                    startScriptThread[i] = new Thread(startScript[i]);
                    startScriptThread[i].setName("startScriptThread" + i);
                    startScriptThread[i].start();
                }
                for (int i = 0; i < startScript.length; i++) {
                    try {
                        startScriptThread[i].join();
                    } catch (InterruptedException ex) {
                    }
                }

            }
            return null// return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
            if (null != startScript) {
                for (int i = 0; i < startScript.length; i++) {
                    startScript[i].log.gettI().setReserved(false);
                }
            }
            CardReaderManagerView.this.enableCardRelatedComponents();
        }
    }

    public abstract class MultiTerminalActionTask implements Runnable {

        final TerminalLoggingWindow log;

        MultiTerminalActionTask(TerminalLoggingWindow log) {
            this.log = log;
        }

        abstract void doAction() throws InterruptedException, StopRequestFromUserException, ScardException, CardNotPresentException;

        public void run() {
            try {
                doAction();
            } catch (InterruptedException ex) {
                //do nothing
            } catch (StopRequestFromUserException ex) {
                //do nothing
            } catch (Throwable ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private abstract class MultiTerminalActionStarterTask extends org.jdesktop.application.Task<Object, Void> {

        MultiTerminalActionTask actionStarters[];

        abstract void commonInit();

        abstract MultiTerminalActionTask getNewActionTask(TerminalLoggingWindow log);

        MultiTerminalActionStarterTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to MultiTerminalActionStarterTask fields, here.
            super(app);
            int selected[] = readersList.getSelectedIndices();
            TerminalLoggingWindow logs[] = null;
            if (0 == selected.length) {//CardReaderManagerView.LIST_IDLE_TERMINALS!=terminalsListSelection){
                //in this case, only single terminal is possible
                //the terminal is the current one in the log tabs
                TerminalLoggingWindow log = loggingTabbedPane.getSelectedTerminalLoggingWindow();
                if (null != log) {
                    logs = new TerminalLoggingWindow[1];
                    logs[0] = log;
                    selected = new int[1];
                }
            } else {
                logs = new TerminalLoggingWindow[selected.length];
                for (int i = 0; i < selected.length; i++) {
                    NamedObject o = (NamedObject) readersList.getModel().getElementAt(selected[i]);
                    TerminalInfo tI = (TerminalInfo) o.getObject();
                    logs[i] = loggingTabbedPane.getTerminalTab(tI.getTerminal().getName());
                    if(null==logs[i])
                        throw new RuntimeException("null==logs["+i+"] ! (tI.getTerminal().getName()="+tI.getTerminal().getName()+")");
                }
            }
            if ((null != logs) && (0 < logs.length)) {
                actionStarters = new MultiTerminalActionTask[logs.length];
                commonInit();
                for (int i = 0; i < logs.length; i++) {
                    TerminalInfo tI=logs[i].gettI();
                    tI.setReserved(true);
                    actionStarters[i] = getNewActionTask(logs[i]);
                }
            } else {
                System.out.println("No connected terminal selected");
                return;
            }
            CardReaderManagerView.this.enableCardRelatedComponents();
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.
            Thread actionThread[] = new Thread[actionStarters.length];
            for (int i = 0; i < actionStarters.length; i++) {
                actionThread[i] = new Thread(actionStarters[i]);
                actionThread[i].setName("scardAction" + i);
                actionThread[i].start();
            }
            for (int i = 0; i < actionStarters.length; i++) {
                try {
                    actionThread[i].join();
                } catch (InterruptedException ex) {
                }
            }
            return null// return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
            if (null != actionStarters) {
                for (int i = 0; i < actionStarters.length; i++) {
                    actionStarters[i].log.gettI().setReserved(false);
                }
            }
            CardReaderManagerView.this.enableCardRelatedComponents();
        }
    }

    @Action
    public Task browseScriptAction() {
        TerminalLoggingWindow log = loggingTabbedPane.getSelectedTerminalLoggingWindow();
        if (null == log) {
            throw new RuntimeException("sendApduAction invoked but loggingTabbedPane.getSelectedTerminalLoggingWindow() return null");
        }
        if (log.gettI().isBusy()) {
            throw new RuntimeException("sendApduAction invoked but log.gettI().isBusy() return true");
        }

        return new CheckScriptActionTask(getApplication(), log, true);
    }

    private class CheckScriptActionTask extends org.jdesktop.application.Task<Object, Void> {

        boolean browse;
        TerminalLoggingWindow log;

        CheckScriptActionTask(org.jdesktop.application.Application app, TerminalLoggingWindow log, boolean browse) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to BrowseScriptActionTask fields, here.
            super(app);
            this.browse = browse;
            this.log = log;
        }

        @Override
        protected Object doInBackground() {
            script = null;
            try {
                // Your Task's code here.  This method runs
                // on a background thread, so don't reference
                // the Swing GUI from here.
                if (browse) {
                    browseScriptFile();
                }
                if (null != scriptFile) {
                    try {
                        script = new StarScriptReader(scriptFile);
                    } catch (InputFileFormatException e) {
                        String msg = "Failed to open input file \"" + scriptFile.getName() + "\"\n\n" + e.getMessage() + "\n";
                        JOptionPane.showMessageDialog(null, msg);
                        return null;
                    }
                }
                // return your result
            } catch (FileNotFoundException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                scriptFile = null;
            } catch (IOException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                scriptFile = null;
            }
            return script; // return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
            if (null != result) {
                CardReaderManagerView.this.scriptFileTextField.setText(scriptFile.getName());
                CardReaderManagerView.this.scriptFileTextField.setToolTipText(scriptFile.getAbsolutePath());
                CardReaderManagerView.this.startScriptButton.setText(START_SCRIPT_BUTTON_TEXT);
                CardReaderManagerView.this.startScriptButton.setEnabled(true);
            } else {
                if (null != scriptFile) {
                    CardReaderManagerView.this.scriptFileTextField.setText(scriptFile.getName());
                    CardReaderManagerView.this.scriptFileTextField.setToolTipText(scriptFile.getAbsolutePath());
                    CardReaderManagerView.this.startScriptButton.setText(CHECK_SCRIPT_BUTTON_TEXT);
                    CardReaderManagerView.this.startScriptButton.setEnabled(true);
                } else {
                    CardReaderManagerView.this.scriptFileTextField.setText("");
                    CardReaderManagerView.this.scriptFileTextField.setToolTipText("Please use the browse button to select a file");
                    CardReaderManagerView.this.startScriptButton.setEnabled(false);
                }
            }
            log.gettI().setReserved(false);
            CardReaderManagerView.this.enableCardRelatedComponents();

        }
    }
    final public String START_SCRIPT_BUTTON_TEXT = "Start";
    final public String CHECK_SCRIPT_BUTTON_TEXT = "Check";

    @Action
    public void moveLoggers() {
        if (this.moveLoggersButton.getText().equals(">")) {
            addLogHandler();
        } else {
            removeLogHandler();
        }
    }

    @Action
    public void clearApduButton() {
        this.apduComboBox.setModel(new DefaultComboBoxModel());
    }

    @Action
    public Task garbageCollectorAction() {
        return new GarbageCollectorActionTask(getApplication());
    }

    private class GarbageCollectorActionTask extends org.jdesktop.application.Task<Object, Void> {

        GarbageCollectorActionTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to GarbageCollectorActionTask fields, here.
            super(app);
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.
            System.gc();
            return null// return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
        }
    }

    @Action
    public Task debugBackgroundAction() {
        return new DebugBackgroundActionTask(getApplication());
    }

    private class DebugBackgroundActionTask extends org.jdesktop.application.Task<Object, Void> {

        SmartCardTaskProcessor engine;

        DebugBackgroundActionTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to DebugBackgroundActionTask fields, here.
            super(app);
            engine = CardReaderManagerView.this;
        }

        @Override
        protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.
            RmiServerThread rmiServer = new RmiServerThread(engine);
            Thread rmiServerThread = new Thread(rmiServer);
            rmiServerThread.setName("RmiServerThread");
            rmiServerThread.setDaemon(true);
            rmiServerThread.start();
            return null// return your result
        }

        @Override
        protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
        }
    }
    String debugPass = "";
    final static String DEBUG_PASS = "babba";

    @Action
    public void debugModeAction() {
        String inputValue = JOptionPane.showInputDialog("Please enter password");
        if (inputValue.equals(DEBUG_PASS)) {
            debugMenu.setVisible(!debugMenu.isVisible());
        }
    }

    @Action
    public void openAllTerminalsAction() {
        openAllTerminalsAction(false);
    }

    @Action
    public void openAllTerminalsWithCardAction() {
        openAllTerminalsAction(true);
    }

    void openAllTerminalsAction(boolean requireCardPresent) {
        int added=0;
        int lastIndex=0;
        for(TerminalInfo tI:terminals.values()){
            try {
                if (tI.isInTab()) {
                    continue;
                }
                if (requireCardPresent & !tI.getTerminal().isCardPresent()) {
                    continue;
                }
                String name = tI.getTerminal().getName();
                StatusDisplayerLabel sdl = new StatusDisplayerLabel();
                sdl.setText(name);
                tI.setStatusDisplayer(sdl);
                int index = loggingTabbedPane.getTabCount();
                lastIndex=index;
                TerminalLoggingWindow logWindow;
                try {
                    logWindow = new TerminalLoggingWindow(tI);
                    loggingTabbedPane.addTab(name, logWindow);
                    tI.setTopComponentInTab(loggingTabbedPane.getComponentAt(index));
                    added++;
                } catch (IOException ex) {
                    Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (ScardException ex) {
                Logger.getLogger(CardReaderManagerView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        if(added>0){
            controlTabbedPane.add(logControlPanel);
            terminalsListButtonGroup.setSelected(openedRadioButton.getModel(), true);
            openedAction().run();
            DefaultListModel model = (DefaultListModel) readersList.getModel();
            readersList.setSelectionInterval(0, model.size()-1);
            enableConnectedTerminalsLists(true);
            loggingTabbedPane.setSelectedIndex(lastIndex);
        }else{
            JOptionPane.showMessageDialog(null, "Could not find any terminal to connect");
        }
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox apduComboBox;
    private javax.swing.JTextField apduHeaderTextField;
    private javax.swing.JList availableLoggersList;
    private javax.swing.JRadioButton availableRadioButton;
    private javax.swing.JButton browseScriptButton;
    private javax.swing.JRadioButton busyRadioButton;
    private javax.swing.JButton cardConnectButton;
    private javax.swing.JButton cardConnectButton1;
    private javax.swing.JButton cardDisconnectButton;
    private javax.swing.JButton clearApduButton;
    private javax.swing.JButton clearLogButton;
    private javax.swing.JTabbedPane controlTabbedPane;
    private javax.swing.JMenuItem debugBackGroundMenuItem;
    private javax.swing.JMenu debugMenu;
    private javax.swing.JMenuItem debugMenuItem;
    private javax.swing.JMenuItem debugModeMenuItem;
    private javax.swing.JPanel dummySharedPanel;
    private javax.swing.JMenuItem garbageCollectorMenuItem;
    private javax.swing.JRadioButton idleRadioButton;
    private javax.swing.JLabel jLabel1;
    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.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JEditorPane lcDataEditor;
    private javax.swing.JTextField lcTextField;
    private javax.swing.JTextField leTextField;
    private javax.swing.JPanel logControlPanel;
    private uk.co.nimp.scardterminalmanager.LogTabbedPane loggingTabbedPane;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JPanel manualControlPanel;
    private javax.swing.JPanel manualSharedPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JButton moveLoggersButton;
    private javax.swing.JTextField nRunTextField;
    private javax.swing.JRadioButton noCardRadioButton;
    private javax.swing.JButton openAllTerminalsButton;
    private javax.swing.JButton openAllTerminalsWithCardButton;
    private javax.swing.JRadioButton openedRadioButton;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JList readersList;
    private javax.swing.JList registeredLoggersList;
    private javax.swing.JTextField scriptFileTextField;
    private javax.swing.JPanel scriptPanel;
    private javax.swing.JButton sendApduButton;
    private javax.swing.JButton sendApduNoLcButton;
    private javax.swing.JButton sendApduNoLeButton;
    private javax.swing.JPanel sharedPanel;
    private javax.swing.JButton startScriptButton;
    private javax.swing.JButton startTaskButton;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JPanel taskPanel;
    private javax.swing.JPanel terminalConnectedPanel;
    private javax.swing.ButtonGroup terminalsListButtonGroup;
    // End of variables declaration//GEN-END:variables
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;
    Timer terminalListRefreshTimer;
}
TOP

Related Classes of uk.co.nimp.scardterminalmanager.CardReaderManagerView$CardWarmConnectActionTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.