com.qspin.qtaste.ui.TestCasePane.java Source code

Java tutorial

Introduction

Here is the source code for com.qspin.qtaste.ui.TestCasePane.java

Source

/*
Copyright 2007-2009 QSpin - www.qspin.be
    
This file is part of QTaste framework.
    
QTaste is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
QTaste is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.
    
You should have received a copy of the GNU Lesser General Public License
along with QTaste. If not, see <http://www.gnu.org/licenses/>.
 */
package com.qspin.qtaste.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.qspin.qtaste.config.GUIConfiguration;
import com.qspin.qtaste.config.StaticConfiguration;
import com.qspin.qtaste.config.TestBedConfiguration;
import com.qspin.qtaste.config.TestEngineConfiguration;
import com.qspin.qtaste.debug.Breakpoint;
import com.qspin.qtaste.event.DumpPythonResultEvent;
import com.qspin.qtaste.event.DumpPythonResultEventHandler;
import com.qspin.qtaste.event.DumpPythonResultListener;
import com.qspin.qtaste.event.TestScriptBreakpointEvent;
import com.qspin.qtaste.event.TestScriptBreakpointHandler;
import com.qspin.qtaste.event.TestScriptBreakpointListener;
import com.qspin.qtaste.kernel.engine.TestEngine;
import com.qspin.qtaste.testsuite.TestSuite;
import com.qspin.qtaste.testsuite.impl.DirectoryTestSuite;
import com.qspin.qtaste.ui.csveditor.TestDataEditor;
import com.qspin.qtaste.ui.debug.DebugVariable;
import com.qspin.qtaste.ui.debug.DebugVariablePanel;
import com.qspin.qtaste.ui.jedit.DebuggerShortcuts;
import com.qspin.qtaste.ui.jedit.GenericShortcuts;
import com.qspin.qtaste.ui.jedit.NonWrappingTextPane;
import com.qspin.qtaste.ui.log4j.Log4jPanel;
import com.qspin.qtaste.ui.log4j.TextAreaAppender;
import com.qspin.qtaste.ui.testcampaign.TestCampaignMainPanel;
import com.qspin.qtaste.ui.tools.FileNode;
import com.qspin.qtaste.ui.tools.HTMLDocumentLoader;
import com.qspin.qtaste.ui.tools.PythonTestScript;
import com.qspin.qtaste.ui.tools.ResourceManager;
import com.qspin.qtaste.ui.xmleditor.TestRequirementEditor;
import com.qspin.qtaste.util.Log4jLoggerFactory;
import com.qspin.qtaste.util.ScriptCheckSyntaxValidator;
import com.qspin.qtaste.util.ThreadManager;

@SuppressWarnings("serial")
public class TestCasePane extends JPanel implements TestScriptBreakpointListener, DumpPythonResultListener {

    private static Logger logger = Log4jLoggerFactory.getLogger(TestCasePane.class);
    protected JTextPane tcDocsPane = new JTextPane();
    protected Log4jPanel tcLogsPane;
    private NonWrappingTextPane tcSourceTextPane = null;
    protected JButton executeButton = new JButton();
    protected JButton startExecutionButton = new JButton();
    protected JButton stepOverExecutionButton = new JButton();
    protected JButton stepIntoExecutionButton = new JButton();
    protected JButton stopExecutionButton = new JButton();
    protected JButton saveButton = new JButton();
    protected JButton resultsButton = new JButton("View Test Report");
    protected JButton debugButton = new JButton();
    protected JTabbedPane editorTabbedPane;
    protected JPanel tcSourcePanel = new JPanel(new BorderLayout());
    protected DebugVariablePanel debugPanel;
    public TestCaseTree tcTree;
    protected TestCaseResultsPane resultsPane;
    protected JTabbedPane tabbedPane;
    protected MainPanel parent;
    protected JSplitPane sourcePanel;
    protected boolean stopExecution = false;
    private static final String DOC = "Documentation";
    private static final String SOURCE = "Test Case Source";
    private static final String RESULTS = "Results";
    private static final String LOGS = "Logs";
    private static final String SHOW_LOGS_TAB = "show_logs_tab";
    public static final int DOC_INDEX = 0;
    public static final int SOURCE_INDEX = 1;
    public static final int RESULTS_INDEX = 2;
    public static final int LOGS_INDEX = 3;
    public static final int SRC_TAB_SIZE = 2;
    private TestExecutionThread testExecutionHandler = null;
    private TestCampaignMainPanel.CampaignExecutionThread testCampaignExecutionHandler = null;
    private TestScriptBreakpointHandler breakPointEventHandler;
    public boolean isExecuting = false;
    public boolean isEnabledToExecute = true;
    private String currentSelectedTestsuite = "TestSuite";
    private FileNode currentSelectedFileNode = null;
    protected DumpPythonResultEventHandler pythonResultEventHandler = DumpPythonResultEventHandler.getInstance();
    private String mTestCaseSuitesRootDir = StaticConfiguration.DEFAULT_TESTSUITES_DIR;
    protected static final HTMLDocument EMPTY_DOC = new HTMLDocument();

    public TestCasePane(MainPanel parent) {
        super(new BorderLayout());

        GUIConfiguration guiConfiguration = GUIConfiguration.getInstance();
        boolean showLogsTab = guiConfiguration.getBoolean(SHOW_LOGS_TAB, true);
        if (showLogsTab) {
            tcLogsPane = new Log4jPanel();
        }

        this.parent = parent;
        resultsPane = new TestCaseResultsPane(this);
        breakPointEventHandler = TestScriptBreakpointHandler.getInstance();
        breakPointEventHandler.addTestScriptBreakpointListener(this);
        pythonResultEventHandler.addPythonResultListener(this);
        genUI();
    }

    public void addTabPane(JScrollPane pPanel, String pTabTile) {
        tabbedPane.addTab(pTabTile, pPanel);
    }

    public void removeTabPane(JScrollPane pEditor) {
        tabbedPane.remove(pEditor);
    }

    @Override
    protected void finalize() {
        breakPointEventHandler.removeTestScriptBreakpointListener(this);
    }

    public void setTestCaseTree(TestCaseTree tcTree) {
        this.tcTree = tcTree;
        resultsPane.setTestCaseTree(tcTree);
    }

    public TestCaseTree getTestCaseTree() {
        return tcTree;
    }

    public boolean isDocTabSelected() {
        return tabbedPane.getSelectedIndex() == DOC_INDEX;
    }

    public void importTestSuites() {

        JFileChooser chooser = new JFileChooser(mTestCaseSuitesRootDir);
        chooser.setDialogTitle("Load TestSuites directory ...");
        //chooser.setFileHidingEnabled(false);
        chooser.setAcceptAllFileFilterUsed(false);
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int returnVal = chooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            try {
                String selectedTestSuites = chooser.getSelectedFile().getAbsoluteFile().getCanonicalPath();
                setTestSuiteDirectory(selectedTestSuites);
                tcTree.generateScriptsTree(selectedTestSuites);
            } catch (IOException e) {
                logger.error(e);
            }
        }
    }

    public void setExecuteButtonsEnabled(boolean enabled) {
        executeButton.setEnabled(enabled);
        debugButton.setEnabled(enabled);
        isEnabledToExecute = enabled;
    }

    public void setStopButtonEnabled(boolean enabled, boolean visible) {
        stopExecutionButton.setEnabled(enabled);
        stopExecutionButton.setVisible(visible);
    }

    protected void genUI() {
        executeButton.setMnemonic(KeyEvent.VK_R);
        saveButton.setMnemonic(KeyEvent.VK_C);
        startExecutionButton.setMnemonic(KeyEvent.VK_N);
        tcDocsPane.setEditable(false);
        tcDocsPane.setContentType("text/html");

        if (tcLogsPane != null) {
            TextAreaAppender.addTextArea(tcLogsPane);
        }
        tcDocsPane.setEditorKit(new HTMLEditorKit());
        tcDocsPane.addHyperlinkListener(new HyperlinkListener() {

            public void hyperlinkUpdate(HyperlinkEvent e) {
            }
        });

        ExecuteButtonAction buttonListener = new ExecuteButtonAction();
        executeButton.addActionListener(buttonListener);
        executeButton.setIcon(ResourceManager.getInstance().getImageIcon("icons/running_32"));
        executeButton.setToolTipText("Run Test(s)");

        startExecutionButton.setIcon(ResourceManager.getInstance().getImageIcon("icons/start"));
        startExecutionButton.setToolTipText("Continue test case execution (F8)");
        startExecutionButton.setVisible(false);
        startExecutionButton.addActionListener(new ActionListener() {

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

        stepOverExecutionButton.setIcon(ResourceManager.getInstance().getImageIcon("icons/stepover"));
        stepOverExecutionButton.setToolTipText("Step over the script execution (F6)");
        stepOverExecutionButton.setVisible(false);
        stepOverExecutionButton.addActionListener(new ActionListener() {

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

        stepIntoExecutionButton.setIcon(ResourceManager.getInstance().getImageIcon("icons/stepinto"));
        stepIntoExecutionButton.setToolTipText("Step into the script execution (F5)");
        stepIntoExecutionButton.setVisible(false);
        stepIntoExecutionButton.addActionListener(new ActionListener() {

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

        stopExecutionButton.setIcon(ResourceManager.getInstance().getImageIcon("icons/stop"));
        stopExecutionButton.setToolTipText("Stop execution");
        stopExecutionButton.setVisible(false);
        stopExecutionButton.addActionListener(new ActionListener() {

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

        debugButton.setIcon(ResourceManager.getInstance().getImageIcon("icons/debug"));
        debugButton.setToolTipText("Debug Test(s)");
        debugButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                {
                    runTestSuite(true, 1, false);
                }
            }
        });
        saveButton.setIcon(ResourceManager.getInstance().getImageIcon("icons/save_32"));
        saveButton.setToolTipText("Save and check script(s) syntax");
        saveButton.setName("save button");
        saveButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                if (checkScriptsSyntax()) // display dialog when syntax is correct
                {
                    JOptionPane.showMessageDialog(null, "Syntax checked successfully");
                }
            }
        });

        resultsButton.addActionListener(new ActionListener() {

            // Show the browser displayed the last test report
            public void actionPerformed(ActionEvent e) {
                boolean showTestSuiteReport = resultsPane.getCurrentRunName().equals("Run1");
                String resDir = TestEngineConfiguration.getInstance().getString("reporting.generated_report_path");
                String baseDir = System.getProperty("user.dir");
                String filename = baseDir + File.separator + resDir + File.separator
                        + (showTestSuiteReport ? "index.html" : "campaign.html");
                File resultsFile = new File(filename);
                try {
                    if (Desktop.isDesktopSupported()) {
                        Desktop.getDesktop().open(resultsFile);
                    } else {
                        logger.error("Feature not supported by this platform");
                    }
                } catch (IOException ex) {
                    logger.error("Could not open " + filename);
                }
            }
        });

        resultsButton.setToolTipText("View the HTML Test Run Summary Results");
        resultsButton.setName("test run results button");

        FormLayout layout = new FormLayout(
                "6px, pref, 6px, pref, 6px, pref, 6px, pref, 6px, pref, 6px, pref, 6px, pref, 6px, pref, 6px, pref, 6px:grow",
                "6px, fill:pref, 6px");
        PanelBuilder builder = new PanelBuilder(layout);
        CellConstraints cc = new CellConstraints();

        int rowIndex = 2;
        int colIndex = 2;
        builder.add(executeButton, cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(saveButton, cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(debugButton, cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(resultsButton, cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(new CommonShortcutsPanel(), cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(startExecutionButton, cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(stepOverExecutionButton, cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(stepIntoExecutionButton, cc.xy(colIndex, rowIndex));
        colIndex += 2;
        builder.add(stopExecutionButton, cc.xy(colIndex, rowIndex));

        JPanel northP = builder.getPanel();
        add(northP, BorderLayout.NORTH);
        tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM);
        editorTabbedPane = new JTabbedPane(JTabbedPane.TOP);
        editorTabbedPane.addMouseListener(new TabMouseListener());
        editorTabbedPane.setFocusable(false);
        sourcePanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

        getTcSourcePane().add(editorTabbedPane);
        sourcePanel.setTopComponent(getTcSourcePane());
        sourcePanel.setFocusable(false);

        sourcePanel.setDividerSize(4);

        debugPanel = new DebugVariablePanel();
        debugPanel.setPreferredSize(new Dimension(100, 150));
        sourcePanel.setResizeWeight(0.9);
        sourcePanel.setBottomComponent(debugPanel);
        ////////////////////////
        debugPanel.setVisible(false);
        //sourcePanel.add(debugPanel, BorderLayout.SOUTH);
        tabbedPane.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                // transfer focus to editor if necessary
                if (tabbedPane.getSelectedIndex() == SOURCE_INDEX) {
                    Component tab = editorTabbedPane.getSelectedComponent();
                    if (tab != null && tab instanceof JScrollPane) {
                        JScrollPane scrollPane = (JScrollPane) tab;
                        tab = scrollPane.getViewport().getView();
                        if (tab != null) {
                            tab.requestFocusInWindow();
                        }
                    }
                } else {
                    Component tab = tabbedPane.getSelectedComponent();
                    if (tab != null && tab instanceof JScrollPane) {
                        JScrollPane scrollPane = (JScrollPane) tab;
                        tab = scrollPane.getViewport().getView();
                        if (tab != null) {
                            tab.requestFocusInWindow();
                        }
                    }
                }
                if (!isDocTabSelected()) {
                    return;
                }
                // generate doc if necessary
                NonWrappingTextPane tsPane = getTcSourceTextPane();
                if (tsPane != null) {
                    File tsFile = new File(tsPane.getFileName());
                    PythonTestScript pScript = new PythonTestScript(tsFile, getTestSuiteDirectory());
                    if (pScript.isDocSynchronized()) {
                        return;
                    }
                    // re-generate the doc
                    parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                    pScript.generateDoc();
                    HTMLDocumentLoader loader = new HTMLDocumentLoader();
                    HTMLDocument doc;
                    try {
                        File tcDoc = pScript.getTestcaseDoc();
                        if (tcDoc != null) {
                            doc = loader.loadDocument(tcDoc.toURI().toURL());
                            setTestCaseInfo(doc);
                        } else {
                            setTestCaseInfo(null);
                        }
                    } catch (MalformedURLException e1) {
                        logger.error(e1);
                        setTestCaseInfo(null);
                    } catch (IOException e1) {
                        logger.error(e1);
                        setTestCaseInfo(null);
                    }
                    parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                }
            }
        });

        tabbedPane.add(DOC, new JScrollPane(tcDocsPane));
        tabbedPane.add(SOURCE, sourcePanel);

        tabbedPane.add(RESULTS, resultsPane);
        if (tcLogsPane != null) {
            tabbedPane.add(LOGS, tcLogsPane);
        }

        add(tabbedPane, BorderLayout.CENTER);
    }

    public void stopExecution() {
        setStopButtonEnabled(false, true);
        stopDebug();
        stopExecution = true;
        TestEngine.setAbortedByUser(); // Flag to terminate test suites
        if (testExecutionHandler != null) {
            testExecutionHandler.stop();
        } else if (testCampaignExecutionHandler != null) {
            testCampaignExecutionHandler.stop();
        }

        if (!TestEngine.isSUTStartedManually()) {
            Thread t = new Thread(new Runnable() {
                public void run() {
                    TestEngine.cancelStartStopSUT();
                }
            });
            t.start();
        }
    }

    public boolean checkScriptsSyntax() {
        // check the test scripts syntax
        // save and check syntax of the documents
        for (int i = 0; i < editorTabbedPane.getTabCount(); i++) {
            NonWrappingTextPane tabTextPane = getTextPane(i);
            if (tabTextPane != null) {
                if (tabTextPane.isModified()) {
                    tabTextPane.save();
                }
                // check only opened Python files
                if (tabTextPane.getFileName().endsWith(".py")) {
                    ScriptCheckSyntaxValidator scriptCheckSyntaxValidator = new ScriptCheckSyntaxValidator(
                            tabTextPane.getFileName(), tabTextPane.getText());
                    if (!scriptCheckSyntaxValidator.check()) {
                        return false;
                    }
                }
            }
            TestDataEditor tabDataPane = this.getTestDataPane(i);
            if (tabDataPane != null && tabDataPane.isModified()) {
                tabDataPane.save();
            }
        }

        // check the module imported found in pythonlib

        // check all testdata
        return true;
    }

    public void stopDebug() {
        logger.trace("Test case pane: stop debug");
        breakPointEventHandler.stop();
    }

    public void continueDebug() {
        logger.trace("Test case pane: continue");
        breakPointEventHandler.continue_();
    }

    public void continueStep() {
        logger.trace("Test case pane: continue step");
        breakPointEventHandler.step();
    }

    public void continueStepInto() {
        logger.trace("Test case pane: continue step into");
        breakPointEventHandler.stepInto();
    }

    public JTabbedPane getTabbedPane() {
        return tabbedPane;
    }

    public Log4jPanel getResultsLog4jPanel() {
        return resultsPane.getLog4jPanel();
    }

    public Document getCurrentTestCaseDoc() {
        return tcDocsPane.getDocument();
    }

    public JTextPane getDocPane() {
        return tcDocsPane;
    }

    public void setTestCaseInfo(Document htmlDoc) {
        if (htmlDoc == null) {
            tcDocsPane.setDocument(EMPTY_DOC);
        } else {
            tcDocsPane.setDocument(htmlDoc);
        }
        tcDocsPane.setCaretPosition(0);
        tcDocsPane.scrollRectToVisible(new Rectangle(0, 0, 0, 0));
        tcDocsPane.setEditable(false);
    }

    /**
     * loadTestCaseSource method loads the file contents if necessary. If the
     *   file is already loaded, this method activates the correct tab based
     *   on the filename
     * @param f : file to load in the JTextPane
     * @param activateSourceTab : specifies if the tab "TestCase Source" must be activated
     * @param isTestScript : specifies if the file to load is the main TestScript
     * @return the JTextPane(NonWrappingTextPane) containing the file content
     */
    public NonWrappingTextPane loadTestCaseSource(final File f, final boolean activateSourceTab,
            final boolean isTestScript) {
        return this.loadTestCaseSource(f, activateSourceTab, isTestScript, false);
    }

    /**
     * loadTestCaseSource method loads the file contents if necessary. If the
     *   file is already loaded, this method activates the correct tab based
     *   on the filename
     * @param f : file to load in the JTextPane
     * @param activateSourceTab : specifies if the tab "TestCase Source" must be activated
     * @param isTestScript : specifies if the file to load is the main TestScript
     * @param force : specifies if the file must be read from source
     * @return the JTextPane(NonWrappingTextPane) containing the file content
     */
    public NonWrappingTextPane loadTestCaseSource(final File f, final boolean activateSourceTab,
            final boolean isTestScript, final boolean force) {
        String absolutePath;
        try {
            absolutePath = f.getAbsoluteFile().getCanonicalPath();
        } catch (IOException e) {
            logger.fatal("Cannot load testcase source", e);
            return null;
        }
        NonWrappingTextPane textPane = activateSourceIfAlreadyLoaded(absolutePath, isTestScript);
        if (!force & textPane != null) {
            return textPane;
        }
        if (f.exists() && f.canRead()) {
            StringBuffer contents = new StringBuffer();
            BufferedReader in = null;
            try {
                in = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
                while (in.ready()) {
                    contents.append(in.readLine()).append("\n");
                }
                boolean newTab = textPane == null;
                if (textPane == null) {
                    textPane = new NonWrappingTextPane(isTestScript);
                }
                if (newTab) {
                    JScrollPane sp = new JScrollPane(textPane);
                    if (absolutePath.endsWith(".py")) {
                        textPane.init("text/python");
                    } else if (absolutePath.endsWith(".xml")) {
                        textPane.init("text/xml");
                    } else if (absolutePath.endsWith(".sh")) {
                        textPane.init("text/bash");
                    } else if (absolutePath.endsWith(".bat") || absolutePath.endsWith(".cmd")) {
                        textPane.init("text/dosbatch");
                    } else {
                        textPane.init("text/plain");
                    }
                    textPane.setFileName(absolutePath);

                    if (isTestScript) {
                        tcSourceTextPane = textPane;
                    }
                    textPane.setTestCasePane(this);

                    editorTabbedPane.addTab(f.getName(), null, sp, absolutePath);
                    editorTabbedPane.setSelectedIndex(editorTabbedPane.getTabCount() - 1);
                    textPane.addDocumentListener();
                    textPane.addPropertyChangeListener("isModified", new PropertyChangeListener() {

                        public void propertyChange(PropertyChangeEvent evt) {
                            if (evt.getNewValue().equals(true)) {
                                String currentTitle = editorTabbedPane
                                        .getTitleAt(editorTabbedPane.getSelectedIndex());
                                if (!currentTitle.contains("*")) {
                                    currentTitle += " *";
                                    editorTabbedPane.setTitleAt(editorTabbedPane.getSelectedIndex(), currentTitle);
                                }
                            } else {
                                String currentTitle = editorTabbedPane
                                        .getTitleAt(editorTabbedPane.getSelectedIndex());
                                if (currentTitle.contains(" *")) {
                                    currentTitle = currentTitle.replace(" *", "");
                                    editorTabbedPane.setTitleAt(editorTabbedPane.getSelectedIndex(), currentTitle);
                                }
                            }
                        }
                    });
                }
                setTestCaseSource(textPane, absolutePath, contents.toString(), isTestScript);
                textPane.setModified(false);
                textPane.clearUndos();

                if (absolutePath.endsWith(".py")) {
                    new DebuggerShortcuts(this); // TO MOVE TO NONWRAPPINGTEXTPANE
                }
                new GenericShortcuts(this); // TO MOVE TO NONWRAPPINGTEXTPANE
                if (activateSourceTab) {
                    tabbedPane.setSelectedIndex(TestCasePane.SOURCE_INDEX);
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            } finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException ioe) {
                    //So I couldn't close the connection?
                }
            }
        }
        return textPane;
    }

    /**
     * This method gets the current activated textPane
     * @return null if there is no tab or the current tab is not a TextPane
     */
    public NonWrappingTextPane getActiveTextPane() {
        int tabIndex = editorTabbedPane.getSelectedIndex();
        if (tabIndex == -1) {
            return null;
        }
        return this.getTextPane(tabIndex);
    }

    /**
     * This method return the textPane in which the main TestScript is loaded
     * @return NonWrappingTextPane object containing the TestScript file
     */
    public NonWrappingTextPane getTcSourceTextPane() {
        return tcSourceTextPane;
    }

    /**
     * This method activates the python script based on the file name if already loaded
     * @param fileName of the script file
     * @param isTestScript specifies if the python script is the main TestScript file
     * @return TextPane is already loaded otherwise null
     */
    public NonWrappingTextPane activateSourceIfAlreadyLoaded(String fileName, boolean isTestScript) {
        // check if already loaded
        boolean tcTextFound = false;

        int testScriptTabIndex = getTestScriptTabIndex();
        if (testScriptTabIndex != -1) {
            tcTextFound = true;
        }
        int textPaneTabIndex = getTextPane(fileName);
        if (textPaneTabIndex != -1 && (!isTestScript || textPaneTabIndex == 0)) {
            editorTabbedPane.setSelectedIndex(textPaneTabIndex);
            tabbedPane.setSelectedIndex(TestCasePane.SOURCE_INDEX);
            return getTextPane(textPaneTabIndex);
        }

        if (tcTextFound && isTestScript) {
            // remove all tabs
            closeAllTabs();
        }
        return null;
    }

    /**
     * Close all tabs and ask user confirmation if a file is modified
     */
    public void closeAllTabs() {
        while (editorTabbedPane.getTabCount() > 0) {
            // check if the current tab must be saved
            NonWrappingTextPane currentPane = getTextPane(0);
            if (currentPane != null) {
                if (currentPane.isModified()) {

                    if (JOptionPane.showConfirmDialog(null,
                            "Do you want to save your current modification in '" + currentPane.getFileName() + "?'",
                            "Save confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                        currentPane.save();
                    }
                }
                // remove all breakpoints and listeners if any
                currentPane.removeAllBreakpoints();
                currentPane = null;
            } else {
                TestDataEditor currentDataPane = getTestDataPane(0);
                if (currentDataPane != null) {
                    if (currentDataPane.isModified()) {

                        if (JOptionPane.showConfirmDialog(null,
                                "Do you want to save your current modification in '"
                                        + currentDataPane.getCurrentCSVFile() + "?'",
                                "Save confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                            currentDataPane.save();
                        }
                    }
                    currentDataPane = null;
                } else {
                    TestRequirementEditor currentrequirementPane = getTestRequirementPane(0);
                    if (currentrequirementPane != null) {
                        if (currentrequirementPane.isModified()) {

                            if (JOptionPane.showConfirmDialog(null,
                                    "Do you want to save your current modification in '"
                                            + currentrequirementPane.getCurrentXMLFile() + "?'",
                                    "Save confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                                currentrequirementPane.save();
                            }
                        }
                        currentrequirementPane = null;
                    }
                }
            }
            editorTabbedPane.removeTabAt(0);
        }
    }

    /**
     * This method saves the current document only if the current pane is a textpane containing a python script
     */
    public void saveActiveDocument() {
        NonWrappingTextPane activeTextPane = getActiveTextPane();
        if (activeTextPane != null) {
            activeTextPane.save();
        }

    }

    public void setTestCaseSource(NonWrappingTextPane textPane, String fileName, String contents,
            boolean isTestScript) {
        textPane.setText(contents);
        textPane.setCaretPosition(0);
    }

    public NonWrappingTextPane getTestScripPane() {
        int testScriptTabIndex = this.getTestScriptTabIndex();
        if (testScriptTabIndex != -1) {
            return this.getTextPane(testScriptTabIndex);
        }
        return null;

    }

    public int getTestScriptTabIndex() {
        for (int i = 0; i < editorTabbedPane.getTabCount(); i++) {
            NonWrappingTextPane tabTextPane = getTextPane(i);
            if (tabTextPane != null) {
                if (tabTextPane.isTestScript) {
                    return i;
                }
            }
        }
        return -1; // not found
    }

    public NonWrappingTextPane[] getVisibleTextPanes() {
        ArrayList<NonWrappingTextPane> textPanes = new ArrayList<NonWrappingTextPane>();
        for (int i = 0; i < editorTabbedPane.getTabCount(); i++) {
            NonWrappingTextPane tabTextPane = getTextPane(i);
            if (tabTextPane == null) {
                continue;
            }
            textPanes.add(tabTextPane);

        }
        NonWrappingTextPane[] array = new NonWrappingTextPane[textPanes.size()];

        textPanes.toArray(array);
        return array;
    }

    public int getTextPane(String fileName) {
        for (int i = 0; i < editorTabbedPane.getTabCount(); i++) {
            NonWrappingTextPane tabTextPane = getTextPane(i);
            if (tabTextPane == null) {
                continue;
            }
            if (tabTextPane.getFileName().equals(fileName)) {
                return i;
            }
        }
        return -1; // not found

    }

    public NonWrappingTextPane getTextPane(int tabIndex) {
        Component comp = editorTabbedPane.getComponentAt(tabIndex);
        if (comp instanceof JScrollPane) {
            JScrollPane sp = (JScrollPane) comp;
            if (sp.getViewport() != null) {
                for (int j = 0; j < sp.getViewport().getComponentCount(); j++) {
                    comp = sp.getViewport().getComponent(j);
                    if (comp instanceof NonWrappingTextPane) {
                        return (NonWrappingTextPane) comp;
                    }
                }
            }
        }
        return null;
    }

    public TestDataEditor getTestDataPane(int tabIndex) {
        Component comp = editorTabbedPane.getComponentAt(tabIndex);
        if (comp instanceof TestDataEditor) {
            return (TestDataEditor) comp;
        }
        return null;
    }

    public TestRequirementEditor getTestRequirementPane(int tabIndex) {
        Component comp = editorTabbedPane.getComponentAt(tabIndex);
        if (comp instanceof TestRequirementEditor) {
            return (TestRequirementEditor) comp;
        }
        return null;
    }

    public TestDataEditor getTestDataPane() {
        for (int i = 0; i < editorTabbedPane.getTabCount(); i++) {
            TestDataEditor testDataEditor = getTestDataPane(i);
            if (testDataEditor != null) {
                return testDataEditor;
            }
        }
        return null;
    }

    public int getTestDataTabIndex() {
        for (int i = 0; i < editorTabbedPane.getTabCount(); i++) {
            TestDataEditor tabTestDataPane = getTestDataPane(i);
            if (tabTestDataPane != null) {
                return i;
            }
        }
        return -1; // not found
    }

    public int getTestRequirementTabIndex() {
        for (int i = 0; i < editorTabbedPane.getTabCount(); i++) {
            TestRequirementEditor tabTestRequirementPane = getTestRequirementPane(i);
            if (tabTestRequirementPane != null) {
                return i;
            }
        }
        return -1; // not found
    }

    public void activateTestcaseSourceTab() {
        int testScriptTabIndex = getTestScriptTabIndex();
        if (testScriptTabIndex != -1) {
            editorTabbedPane.setSelectedIndex(testScriptTabIndex);
        }
    }

    public void showTestcaseResultsTab() {
        //resultsPane.setVisible(true);
        tabbedPane.setSelectedIndex(RESULTS_INDEX);
    }

    public void loadCSVFile(String fileName) {
        // load also the test data CSV file
        int testDataTabIndex = getTestDataTabIndex();
        if (testDataTabIndex != -1) {
            TestDataEditor currentTestDataEditor = this.getTestDataPane(testDataTabIndex);
            if (currentTestDataEditor != null) {
                if (currentTestDataEditor.getCurrentCSVFile().equals(fileName)) {
                    return;
                }
            }
        }
        TestDataEditor dataEditor = new TestDataEditor();
        dataEditor.loadCSVFile(fileName);
        editorTabbedPane.addTab("TestData", null, dataEditor, fileName);
        dataEditor.addPropertyChangeListener("isModified", new PropertyChangeListener() {

            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getNewValue().equals(true)) {
                    String currentTitle = editorTabbedPane.getTitleAt(editorTabbedPane.getSelectedIndex());
                    if (!currentTitle.contains("*")) {
                        currentTitle += " *";
                        editorTabbedPane.setTitleAt(editorTabbedPane.getSelectedIndex(), currentTitle);
                    }
                } else {
                    String currentTitle = editorTabbedPane.getTitleAt(editorTabbedPane.getSelectedIndex());
                    if (currentTitle.contains(" *")) {
                        currentTitle = currentTitle.replace(" *", "");
                        editorTabbedPane.setTitleAt(editorTabbedPane.getSelectedIndex(), currentTitle);
                    }
                }
            }
        });

    }

    public void loadXMLFile(String fileName) {
        int testRequirementTabIndex = getTestRequirementTabIndex();
        if (testRequirementTabIndex != -1) {
            TestRequirementEditor currentTestRequirementEditor = this
                    .getTestRequirementPane(testRequirementTabIndex);
            if (currentTestRequirementEditor != null) {
                if (currentTestRequirementEditor.getCurrentXMLFile().equals(fileName)) {
                    return;
                }
            }
        }
        TestRequirementEditor requirementEditor = new TestRequirementEditor();
        requirementEditor.loadXMLFile(fileName);
        editorTabbedPane.addTab("TestRequirements", null, requirementEditor, fileName);
        requirementEditor.addPropertyChangeListener("isModified", new PropertyChangeListener() {

            private static final String MODIFIED_SUFFIX = " *";

            public void propertyChange(PropertyChangeEvent evt) {
                String currentTitle = editorTabbedPane.getTitleAt(editorTabbedPane.getSelectedIndex());
                if (evt.getNewValue().equals(true)) {
                    if (!currentTitle.endsWith(MODIFIED_SUFFIX)) {
                        currentTitle += MODIFIED_SUFFIX;
                    }
                } else if (currentTitle.endsWith(MODIFIED_SUFFIX)) {
                    currentTitle = currentTitle.replace(MODIFIED_SUFFIX, "");
                }
                editorTabbedPane.setTitleAt(editorTabbedPane.getSelectedIndex(), currentTitle);
            }
        });

    }

    public JPanel getTcSourcePane() {
        return tcSourcePanel;
    }

    public MainPanel getMainPanel() {
        return parent;
    }

    public String getCurrentSelectedTestsuite() {
        return currentSelectedTestsuite;
    }

    public void setCurrentSelectedTestsuite(String currentSelectedTestsuite) {
        this.currentSelectedTestsuite = currentSelectedTestsuite;
    }

    public FileNode getCurrentSelectedFileNode() {
        return currentSelectedFileNode;
    }

    public void setCurrentSelectedFileNode(FileNode currentSelectedFileNode) {
        this.currentSelectedFileNode = currentSelectedFileNode;
    }

    protected class ExecuteButtonAction implements ActionListener {

        /**
         * Invoked when an action occurs.
         */
        public void actionPerformed(ActionEvent e) {
            runTestSuite(false);
        }
    }

    public void runTestSuite(boolean debug) {
        runTestSuite(debug, 1, false);
    }

    public void runTestSuite(final boolean debug, final int numberLoops, final boolean loopsInHours) {
        // change the testsuite to run
        final TreePath[] selectedTcs = tcTree.getSelectionPaths();
        if (selectedTcs == null) {
            logger.warn("No testsuite selected");
            return;
        }
        Object[] obj = selectedTcs[0].getPath();
        // this directory is saved into the root testcase tree
        String testSuiteDir = mTestCaseSuitesRootDir;
        for (Object o : obj) {
            if (o instanceof TCTreeNode) {
                TCTreeNode tcTreeNode = (TCTreeNode) o;
                // remove the root path (test cases)
                if (tcTreeNode.getParent() != null) {
                    testSuiteDir += File.separator + o.toString();
                }
            }
        }
        DirectoryTestSuite testSuite = DirectoryTestSuite.createDirectoryTestSuite(testSuiteDir);
        if (testSuite != null) {
            testSuite.setExecutionLoops(numberLoops, loopsInHours);
            runTestSuite(testSuite, debug);
        }
    }

    public void setTestSuiteDirectory(String dir) {
        mTestCaseSuitesRootDir = dir;
    }

    public String getTestSuiteDirectory() {
        return mTestCaseSuitesRootDir;
    }

    public void runTestSuite(final TestSuite testSuite, final boolean debug) {
        if (!this.checkScriptsSyntax()) {
            return;
        }
        resultsPane.setRunTab("Run1");
        resultsPane.resetTables();
        tabbedPane.setSelectedIndex(RESULTS_INDEX);

        resultsPane.setVisible(true);
        stopExecution = false;
        resultsPane.proceedExecution();
        // update the config panel
        parent.setTestSuite(testSuite.getName());
        parent.refreshParams();
        TestBedConfiguration.setSUTVersion(parent.getSUTVersion());
        isExecuting = true;
        stopExecution = false;
        setStopButtonEnabled(true, true);

        parent.getHeaderPanel().setControlTestbedButtonsEnabled();
        parent.getTestCampaignPanel().setExecuteButtonsEnabled(!isExecuting);

        testExecutionHandler = new TestExecutionThread(testSuite, debug);
        Thread t = new Thread(testExecutionHandler);
        t.start();
    }

    public void doAction(TestScriptBreakpointEvent event) {
        switch (event.getAction()) {
        case CONTINUE:
        case STEP:
        case STEPINTO:
        case STOP:
            startExecutionButton.setVisible(false);
            //getVarButton.setVisible(false);
            //                stopExecutionButton.setVisible(false);
            stepOverExecutionButton.setVisible(false);
            stepIntoExecutionButton.setVisible(false);
            tabbedPane.setSelectedIndex(RESULTS_INDEX);
            debugPanel.setVisible(false);
            //this.getTe
            NonWrappingTextPane[] panes = this.getVisibleTextPanes();
            for (int i = 0; i < panes.length; i++) {
                NonWrappingTextPane textPane = panes[i];
                textPane.getDefaultLineNumberPanel().update(event);
            }
            break;
        case BREAK:
            startExecutionButton.setVisible(true);
            stepOverExecutionButton.setVisible(true);
            stepIntoExecutionButton.setVisible(true);
            debugPanel.setVisible(true);
            sourcePanel.setDividerLocation(sourcePanel.getDividerLocation() - 150);
            // update the button status
            //                stopExecutionButton.setVisible(true);
            //getVarButton.setVisible(true);
            tabbedPane.setSelectedIndex(SOURCE_INDEX);
            getTcSourcePane().setVisible(true);
            // set the current line highlighted
            Object extraData = event.getExtraData();
            if (extraData instanceof Breakpoint) {
                Breakpoint breakpoint = (Breakpoint) extraData;

                // load the file into the tabbedPaned
                File f = new File(breakpoint.getFileName());
                NonWrappingTextPane textPane = null;
                if (f.exists() && f.canRead()) {

                    textPane = loadTestCaseSource(f, true,
                            f.getName().equals(StaticConfiguration.TEST_SCRIPT_FILENAME));
                    tabbedPane.setSelectedIndex(TestCasePane.SOURCE_INDEX);
                    // now go to the given line
                    textPane.selectLine(breakpoint.getLineIndex());
                    textPane.getLineNumberPanel().update(event);
                }
            }
            break;
        }
    }

    public void setExecutingTestCampaign(boolean executing,
            TestCampaignMainPanel.CampaignExecutionThread testCampaignExecutionHandler) {
        isExecuting = executing;
        this.testCampaignExecutionHandler = testCampaignExecutionHandler;
    }

    public void updateButtons() {
        SwingUtilities.invokeLater(new UpdateButtons());
    }

    public void updateButtons(boolean enableStopButton) {
        SwingUtilities.invokeLater(new UpdateButtons(enableStopButton));
    }

    public void setSelectedTab(int index) {
        tabbedPane.setSelectedIndex(index);
    }

    @SuppressWarnings("unchecked")
    public void pythonResult(DumpPythonResultEvent event) {
        if (event.getSource() instanceof ArrayList) {
            ArrayList<DebugVariable> debugVariables = (ArrayList<DebugVariable>) event.getSource();
            debugPanel.setDebugVariables(debugVariables);
        }
    }

    public class UpdateButtons implements Runnable {

        private boolean enableStopButton;

        public UpdateButtons() {
            this.enableStopButton = false;
        }

        public UpdateButtons(final boolean enableStopButton) {
            this.enableStopButton = enableStopButton;
        }

        public void run() {
            executeButton.setEnabled(!isExecuting);
            stopExecutionButton.setVisible(isExecuting);
            if (this.enableStopButton) {
                stopExecutionButton.setEnabled(true);
            }
            debugButton.setEnabled(!isExecuting);
            parent.getHeaderPanel().setControlTestbedButtonsEnabled();
            parent.getTestCampaignPanel().setExecuteButtonsEnabled(!isExecuting);
            if (!isExecuting) {
                // set the focus to the test results
                tabbedPane.setSelectedIndex(RESULTS_INDEX);
            }
        }
    }

    public class TestExecutionThread implements Runnable {

        private TestSuite testSuite;
        private boolean debug;

        public TestExecutionThread(final TestSuite testSuite, final boolean debug) {
            this.testSuite = testSuite;
            this.debug = debug;
        }

        public void stop() {
            ThreadGroup root = Thread.currentThread().getThreadGroup();
            ThreadManager.stopThread(root, 0);
        }

        public void run() {
            SwingUtilities.invokeLater(new UpdateButtons());
            isExecuting = true;

            try {
                TestEngine.execute(testSuite, debug);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                TestEngine.tearDown();
                isExecuting = false;
                SwingUtilities.invokeLater(new UpdateButtons());
                testExecutionHandler = null;
                debugPanel.setVisible(false);
            }
        }
    }

    public void closeCurrentEditorFile() {
        NonWrappingTextPane textPane = getActiveTextPane();
        if (textPane != null) {
            if (!textPane.isTestScript) {
                int tabIndex = editorTabbedPane.getSelectedIndex();
                if (tabIndex != -1) {
                    // check if the textpane must be saved

                    if (textPane.isModified()) {
                        if (JOptionPane.showConfirmDialog(null,
                                "Do you want to save your current modification in '" + textPane.getFileName()
                                        + "?'",
                                "Save confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                            textPane.save();
                        }
                    }
                    editorTabbedPane.remove(tabIndex);
                }
            }
        }

    }

    public class TabMouseListener extends MouseAdapter {

        private void evaluatePopup(MouseEvent e) {
            if (e.isPopupTrigger()) {
                // force selection of clicked row
                // display a popup menu to run/debug a test
                // display the context dialog
                JPopupMenu menu = new JPopupMenu();
                menu.add(new FileCloseAction());
                Point pt = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), TestCasePane.this);
                menu.show(TestCasePane.this, pt.x, pt.y);
                e.consume();
            }
        }

        @Override
        public void mousePressed(MouseEvent e) {
            evaluatePopup(e);
            if (e.isConsumed()) {
                return;
            }
            if (e.getButton() == MouseEvent.BUTTON2) {
                closeCurrentEditorFile();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            evaluatePopup(e);
        }
    }

    class FileCloseAction extends AbstractAction {

        public FileCloseAction() {
            super("Close");
        }

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

        @Override
        public boolean isEnabled() {
            NonWrappingTextPane textPane = getActiveTextPane();
            if (textPane != null) {
                if (!textPane.isTestScript) {
                    return true;
                }
            }
            return false;
        }
    }

}