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

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

"""
Module implementing the main user interface.
"""

import os
import sys
import string

from qt import *
from qtext import QSCINTILLA_VERSION_STR

from Icons.Icons import *
from Icons.ToolIcons import *
from Debugger.DebugUI import DebugUI
from Debugger.DebugServer import DebugServer
from SBVviewer import SBVviewer
from Shell import Shell
from Info import *
from EmailDialog import EmailDialog
from PyUnit.UnittestDialog import UnittestDialog
from Helpviewer.HelpWindow import HelpWindow
from Preferences.PreferencesDialog import PreferencesDialog
from Preferences.ShortcutsDialog import ShortcutsDialog
from ToolConfigurationDialog import ToolConfigurationDialog
from Project.Project import Project
from Project.ProjectBrowser import ProjectBrowser
from LogView import LogView
from FindFileDialog import FindFileDialog
from Wizards.Wizard import Wizards
import Preferences
import ViewManager
import Utilities
import Scripting
from Scripting.LoadScriptDialog import LoadScriptDialog
from Scripting.ScriptManager import *

if Utilities.getPythonVersion() >= 0x202:
    from Refactoring.Refactoring import Refactoring, BRM_VERSION_STR
else:
    BRM_VERSION_STR = 'not available'


class Redirector(QObject):
    """
    Helper class used to redirect stdout and stderr to the log window
    
    Signals
    
        appendStderr(string) -- emitted to write data to stderr logger
        
        appendStdout(string) -- emitted to write data to stdout logger
    """
    def __init__(self, stderr):
        """
        Constructor
        
        Arguments
        
            stderr -- flag indicating stderr is being redirected
        """
        QObject.__init__(self)
        self.stderr = stderr
        self.buffer = ''
        
    def nWrite(self, n):
        """
        Private method used to write data.
        
        Arguments
        
            n -- max numebr of bytes to write
        """
        if n:
            if self.buffer[n-1] == '\n':
                line = self.buffer[:n-1]
            else:
                line = self.buffer[:n]
            if self.stderr:
                qApp.mainWidget().showLogTab("stderr")
                self.emit(PYSIGNAL('appendStderr'), (line,))
            else:
                qApp.mainWidget().showLogTab("stdout")
                self.emit(PYSIGNAL('appendStdout'), (line,))
            self.buffer = self.buffer[n:]
            
    def bufferedWrite(self):
        """
        Private method returning number of characters to write.
        
        Returns
        
            number of characters buffered or length of buffered line
        """
        return self.buffer.rfind('\n') + 1
        
    def flush(self):
        """
        Public method used to flush the buffered data.
        """
        self.nWrite(len(self.buffer))
        
    def write(self, s):
        """
        Public method used to write data.
        
        Arguments
        
            s -- data to be written (it must support the str-method)
        """
        self.buffer = self.buffer + str(s)
        self.nWrite(self.bufferedWrite())
        
class UserInterface(QMainWindow):
    """
    Class implementing the main user interface.
    
    Signals
    
        appendStderr(string) -- emitted to write data to stderr logger
        
        appendStdout(string) -- emitted to write data to stdout logger
        
        preferencesChanged() -- emitted after the preferences were changed
    """
    def __init__(self, loc):
        """
        Constructor
        
        Arguments
        
            loc -- locale to be used by the UI (string)
        """
        QMainWindow.__init__(self)

        self.loc = loc
        
        self.layout = Preferences.getUILayout()
        self.passiveMode = Preferences.getDebugger("PassiveDbgEnabled")
        
        g = Preferences.getGeometry("MainGeometry")
        if g == [0,0,0,0]:
            s = QSize(800, 600)
            self.resize(s)
        else:
            self.move(g[0], g[1])
            self.resize(g[2], g[3])
            
        self.setIcon(IconEric)
        self.setWindowCaption()
        
        if self.layout in [0, 1]:
            self.setCentralWidget(QWidget(self))
            appWindowLayout = QHBoxLayout(self.centralWidget(),0,6)

        self.qtdir = Preferences.getQtDir()

        # Generate the debug server object
        dbs = DebugServer()
        
        # Generate an empty project object
        self.project = Project(self)
        
        # Create the workspace now so that we can connect QActions to it.
        # Create the main layout type 0 (three horizontal splitters)
        if self.layout == 0:
            # A layout like the appearence of Qt Designer.
            self.hSplitter = QSplitter(self.centralWidget(),"hSplitter")
            self.hSplitter.setOrientation(QSplitter.Horizontal)
            
            # Create the project browser
            self.projectBrowser = ProjectBrowser(self.project, self.qtdir, self.hSplitter)
            self.projectBrowser.show()
            
            # Create the view manager depending on the configuration setting
            self.viewmanager = ViewManager.factory(self.hSplitter, self, dbs)
            
            # Create a splitter for the right hand side
            self.vSplitter = QSplitter(self.hSplitter,"vSplitter")
            self.vSplitter.setOrientation(QSplitter.Vertical)
            
            # Create the shell, browser, variables part of the user interface
            self.sbv = SBVviewer(dbs, self.vSplitter)
            self.shell = self.sbv.shell
            
            # Create the log viewer part of the user interface
            self.logViewer = LogView(self.vSplitter)
            self.logViewer.setMinimumSize(100,100)
            
            # Add the splitter to the main windows layout
            appWindowLayout.addWidget(self.hSplitter)
            
        # Create the main layout type 1 (vertical splitter, three horizontal splitters
        # in top part and two horizontal splitters in bottom part)
        elif self.layout == 1:
            # A layout like the appearance of KDevelop
            self.vSplitter = QSplitter(self.centralWidget(),"vSplitter")
            self.vSplitter.setOrientation(QSplitter.Vertical)
            
            # Create the top part
            self.hSplitter1 = QSplitter(self.vSplitter,"hSplitter1")
            self.hSplitter1.setOrientation(QSplitter.Horizontal)
        
            # Create the project browser
            self.projectBrowser = ProjectBrowser(self.project, self.qtdir, self.hSplitter1)
            self.projectBrowser.show()
            
            # Create the view manager depending on the configuration setting
            self.viewmanager = ViewManager.factory(self.hSplitter1, self, dbs)
            
            # Create the shell, browser, variables part of the user interface
            # but without the shell. The shell gets a separate part of the UI
            self.sbv = SBVviewer(dbs, self.hSplitter1, 1)
            
            # Create the bottom part
            self.hSplitter2 = QSplitter(self.vSplitter,"hSplitter2")
            self.hSplitter2.setOrientation(QSplitter.Horizontal)
            
            # Create the shell
            self.shell = Shell(dbs, self.hSplitter2)
        
            # Create the log viewer part of the user interface
            self.logViewer = LogView(self.hSplitter2)
            self.logViewer.setMinimumSize(100,100)
            
            # Add the splitter to the main windows layout
            appWindowLayout.addWidget(self.vSplitter)
            
        # Create the main layout type 2 (movable dock windows)
        elif self.layout == 2:
            # Create the project browser
            self.projectBrowserDock = self.createDockWindow()
            self.projectBrowser = ProjectBrowser(self.project, self.qtdir, self.projectBrowserDock)
            self.setupDockWindow(self.projectBrowserDock, Qt.DockLeft,
                                 self.projectBrowser, self.trUtf8("Project-Browser"))

            # Create the shell, browser, variables part of the user interface
            self.sbvDock = self.createDockWindow()
            self.sbv = SBVviewer(dbs, self.sbvDock)
            self.shell = self.sbv.shell
            self.setupDockWindow(self.sbvDock, Qt.DockRight,
                                 self.sbv, self.trUtf8("Debug-Browser"))

            # Create the log viewer part of the user interface
            self.logViewerDock = self.createDockWindow()
            self.logViewer = LogView(self.logViewerDock)
            self.setupDockWindow(self.logViewerDock, Qt.DockRight,
                                 self.logViewer, self.trUtf8("Log-Viewer"))

            self.dockwindows = {}
            self.dockwindows[0] = (self.trUtf8('Project-Browser'), self.projectBrowserDock)
            self.dockwindows[1] = (self.trUtf8('Debug-Browser'), self.sbvDock)
            self.dockwindows[2] = (self.trUtf8('Log-Viewer'), self.logViewerDock)

            # Create the view manager depending on the configuration setting
            self.viewmanager = ViewManager.factory(self, self, dbs)
            self.setCentralWidget(self.viewmanager)

        # Create the main layout type 3 (movable dock windows with seperate shell)
        elif self.layout == 3:
            # Create the project browser
            self.projectBrowserDock = self.createDockWindow()
            self.projectBrowser = ProjectBrowser(self.project, self.qtdir, self.projectBrowserDock)
            self.setupDockWindow(self.projectBrowserDock, Qt.DockLeft,
                                 self.projectBrowser, self.trUtf8("Project-Browser"))

            # Create the shell, browser, variables part of the user interface
            # but without the shell. The shell gets a separate part of the UI
            self.sbvDock = self.createDockWindow()
            self.sbv = SBVviewer(dbs, self.sbvDock, 1)
            self.setupDockWindow(self.sbvDock, Qt.DockRight,
                                 self.sbv, self.trUtf8("Debug-Browser"))

            # Create the shell
            self.shellDock = self.createDockWindow()
            self.shell = Shell(dbs, self.shellDock)
            self.setupDockWindow(self.shellDock, Qt.DockBottom,
                                 self.shell, self.trUtf8("Python-Shell"))

            # Create the log viewer part of the user interface
            self.logViewerDock = self.createDockWindow()
            self.logViewer = LogView(self.logViewerDock)
            self.setupDockWindow(self.logViewerDock, Qt.DockBottom,
                                 self.logViewer, self.trUtf8("Log-Viewer"))

            self.dockwindows = {}
            self.dockwindows[0] = (self.trUtf8('Project-Browser'), self.projectBrowserDock)
            self.dockwindows[1] = (self.trUtf8('Debug-Browser'), self.sbvDock)
            self.dockwindows[2] = (self.trUtf8('Python-Shell'), self.shellDock)
            self.dockwindows[3] = (self.trUtf8('Log-Viewer'), self.logViewerDock)

            # Create the view manager depending on the configuration setting
            self.viewmanager = ViewManager.factory(self, self, dbs)
            self.setCentralWidget(self.viewmanager)

        # Create and add the log viewer tabs
        self.logTabs = {}
        (self.logTabs["stdout"], self.stdoutTab) = self.logViewer.addTab(self.trUtf8("stdout"))

        (self.logTabs["stderr"], self.stderrTab) = self.logViewer.addTab(self.trUtf8("stderr"))

        # Generate the debugger part of the ui
        self.dbg = DebugUI(self, self.viewmanager, dbs, self.sbv)
        
        # Generate the redirection helpers
        self.stdout = Redirector(0)
        self.stderr = Redirector(1)
        
        # Generate the shortcuts configuration dialog
        self.shortcutsDialog = ShortcutsDialog(self, 'Shortcuts')
        
        # Generate the refactoring object
        if Utilities.getPythonVersion() >= 0x202:
            self.refactoring = Refactoring(self)
        else:
            self.refactoring = None
        
        # now setup the connections
        self.connect(self.sbv.browser,PYSIGNAL('pythonFile'),
                     self.viewmanager.handlePythonFile)
        self.connect(self.sbv.browser,PYSIGNAL('designerFile'),
                     self.handleDesigner)
        self.connect(self.sbv.browser,PYSIGNAL('linguistFile'),
                     self.handleLinguist)
        self.connect(self.sbv.browser,PYSIGNAL('projectFile'),
                     self.project.openProject)
        self.connect(self.sbv.browser,PYSIGNAL('unittestOpen'),
                     self.handleUnittest)
                     
        self.connect(self.sbv.exceptionLogger,PYSIGNAL('pythonFile'),
                     self.viewmanager.handlePythonFile)
                     
        self.connect(self.sbv,PYSIGNAL('pythonFile'),
                     self.viewmanager.handlePythonFile)
                     
        self.connect(self.projectBrowser.psBrowser,PYSIGNAL('pythonFile'),
                     self.viewmanager.handlePythonFile)
        self.connect(self.projectBrowser.psBrowser,PYSIGNAL('closeSourceWindow'),
                     self.viewmanager.handleCloseWindow)
                     
        self.connect(self.projectBrowser.pfBrowser,PYSIGNAL('designerFile'),
                     self.handleDesigner)
        self.connect(self.projectBrowser.pfBrowser,PYSIGNAL('appendStdout'),
                     self.stdoutTab.append)
        self.connect(self.projectBrowser.pfBrowser,PYSIGNAL('appendStderr'),
                     self.stderrTab.append)
                     
        self.connect(self.projectBrowser.ptBrowser,PYSIGNAL('linguistFile'),
                     self.handleLinguist)
        self.connect(self.projectBrowser.ptBrowser,PYSIGNAL('appendStdout'),
                     self.stdoutTab.append)
        self.connect(self.projectBrowser.ptBrowser,PYSIGNAL('appendStderr'),
                     self.stderrTab.append)
                     
        self.connect(self.projectBrowser.piBrowser,PYSIGNAL('pythonFile'),
                     self.viewmanager.handlePythonFile)
        self.connect(self.projectBrowser.piBrowser,PYSIGNAL('closeSourceWindow'),
                     self.viewmanager.handleCloseWindow)
        self.connect(self.projectBrowser.piBrowser,PYSIGNAL('appendStdout'),
                     self.stdoutTab.append)
        self.connect(self.projectBrowser.piBrowser,PYSIGNAL('appendStderr'),
                     self.stderrTab.append)
                     
        self.connect(self.projectBrowser.poBrowser,PYSIGNAL('pythonFile'),
                     self.viewmanager.handlePythonFile)
        self.connect(self.projectBrowser.poBrowser,PYSIGNAL('closeSourceWindow'),
                     self.viewmanager.handleCloseWindow)
                     
        self.connect(self.project,PYSIGNAL('pythonFile'),
                    self.viewmanager.handleOpen)
        self.connect(self.project,PYSIGNAL('newProject'),
                     self.viewmanager.handleNewProject)
        self.connect(self.project,PYSIGNAL('projectOpened'),
                     self.viewmanager.handleProjectOpened)
        self.connect(self.project,PYSIGNAL('projectClosed'),
                     self.viewmanager.handleProjectClosed)
        self.connect(self.project,PYSIGNAL('newProject'),
                     self.handleNewProject)
        self.connect(self.project,PYSIGNAL('projectOpened'),
                     self.handleProjectOpened)
        self.connect(self.project,PYSIGNAL('projectClosed'),
                     self.handleProjectClosed)
                     
        self.connect(self.dbg,PYSIGNAL('resetUI'),
                     self.viewmanager.handleResetUI)
        self.connect(self.dbg,PYSIGNAL('resetUI'),
                     self.sbv.handleResetUI)
        self.connect(self.dbg,PYSIGNAL('clientStack'),
                     self.sbv.handleClientStack)
        self.connect(self.dbg,PYSIGNAL('debuggingStarted'),
                     self.sbv.browser.handleProgramChange)
        self.connect(self.dbg,PYSIGNAL('debuggingStarted'),
                     self.sbv.exceptionLogger.debuggingStarted)
        self.connect(self.dbg,PYSIGNAL('debuggingStarted'),
                     self.handleProgramChange)
                     
        self.connect(dbs,PYSIGNAL('clientStack'),
                     self.sbv.handleClientStack)
        self.connect(dbs,PYSIGNAL('passiveDebugStarted'),
                     self.sbv.exceptionLogger.debuggingStarted)
        self.connect(dbs,PYSIGNAL('clientException'),
                     self.sbv.exceptionLogger.addException)
                     
        self.connect(self.stdout,PYSIGNAL('appendStdout'),
                     self.stdoutTab.append)
                     
        self.connect(self.stderr,PYSIGNAL('appendStderr'),
                     self.stderrTab.append)
                     
        self.connect(self,PYSIGNAL('preferencesChanged'),
                     self.viewmanager.handlePreferencesChanged)
        self.connect(self,PYSIGNAL('appendStdout'),
                     self.stdoutTab.append)
        self.connect(self,PYSIGNAL('appendStderr'),
                     self.stderrTab.append)
        self.connect(self,PYSIGNAL('preferencesChanged'),
                     self.shell.handlePreferencesChanged)
        if self.refactoring is not None:
            self.connect(self,PYSIGNAL('preferencesChanged'),
                         self.refactoring.handlePreferencesChanged)
                     
        self.connect(self.viewmanager,PYSIGNAL('editorSaved'),
                     self.projectBrowser.psBrowser.handleEditorSaved)
        self.connect(self.viewmanager,PYSIGNAL('lastEditorClosed'),
                     self.handleLastEditorClosed)
        self.connect(self.viewmanager,PYSIGNAL('editorOpened'),
                     self.handleEditorOpened)
        
        # Set the sizes of the splitters
        width = self.width()
        height = self.height()
        if self.layout == 0:
            g = Preferences.getGeometry("MainSplitter0")
            if g == [0,0,0,0,0]:
                hSizes = [int(0.21*width), int(0.49*width), int(0.3*width)]
                vSizes = [int(0.8*height), int(0.2*height)]
            else:
                hSizes = g[:3]
                vSizes = g[3:]
            self.hSplitter.setSizes(hSizes)
            self.vSplitter.setSizes(vSizes)
        elif self.layout == 1:
            g = Preferences.getGeometry("MainSplitter1")
            if g == [0,0,0,0,0,0,0]:
                vSizes = [int(0.9*height), int(0.1*height)]
                hSizes1 = [int(0.23*width), int(0.52*width), int(0.25*width)]
                hSizes2 = [int(0.5*width), int(0.5*width)]
            else:
                vSizes = g[:2]
                hSizes1 = g[2:5]
                hSizes2 = g[5:]
            self.vSplitter.setSizes(vSizes)
            self.hSplitter1.setSizes(hSizes1)
            self.hSplitter2.setSizes(hSizes2)
        elif self.layout == 2:
            if not Preferences.getMainDockLayout(self, 0):
                self.projectBrowserDock.setFixedExtentWidth(int(0.21*width))
                self.sbvDock.setFixedExtentWidth(int(0.3*width))
                self.logViewerDock.setFixedExtentWidth(int(0.3*height))
                self.logViewer.setMinimumSize(int(0.2*width),int(0.1*height))
        elif self.layout == 3:
            if not Preferences.getMainDockLayout(self, 1):
                self.projectBrowserDock.setFixedExtentWidth(int(0.23*width))
                self.sbvDock.setFixedExtentWidth(int(0.3*width))
                self.shellDock.setFixedExtentHeight(int(0.1*height))
                self.shell.setMinimumSize(int(0.4*width),int(0.1*height))
                self.logViewerDock.setFixedExtentHeight(int(0.1*height))
            
        # Generate the unittest dialog
        self.unittestDialog = UnittestDialog(None, self.dbg.dbs, self)
        self.connect(self.unittestDialog,PYSIGNAL('unittestFile'),
                     self.viewmanager.setFileLine)
        
        # Generate the find in project files dialog
        self.findFilesDialog = FindFileDialog(self.project)
        self.connect(self.findFilesDialog, PYSIGNAL('pythonFile'),
                     self.viewmanager.handlePythonFile)
        self.connect(self.findFilesDialog,PYSIGNAL('designerFile'),
                     self.handleDesigner)
                     
        # generate the wizards
        self.wizards = Wizards(self.loc, self)
        
        # Initialize the actions, menues, toolbar and statusbar
        self.initActions()
        self.initMenus()
        self.initToolbars()
        self.initStatusbar()

        # Initialise the instance variables.
        self.currentProg = None
        self.isProg = 0

        # Initialize the toollist and list of started tools
        self.toollist = Preferences.readToolsMenu()
        self.toolProcs = []
        
        # now redirect stdout and stderr
        sys.stdout = self.stdout
        sys.stderr = self.stderr

        # now fire up the scripting stuff
        self.scriptManager = Scripting.init(self)
        self.connect(self.scriptManager, PYSIGNAL("firstScriptAdded"),
            self.handleFirstScriptAdded)
        self.connect(self.scriptManager, PYSIGNAL("lastScriptDeleted"),
            self.handleLastScriptDeleted)
        Scripting.runStartupScripts(self)
        
    def showLogTab(self, tabname):
        """
        Public method to show a particular Log-Viewer tab.
        
        Arguments
        
            tabname -- string naming the tab to be shown (string)
        """
        if tabname in self.logTabs.keys():
            self.logViewer.setCurrentPage(self.logTabs[tabname])
        
    def processArgs(self, args):
        """
        Public method to process the command line args passed to the UI.
        
        Arguments
        
            args -- list of files to open
                The args are processed one at a time, if the arg ends 
                in .py, the file is opened in the text editor. Once the last .py 
                file is reached, any arguments after that are considered debug 
                arguments to the program for the debugger. (The assumption being 
                that you are launching eric3 to debug a script that takes args.).
                All files prior to the last .py encountered are opened in the text 
                editor, unless the argument ends in .e3p, then it is opened as a 
                project file.
        """
        # no args, return
        if args is None:
            return

        # holds space delimited list of command args, if any
        argsStr = None
        pyProg = None

        for arg in args:
            dummy, ext = os.path.splitext(arg)
            ext = os.path.normcase(ext)

            # if py, set current prog to it and open
            if ext == '.py':
                pyProg = arg
                self.viewmanager.handleOpen(arg)

            # otherwise, if no py seen, then open appropriately
            elif pyProg is None:
                if ext == '.e3p':
                    self.project.openProject(arg)
                else:
                    self.viewmanager.handleOpen(arg)

            # ok, we have args and have seen a .py, pass it as args and do not open
            else:
                if argsStr is None:
                    argsStr = arg
                else:
                    argsStr = argsStr + ' ' + arg

        # store away any args we had
        if argsStr is not None:
            self.dbg.setArgvHistory(argsStr)
        
    def createDockWindow(self):
        """
        Private method to create a dock window with common properties.
        
        Returns
        
            the generated dock window (QDockWindow)
        """
        dock = QDockWindow()
        dock.setResizeEnabled(1)
        dock.setCloseMode(QDockWindow.Always)
        return dock

    def setupDockWindow(self, dock, where, widget, caption):
        """
        Private method to configure the dock window created with createDockWindow().
        
        Arguments
        
            dock -- the dock window (QDockWindow)
            
            where -- dock area to be docked to (QDockArea)
            
            widget -- widget to be shown in the dock window (QWidget)
            
            caption -- caption of the dock window (string or QString)
        """
        self.addDockWindow(dock, where)
        dock.setWidget(widget)
        dock.setCaption(caption)
        dock.show()
        self.setAppropriate(dock, 1)

    def setWindowCaption(self, project=None):
        """
        Private method to set the caption of the Main Window.
        
        Arguments
        
            project -- project name to be displayed (string or QString)
        """
        if self.passiveMode:
            if project is None:
                self.setCaption(self.trUtf8("%1 - Passive Mode").arg(Program))
            else:
                self.setCaption(self.trUtf8("%1 - %2 - Passive Mode")\
                    .arg(project)\
                    .arg(Program))
        else:
            if project is None:
                self.setCaption(Program)
            else:
                self.setCaption("%s - %s" % (project, Program))
        
    def initActions(self):
        """
        Private method to define the user interface actions.
        """
        self.exitAct = QAction(self.trUtf8('Quit'),
                QIconSet(IconExit),
                self.trUtf8('&Quit'),
                QKeySequence(self.trUtf8("CTRL+Q","File|Quit")),self)
        self.exitAct.setStatusTip(self.trUtf8('Quit the IDE'))
        self.exitAct.setWhatsThis(self.trUtf8(
            """<b>Quit the IDE</b>"""
            """<p>This quits the IDE. Any unsaved changes may be saved first."""
            """ Any Python program being debugged will be stopped and the"""
            """ preferences will be written to disc.</p>"""
        ))
        self.connect(self.exitAct,SIGNAL('activated()'), self.handleQuit)

        self.pbAct = QAction(self.trUtf8('Project-Browser'),
                self.trUtf8('&Project-Browser'),0,self,None,1)
        self.pbAct.setStatusTip(self.trUtf8('Toggle the Project-Browser window'))
        self.pbAct.setWhatsThis(self.trUtf8(
            """<b>Toggle the Project-Browser window</b>"""
            """<p>If the Project-Browser window is hidden then display it. It is displayed"""
            """ then close it.</p>"""
        ))
        self.connect(self.pbAct,SIGNAL('activated()'),self.handleProjectBrowser)

        self.sbvAct = QAction(self.trUtf8('Debug-Browser'),
                self.trUtf8('&Debug-Browser'),0,self,None,1)
        self.sbvAct.setStatusTip(self.trUtf8('Toggle the Debug-Browser window'))
        self.sbvAct.setWhatsThis(self.trUtf8(
            """<b>Toggle the Debug-Browser window</b>"""
            """<p>If the Debug-Browser window is hidden then display it."""
            """ If it is displayed then close it.</p>"""
        ))
        self.connect(self.sbvAct,SIGNAL('activated()'),self.handleSBV)
        
        if self.layout in [1, 3]:
            self.shellAct = QAction(self.trUtf8('Python-Shell'),
                    self.trUtf8('Python-&Shell'),0,self,None,1)
            self.shellAct.setStatusTip(self.trUtf8('Toggle the Python-Shell window'))
            self.shellAct.setWhatsThis(self.trUtf8(
                """<b>Toggle the Python-Shell window</b>"""
                """<p>If the Python-Shell window is hidden then display it."""
                """ If it is displayed then close it.</p>"""
            ))
            self.connect(self.shellAct,SIGNAL('activated()'),self.handleShell)

        self.lvAct = QAction(self.trUtf8('Log-Viewer'),
                self.trUtf8('&Log-Viewer'),0,self,None,1)
        self.lvAct.setStatusTip(self.trUtf8('Toggle the Log-Viewer window'))
        self.lvAct.setWhatsThis(self.trUtf8(
            """<b>Toggle the Log-Viewer window</b>"""
            """<p>If the Log-Viewer window is hidden then display it."""
            """ If it is displayed then close it.</p>"""
        ))
        self.connect(self.lvAct,SIGNAL('activated()'),self.handleLogViewer)

        self.whatsThisAct = QAction(self.trUtf8('What\'s This?'),
                QIconSet(IconWhatsThis),
                self.trUtf8('&What\'s This?'), Qt.SHIFT+Qt.Key_F1,self)
        self.whatsThisAct.setStatusTip(self.trUtf8('Context sensitive help'))
        self.whatsThisAct.setWhatsThis(self.trUtf8(
            """<b>Display context sensitive help</b>"""
            """<p>In What's This? mode, the mouse cursor shows an arrow with a question"""
            """ mark, and you can click on the interface elements to get a short"""
            """ description of what they do and how to use them. In dialogs, this"""
            """ feature can be accessed using the context help button in the"""
            """ titlebar.</p>"""
        ))
        self.connect(self.whatsThisAct,SIGNAL('activated()'),self.whatsThis)

        self.helpviewerAct = QAction(self.trUtf8('Helpviewer'),
                self.trUtf8('&Helpviewer...'), Qt.Key_F1,self)
        self.helpviewerAct.setStatusTip(self.trUtf8('Open the helpviewer window'))
        self.helpviewerAct.setWhatsThis(self.trUtf8(
            """<b>Helpviewer</b>"""
            """<p>Display the helpviewer window. This window will show"""
            """ HTML help files. It has the capability to navigate to"""
            """ links, set bookmarks, print the displayed help and some"""
            """ more features.</p>"""
        ))
        self.connect(self.helpviewerAct,SIGNAL('activated()'),self.handleHelpViewer)
        
        self.initQtDocAction()
        self.initPythonDocAction()
        self.initEricDocAction()
      
              
        self.aboutAct = QAction(self.trUtf8('About %1').arg(Program),
                self.trUtf8('&About %1').arg(Program),
                0,self)
        self.aboutAct.setStatusTip(self.trUtf8('Display information about this software'))
        self.aboutAct.setWhatsThis(self.trUtf8(
            """<b>About %1</b>"""
            """<p>Display some information about this software.</p>"""
                             ).arg(Program))
        self.connect(self.aboutAct,SIGNAL('activated()'),self.handleAbout)

        self.aboutQtAct = QAction(self.trUtf8('About Qt'),
                self.trUtf8('About &Qt'),0,self)
        self.aboutQtAct.setStatusTip(self.trUtf8('Display information about the Qt toolkit'))
        self.aboutQtAct.setWhatsThis(self.trUtf8(
            """<b>About Qt</b>"""
            """<p>Display some information about the Qt toolkit.</p>"""
        ))
        self.connect(self.aboutQtAct,SIGNAL('activated()'),self.handleAboutQt)

        self.versionAct = QAction(self.trUtf8('Show Versions'),
                self.trUtf8('Show &Versions'), 0,self)
        self.versionAct.setStatusTip(self.trUtf8('Display version information'))
        self.versionAct.setWhatsThis(self.trUtf8(
            """<b>Show Versions</b>"""
            """<p>Display version information.</p>"""
                             ))
        self.connect(self.versionAct,SIGNAL('activated()'),self.handleVersions)

        self.reportBugAct = QAction(self.trUtf8('Report Bug'),
                self.trUtf8('Report &Bug...'), 0,self)
        self.reportBugAct.setStatusTip(self.trUtf8('Report a bug'))
        self.reportBugAct.setWhatsThis(self.trUtf8(
            """<b>Report Bug...</b>"""
            """<p>Opens a dialog to report a bug.</p>"""
                             ))
        self.connect(self.reportBugAct,SIGNAL('activated()'),self.handleReportBug)

        self.toolsActGrp = QActionGroup(self)
        
        act = QAction(self.trUtf8('Unittest'), 
                QIconSet(IconUnittest),
                self.trUtf8('&Unittest...'),
                0, self.toolsActGrp)
        act.setStatusTip(self.trUtf8('Start unittest dialog'))
        act.setWhatsThis(self.trUtf8(
            """<b>Unittest</b>"""
            """<p>Perform unit tests. The dialog gives you the"""
            """ ability to select and run a unittest suite. """
            """ The python file implementing the suite must have"""
            """ a function called 'suite()' returning a"""
            """ unittest.TestSuite object.</p>"""
        ))
        self.connect(act,SIGNAL('activated()'), self.handleUnittest)

        if self.qtdir is None:
            self.qtActGrp = None
        else:
            self.qtActGrp = QActionGroup(self)
            
            act = QAction(self.trUtf8('Qt-Designer'), 
                    QIconSet(IconDesigner),
                    self.trUtf8('&Designer...'), 0, self.qtActGrp)
            act.setStatusTip(self.trUtf8('Start the Qt-Designer'))
            act.setWhatsThis(self.trUtf8(
                """<b>Qt-Designer</b>"""
                """<p>Start the Qt-Designer.</p>"""
            ))
            self.connect(act,SIGNAL('activated()'), self.handleDesigner)
            
            act = QAction(self.trUtf8('Qt-Linguist'), 
                    QIconSet(IconLinguist), 
                    self.trUtf8('&Linguist...'), 0, self.qtActGrp)
            act.setStatusTip(self.trUtf8('Start the Qt-Linguist'))
            act.setWhatsThis(self.trUtf8(
                """<b>Qt-Linguist</b>"""
                """<p>Start the Qt-Linguist.</p>"""
            ))
            self.connect(act,SIGNAL('activated()'), self.handleLinguist)
        
        self.prefAct = QAction(self.trUtf8('Preferences'),
                QIconSet(IconConfigure), 
                self.trUtf8('&Preferences...'), 0, self)
        self.prefAct.setStatusTip(self.trUtf8('Set the prefered configuration'))
        self.prefAct.setWhatsThis(self.trUtf8(
            """<b>Preferences</b>"""
            """<p>Set the configuration items of the application"""
            """ with your prefered values.</p>"""
        ))
        self.connect(self.prefAct,SIGNAL('activated()'), self.handlePreferences)

        self.shortcutsAct = QAction(self.trUtf8('Keyboard Shortcuts'),
                QIconSet(IconConfigureShortcuts), 
                self.trUtf8('Keyboard &Shortcuts...'), 0, self)
        self.shortcutsAct.setStatusTip(self.trUtf8('Set the keyboard shortcuts'))
        self.shortcutsAct.setWhatsThis(self.trUtf8(
            """<b>Keyboard Shortcuts</b>"""
            """<p>Set the keyboard shortcuts of the application"""
            """ with your prefered values.</p>"""
        ))
        self.connect(self.shortcutsAct,SIGNAL('activated()'), self.handleConfigShortcuts)

        self.toolsConfAct = QAction(self.trUtf8('Configure Tools'),
                QIconSet(IconToolsConfigure), 
                self.trUtf8('&Configure Tools...'), 0, self)
        self.toolsConfAct.setStatusTip(self.trUtf8('Configure the entries for the tools menu'))
        self.toolsConfAct.setWhatsThis(self.trUtf8(
            """<b>Configure Tools</b>"""
            """<p>Configure the entries for the tools menu.</p>"""
        ))
        self.connect(self.toolsConfAct,SIGNAL('activated()'), self.handleToolsConfiguration)

        self.scriptsActGrp = QActionGroup(self)
        
        act = QAction(self.trUtf8('Load Script'),
                self.trUtf8('&Load Script...'), 0, self.scriptsActGrp)
        act.setStatusTip(self.trUtf8('Load an eric3 script'))
        act.setWhatsThis(self.trUtf8(
            """<b>Load Script</b>"""
            """<p>Load an eric3 script for later use.</p>"""
        ))
        self.connect(act,SIGNAL('activated()'), self.handleLoadScript)

        self.scriptsExecAct = QAction(self.trUtf8('Execute Script'),
                self.trUtf8('&Execute Script...'), 0, self.scriptsActGrp)
        self.scriptsExecAct.setStatusTip(self.trUtf8('Execute an eric3 script'))
        self.scriptsExecAct.setWhatsThis(self.trUtf8(
            """<b>Execute Script</b>"""
            """<p>Execute an eric3 script.</p>"""
        ))
        self.connect(self.scriptsExecAct,SIGNAL('activated()'), self.handleExecuteScript)
        self.scriptsExecAct.setEnabled(0)
        
        self.scriptsDeleteAct = QAction(self.trUtf8('Delete Script'),
                self.trUtf8('&Delete Script...'), 0, self.scriptsActGrp)
        self.scriptsDeleteAct.setStatusTip(self.trUtf8('Delete an eric3 script'))
        self.scriptsDeleteAct.setWhatsThis(self.trUtf8(
            """<b>Delete Script</b>"""
            """<p>Delete an eric3 script.</p>"""
        ))
        self.connect(self.scriptsDeleteAct,SIGNAL('activated()'), self.handleDeleteScript)
        self.scriptsDeleteAct.setEnabled(0)
        
        self.scriptsExecDocAct = QAction(self.trUtf8('Execute Document as Script'),
                self.trUtf8('E&xecute Document as Script'), 0, self)
        self.scriptsExecDocAct.setStatusTip(self.trUtf8('Execute current document as an eric3 script'))
        self.scriptsExecDocAct.setWhatsThis(self.trUtf8(
            """<b>Execute Document as Script</b>"""
            """<p>Execute the current document as an eric3 script.</p>"""
        ))
        self.connect(self.scriptsExecDocAct,SIGNAL('activated()'), self.handleExecuteDocumentAsScript)
        self.scriptsExecDocAct.setEnabled(0)
        
        # initialize viewmanager actions
        self.viewmanager.initActions()
        
        # initialize debugger actions
        self.dbg.initActions()
        
        # initialize project actions
        self.project.initActions()
        
        # initialize refactoring actions
        if self.refactoring is not None:
            self.refactoring.initActions()
        
        # now read the keyboard shortcuts for the actions
        Preferences.readShortcuts(self)
    
    def initQtDocAction(self):
        """
        Private slot to initilize the action to show the Qt documentation.
        """
        self.qtDocAct = None
        if self.qtdir is None:
            return
        self.qtDocAct = QAction(self.trUtf8('Qt Documentation'),
                self.trUtf8('Q&t Documentation'), 0,self)
        self.qtDocAct.setStatusTip(self.trUtf8('Open Qt Documentation'))
        self.qtDocAct.setWhatsThis(self.trUtf8(
            """<b>Qt Documentation</b>"""
            """<p>Display the Qt Documentation. Dependant upon your settings, this"""
            """ will either show the help in Eric's internal help viewer, or execute"""
            """ Qt Assistant. </p>"""
        ))
        self.connect(self.qtDocAct,SIGNAL('activated()'),self.handleQtDoc)
      
    def initPythonDocAction(self):
        """
        Private slot to initilize the action to show the Python documentation.
        """
        self.pythonDocAct = None
        if sys.platform == "win32":
            self.pythonDocDir = os.environ.get("PYTHONDOCDIR", 
                os.path.join(os.path.dirname(sys.executable), "doc"))
        else:
            self.pythonDocDir = os.environ.get("PYTHONDOCDIR", 
                '/usr/share/doc/packages/python/html')
         
        if os.path.exists(self.pythonDocDir):
            self.pythonDocAct = QAction(self.trUtf8('Python Documentation'),
                self.trUtf8('&Python Documentation'), 0, self)
            self.pythonDocAct.setStatusTip(self.trUtf8('Open Python Documentation'))
            self.pythonDocAct.setWhatsThis(self.trUtf8(
                    """<b>Python Documentation</b>"""
                    """<p>Display the python documentation."""
                    """ The location of the python documentation is assumed to be the doc"""
                    """ directory underneath the location of the python executable on"""
                    """ Windows and <i>/usr/share/doc/packages/python/html</i> on Unix."""
                    """ Set PYTHONDOCDIR in your environment to override this. </p>"""
            ))
            self.connect(self.pythonDocAct,SIGNAL('activated()'),self.handlePythonDoc)
        
    def initEricDocAction(self):
        """
        Private slot to initialize the action to show the eric3 documentation.
        """
        self.ericDocAct = None
        if os.path.exists(os.path.join(os.path.dirname(sys.argv[0]), 
                          "Documentation", "Source", "index.html")):
            self.ericDocAct = QAction(self.trUtf8("Eric Documentation"),
                self.trUtf8('&Eric Documentation'), 0, self)
            self.ericDocAct.setStatusTip(self.trUtf8("Open Eric Documentation"))
            self.ericDocAct.setWhatsThis(self.trUtf8(
                """<b>Eric Documentation</b>"""
                """<p>Display the Eric documantation."""
                """ The location for the documentation is the Documentation/Source"""
                """ subdirectory of the eric3 installation directory.</p>"""
            ))
            self.connect(self.ericDocAct,SIGNAL('activated()'),self.handleEricDoc)
        
    def initMenus(self):
        """
        Private slot to create the menus.
        """
        mb = self.menuBar()

        self.fileMenu = self.viewmanager.initFileMenu()
        mb.insertItem(self.trUtf8('&File'), self.fileMenu)
        self.fileMenu.insertSeparator()
        self.exitAct.addTo(self.fileMenu)
        
        self.editMenu = self.viewmanager.initEditMenu()
        mb.insertItem(self.trUtf8('&Edit'), self.editMenu)
        
        self.searchMenu = self.viewmanager.initSearchMenu()
        mb.insertItem(self.trUtf8('&Search'), self.searchMenu)
        
        self.viewMenu = self.viewmanager.initViewMenu()
        mb.insertItem(self.trUtf8('&View'), self.viewMenu)
        
        self.debugMenu = self.dbg.initMenu()
        mb.insertItem(self.trUtf8('&Debug'), self.debugMenu)
        
        self.projectMenu = self.project.initMenu()
        mb.insertItem(self.trUtf8('&Project'), self.projectMenu)
        
        if self.refactoring is not None:
            self.refactoringMenu = self.refactoring.initMenu()
            mb.insertItem(self.trUtf8('&Refactoring'), self.refactoringMenu)
        
        self.toolsMenu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&Tools'), self.toolsMenu)
        self.connect(self.toolsMenu, SIGNAL('aboutToShow()'), self.handleShowToolsMenu)
        
        self.wizardsMenu = self.wizards.initMenu()
        self.wizardsMenuItem = mb.insertItem(self.trUtf8('Wi&zards'), self.wizardsMenu)
        mb.setItemEnabled(self.wizardsMenuItem, 0)
        
        self.extrasMenu = QPopupMenu(self)
        self.extrasMenu.insertTearOffHandle()
        mb.insertItem(self.trUtf8('E&xtras'), self.extrasMenu)
        self.macrosMenu = self.viewmanager.initMacroMenu()
        self.extrasMenu.insertItem(self.trUtf8("&Macros"), self.macrosMenu)
        self.scriptsMenu = QPopupMenu(self)
        self.scriptsMenu.insertTearOffHandle()
        self.scriptsActGrp.addTo(self.scriptsMenu)
        self.scriptsMenu.insertSeparator()
        self.scriptsExecDocAct.addTo(self.scriptsMenu)
        self.scriptsMenu.insertSeparator()
        self.extrasMenu.insertItem(self.trUtf8("&Scripts"), self.scriptsMenu)
        
        self.settingsMenu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&Settings'), self.settingsMenu)
        self.settingsMenu.insertTearOffHandle()
        self.prefAct.addTo(self.settingsMenu)
        self.shortcutsAct.addTo(self.settingsMenu)
        self.toolsConfAct.addTo(self.settingsMenu)
        
        self.windowMenu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&Window'), self.windowMenu)
        self.connect(self.windowMenu, SIGNAL('aboutToShow()'), self.handleShowWindowMenu)
        
        self.toolbarsMenu = QPopupMenu(self.windowMenu)
        self.connect(self.toolbarsMenu, SIGNAL('aboutToShow()'), self.handleShowToolbarsMenu)
        
        self.bookmarkMenu = self.viewmanager.initBookmarkMenu()
        mb.insertItem(self.trUtf8('&Bookmarks'), self.bookmarkMenu)

        mb.insertSeparator()

        self.helpMenu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&Help'), self.helpMenu)
        self.helpMenu.insertTearOffHandle()
        self.helpviewerAct.addTo(self.helpMenu)
        self.helpMenu.insertSeparator()
        separatorNeeded = 0
        if not self.ericDocAct is None:
            self.ericDocAct.addTo(self.helpMenu)
            separatorNeeded = 1
        if not self.pythonDocAct is None:
            self.pythonDocAct.addTo(self.helpMenu)
            separatorNeeded = 1
        if not self.qtDocAct is None:
            self.qtDocAct.addTo(self.helpMenu)
            separatorNeeded = 1
        if separatorNeeded:
            self.helpMenu.insertSeparator()
        self.aboutAct.addTo(self.helpMenu)
        self.aboutQtAct.addTo(self.helpMenu)
        self.versionAct.addTo(self.helpMenu)
        self.helpMenu.insertSeparator()
        self.reportBugAct.addTo(self.helpMenu)
        self.helpMenu.insertSeparator()
        self.whatsThisAct.addTo(self.helpMenu)

    def initToolbars(self):
        """
        Private slot to create the toolbars.
        """
        filetb = self.viewmanager.initFileToolbar()
        edittb = self.viewmanager.initEditToolbar()
        searchtb = self.viewmanager.initSearchToolbar()
        viewtb = self.viewmanager.initViewToolbar()
        debugtb = self.dbg.initToolbar()
        projecttb = self.project.initToolbar()
        toolstb = QToolBar(self)
        bookmarktb = self.viewmanager.initBookmarkToolbar()
        settingstb = QToolBar(self)
        helptb = QToolBar(self)
        self.scriptsToolBar = QToolBar(self)

        filetb.addSeparator()
        self.exitAct.addTo(filetb)
        
        self.toolsActGrp.addTo(toolstb)
        if self.qtActGrp is not None:
            toolstb.addSeparator()
            self.qtActGrp.addTo(toolstb)
        
        self.prefAct.addTo(settingstb)
        self.shortcutsAct.addTo(settingstb)
        self.toolsConfAct.addTo(settingstb)
        
        self.whatsThisAct.addTo(helptb)

        self.toolbars = {}
        self.toolbars[0] = (self.trUtf8('File'), filetb)
        self.toolbars[1] = (self.trUtf8('Edit'), edittb)
        self.toolbars[2] = (self.trUtf8('Search'), searchtb)
        self.toolbars[3] = (self.trUtf8('View'), viewtb)
        self.toolbars[4] = (self.trUtf8('Debug'), debugtb)
        self.toolbars[5] = (self.trUtf8('Project'), projecttb)
        self.toolbars[6] = (self.trUtf8('Tools'), toolstb)
        self.toolbars[7] = (self.trUtf8('Help'), helptb)
        self.toolbars[8] = (self.trUtf8('Settings'), settingstb)
        self.toolbars[9] = (self.trUtf8('Scripts'), self.scriptsToolBar)
        self.toolbars[10] = (self.trUtf8('Bookmarks'), bookmarktb)
        Preferences.readToolbarSettings(self, self.toolbars)
        
    def initStatusbar(self):
        """
        Private slot to set up the status bar.
        """
        sb = self.statusBar()

        self.sbWritable = QLabel(sb)
        sb.addWidget(self.sbWritable,0,1)
        QWhatsThis.add(self.sbWritable,self.trUtf8(
            """<p>This part of the status bar displays an indications of the"""
            """ current editors files writability.</p>"""
        ))

        self.sbFile = QLabel(sb)
        sb.addWidget(self.sbFile,0,1)
        QWhatsThis.add(self.sbFile,self.trUtf8(
            """<p>This part of the status bar displays the name of the file of"""
            """ the current editor or of the file containing the"""
            """ Python statement that is about to be executed if a program is"""
            """ currently being debugged.</p>"""
        ))

        self.sbLine = QLabel(sb)
        sb.addWidget(self.sbLine,0,1)
        QWhatsThis.add(self.sbLine,self.trUtf8(
            """<p>This part of the status bar displays the line number of the"""
            """ current editor or the line number of the Python"""
            """ statement that is about to be executed if a program is"""
            """ currently being debugged.</p>"""
        ))

        self.sbPos = QLabel(sb)
        sb.addWidget(self.sbPos,0,1)
        QWhatsThis.add(self.sbPos,self.trUtf8(
            """<p>This part of the status bar displays the cursor position of"""
            """ the current editor. It is blank if there is no current editor or"""
            """ a program is currently being debugged.</p>"""
        ))
            
        self.viewmanager.setSbInfo(self.sbFile, self.sbLine, self.sbPos, self.sbWritable)

    def handleAbout(self):
        """
        Private slot to handle the About dialog.
        """
        QMessageBox.about(self,Program,self.trUtf8(
            """<h3> About %1</h3>"""
            """<p>%1 is an Integrated Development Environment for the Python"""
            """ programming language. It is written using the PyQt Python bindings for"""
            """ the Qt GUI toolkit and the QScintilla editor widget.</p>"""
            """<p>This version is %2.</p>"""
            """<p>For more information see"""
            """ <tt>http://www.die-offenbachs.de/detlev/eric3.html</tt>.</p>"""
            """<p>Please send bug reports or feature wishes to"""
            """ <tt>eric-bugs@die-offenbachs.de</tt>.</p>"""
            """<p>%3</p>"""
            """<p>%4 uses third party software which is copyrighted"""
            """ by its respective copyright holder. For details see"""
            """ the copyright notice of the individual package.</p>"""
            )
            .arg(Program)
            .arg(Program)
            .arg(Version)
            .arg(Copyright)
            .arg(Program)
        )

    def handleAboutQt(self):
        """
        Private slot to handle the About Qt dialog.
        """
        QMessageBox.aboutQt(self,Program)

    def handleVersions(self):
        """
        Private slot to handle the Versions dialog.
        """
        QMessageBox.about(self,Program,self.trUtf8(
            """<h3>Version Numbers</h3>"""
            """<table>"""
            """<tr><td><b>Python</b></td><td>%1</td></tr>"""
            """<tr><td><b>Qt</b></td><td>%2</td></tr>"""
            """<tr><td><b>PyQt</b></td><td>%3</td></tr>"""
            """<tr><td><b>QScintilla</b></td><td>%4</td></tr>"""
            """<tr><td><b>%5</b></td><td>%6</td></tr>"""
            """<tr><td><b>Bicycle Repair Man</b></td><td>%7</td></tr>"""
            """</table>"""
                               )
            .arg(string.split(sys.version)[0])
            .arg(QT_VERSION_STR)
            .arg(PYQT_VERSION_STR)
            .arg(QSCINTILLA_VERSION_STR)
            .arg(Program)
            .arg(Version)
            .arg(BRM_VERSION_STR)
        )
        
    def handleReportBug(self):
        """
        Private slot to handle the Report Bug dialog.
        """
        if Preferences.getUser("Email").isEmpty() or \
           Preferences.getUser("MailServer").isEmpty():
            QMessageBox.critical(None,
                self.trUtf8("Report Bug"),
                self.trUtf8("""Email address or mail server address is empty. 
Please configure your Email settings in the Preferences Dialog."""),
                self.trUtf8("&OK"),
                None,
                None,
                0, -1)
            self.handlePreferences()
            return
            
        self.dlg = EmailDialog()
        self.dlg.show()

    def getViewManager(self):
        """
        Public method to retrieve the viewmanager object.
        
        Returns
        
            reference to the viewmanager object
        """
        return self.viewmanager
        
    def getProject(self):
        """
        Public method to retrieve the project object.
        
        Returns
        
            reference to the project object
        """
        return self.project
        
    def getDebugServer(self):
        """
        Public method to retrieve the debug server object.
        
        Returns
        
            reference to the debug server object
        """
        return self.dbg.dbs
        
    def getDebugger(self):
        """
        Public method to retrieve the debugger object
        
        Returns
        
            reference to the debug UI object
        """
        return self.dbg
        
    def getWizards(self):
        """
        Public method to retrieve the wizards object
        
        Returns
        
            reference to the wizards object
        """
        return self.wizards
        
    def getRefactoring(self):
        """
        Public method to retrieve the refactoring object
        
        Returns
        
            reference to the refactoring object
        """
        return self.refactoring
        
    def getActions(self):
        """
        Public method to get a list of all actions.
        
        Returns
        
            list of all actions (list of QAction)
        """
        actionList = []
        for act in self.queryList("QAction", None, 1, 0):
            if not isinstance(act, QActionGroup) and \
               not isinstance(act, ScriptAction):
                actionList.append(act)
        for act in self.toolsActGrp.queryList("QAction"):
            if not isinstance(act, QActionGroup):
                actionList.append(act)
        if self.qtActGrp is not None:
            for act in self.qtActGrp.queryList("QAction"):
                if not isinstance(act, QActionGroup):
                    actionList.append(act)
                
        return actionList
        
    def handleQuit(self):
        """
        Private method to quit the application.
        """
        if self.shutdown():
            qApp.closeAllWindows()
        
    def handleShowToolsMenu(self):
        """
        Private slot to display the Tools menu.
        """
        self.toolsMenu.clear()
        
        self.toolsMenu.insertTearOffHandle()
        
        # add the fixed entries
        self.toolsActGrp.addTo(self.toolsMenu)
        self.toolsMenu.insertSeparator()
        if self.qtActGrp is not None:
            self.qtActGrp.addTo(self.toolsMenu)
            self.toolsMenu.insertSeparator()
        
        #add the configurable entries
        idx = 0

        for tool in self.toollist:
            id = self.toolsMenu.insertItem(tool[0], self.handleToolExecute)
            self.toolsMenu.setItemParameter(id,idx)
            
            idx = idx + 1
        
    def handleShowWindowMenu(self):
        """
        Private slot to display the Window menu.
        """
        self.windowMenu.clear()

        self.windowMenu.insertTearOffHandle()

        # Set the options according to what is being displayed.
        self.pbAct.addTo(self.windowMenu)
        if self.layout in [2, 3]:
            self.pbAct.setOn(not self.projectBrowserDock.isHidden())
        else:
            self.pbAct.setOn(not self.projectBrowser.isHidden())
        
        self.sbvAct.addTo(self.windowMenu)
        if self.layout in [2, 3]:
            self.sbvAct.setOn(not self.sbvDock.isHidden())
        else:
            self.sbvAct.setOn(not self.sbv.isHidden())
        
        if self.layout in [1, 3]:
            self.shellAct.addTo(self.windowMenu)
            if self.layout == 3:
                self.shellAct.setOn(not self.shellDock.isHidden())
            else:
                self.shellAct.setOn(not self.shell.isHidden())
            
        self.lvAct.addTo(self.windowMenu)
        if self.layout in [2, 3]:
            self.lvAct.setOn(not self.logViewerDock.isHidden())
        else:
            self.lvAct.setOn(not self.logViewer.isHidden())

        # Insert menu entry for toolbar settings
        self.windowMenu.insertSeparator()
        self.windowMenu.insertItem(self.trUtf8('&Toolbars'), self.toolbarsMenu)
        
        # Now do any Source Viewer related stuff.
        self.viewmanager.handleShowWindowMenu(self.windowMenu)
        
    def handleShowToolbarsMenu(self):
        """
        Private slot to display the Toolbars menu.
        """
        self.toolbarsMenu.clear()
        
        for ind, (text, tb) in self.toolbars.items():
            id = self.toolbarsMenu.insertItem(text, self.handleTBMenu)
            self.toolbarsMenu.setItemParameter(id,ind)
            self.toolbarsMenu.setItemChecked(id,not tb.isHidden())
            
        self.toolbarsMenu.insertSeparator()
        self.toolbarsMenu.insertItem(self.trUtf8('Line up'), self.handleLineUpTBs)

    def handleTBMenu(self,idx):
        """
        Private method to handle the toggle of a toolbar.
        """
        dummy, tb = self.toolbars[idx]
        self.toggleWindow(tb)
        
    def handleLineUpTBs(self):
        """
        Private slot to handle the line up toolbars menu entry.
        """
        self.lineUpDockWindows()
        
    def handleProjectBrowser(self):
        """
        Private slot to handle the toggle of the Project Browser window.
        """
        if self.layout in [2, 3]:
            self.toggleWindow(self.projectBrowserDock)
        else:
            self.toggleWindow(self.projectBrowser)

    def handleSBV(self):
        """
        Private slot to handle the toggle of the Shell/Browser/Variables window.
        """
        if self.layout in [2, 3]:
            self.toggleWindow(self.sbvDock)
        else:
            self.toggleWindow(self.sbv)

    def handleShell(self):
        """
        Private slot to handle the toggle of the Shell window .
        """
        if self.layout in [2, 3]:
            self.toggleWindow(self.shellDock)
        else:
            self.toggleWindow(self.shell)

    def handleLogViewer(self):
        """
        Private slot to handle the toggle of the Log Viewer window.
        """
        if self.layout in [2, 3]:
            self.toggleWindow(self.logViewerDock)
        else:
            self.toggleWindow(self.logViewer)

    def toggleWindow(self,w):
        """
        Private method to toggle a workspace editor window.
        """
        if w.isHidden():
            w.show()
        else:
            w.hide()
        
    def handleToolsConfiguration(self):
        """
        Private slot to handle the tools configuration menu entry.
        """
        dlg = ToolConfigurationDialog(self.toollist, self)
        if dlg.exec_loop() == QDialog.Accepted:
            self.toollist = dlg.getToollist()
            
    def handleUnittest(self,prog=None):
        """
        Private slot for displaying the unittest dialog.
        
        Arguments
        
            prog -- the python program to be opened
        """
        if prog:
            self.unittestDialog.insertProg(prog)
        self.unittestDialog.show() 

    def handleDesigner(self,fn=None):
        """
        Private slot to start the Qt-Designer executable.
        
        Arguments
        
            fn -- filename of the form to be opened
        """
        proc = QProcess(self)
        
        designer = os.path.join(self.qtdir, 'bin', 'designer')
        if sys.platform == "win32":
            designer = designer + '.exe'
        proc.addArgument(designer)
        if fn is not None:
            fn = str(fn)
            try:
                if os.path.isfile(fn) and os.path.getsize(fn):
                    proc.addArgument(fn)
                else:
                    QMessageBox.critical(self,
                        self.trUtf8('Problem'),
                        self.trUtf8('The file <b>%1</b> does not exist or is zero length.')
                            .arg(fn))
                    return
            except:
                QMessageBox.critical(self,
                    self.trUtf8('Problem'),
                    self.trUtf8('The file <b>%1</b> does not exist or is zero length.')
                        .arg(fn))
                return
                
        if not proc.start():
            QMessageBox.critical(self,
                self.trUtf8('Process Generation Error'),
                self.trUtf8(
                    'Could not start Qt-Designer.<br>'
                    'Ensure that it is available as <b>%1</b>.'
                ).arg(designer),
                self.trUtf8('OK'))
        
    def handleLinguist(self,fn=None):
        """
        Private slot to start the Qt-Linguist executable.
        
        Arguments
        
            fn -- filename of the translation file to be opened
        """
        proc = QProcess(self)
        
        linguist = os.path.join(self.qtdir, 'bin', 'linguist')
        if sys.platform == "win32":
            linguist = linguist + '.exe'
        proc.addArgument(linguist)
        if fn is not None:
            fn = str(fn)
            try:
                if os.path.isfile(fn) and os.path.getsize(fn):
                    proc.addArgument(fn)
                else:
                    QMessageBox.critical(self,
                        self.trUtf8('Problem'),
                        self.trUtf8('The file <b>%1</b> does not exist or is zero length.')
                            .arg(fn))
                    return
            except:
                QMessageBox.critical(self,
                    self.trUtf8('Problem'),
                    self.trUtf8('The file <b>%1</b> does not exist or is zero length.')
                        .arg(fn))
                return
                
        if not proc.start():
            QMessageBox.critical(self,
                self.trUtf8('Process Generation Error'),
                self.trUtf8(
                    'Could not start Qt-Linguist.<br>'
                    'Ensure that it is available as <b>%1</b>.'
                ).arg(linguist),
                self.trUtf8('OK'))

    def handleAssistant(self):
        """
        Private slot to start the Qt-Assistant executable.
        """
        proc = QProcess(self)
        
        assistant = os.path.join(self.qtdir, 'bin', 'assistant')
        if sys.platform == "win32":
            assistant = assistant + '.exe'
        proc.addArgument(assistant)
        
        if not proc.start():
            QMessageBox.critical(self,
                self.trUtf8('Process Generation Error'),
                self.trUtf8(
                    'Could not start Qt-Assistant.<br>'
                    'Ensure that it is available as <b>%1</b>.'
                ).arg(assistant),
                self.trUtf8('OK'))

    def handleToolExecute(self, idx):
        """
        Private slot to execute a particular tool.
        
        Arguments
        
            idx -- index into the list of configured tools
        """
        proc = QProcess(self)
        proc.addArgument(self.toollist[idx][1])
        argv = Utilities.parseOptionString(self.toollist[idx][2])
        for arg in argv:
            proc.addArgument(arg)
            
        self.connect(proc, SIGNAL('processExited()'), self.handleToolExited)
        if self.toollist[idx][3]:
            proc.setCommunication(QProcess.Stdout | QProcess.Stderr)
            self.connect(proc, SIGNAL('readyReadStdout()'), self.handleToolStdout)
            self.connect(proc, SIGNAL('readyReadStderr()'), self.handleToolStderr)
        else:
            proc.setCommunication(0)
            
        if not proc.start():
            QMessageBox.critical(self,
                self.trUtf8('Process Generation Error'),
                self.trUtf8(
                    'Could not start the tool entry <b>%1</b>.<br>'
                    'Ensure that it is available as <b>%2</b>.')\
                .arg(self.toollist[idx][0])\
                .arg(self.toollist[idx][1]),
                self.trUtf8('OK'))
        else:
            self.toolProcs.append(proc)
        
    def handleToolStdout(self):
        """
        Private slot to handle the readyReadStdout signal of a tool process.
        """
        # loop through all running tool processes
        for toolProc in self.toolProcs:
            if toolProc.canReadLineStdout():
                pl = toolProc.arguments()
                tool = pl[0]
                tool.append(" - ")
                while toolProc.canReadLineStdout():
                    s = QString(tool)
                    s.append(toolProc.readLineStdout())
                    self.emit(PYSIGNAL('appendStdout'), (s,))
        
    def handleToolStderr(self):
        """
        Private slot to handle the readyReadStderr signal of a tool process.
        """
        # loop through all running tool processes
        for toolProc in self.toolProcs:
            if toolProc.canReadLineStderr():
                pl = toolProc.arguments()
                tool = pl[0]
                tool.append(" - ")
                while toolProc.canReadLineStderr():
                    s = QString(tool)
                    s.append(toolProc.readLineStderr())
                    self.emit(PYSIGNAL('appendStderr'), (s,))
            
    def handleToolExited(self):
        """
        Private slot to handle the processExited signal of a tool process.
        """
        exitedProcs = []
        
        # loop through all running tool processes
        for toolProc in self.toolProcs:
            if not toolProc.isRunning():
                exitedProcs.append(toolProc)
                
        # now delete the exited procs from the list of running processes
        for proc in exitedProcs:
            self.toolProcs.remove(proc)
            pl = proc.arguments()
            tool = pl[0]
            t = self.trUtf8("Process '%1' has exited.").arg(tool)
            self.emit(PYSIGNAL('appendStdout'), (t,))
    
    def handlePythonDoc(self):
        """
        Private slot to show the Python documentation.
        """
        home = Utilities.normjoinpath(self.pythonDocDir, 'index.html')
        #
        # On win32 take advantage of default browser
        #
        if sys.platform == "win32":
            os.startfile(home)
            return
      
        self.launchHelpViewer(home)

    def handleQtDoc(self):
        """
        Private slot to show the Qt documentation.
        """
        if self.qtdir is None:
          return

        if Preferences.getHelp("UseQtAssistant"):
            self.handleAssistant()
            return
          
        # use our internal help viewer
        home = Utilities.normjoinpath(self.qtdir, 'doc', 'html', 'index.html')
        self.launchHelpViewer(home)
        
    def handleEricDoc(self):
        """
        Private slot to show the Eric documentation.
        """
        home = Utilities.normjoinpath(os.path.dirname(sys.argv[0]),
            "Documentation", "Source", "index.html")
            
        self.launchHelpViewer(home)
        
    def launchHelpViewer(self, home):
        """
        Private slot to start the help viewer.
        
        Arguments
        
            home -- filename of to be shown
        """
        help = HelpWindow(home, '.', None, 'help viewer', 1)
        help.setCaption(self.trUtf8('Helpviewer'))

        if QApplication.desktop().width() > 400 and \
           QApplication.desktop().height() > 500:
            help.show()
        else:
            help.showMaximized()
    
    def handleHelpViewer(self):
        """
        Private slot to start an empty help viewer.
        """
        self.launchHelpViewer(None)   

    def handlePreferences(self):
        """
        Private slot to set the preferences.
        """
        dlg = PreferencesDialog(self, 'Preferences', 1)
        dlg.exec_loop()
        if dlg.result() == QDialog.Accepted:
            dlg.setPreferences()
            Preferences.syncPreferences()
            self.emit(PYSIGNAL('preferencesChanged'), ())
            
    def handleConfigShortcuts(self):
        """
        Private slot to configure the keyboard shortcuts.
        """
        self.shortcutsDialog.show()
            
    def handleNewProject(self):
        """
        Public slot to handle the NewProject signal.
        """
        self.setWindowCaption(self.project.name)
        
    def handleProjectOpened(self):
        """
        Public slot to handle the projectOpened signal.
        """
        self.setWindowCaption(self.project.name)
        
    def handleProjectClosed(self):
        """
        Public slot to handle the projectClosed signal.
        """
        self.setWindowCaption()

    def handleProgramChange(self,fn):
        """
        Public slot to handle the programChange signal.
        
        This primarily is here to set the currentProg variable.
        """
        # Delete the old program if there was one.
        if self.currentProg is not None:
            del self.currentProg

        self.currentProg = os.path.normpath(fn)
        
    def handleLastEditorClosed(self):
        """
        Public slot to handle the lastEditorClosed signal.
        """
        self.menuBar().setItemEnabled(self.wizardsMenuItem, 0)
        self.scriptsExecDocAct.setEnabled(0)
        
    def handleEditorOpened(self):
        """
        Public slot to handle the editorOpened signal.
        """
        self.menuBar().setItemEnabled(self.wizardsMenuItem, 1)
        self.scriptsExecDocAct.setEnabled(1)
        
    ##########################################################
    ## Below are slots needed by the scripts menu
    ##########################################################
    
    def handleLoadScript(self):
        """
        Private slot to handle the load script menu action.
        """
        dlg = LoadScriptDialog()
        if dlg.exec_loop() == QDialog.Accepted:
            name, fname, execute, delete = dlg.getData()
            if fname == "":
                return      # no file name entered -> ignore the action
                
            if name == "":
                # empty script name -> execute it once and delete it
                execute = 1
                delete = 1
                name = "temp_script"
                
            try:
                f = open(fname)
                code = f.read()
                f.close()
            except IOError, e:
                QMessageBox.critical(self,
                    self.trUtf8('Error loading script'),
                    self.trUtf8('The script file <b>%1</b> could not be loaded.<br>'
                        'Problem: %2')
                        .arg(fname).arg(str(e)))
                return
                
            try:
                self.scriptManager.addScript(name, code)
            except CompilationError, e:
                QMessageBox.critical(self,
                    self.trUtf8('Error loading script'),
                    self.trUtf8('The script file <b>%1</b> could not be loaded.<br>'
                        'Problem: %2')
                        .arg(fname).arg(str(e)))
                return
                
            if execute:
                oldpwd = os.getcwd()
                os.chdir(os.path.dirname(fname))
                try:
                    self.scriptManager.executeScript(name)
                except ExecutionError, e:
                    QMessageBox.critical(self,
                        self.trUtf8('Error loading script'),
                        self.trUtf8('The script file <b>%1</b> could not be loaded.<br>'
                            'Problem: %2')
                            .arg(fname).arg(str(e)))
                    delete = 1
                os.chdir(oldpwd)
                    
            if delete:
                self.scriptManager.deleteScript(name)
    
    def handleDeleteScript(self):
        """
        Public method to delete a script.
        """
        name, ok = self.scriptManager.getScriptName()
        if ok and not name.isEmpty():
            self.scriptManager.deleteScript(name)
    
    def handleExecuteScript(self):
        """
        Public method to execute a script.
        """
        name, ok = self.scriptManager.getScriptName()
        if ok and not name.isEmpty():
            try:
                self.scriptManager.executeScript(name)
            except ExecutionError, e:
                QMessageBox.critical(self,
                    self.trUtf8('Error executing script'),
                    self.trUtf8('The script <b>%1</b> could not be executed.<br>'
                        'Problem: %2')
                        .arg(name).arg(str(e)))
        
    def handleExecuteDocumentAsScript(self):
        """
        Private slot to handle the execute document as script menu action.
        """
        aw = self.viewmanager.activeWindow()
        if aw is None:
            return
            
        code = aw.text()
        name = "temp_script"
        try:
            self.scriptManager.addScript(name, code)
            self.scriptManager.executeScript(name)
            self.scriptManager.deleteScript(name)
        except Error, e:
            QMessageBox.critical(self,
                self.trUtf8('Error executing document'),
                self.trUtf8('The current document could not be executed.<br>'
                    'Problem: %1')
                    .arg(str(e)))
     
    def handleFirstScriptAdded(self):
        """
        Private slot to handle the firstScriptAdded signal
        """
        self.scriptsDeleteAct.setEnabled(1)
        self.scriptsExecAct.setEnabled(1)
        
    def handleLastScriptDeleted(self):
        """
        Private slot to handle the lastScriptDeleted signal
        """
        self.scriptsDeleteAct.setEnabled(0)
        self.scriptsExecAct.setEnabled(0)
    
    ##########################################################
    ## Below are methods needed for shutting down the IDE
    ##########################################################

    def closeEvent(self, event):
        """
        Private event handler for the close event.
        
        This event handler saves the preferences.
        
        Arguments
        
            event -- close event (QCloseEvent)
        """
        if self.shutdown():
            event.accept()
        else:
            event.ignore()

    def shutdown(self):
        """
        Private method to perform all neccessary steps to close down the IDE.
        
        Returns
        
            flag indicating success
        """
        if not self.project.closeProject():
            return 0
        if not self.viewmanager.closeViewManager():
            return 0
        if not self.dbg.shutdownServer():
            return 0
        s = self.geometry()
        p = self.frameGeometry()
        Preferences.setGeometry("MainGeometry", [p.x(),p.y(),s.width(),s.height()])
        if self.layout == 0:
            h = self.hSplitter.sizes()
            v = self.vSplitter.sizes()
            Preferences.setGeometry("MainSplitter0", h + v)
        elif self.layout == 1:
            v = self.vSplitter.sizes()
            h1 = self.hSplitter1.sizes()
            h2 = self.hSplitter2.sizes()
            Preferences.setGeometry("MainSplitter1", v + h1 + h2)
        elif self.layout == 2:
            Preferences.setMainDockLayout(self, 0)
        elif self.layout == 3:
            Preferences.setMainDockLayout(self, 1)

        Preferences.savePreferences()
        Preferences.saveToolbarSettings(self, self.toolbars)
        Preferences.saveToolsMenu(self.toollist)
        return 1
