# -*- coding: utf-8 -*-

# Copyright (c) 2002 - 2005 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the debugger UI.
"""

import os

from qt import *

from KdeQt import KQMessageBox, KQInputDialog

from UI.Info import *
from VariablesFilterDialog import *
from ExceptionsFilterDialog import *
from StartDialog import *
from DebugClients.Python.DebugClientCapabilities import *
import Preferences
import Utilities
import UI.PixmapCache

from UI.E3Action import E3Action, E3ActionGroup

class DebugUI(QObject):
    """
    Class implementing the debugger part of the UI.
    
    @signal clientStack(stack) emitted at breaking after a reported exception
    @signal compileForms() emitted if changed project forms should be compiled
    @signal debuggingStarted(filename) emitted when a debugging session was started
    @signal resetUI()   emitted to reset the UI
    """
    def __init__(self,ui,vm,dbs,sbv,pro):
        """
        Constructor
        
        @param ui reference to the main UI
        @param vm reference to the viewmanager
        @param dbs reference to the debug server
        @param sbv reference to the shell/browser/variables/exception widget
        @param pro reference to the project object
        """
        QObject.__init__(self, ui)
        
        self.ui = ui
        self.viewmanager = vm
        self.dbs = dbs
        self.sbv = sbv
        self.project = pro
        
        # Clear some variables
        self.projectOpen = 0
        self.editorOpen = 0
        self.excList = []
        
        # Generate the variables filter dialog
        self.dbgFilterDialog = VariablesFilterDialog(self.ui, 'Filter Dialog', 1)

        self.argvHistory = QStringList()
        self.wdHistory = QStringList()
        self.envHistory = QStringList()
        self.mfHistory = QStringList()
        self.covexcHistory = QStringList()
        self.exceptions = 1
        self.evalHistory = QStringList()
        self.execHistory = QStringList()
        self.tracePython = 0
        self.lastDebuggedFile = None
        self.lastStartAction = 0    # 0=None, 1=Script, 2=Project
        self.lastAction = -1
        self.debugActions = [self.handleContinue, self.handleStep,\
                        self.handleStepOver, self.handleStepOut,\
                        self.handleStepQuit, self.handleRunToCursor]
        self.localsVarFilter, self.globalsVarFilter = Preferences.getVarFilters()
        self.sbv.setVariablesFilter(self.globalsVarFilter, self.localsVarFilter)
        
        # Connect the signals emitted by the debug-server
        self.connect(dbs,PYSIGNAL('clientGone'),self.handleClientGone)
        self.connect(dbs,PYSIGNAL('clientLine'),self.handleLineChange)
        self.connect(dbs,PYSIGNAL('clientExit'),self.handleExit)
        self.connect(dbs,PYSIGNAL('clientSyntaxError'),self.handleSyntaxError)
        self.connect(dbs,PYSIGNAL('clientException'),self.handleException)
        self.connect(dbs,PYSIGNAL('clientVariables'),self.handleClientVariables)
        self.connect(dbs,PYSIGNAL('clientVariable'),self.handleClientVariable)
        self.connect(dbs,PYSIGNAL('clientClearBreak'),self.handleClientClearBreak)
        self.connect(dbs,PYSIGNAL('passiveDebugStarted'),self.handlePassiveDebugStarted)
        self.connect(dbs,PYSIGNAL('cyclopsError'),self.handleCyclopsError)
        
        self.connect(dbs,PYSIGNAL('clientRawInput'),sbv.handleRawInput)
        self.connect(dbs,PYSIGNAL('clientRawInputSent'),sbv.restoreCurrentPage)
        
        # Connect the signals emitted by the viewmanager
        self.connect(vm,PYSIGNAL('editorOpened'),self.handleEditorOpened)
        self.connect(vm,PYSIGNAL('lastEditorClosed'),self.handleLastEditorClosed)
        self.connect(vm,PYSIGNAL('checkActions'),self.checkActions)
        self.connect(vm,PYSIGNAL('cursorChanged'),self.handleCursorChanged)
        self.connect(vm,PYSIGNAL('breakpointToggled'),self.handleCursorChanged)
        
        # Connect the signals emitted by the project
        project = ui.getProject()
        self.connect(project,PYSIGNAL('projectOpened'),self.handleProjectOpened)
        self.connect(project,PYSIGNAL('newProject'),self.handleProjectOpened)
        self.connect(project,PYSIGNAL('projectClosed'),self.handleProjectClosed)
        self.connect(project,PYSIGNAL('projectSessionLoaded'),self.handleProjectSessionLoaded)
        
        # Set a flag for the passive debug mode
        self.passive = Preferences.getDebugger("PassiveDbgEnabled")
        
    def initActions(self):
        """
        Method defining the user interface actions.
        """
        self.actions = []
        
        self.runAct = E3Action(self.trUtf8('Run Script'),
                QIconSet(UI.PixmapCache.getPixmap("runScript.png")),
                self.trUtf8('&Run Script...'),Qt.Key_F2,0,self,'dbg_run_script')
        self.runAct.setStatusTip(self.trUtf8('Run the current Script'))
        self.runAct.setWhatsThis(self.trUtf8(
            """<b>Run Script</b>"""
            """<p>Set the command line arguments and run the script outside the debugger."""
            """ If the file has unsaved changes it may be saved first.</p>"""
        ))
        self.runAct.connectIt(SIGNAL('activated()'),self.handleRunScript)
        self.actions.append(self.runAct)

        self.runProjectAct = E3Action(self.trUtf8('Run Project'),
                QIconSet(UI.PixmapCache.getPixmap("runProject.png")),
                self.trUtf8('Run &Project...'),Qt.SHIFT + Qt.Key_F2,0,self,'dbg_run_project')
        self.runProjectAct.setStatusTip(self.trUtf8('Run the current Project'))
        self.runProjectAct.setWhatsThis(self.trUtf8(
            """<b>Run Project</b>"""
            """<p>Set the command line arguments and run the current project"""
            """ outside the debugger."""
            """ If files of the current project have unsaved changes they may"""
            """ be saved first.</p>"""
        ))
        self.runProjectAct.connectIt(SIGNAL('activated()'),self.handleRunProject)
        self.actions.append(self.runProjectAct)

        self.coverageAct = E3Action(self.trUtf8('Coverage run of Script'),
                QIconSet(UI.PixmapCache.getPixmap("coverageScript.png")),
                self.trUtf8('Coverage run of Script...'),0,0,self,'dbg_coverage_script')
        self.coverageAct.setStatusTip(self.trUtf8('Perform a coverage run of the current Script'))
        self.coverageAct.setWhatsThis(self.trUtf8(
            """<b>Coverage run of Script</b>"""
            """<p>Set the command line arguments and run the script under the control of a"""
            """ coverage analysis tool. If the file has unsaved changes it may be"""
            """ saved first.</p>"""
        ))
        self.coverageAct.connectIt(SIGNAL('activated()'),self.handleCoverageScript)
        self.actions.append(self.coverageAct)

        self.coverageProjectAct = E3Action(self.trUtf8('Coverage run of Project'),
                QIconSet(UI.PixmapCache.getPixmap("coverageProject.png")),
                self.trUtf8('Coverage run of Project...'),0,0,self,'dbg_coverage_project')
        self.coverageProjectAct.setStatusTip(self.trUtf8('Perform a coverage run of the current Project'))
        self.coverageProjectAct.setWhatsThis(self.trUtf8(
            """<b>Coverage run of Project</b>"""
            """<p>Set the command line arguments and run the current project"""
            """ under the control of a coverage analysis tool."""
            """ If files of the current project have unsaved changes they may"""
            """ be saved first.</p>"""
        ))
        self.coverageProjectAct.connectIt(SIGNAL('activated()'),self.handleCoverageProject)
        self.actions.append(self.coverageProjectAct)

        self.profileAct = E3Action(self.trUtf8('Profile Script'),
                QIconSet(UI.PixmapCache.getPixmap("profileScript.png")),
                self.trUtf8('Profile Script...'),0,0,self,'dbg_profile_script')
        self.profileAct.setStatusTip(self.trUtf8('Profile the current Script'))
        self.profileAct.setWhatsThis(self.trUtf8(
            """<b>Profile Script</b>"""
            """<p>Set the command line arguments and profile the script."""
            """ If the file has unsaved changes it may be saved first.</p>"""
        ))
        self.profileAct.connectIt(SIGNAL('activated()'),self.handleProfileScript)
        self.actions.append(self.profileAct)

        self.profileProjectAct = E3Action(self.trUtf8('Profile Project'),
                QIconSet(UI.PixmapCache.getPixmap("profileProject.png")),
                self.trUtf8('Profile Project...'),0,0,self,'dbg_profile_project')
        self.profileProjectAct.setStatusTip(self.trUtf8('Profile the current Project'))
        self.profileProjectAct.setWhatsThis(self.trUtf8(
            """<b>Profile Project</b>"""
            """<p>Set the command line arguments and profile the current project."""
            """ If files of the current project have unsaved changes they may"""
            """ be saved first.</p>"""
        ))
        self.profileProjectAct.connectIt(SIGNAL('activated()'),self.handleProfileProject)
        self.actions.append(self.profileProjectAct)

        self.cyclopsAct = E3Action(self.trUtf8('Cyclops Script'),
                QIconSet(UI.PixmapCache.getPixmap("cyclopsScript.png")),
                self.trUtf8('Cyclops Script...'),0,0,self,'dbg_cyclops_script')
        self.cyclopsAct.setStatusTip(self.trUtf8('Run the current Script through Cyclops'))
        self.cyclopsAct.setWhatsThis(self.trUtf8(
            """<b>Cyclops Script</b>"""
            """<p>Set the command line arguments and run the script through Cyclops."""
            """ If the file has unsaved changes it may be saved first.</p>"""
        ))
        self.cyclopsAct.connectIt(SIGNAL('activated()'),self.handleCyclopsScript)
        self.actions.append(self.cyclopsAct)

        self.cyclopsProjectAct = E3Action(self.trUtf8('Cyclops Project'),
                QIconSet(UI.PixmapCache.getPixmap("cyclopsProject.png")),
                self.trUtf8('Cyclops Project...'),0,0,self,'dbg_cyclops_project')
        self.cyclopsProjectAct.setStatusTip(self.trUtf8('Run the current Project through Cyclops'))
        self.cyclopsProjectAct.setWhatsThis(self.trUtf8(
            """<b>Cyclops Project</b>"""
            """<p>Set the command line arguments and run the current project through Cyclops."""
            """ If files of the current project have unsaved changes they may"""
            """ be saved first.</p>"""
        ))
        self.cyclopsProjectAct.connectIt(SIGNAL('activated()'),self.handleCyclopsProject)
        self.actions.append(self.cyclopsProjectAct)

        self.debugAct = E3Action(self.trUtf8('Debug Script'),
                QIconSet(UI.PixmapCache.getPixmap("debugScript.png")),
                self.trUtf8('&Debug Script...'),Qt.Key_F5,0,self,'dbg_debug_script')
        self.debugAct.setStatusTip(self.trUtf8('Debug the current Script'))
        self.debugAct.setWhatsThis(self.trUtf8(
            """<b>Debug Script</b>"""
            """<p>Set the command line arguments and set the current line to be the first"""
            """ executable Python statement of the current editor window."""
            """ If the file has unsaved changes it may be saved first.</p>"""
        ))
        self.debugAct.connectIt(SIGNAL('activated()'),self.handleDebugScript)
        self.actions.append(self.debugAct)

        self.debugProjectAct = E3Action(self.trUtf8('Debug Project'),
                QIconSet(UI.PixmapCache.getPixmap("debugProject.png")),
                self.trUtf8('Debug &Project...'),Qt.SHIFT + Qt.Key_F5,0,self,'dbg_debug_project')
        self.debugProjectAct.setStatusTip(self.trUtf8('Debug the current Project'))
        self.debugProjectAct.setWhatsThis(self.trUtf8(
            """<b>Debug Project</b>"""
            """<p>Set the command line arguments and set the current line to be the first"""
            """ executable Python statement of the main script of the current project."""
            """ If files of the current project have unsaved changes they may"""
            """ be saved first.</p>"""
        ))
        self.debugProjectAct.connectIt(SIGNAL('activated()'),self.handleDebugProject)
        self.actions.append(self.debugProjectAct)

        self.restartAct = E3Action(self.trUtf8('Restart Script'),
                QIconSet(UI.PixmapCache.getPixmap("restart.png")),
                self.trUtf8('Restart Script'),Qt.Key_F4,0,self,'dbg_restart_script')
        self.restartAct.setStatusTip(self.trUtf8('Restart the last debugged script'))
        self.restartAct.setWhatsThis(self.trUtf8(
            """<b>Restart Script</b>"""
            """<p>Set the command line arguments and set the current line to be the first"""
            """ executable Python statement of the script that was debugged last."""
            """ If there are unsaved changes, they may be saved first.</p>"""
        ))
        self.restartAct.connectIt(SIGNAL('activated()'),self.handleRestart)
        self.actions.append(self.restartAct)

        self.debugActGrp = E3ActionGroup(self)

        act = E3Action(self.trUtf8('Continue'),
                QIconSet(UI.PixmapCache.getPixmap("continue.png")),
                self.trUtf8('&Continue'),Qt.Key_F6,0,
                self.debugActGrp,'dbg_continue')
        act.setStatusTip(self.trUtf8('Continue running the program from the current line'))
        act.setWhatsThis(self.trUtf8(
            """<b>Continue</b>"""
            """<p>Continue running the program from the current line. The program will"""
            """ stop when it terminates or when a breakpoint is reached.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleContinue)
        self.actions.append(act)

        act = E3Action(self.trUtf8('Continue to Cursor'),
                QIconSet(UI.PixmapCache.getPixmap("continueToCursor.png")),
                self.trUtf8('Continue &To Cursor'),Qt.SHIFT + Qt.Key_F6,0,
                self.debugActGrp,'dbg_continue_to_cursor')
        act.setStatusTip(self.trUtf8('Continue running the program from the current line to the current cursor position'))
        act.setWhatsThis(self.trUtf8(
            """<b>Continue To Cursor</b>"""
            """<p>Continue running the program from the current line to the current cursor position.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleRunToCursor)
        self.actions.append(act)

        act = E3Action(self.trUtf8('Single Step'),
                QIconSet(UI.PixmapCache.getPixmap("step.png")),
                self.trUtf8('Sin&gle Step'),Qt.Key_F7,0,
                self.debugActGrp,'dbg_single_step')
        act.setStatusTip(self.trUtf8('Execute a single Python statement'))
        act.setWhatsThis(self.trUtf8(
            """<b>Single Step</b>"""
            """<p>Execute a single Python statement. If the statement"""
            """ is an <tt>import</tt> statement, a class constructor, or a"""
            """ method or function call then control is returned to the debugger at"""
            """ the next statement.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleStep)
        self.actions.append(act)

        act = E3Action(self.trUtf8('Step Over'),
                QIconSet(UI.PixmapCache.getPixmap("stepOver.png")),
                self.trUtf8('Step &Over'),Qt.Key_F8,0,
                self.debugActGrp,'dbg_step_over')
        act.setStatusTip(self.trUtf8('Execute a single Python statement staying in the current frame'))
        act.setWhatsThis(self.trUtf8(
            """<b>Step Over</b>"""
            """<p>Execute a single Python statement staying in the same frame. If"""
            """ the statement is an <tt>import</tt> statement, a class constructor, or a"""
            """ method or function call then control is returned to the debugger after"""
            """ the statement has completed.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleStepOver)
        self.actions.append(act)

        act = E3Action(self.trUtf8('Step Out'),
                QIconSet(UI.PixmapCache.getPixmap("stepOut.png")),
                self.trUtf8('Step Ou&t'),Qt.Key_F9,0,
                self.debugActGrp,'dbg_step_out')
        act.setStatusTip(self.trUtf8('Execute Python statements until leaving the current frame'))
        act.setWhatsThis(self.trUtf8(
            """<b>Step Out</b>"""
            """<p>Execute Python statements until leaving the current frame. If"""
            """ the statements are inside an <tt>import</tt> statement, a class constructor, or a"""
            """ method or function call then control is returned to the debugger after"""
            """ the current frame has been left.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleStepOut)
        self.actions.append(act)

        act = E3Action(self.trUtf8('Stop'),
                QIconSet(UI.PixmapCache.getPixmap("stepQuit.png")),
                self.trUtf8('&Stop'),Qt.Key_F10,0,
                self.debugActGrp,'dbg_stop')
        act.setStatusTip(self.trUtf8('Stop debugging'))
        act.setWhatsThis(self.trUtf8(
            """<b>Stop</b>"""
            """<p>Stop the running debugging session.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleStepQuit)
        self.actions.append(act)
        
        self.debugActGrp2 = E3ActionGroup(self)

        act = E3Action(self.trUtf8('Evaluate'),
                self.trUtf8('E&valuate...'),
                0,0,self.debugActGrp2,'dbg_evaluate')
        act.setStatusTip(self.trUtf8('Evaluate in current context'))
        act.setWhatsThis(self.trUtf8(
            """<b>Evaluate</b>"""
            """<p>Evaluate an expresion in the current context of the"""
            """ debugged program. The result is displayed in the"""
            """ shell window.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleEval)
        self.actions.append(act)
        
        act = E3Action(self.trUtf8('Execute'),
                self.trUtf8('E&xecute...'),
                0,0,self.debugActGrp2,'dbg_execute')
        act.setStatusTip(self.trUtf8('Execute a one line statement in the current context'))
        act.setWhatsThis(self.trUtf8(
            """<b>Execute</b>"""
            """<p>Execute a one line statement in the current context"""
            """ of the debugged program.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'),self.handleExec)
        self.actions.append(act)
        
        self.dbgFilterAct = E3Action(self.trUtf8('Variables Type Filter'),
                self.trUtf8('Varia&bles Type Filter...'), 0, 0, self, 'dbg_variables_filter')
        self.dbgFilterAct.setStatusTip(self.trUtf8('Configure variables type filter'))
        self.dbgFilterAct.setWhatsThis(self.trUtf8(
            """<b>Variables Type Filter</b>"""
            """<p>Configure the variables type filter. Only variable types that are not"""
            """ selected are displayed in the global or local variables window"""
            """ during a debugging session.</p>"""
        ))
        self.dbgFilterAct.connectIt(SIGNAL('activated()'), self.handleConfigFilters)
        self.actions.append(self.dbgFilterAct)

        self.excFilterAct = E3Action(self.trUtf8('Exceptions Filter'),
                self.trUtf8('&Exceptions Filter...'), 0, 0, self, 'dbg_exceptions_filter')
        self.excFilterAct.setStatusTip(self.trUtf8('Configure exceptions filter'))
        self.excFilterAct.setWhatsThis(self.trUtf8(
            """<b>Exceptions Filter</b>"""
            """<p>Configure the exceptions filter. Only exception types that are"""
            """ listed are highlighted during a debugging session.</p>"""
            """<p>Please note, that all unhandled exceptions are highlighted"""
            """ indepent from the filter list.</p>"""
        ))
        self.excFilterAct.connectIt(SIGNAL('activated()'), self.handleExceptionsFilter)
        self.actions.append(self.excFilterAct)

        self.dbgSetBpActGrp = E3ActionGroup(self)

        act = E3Action(self.trUtf8('Toggle Breakpoint'),
                QIconSet(UI.PixmapCache.getPixmap("breakpointToggle.png")),
                self.trUtf8('Toggle Breakpoint'), Qt.Key_F11, 0,
                self.dbgSetBpActGrp, 'dbg_toggle_breakpoint')
        act.setStatusTip(self.trUtf8('Toggle Breakpoint'))
        act.setWhatsThis(self.trUtf8(
            """<b>Toggle Breakpoint</b>"""
            """<p>Toggles a breakpoint at the current line of the"""
            """ current editor.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'), self.handleToggleBreakpoint)
        self.actions.append(act)
        
        self.dbgEditBpAct = E3Action(self.trUtf8('Edit Breakpoint'),
                QIconSet(UI.PixmapCache.getPixmap("cBreakpointToggle.png")),
                self.trUtf8('Edit Breakpoint...'), Qt.Key_F12, 0,
                self.dbgSetBpActGrp, 'dbg_edit_breakpoint')
        self.dbgEditBpAct.setStatusTip(self.trUtf8('Edit Breakpoint'))
        self.dbgEditBpAct.setWhatsThis(self.trUtf8(
            """<b>Edit Breakpoint</b>"""
            """<p>Opens a dialog to edit the breakpoints properties."""
            """ It works at the current line of the current editor.</p>"""
        ))
        self.dbgEditBpAct.connectIt(SIGNAL('activated()'), self.handleEditBreakpoint)
        self.actions.append(self.dbgEditBpAct)

        self.dbgNextBpAct = E3Action(self.trUtf8('Next Breakpoint'),
                QIconSet(UI.PixmapCache.getPixmap("breakpointNext.png")),
                self.trUtf8('Next Breakpoint'),
                QKeySequence(self.trUtf8("CTRL+Shift+PgDown","Debug|Next Breakpoint")), 0,
                self.dbgSetBpActGrp, 'dbg_next_breakpoint')
        self.dbgNextBpAct.setStatusTip(self.trUtf8('Next Breakpoint'))
        self.dbgNextBpAct.setWhatsThis(self.trUtf8(
            """<b>Next Breakpoint</b>"""
            """<p>Go to next breakpoint of the current editor.</p>"""
        ))
        self.dbgNextBpAct.connectIt(SIGNAL('activated()'), self.handleNextBreakpoint)
        self.actions.append(self.dbgNextBpAct)

        self.dbgPrevBpAct = E3Action(self.trUtf8('Previous Breakpoint'),
                QIconSet(UI.PixmapCache.getPixmap("breakpointPrevious.png")),
                self.trUtf8('Previous Breakpoint'),
                QKeySequence(self.trUtf8("CTRL+Shift+PgUp","Debug|Previous Breakpoint")), 0,
                self.dbgSetBpActGrp, 'dbg_previous_breakpoint')
        self.dbgPrevBpAct.setStatusTip(self.trUtf8('Previous Breakpoint'))
        self.dbgPrevBpAct.setWhatsThis(self.trUtf8(
            """<b>Previous Breakpoint</b>"""
            """<p>Go to previous breakpoint of the current editor.</p>"""
        ))
        self.dbgPrevBpAct.connectIt(SIGNAL('activated()'), self.handlePreviousBreakpoint)
        self.actions.append(self.dbgPrevBpAct)

        act = E3Action(self.trUtf8('Clear Breakpoints'),
                self.trUtf8('Clear Breakpoints'),
                QKeySequence(self.trUtf8("CTRL+Shift+C","Debug|Clear Breakpoints")), 0,
                self.dbgSetBpActGrp, 'dbg_clear_breakpoint')
        act.setStatusTip(self.trUtf8('Clear Breakpoints'))
        act.setWhatsThis(self.trUtf8(
            """<b>Clear Breakpoints</b>"""
            """<p>Clear breakpoints of all editors.</p>"""
        ))
        act.connectIt(SIGNAL('activated()'), self.handleClearBreakpoints)
        self.actions.append(act)

        self.debugActGrp.setEnabled(0)
        self.debugActGrp2.setEnabled(0)
        self.dbgSetBpActGrp.setEnabled(0)
        self.runAct.setEnabled(0)
        self.runProjectAct.setEnabled(0)
        self.profileAct.setEnabled(0)
        self.profileProjectAct.setEnabled(0)
        self.coverageAct.setEnabled(0)
        self.coverageProjectAct.setEnabled(0)
        self.cyclopsAct.setEnabled(0)
        self.cyclopsProjectAct.setEnabled(0)
        self.debugAct.setEnabled(0)
        self.debugProjectAct.setEnabled(0)
        self.restartAct.setEnabled(0)
        
    def initMenu(self):
        """
        Public slot to initialize the project menu.
        
        @return the generated menu
        """
        menu = QPopupMenu(self.parent())
        self.breakpointsMenu = QPopupMenu(menu)
        
        menu.insertTearOffHandle()
        self.restartAct.addTo(menu)
        menu.insertSeparator()
        self.runAct.addTo(menu)
        self.runProjectAct.addTo(menu)
        menu.insertSeparator()
        self.profileAct.addTo(menu)
        self.profileProjectAct.addTo(menu)
        menu.insertSeparator()
        self.coverageAct.addTo(menu)
        self.coverageProjectAct.addTo(menu)
        menu.insertSeparator()
        self.cyclopsAct.addTo(menu)
        self.cyclopsProjectAct.addTo(menu)
        menu.insertSeparator()
        self.debugAct.addTo(menu)
        self.debugProjectAct.addTo(menu)
        self.debugActGrp.addTo(menu)
        menu.insertSeparator()
        self.debugActGrp2.addTo(menu)
        menu.insertSeparator()
        self.dbgSetBpActGrp.addTo(menu)
        menu.insertItem(self.trUtf8('&Breakpoints'), self.breakpointsMenu)
        self.connect(self.breakpointsMenu,SIGNAL('aboutToShow()'),self.handleShowBreakpointsMenu)
        self.connect(self.breakpointsMenu,SIGNAL('activated(int)'),self.handleBreakpointSelected)
        menu.insertSeparator()
        self.dbgFilterAct.addTo(menu)
        self.excFilterAct.addTo(menu)
        
        return menu
        
    def initToolbar(self):
        """
        Public slot to initialize the project toolbar.
        
        @return the generated toolbar
        """
        tb = QToolBar(self.parent())
        self.restartAct.addTo(tb)
        tb.addSeparator()
        self.runAct.addTo(tb)
        self.runProjectAct.addTo(tb)
        tb.addSeparator()
        self.profileAct.addTo(tb)
        self.profileProjectAct.addTo(tb)
        tb.addSeparator()
        self.coverageAct.addTo(tb)
        self.coverageProjectAct.addTo(tb)
        tb.addSeparator()
        self.cyclopsAct.addTo(tb)
        self.cyclopsProjectAct.addTo(tb)
        tb.addSeparator()
        self.debugAct.addTo(tb)
        self.debugProjectAct.addTo(tb)
        self.debugActGrp.addTo(tb)
        tb.addSeparator()
        self.dbgSetBpActGrp.addTo(tb)
        
        return tb
        
    def setArgvHistory(self, argsStr):
        """
        Public slot to initialize the argv History used for debugging.
        
        @param argsStr the commandline argumnets (string or QString)
        """
        self.argvHistory.remove(argsStr)
        self.argvHistory.prepend(argsStr)

    def setWdHistory(self, wdStr):
        """
        Public slot to initialize the wd History used for debugging.
        
        @param wdStr the working directory (string or QString)
        """
        self.wdHistory.remove(wdStr)
        self.wdHistory.prepend(wdStr)
        
    def setEnvHistory(self, envStr):
        """
        Public slot to initialize the env History used for debugging.
        
        @param envStr the environment settings (string or QString)
        """
        self.envHistory.remove(envStr)
        self.envHistory.prepend(envStr)
        
    def setExceptionReporting(self, exceptions):
        """
        Public slot to initialize the exception reporting flag.
        
        @param exceptions flag indicating exception reporting status (boolean)
        """
        self.exceptions = exceptions

    def setExcList(self, excList):
        """
        Public slot to initialize the exceptions type list.
        
        @param excList list of exception types (list of strings)
        """
        self.excList = excList
        
    def setTracePython(self, tracePython):
        """
        Public slot to initialize the trace Python flag.
        
        @param tracePython flag indicating if the Python library should be
            traced as well (boolean)
        """
        self.dbgTracePython = tracePython

    def setCovexcHistory(self, covexcStr):
        """
        Public slot to initialize the coverage exclusion pattern History.
        
        @param covexcStr the environment settings (string or QString)
        """
        self.covexcHistory.remove(covexcStr)
        self.covexcHistory.prepend(covexcStr)
        
    def handleEditorOpened(self, fn):
        """
        Private slot to handle the editorOpened signal.
        
        @param fn filename of the opened editor
        """
        self.editorOpen = 1
        
        if fn:
            editor = self.viewmanager.getOpenEditor(fn)
        else:
            editor = None
        self.checkActions(editor)
        
    def handleLastEditorClosed(self):
        """
        Private slot to handle the closeProgram signal.
        """
        self.editorOpen = 0
        self.debugAct.setEnabled(0)
        self.runAct.setEnabled(0)
        self.profileAct.setEnabled(0)
        self.coverageAct.setEnabled(0)
        self.cyclopsAct.setEnabled(0)
        self.debugActGrp.setEnabled(0)
        self.debugActGrp2.setEnabled(0)
        self.dbgSetBpActGrp.setEnabled(0)
        self.lastAction = -1
        if not self.projectOpen:
            self.restartAct.setEnabled(0)
            self.lastDebuggedFile = None
            self.lastStartAction = 0
        
    def checkActions(self, editor):
        """
        Private slot to check some actions for their enable/disable status.
        
        @param editor editor window
        """
        if editor:
            fn = editor.getFileName()
        else:
            fn = None
            
        if fn and ((os.path.splitext(fn)[1] in ['.py', '.rb']) or editor.isPyFile()):
            ext = os.path.splitext(fn)[1]
            if ext == '.py' or editor.isPyFile():
                cap = self.dbs.getClientCapabilities('Python')
            elif ext == '.rb':
                cap = self.dbs.getClientCapabilities('Ruby')
            else:
                cap = 0
                
            if not self.passive:
                self.runAct.setEnabled(cap & HasInterpreter)
                self.coverageAct.setEnabled(cap & HasCoverage)
                self.cyclopsAct.setEnabled(cap & HasCyclesFinder)
                self.profileAct.setEnabled(cap & HasProfiler)
                self.debugAct.setEnabled(cap & HasDebugger)
            self.dbgSetBpActGrp.setEnabled(cap & HasDebugger)
            if editor.curLineHasBreakpoint():
                self.dbgEditBpAct.setEnabled(1)
            else:
                self.dbgEditBpAct.setEnabled(0)
            if editor.hasBreakpoints():
                self.dbgNextBpAct.setEnabled(1)
                self.dbgPrevBpAct.setEnabled(1)
            else:
                self.dbgNextBpAct.setEnabled(0)
                self.dbgPrevBpAct.setEnabled(0)
        else:
            self.runAct.setEnabled(0)
            self.coverageAct.setEnabled(0)
            self.cyclopsAct.setEnabled(0)
            self.profileAct.setEnabled(0)
            self.debugAct.setEnabled(0)
            self.dbgSetBpActGrp.setEnabled(0)
        
    def handleCursorChanged(self, editor):
        """
        Private slot handling the cursorChanged signal of the viewmanager.
        
        @param editor editor window
        """
        if editor is None:
            return
            
        fn = editor.getFileName()
            
        if fn and fn.endswith('.py'):
            if editor.curLineHasBreakpoint():
                self.dbgEditBpAct.setEnabled(1)
            else:
                self.dbgEditBpAct.setEnabled(0)
            if editor.hasBreakpoints():
                self.dbgNextBpAct.setEnabled(1)
                self.dbgPrevBpAct.setEnabled(1)
            else:
                self.dbgNextBpAct.setEnabled(0)
                self.dbgPrevBpAct.setEnabled(0)
        
    def handleProjectOpened(self):
        """
        Private slot to handle the projectOpened signal.
        """
        self.projectOpen = 1
        cap = self.dbs.getClientCapabilities(self.project.pdata["PROGLANGUAGE"][0])
        if not self.passive:
            self.debugProjectAct.setEnabled(cap & HasDebugger)
            self.runProjectAct.setEnabled(cap & HasInterpreter)
            self.profileProjectAct.setEnabled(cap & HasProfiler)
            self.coverageProjectAct.setEnabled(cap & HasCoverage)
            self.cyclopsProjectAct.setEnabled(cap & HasCyclesFinder)
        
    def handleProjectClosed(self):
        """
        Private slot to handle the projectClosed signal.
        """
        self.projectOpen = 0
        self.runProjectAct.setEnabled(0)
        self.profileProjectAct.setEnabled(0)
        self.coverageProjectAct.setEnabled(0)
        self.cyclopsProjectAct.setEnabled(0)
        self.debugProjectAct.setEnabled(0)
        
        if not self.editorOpen:
            self.restartAct.setEnabled(0)
            self.lastDebuggedFile = None
            self.lastStartAction = 0
        
    def handleProjectSessionLoaded(self):
        """
        Private slot to handle the projectSessionLoaded signal.
        """
        fn = self.ui.getProject().getMainScript(1)
        if fn is not None:
            self.lastStartAction = 2
            self.lastDebuggedFile = fn
            self.restartAct.setEnabled(1)
        
    def shutdownServer(self):
        """
        Public method to shutdown the debug server.
        
        This is needed to cleanly close the sockets on Win OS.
        
        @return always true
        """
        self.dbs.shutdownServer()
        return 1
        
    def resetUI(self):
        """
        Private slot to reset the user interface.
        """
        self.debugActGrp.setEnabled(0)
        self.debugActGrp2.setEnabled(0)
        if not self.passive:
            if self.editorOpen:
                editor = self.viewmanager.activeWindow()
            else:
                editor = None
            self.checkActions(editor)
            
            self.debugProjectAct.setEnabled(self.projectOpen)
            self.runProjectAct.setEnabled(self.projectOpen)
            self.profileProjectAct.setEnabled(self.projectOpen)
            self.coverageProjectAct.setEnabled(self.projectOpen)
            self.cyclopsProjectAct.setEnabled(self.projectOpen)
            if self.lastDebuggedFile is not None and \
                (self.editorOpen or self.projectOpen):
                self.restartAct.setEnabled(1)
            else:
                self.restartAct.setEnabled(0)
        self.emit(PYSIGNAL('resetUI'), ())
        
    def handleLineChange(self,fn,line):
        """
        Private method to handle a change to the current line.
        
        @param fn filename (string)
        @param line linenumber (int)
        """
        self.ui.raiseW()
        self.ui.setActiveWindow()
        if self.ui.getViewProfile() != "debug":
            self.ui.handleSetDebugProfile()
        self.viewmanager.setFileLine(fn,line)
        self.getClientVariables()

    def handleExit(self,status):
        """
        Private method to handle the debugged program terminating.
        
        @param tatus exit code of the debugged program (int)
        """
        self.viewmanager.handleExit()

        self.resetUI()

        if self.ui.currentProg is None:
            KQMessageBox.information(self.ui,Program,
                self.trUtf8('<p>The program has terminated with an exit status of %1.</p>')
                    .arg(status))
        else:
            KQMessageBox.information(self.ui,Program,
                self.trUtf8('<p><b>%1</b> has terminated with an exit status of %2.</p>')
                    .arg(Utilities.normabspath(self.ui.currentProg))
                    .arg(status))

    def handleSyntaxError(self,status):
        """
        Private method to handle a syntax error in the debugged program.
        
        @param status information about the syntax error
        """
        self.resetUI()
        self.ui.raiseW()
        self.ui.setActiveWindow()
        
        try:
            message, (fn, ln, cn) = eval(status)
            if fn is None:
                fn = ''
        except:
            KQMessageBox.critical(self.ui,Program,
                self.trUtf8('The program being debugged contains an unspecified syntax error.'))
            return
            
        self.viewmanager.setFileLine(fn,ln,1,1)
        KQMessageBox.critical(self.ui,Program,
            self.trUtf8('<p>The file <b>%1</b> contains the syntax error <b>%2</b> at line <b>%3</b>.</p>')
                .arg(fn)
                .arg(message)
                .arg(ln))
        
    def handleException(self,status):
        """
        Private method to handle an exception of the debugged program.
        
        @param status exception information
        """
        self.ui.raiseW()
        self.ui.setActiveWindow()
        qApp.processEvents()
        try:
            exclist = eval(status)
        except:
            KQMessageBox.critical(self.ui,Program,
                self.trUtf8('An unhandled exception occured. See the shell window for details.'))
            return
            
        try:
            exctype, msg, (fn, ln) = exclist[:3]
            noInfo = 0
        except ValueError:
            exctype, msg = exclist[:2]
            noInfo = 1
        if (self.exceptions and \
            (not len(self.excList) or \
             (len(self.excList) and str(exctype) in self.excList)))\
           or exctype.startswith('unhandled'):
            if noInfo:
                res = KQMessageBox.critical(self.ui,Program,
                    self.trUtf8('<p>The debugged program raised the exception <b>%1</b><br>"<b>%2</b>"</p>')
                        .arg(str(exctype))
                        .arg(Utilities.html_encode(msg)),
                    self.trUtf8('Continue'))
            else:
                self.viewmanager.setFileLine(fn,ln,1)
                res = KQMessageBox.critical(self.ui,Program,
                    self.trUtf8('<p>The debugged program raised the exception <b>%1</b>'
                                '<br>"<b>%2</b>"<br>File: <b>%3</b>, Line: <b>%4</b></p>')
                        .arg(str(exctype))
                        .arg(Utilities.html_encode(msg))
                        .arg(fn)
                        .arg(ln),
                    self.trUtf8('Continue'), self.trUtf8('Break'))
            if res == 1:
                stack = []
                for fn, ln in exclist[2:]:
                    stack.append((fn, ln, ''))
                self.emit(PYSIGNAL('clientStack'),(stack,))
                self.getClientVariables()
                self.ui.handleSetDebugProfile()
                return
            
        if self.lastAction != -1:
            if self.lastAction == 2:
                self.handleSpecialContinue()
            else:
                self.debugActions[self.lastAction]()
        
    def handleClientGone(self,unplanned):
        """
        Private method to handle the disconnection of the debugger client.
        
        @param unplanned 1 if the client died, 0 otherwise
        """
        self.resetUI()
        if unplanned:
            KQMessageBox.information(self.ui,Program,
                self.trUtf8('The program being debugged has terminated unexpectedly.'))

    def getClientVariables(self):
        """
        Private method to request the global and local variables.
        
        In the first step, the global variables are requested from the client.
        Once these have been received, the local variables are requested.
        This happens in the method 'handleClientVariables'.
        """
        # get globals first
        self.dbs.remoteClientVariables(1, self.globalsVarFilter)
        # the local variables are requested once we have received the globals
        
    def handleClientVariables(self, vars):
        """
        Private method to write the clients variables to the user interface.
        
        @param vars the list of variables from the client
        """
        vlist = eval(vars)
        scope = vlist[0]
        try:
            vlist = vlist[1:]
        except:
            vlist = []
            
        if scope > 0:
            self.sbv.showVariables(vlist, 1)
            if scope == 1:
                # now get the local variables
                self.dbs.remoteClientVariables(0, self.localsVarFilter)
        elif scope == 0:
            self.sbv.showVariables(vlist, 0)
        elif scope == -1:
            vlist = [('None','','')]
            self.sbv.showVariables(vlist, 0)
            
        if scope < 1:
            self.debugActGrp.setEnabled(1)
            self.debugActGrp2.setEnabled(1)
            
    def handleClientVariable(self, vars):
        """
        Private method to write the contents of a clients classvariable to the user interface.
        
        @param vars the list of members of a classvariable from the client
        """
        vlist = eval(vars)
        scope = vlist[0]
        try:
            vlist = vlist[1:]
        except:
            vlist = []
            
        if scope == 1:
            self.sbv.showVariable(vlist, 1)
        elif scope == 0:
            self.sbv.showVariable(vlist, 0)
            
    def handleClientClearBreak(self, filename, lineno):
        """
        Private method to clear a temporary breakpoint.
        
        @param filename filename of the breakpoint
        @param lineno linenumber of the breakpoint
        """
        editor = self.viewmanager.getOpenEditor(filename)
        if editor is not None:
            editor.clearBreakpoint(lineno)
        
    def handleConfigFilters(self):
        """
        Private slot for displaying the variables filter configuration dialog.
        """
        result = self.dbgFilterDialog.exec_loop()
        if result == QDialog.Accepted:
            (self.localsVarFilter, self.globalsVarFilter) = \
                self.dbgFilterDialog.getSelection()
        else:
            self.dbgFilterDialog.setSelection(
                self.localsVarFilter, self.globalsVarFilter)
        self.sbv.setVariablesFilter(self.globalsVarFilter, self.localsVarFilter)

    def handleExceptionsFilter(self):
        """
        Private slot for displaying the exception filter dialog.
        """
        dlg = ExceptionsFilterDialog(self.excList)
        if dlg.exec_loop() == QDialog.Accepted:
            self.excList = dlg.getExceptionsList()
        
    def handleToggleBreakpoint(self):
        """
        Private slot to handle the 'Set/Reset breakpoint' action.
        """
        editor = self.viewmanager.activeWindow().handleToggleBreakpoint()
        
    def handleEditBreakpoint(self):
        """
        Private slot to handle the 'Edit breakpoint' action.
        """
        editor = self.viewmanager.activeWindow().handleEditBreakpoint()
        
    def handleNextBreakpoint(self):
        """
        Private slot to handle the 'Next breakpoint' action.
        """
        self.viewmanager.activeWindow().handleNextBreakpoint()
        
    def handlePreviousBreakpoint(self):
        """
        Private slot to handle the 'Previous breakpoint' action.
        """
        self.viewmanager.activeWindow().handlePreviousBreakpoint()
        
    def handleClearBreakpoints(self):
        """
        Private slot to handle the 'Clear breakpoints' action.
        """
        for editor in self.viewmanager.editors:
            editor.handleClearBreakpoints()
        
    def handleShowBreakpointsMenu(self):
        """
        Private method to handle the show breakpoints menu signal.
        """
        self.breakpoints = {}
        self.breakpointsMenu.clear()
        
        filenames = self.viewmanager.getOpenFilenames()
        filenames.sort()
        for filename in filenames:
            editor = self.viewmanager.getOpenEditor(filename)
            for line, cond, _, _, _ in editor.getBreakpoints():
                if len(filename) > 40:
                    dots = "..."
                else:
                    dots = ""
                if cond is None:
                    formattedCond = ""
                else:
                    formattedCond = " : %s" % str(cond)[:20]
                id = self.breakpointsMenu.insertItem(\
                        "%s%s : %d%s" % \
                        (dots, filename[-40:], line, formattedCond))
                self.breakpoints[id] = (filename, line)
    
    def handleBreakpointSelected(self, id):
        """
        Private method to handle the breakpoint selected signal.
        
        @param id index of the selected menu entry
                This acts as an index into the list of breakpoints
                that was created, when the breakpoints menu was built.
        """
        self.viewmanager.displayPythonFile(\
            self.breakpoints[id][0], self.breakpoints[id][1])
        
    def handleGotoBreakpoint(self, filename, lineno):
        """
        Public method to show the source related to a breakpoint.
        
        @param filename name of the related file (string or QString)
        @param line number of the breakpoint (integer)
        """
        self.viewmanager.displayPythonFile(unicode(filename), lineno)
        
    def compileChangedProjectForms(self):
        """
        Private method to signal compilation of changed forms is wanted.
        """
        if Preferences.getProject("AutoCompileForms"):
            self.emit(PYSIGNAL('compileForms'),())
        qApp.processEvents()
        
    def handleCoverageScript(self):
        """
        Private slot to handle the coverage of script action.
        """
        self.handleCoverage(0)
        
    def handleCoverageProject(self):
        """
        Private slot to handle the coverage of project action.
        """
        self.compileChangedProjectForms()
        self.handleCoverage(1)
        
    def handleCoverage(self, runProject):
        """
        Private method to handle the coverage actions.
        
        @param runProject flag indicating coverage of the current project (1)
                or script (0)
        """
        self.resetUI()
        
        # Get the command line arguments, the working directory and the
        # exception reporting flag.
        if runProject:
            cap = self.trUtf8("Coverage of Project")
        else:
            cap = self.trUtf8("Coverage of Script")
        dlg = StartDialog(cap, self.argvHistory, self.wdHistory, self.envHistory,
            self.exceptions, self.ui, 2, covexcList = self.covexcHistory)
        if dlg.exec_loop() == QDialog.Accepted:
            argv, wd, env, exceptions = dlg.getData()
            eraseCoverage, covexcPattern = dlg.getCoverageData()
            
            if runProject:
                project = self.ui.getProject()
                fn = project.getMainScript(1)
                if fn is None:
                    KQMessageBox.critical(self.ui,
                        self.trUtf8("Coverage of Project"),
                        self.trUtf8("There is no main script defined for the"
                            " current project. Aborting"),
                        self.trUtf8("&OK"))
                    return
                    
                if not project.saveAllScripts():
                    return
                    
                # save the info for later use
                project.setDbgInfo(argv, wd, env, exceptions, self.excList, 
                                   covexcPattern=covexcPattern)
                
                self.lastStartAction = 6
            else:
                editor = self.viewmanager.activeWindow()
                if editor is None:
                    return
                
                if not self.viewmanager.checkDirty(editor) or \
                    editor.getFileName() is None:
                    return
                    
                fn = editor.getFileName()
                self.lastStartAction = 5
                
            # save the filename for use by the restart method
            self.lastDebuggedFile = fn
            self.restartAct.setEnabled(1)
            
            # This moves any previous occurence of these arguments to the head
            # of the list.
            self.argvHistory.remove(argv)
            self.argvHistory.prepend(argv)
            self.wdHistory.remove(wd)
            self.wdHistory.prepend(wd)
            self.envHistory.remove(env)
            self.envHistory.prepend(env)
            self.covexcHistory.remove(covexcPattern)
            self.covexcHistory.prepend(covexcPattern)
            
            # Save the exception flags
            self.exceptions = exceptions
            
            # Save the erase coverage flag
            self.eraseCoverage = eraseCoverage
            
            # Hide all error highlights
            self.viewmanager.unhighlight()
            
            # Ask the client to open the new program.
            self.dbs.remoteCoverage(fn,argv,wd,env,eraseCoverage,covexcPattern,
                forProject=runProject)
            
    def handleProfileScript(self):
        """
        Private slot to handle the profile script action.
        """
        self.handleProfile(0)
        
    def handleProfileProject(self):
        """
        Private slot to handle the profile project action.
        """
        self.compileChangedProjectForms()
        self.handleProfile(1)
        
    def handleProfile(self, runProject):
        """
        Private method to handle the profile actions.
        
        @param runProject flag indicating profiling of the current project (1)
                or script (0)
        """
        self.resetUI()
        
        # Get the command line arguments, the working directory and the
        # exception reporting flag.
        if runProject:
            cap = self.trUtf8("Profile of Project")
        else:
            cap = self.trUtf8("Profile of Script")
        dlg = StartDialog(cap, self.argvHistory, self.wdHistory, self.envHistory,
            self.exceptions, self.ui, 3)
        if dlg.exec_loop() == QDialog.Accepted:
            argv, wd, env, exceptions = dlg.getData()
            eraseTimings = dlg.getProfilingData()
            
            if runProject:
                project = self.ui.getProject()
                fn = project.getMainScript(1)
                if fn is None:
                    KQMessageBox.critical(self.ui,
                        self.trUtf8("Profile of Project"),
                        self.trUtf8("There is no main script defined for the"
                            " current project. Aborting"),
                        self.trUtf8("&OK"))
                    return
                    
                if not project.saveAllScripts():
                    return
                    
                # save the info for later use
                project.setDbgInfo(argv, wd, env, exceptions, self.excList)
                
                self.lastStartAction = 8
            else:
                editor = self.viewmanager.activeWindow()
                if editor is None:
                    return
                
                if not self.viewmanager.checkDirty(editor) or \
                    editor.getFileName() is None:
                    return
                    
                fn = editor.getFileName()
                self.lastStartAction = 7
                
            # save the filename for use by the restart method
            self.lastDebuggedFile = fn
            self.restartAct.setEnabled(1)
            
            # This moves any previous occurence of these arguments to the head
            # of the list.
            self.argvHistory.remove(argv)
            self.argvHistory.prepend(argv)
            self.wdHistory.remove(wd)
            self.wdHistory.prepend(wd)
            self.envHistory.remove(env)
            self.envHistory.prepend(env)
            
            # Save the exception flags
            self.exceptions = exceptions
            
            # Save the erase timing flag
            self.eraseTimings = eraseTimings
            
            # Hide all error highlights
            self.viewmanager.unhighlight()
            
            # Ask the client to open the new program.
            self.dbs.remoteProfile(fn,argv,wd,env,eraseTimings,forProject=runProject)
            
    def handleCyclopsScript(self):
        """
        Private slot to handle the cyclops script action.
        """
        self.handleCyclops(0)
        
    def handleCyclopsProject(self):
        """
        Private slot to handle the cyclops project action.
        """
        self.compileChangedProjectForms()
        self.handleCyclops(1)
        
    def handleCyclops(self, runProject):
        """
        Private method to handle the cyclops actions.
        
        @param runProject flag indicating cyclops of the current project (1)
                or script (0)
        """
        # Get the command line arguments, the working directory and the
        # exception reporting flag.
        if runProject:
            cap = self.trUtf8("Cyclops of Project")
        else:
            cap = self.trUtf8("Cyclops of Script")
        dlg = StartDialog(cap, self.argvHistory, self.wdHistory, self.envHistory, 
            self.exceptions, self.ui, 4, self.mfHistory)
        if dlg.exec_loop() == QDialog.Accepted:
            argv, wd, env, exceptions = dlg.getData()
            modfunc, reports = dlg.getCyclopsData()
            
            if runProject:
                project = self.ui.getProject()
                fn = project.getMainScript(1)
                if fn is None:
                    KQMessageBox.critical(self.ui,
                        self.trUtf8("Cyclops of Project"),
                        self.trUtf8("There is no main script defined for the"
                            " current project. Aborting"),
                        self.trUtf8("&OK"))
                    return
                    
                if not project.saveAllScripts():
                    return
                    
                # save the info for later use
                project.setDbgInfo(argv, wd, env, exceptions, self.excList)
                
                self.lastStartAction = 10
            else:
                editor = self.viewmanager.activeWindow()
                if editor is None:
                    return
                
                if not self.viewmanager.checkDirty(editor) or \
                    editor.getFileName() is None:
                    return
                    
                fn = editor.getFileName()
                self.lastStartAction = 9
                
            # save the filename for use by the restart method
            self.lastDebuggedFile = fn
            self.restartAct.setEnabled(1)
            
            # This moves any previous occurence of these arguments to the head
            # of the list.
            self.argvHistory.remove(argv)
            self.argvHistory.prepend(argv)
            self.wdHistory.remove(wd)
            self.wdHistory.prepend(wd)
            self.envHistory.remove(env)
            self.envHistory.prepend(env)
            self.mfHistory.remove(modfunc)
            self.mfHistory.prepend(modfunc)
            
            # Save the exception flags
            self.exceptions = exceptions
            
            # Save the additional cyclops data
            self.cyclopsModfunc = modfunc
            self.cyclopsReports = reports
            
            # Hide all error highlights
            self.viewmanager.unhighlight()
            
            # Ask the client to open the new program.
            self.dbs.remoteCyclops(fn,argv,wd,env,modfunc,reports,forProject=runProject)
            
    def handleCyclopsError(self, fn, modfunc):
        """
        Private slot to handle a cyclops error.
        
        @param fn filename of the file to be run through Cyclops (string)
        @param modfunc function name of the entry point (string)
        """
        KQMessageBox.critical(None,
            self.trUtf8("Cyclops Error"),
            self.trUtf8("""<p>To use Cyclops on a module, the module must define"""
                """ a function which serves as the entrypoint for Cyclops."""
                """ The module <b>%1</b> does not define the function <b>%2</b>.</p>""")
                .arg(fn).arg(modfunc),
            self.trUtf8("&OK"),
            QString.null,
            QString.null,
            0, -1)

    def handleRunScript(self):
        """
        Private slot to handle the run script action.
        """
        self.handleRun(0)
        
    def handleRunProject(self):
        """
        Private slot to handle the run project action.
        """
        self.compileChangedProjectForms()
        self.handleRun(1)
        
    def handleRun(self, runProject):
        """
        Private method to handle the run actions.
        
        @param unProject flag indicating running the current project (1)
                or script (0)
        """
        self.resetUI()
        
        # Get the command line arguments, the working directory and the
        # exception reporting flag.
        if runProject:
            cap = self.trUtf8("Run Project")
        else:
            cap = self.trUtf8("Run Script")
        dlg = StartDialog(cap, self.argvHistory, self.wdHistory, self.envHistory, 
            self.exceptions, self.ui, 1)
        if dlg.exec_loop() == QDialog.Accepted:
            argv, wd, env, exceptions = dlg.getData()
            
            if runProject:
                project = self.ui.getProject()
                fn = project.getMainScript(1)
                if fn is None:
                    KQMessageBox.critical(self.ui,
                        self.trUtf8("Run Project"),
                        self.trUtf8("There is no main script defined for the"
                            " current project. Aborting"),
                        self.trUtf8("&OK"))
                    return
                    
                if not project.saveAllScripts():
                    return
                    
                # save the info for later use
                project.setDbgInfo(argv, wd, env, exceptions, self.excList)
                
                self.lastStartAction = 4
            else:
                editor = self.viewmanager.activeWindow()
                if editor is None:
                    return
                
                if not self.viewmanager.checkDirty(editor) or \
                    editor.getFileName() is None:
                    return
                    
                fn = editor.getFileName()
                self.lastStartAction = 3
                
            # save the filename for use by the restart method
            self.lastDebuggedFile = fn
            self.restartAct.setEnabled(1)
            
            # This moves any previous occurence of these arguments to the head
            # of the list.
            self.argvHistory.remove(argv)
            self.argvHistory.prepend(argv)
            self.wdHistory.remove(wd)
            self.wdHistory.prepend(wd)
            self.envHistory.remove(env)
            self.envHistory.prepend(env)
            
            # Save the exception flags
            self.exceptions = exceptions
            
            # Hide all error highlights
            self.viewmanager.unhighlight()
            
            # Ask the client to open the new program.
            self.dbs.remoteRun(fn,argv,wd,env,forProject=runProject)
            
    def handleDebugScript(self):
        """
        Private slot to handle the debug script action.
        """
        self.handleDebug(0)
        
    def handleDebugProject(self):
        """
        Private slot to handle the debug project action.
        """
        self.compileChangedProjectForms()
        self.handleDebug(1)
        
    def handleDebug(self, debugProject):
        """
        Private method to handle the debug actions.
        
        @param debugProject flag indicating debugging the current project (1)
                or script (0)
        """
        self.resetUI()
        
        # Get the command line arguments, the working directory and the
        # exception reporting flag.
        if debugProject:
            cap = self.trUtf8("Debug Project")
        else:
            cap = self.trUtf8("Debug Script")
        dlg = StartDialog(cap, self.argvHistory, self.wdHistory, self.envHistory, 
            self.exceptions, self.ui, 0, tracePython = self.tracePython)
        if dlg.exec_loop() == QDialog.Accepted:
            argv, wd, env, exceptions = dlg.getData()
            tracePython = dlg.getDebugData()
            
            if debugProject:
                project = self.ui.getProject()
                fn = project.getMainScript(1)
                if fn is None:
                    KQMessageBox.critical(self.ui,
                        self.trUtf8("Debug Project"),
                        self.trUtf8("There is no main script defined for the"
                            " current project. No debugging possible."),
                        self.trUtf8("&OK"))
                    return
                    
                if not project.saveAllScripts():
                    return
                    
                # save the info for later use
                project.setDbgInfo(argv, wd, env, exceptions, self.excList,
                    tracePython = tracePython)
                
                self.lastStartAction = 2
            else:
                editor = self.viewmanager.activeWindow()
                if editor is None:
                    return
                
                if not self.viewmanager.checkDirty(editor) or \
                    editor.getFileName() is None:
                    return
                    
                fn = editor.getFileName()
                self.lastStartAction = 1
                
            # save the filename for use by the restart method
            self.lastDebuggedFile = fn
            self.restartAct.setEnabled(1)
            
            # This moves any previous occurence of these arguments to the head
            # of the list.
            self.argvHistory.remove(argv)
            self.argvHistory.prepend(argv)
            self.wdHistory.remove(wd)
            self.wdHistory.prepend(wd)
            self.envHistory.remove(env)
            self.envHistory.prepend(env)
            
            # Save the exception flags
            self.exceptions = exceptions
            
            # Save the tracePython flag
            self.tracePython = tracePython
            
            # Hide all error highlights
            self.viewmanager.unhighlight()
            
            # Show the local variables viewer, hide the others
            self.sbv.showVariablesTab(0) # locals viewer on top
            if wd.isEmpty():
                self.sbv.setWD(os.path.dirname(os.path.abspath(unicode(fn))))
            else:
                self.sbv.setWD(unicode(wd))
            
            # Ask the client to open the new program.
            self.dbs.remoteLoad(fn,argv,wd,env,tracePython,forProject=debugProject)
            
            # Signal that we have started a debugging session
            self.emit(PYSIGNAL('debuggingStarted'), (fn,))
            
    def handleRestart(self):
        """
        Private slot to handle the restart action to restart the last debugged file.
        """
        self.resetUI()
        
        # first save any changes
        if self.lastStartAction in [1, 3, 5, 7, 9]:
            editor = self.viewmanager.getOpenEditor(self.lastDebuggedFile)
            if editor and not self.viewmanager.checkDirty(editor):
                return
            forProject = 0
        elif self.lastStartAction in [2, 4, 6, 8, 10]:
            project = self.ui.getProject()
            if not project.saveAllScripts():
                return
            self.compileChangedProjectForms()
            forProject = 1
        else:
            return      # should not happen
                    
        # get the saved stuff
        wd = self.wdHistory[0]
        argv = self.argvHistory[0]
        fn = self.lastDebuggedFile
        env = self.envHistory[0]
        
        # Hide all error highlights
        self.viewmanager.unhighlight()
        
        if self.lastStartAction in [1, 2]:
            # Show the local variables viewer, hide the others
            self.sbv.showVariablesTab(0) # locals viewer on top
            if wd.isEmpty():
                self.sbv.setWD(os.path.dirname(os.path.abspath(unicode(fn))))
            else:
                self.sbv.setWD(unicode(wd))
            
            # Ask the client to debug the new program.
            self.dbs.remoteLoad(fn,argv,wd,env,self.tracePython,forProject=forProject)
            
            # Signal that we have started a debugging session
            self.emit(PYSIGNAL('debuggingStarted'), (fn,))
        elif self.lastStartAction in [3, 4]:
            # Ask the client to run the new program.
            self.dbs.remoteRun(fn,argv,wd,env,forProject=forProject)
        elif self.lastStartAction in [5, 6]:
            # Ask the client to coverage run the new program.
            self.dbs.remoteCoverage(fn,argv,wd,env,self.eraseCoverage,
                self.covexcHistory[0],forProject=forProject)
        elif self.lastStartAction in [7, 8]:
            # Ask the client to profile run the new program.
            self.dbs.remoteProfile(fn,argv,wd,env,self.eraseTimings,forProject=forProject)
        elif self.lastStartAction in [9, 10]:
            # Ask the client to run the new program through cyclops.
            self.dbs.remoteCyclops(fn,argv,wd,env,
                self.cyclopsModfunc,self.cyclopsReports,forProject=forProject)
        
    def handlePassiveDebugStarted(self, fn, exc):
        """
        Private slot to handle a passive debug session start.
        
        @param fn filename of the debugged script
        @param exc flag to enable exception reporting of the IDE (boolean)
        """
        # Hide all error highlights
        self.viewmanager.unhighlight()
        
        # Show the local variables viewer, hide the others
        self.sbv.showVariablesTab(0) # locals viewer on top
        
        # Set filename of script being debugged
        self.ui.currentProg = fn
        
        # Set exception reporting
        self.setExceptionReporting(exc)
        
        # Signal that we have started a debugging session
        self.emit(PYSIGNAL('debuggingStarted'), (fn,))
        
    def handleContinue(self):
        """
        Private method to handle the Continue action.
        """
        self.lastAction=0
        self.enterRemote()
        self.dbs.remoteContinue()

    def handleSpecialContinue(self):
        """
        Private method to handle the Special Continue action.
        """
        self.lastAction=2
        self.enterRemote()
        self.dbs.remoteContinue(1)

    def handleStep(self):
        """
        Private method to handle the Step action.
        """
        self.lastAction=1
        self.enterRemote()
        self.dbs.remoteStep()

    def handleStepOver(self):
        """
        Private method to handle the Step Over action.
        """
        self.lastAction=2
        self.enterRemote()
        self.dbs.remoteStepOver()

    def handleStepOut(self):
        """
        Private method to handle the Step Out action.
        """
        self.lastAction=3
        self.enterRemote()
        self.dbs.remoteStepOut()

    def handleStepQuit(self):
        """
        Private method to handle the Step Quit action.
        """
        self.lastAction=4
        self.enterRemote()
        self.dbs.remoteStepQuit()
        self.resetUI()

    def handleRunToCursor(self):
        """
        Private method to handle the Run to Cursor action.
        """
        self.lastAction=0
        aw = self.viewmanager.activeWindow()
        line = aw.getCursorPosition()[0] + 1
        self.enterRemote()
        self.dbs.remoteBreakpoint(aw.getFileName(), 
            line, 1, None, 1)
        self.dbs.remoteContinue()
    
    def handleEval(self):
        """
        Private method to handle the Eval action.
        """
        # Get the command line arguments.
        if len(self.evalHistory) > 0:
            curr = 0
        else:
            curr = -1

        arg, ok = KQInputDialog.getItem(
                        self.trUtf8('Evaluate'),
                        self.trUtf8('Enter the statement to evaluate'),
                        self.evalHistory,curr,1,self.ui)

        if ok:
            if arg.isNull():
                return

            # This moves any previous occurence of this expression to the head
            # of the list.
            self.evalHistory.remove(arg)
            self.evalHistory.prepend(arg)
            
            self.dbs.remoteEval(arg)
            
    def handleExec(self):
        """
        Private method to handle the Exec action.
        """
        # Get the command line arguments.
        if len(self.execHistory) > 0:
            curr = 0
        else:
            curr = -1

        stmt, ok = KQInputDialog.getItem(
                        self.trUtf8('Execute'),
                        self.trUtf8('Enter the statement to execute'),
                        self.execHistory,curr,1,self.ui)

        if ok:
            if stmt.isNull():
                return

            # This moves any previous occurence of this statement to the head
            # of the list.
            self.execHistory.remove(stmt)
            self.execHistory.prepend(stmt)
            
            self.dbs.remoteExec(stmt)
            
    def enterRemote(self):
        """
        Private method to update the user interface.

        This method is called just prior to executing some of
        the program being debugged.
        """
        # Disable further debug commands from the user.
        self.debugActGrp.setEnabled(0)
        self.debugActGrp2.setEnabled(0)
        
        self.viewmanager.unhighlight(1)

    def getFileBreakpoints(self, fn):
        """
        Public method to get all file breakpoints.
        
        @param fn filename (string)
        @return list of file breakpoints
        """
        editor = self.viewmanager.getOpenEditor(fn)
        if editor is not None:
            return editor.getBreakpoints()
        else:
            return []
        
    def getAllBreakpoints(self):
        """
        Public method to get all breakpoints
        
        @return list of all breakpoints
        """
        files = self.viewmanager.getOpenFilenames()
        bpDict = {}
        for file in files:
            bpList = self.viewmanager.getOpenEditor(file).getBreakpoints()
            if bpList:
                bpDict[file] = bpList
                
        return bpDict
        
    def getProjectBreakpoints(self):
        """
        Public method to get all breakpoints of the current project
        
        @return list of breakpoints belonging to the current project
        """
        files = self.ui.getProject().getSources(1)
        bpDict = {}
        for file in files:
            editor = self.viewmanager.getOpenEditor(file)
            if editor is not None:
                bpList = editor.getBreakpoints()
                if bpList:
                    bpDict[file] = bpList
                
        return bpDict

    def newBreakpointWithProperties(self, fn, line, properties):
        """
        Public method to set a new breakpoint and its properties.
        
        @param fn filename of the breakpoint operation (string)
        @param line line number of the breakpoint
        @param properties properties for the breakpoint (tuple)
                (condition, temporary flag, enabled flag, ignore count)
        """
        try:
            dummy, editor = self.viewmanager.getEditor(fn)
        except IOError:
            return
        editor.newBreakpointWithProperties(line, properties)
        
    def toggleBreakpoint(self, fn, line):
        """
        Public method to toggle a breakpoint.
        
        @param fn filename of the breakpoint operation (string)
        @param line line number of the breakpoint
        """
        editor = self.viewmanager.getOpenEditor(fn)
        if editor is not None:
            editor.toggleBreakpoint(line)
        
    def setBreakpointProperties(self, fn, line, properties):
        """
        Public method to set a breakpoints properties.
        
        @param fn filename of the breakpoint operation (string)
        @param line line number of the breakpoint
        @param properties properties for the breakpoint (tuple)
                (condition, temporary flag, enabled flag, ignore count)
        """
        editor = self.viewmanager.getOpenEditor(fn)
        if editor is not None:
            editor.setBreakpointProperties(line, properties)
        
    def getActions(self):
        """
        Public method to get a list of all actions.
        
        @return list of all actions (list of E3Action)
        """
        return self.actions[:]
