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

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

"""
Module implementing a tab widget conatining a shell, a browser, variables viewers and exception logger.
"""

import os

from qt import *

from QScintilla.Shell import Shell
from Browser import Browser
from Debugger.VariablesViewer import VariablesViewer
from Debugger.ExceptionLogger import ExceptionLogger
from Debugger.BreakPointViewer import BreakPointViewer
from Debugger.WatchPointViewer import WatchPointViewer
import Utilities
import UI.PixmapCache

class SBVviewer(QTabWidget):
    """
    Module implementing tab widget conatining a shell, a browser, variables viewers and exception logger.
    
    The individual tabs contain the Python shell (optional), the filesystem browser,
    the two variables viewers (global and local) and the exception logger in that 
    order.
    
    @signal pythonFile(string, int) emitted to open a Python file at a line
    """
    def __init__(self, dbs, docked, vm, parent=None, 
                 embeddedShell=1, embeddedBrowser=1):
        """
        Constructor
        
        @param dbs reference to the debug server object
        @param docked flag indicating a dock window
        @param vm reference to the viewmanager object
        @param parent parent widget (QWidget)
        @param embeddedShell flag indicating whether the shell should be included.
                This flag is set to 0 by those layouts, that have the Python
                shell in a separate window.
        @param embeddedBrowser flag indicating whether the file browser should
                be included. This flag is set to 0 by those layouts, that
                have the file browser in a separate window or embedded
                in the project browser instead
        """
        QTabWidget.__init__(self, parent)
        
        self.dbs = dbs
        self.dbg = None
        
        self.setIcon(UI.PixmapCache.getPixmap("eric.png"))
        
        self.embeddedShell = embeddedShell
        if embeddedShell:
            # add the python shell
            self.shell = Shell(dbs, vm, self)
            self.addTab(self.shell, 
                QIconSet(UI.PixmapCache.getPixmap("shell.png")), '')
            self.setTabToolTip(self.shell, self.shell.caption())
        
        self.embeddedBrowser = embeddedBrowser
        if embeddedBrowser:
            # add the browser
            self.browser = Browser(self)
            self.addTab(self.browser, 
                QIconSet(UI.PixmapCache.getPixmap("browser.png")), '')
            self.setTabToolTip(self.browser, self.browser.caption())
        
        # add the global variables viewer
        self.glvWidget = QWidget(self)
        glvWidgetVLayout = QVBoxLayout(self.glvWidget,0,3)
        
        self.globalsViewer = VariablesViewer(self.glvWidget, 1)
        glvWidgetVLayout.addWidget(self.globalsViewer)
        
        glvWidgetHLayout = QHBoxLayout(glvWidgetVLayout,3)
        
        self.globalsFilterEdit = QLineEdit(self.glvWidget)
        self.globalsFilterEdit.setSizePolicy(QSizePolicy(\
            QSizePolicy.Ignored,QSizePolicy.Fixed,0,0,
            self.globalsFilterEdit.sizePolicy().hasHeightForWidth()))
        glvWidgetHLayout.addWidget(self.globalsFilterEdit)
        QToolTip.add(self.globalsFilterEdit, 
            self.trUtf8("Enter regular expression patterns separated by ';' to define "
                "variable filters. "))
        QWhatsThis.add(self.globalsFilterEdit, 
            self.trUtf8("Enter regular expression patterns separated by ';' to define "
                "variable filters. All variables and class attributes matched by one of "
                "the expressions are not shown in the list above."))
        
        self.setGlobalsFilterButton = QPushButton(self.trUtf8('Set'), self.glvWidget)
        glvWidgetHLayout.addWidget(self.setGlobalsFilterButton)
        
        self.addTab(self.glvWidget, 
            QIconSet(UI.PixmapCache.getPixmap("globalVariables.png")), '')
        self.setTabToolTip(self.glvWidget, self.globalsViewer.caption())
        
        # add the local variables viewer
        self.lvWidget = QWidget(self)
        lvWidgetVLayout = QVBoxLayout(self.lvWidget,0,3)
        
        lvWidgetHLayout1 = QHBoxLayout(lvWidgetVLayout,3)
        
        self.stackComboBox = QComboBox(0,self.lvWidget)
        self.stackComboBox.setSizePolicy(QSizePolicy(\
            QSizePolicy.Ignored,QSizePolicy.Fixed,0,0,
            self.stackComboBox.sizePolicy().hasHeightForWidth()))
        lvWidgetHLayout1.addWidget(self.stackComboBox)

        self.sourceButton = QPushButton(self.trUtf8('Source'), self.lvWidget)
        lvWidgetHLayout1.addWidget(self.sourceButton)
        self.sourceButton.setEnabled(0)

        self.localsViewer = VariablesViewer(self.lvWidget, 0)
        lvWidgetVLayout.addWidget(self.localsViewer)
        
        lvWidgetHLayout2 = QHBoxLayout(lvWidgetVLayout,3)
        
        self.localsFilterEdit = QLineEdit(self.lvWidget)
        self.localsFilterEdit.setSizePolicy(QSizePolicy(\
            QSizePolicy.Ignored,QSizePolicy.Fixed,0,0,
            self.localsFilterEdit.sizePolicy().hasHeightForWidth()))
        lvWidgetHLayout2.addWidget(self.localsFilterEdit)
        QToolTip.add(self.localsFilterEdit, 
            self.trUtf8("Enter regular expression patterns separated by ';' to define "
                "variable filters. "))
        QWhatsThis.add(self.localsFilterEdit, 
            self.trUtf8("Enter regular expression patterns separated by ';' to define "
                "variable filters. All variables and class attributes matched by one of "
                "the expressions are not shown in the list above."))
        
        self.setLocalsFilterButton = QPushButton(self.trUtf8('Set'), self.lvWidget)
        lvWidgetHLayout2.addWidget(self.setLocalsFilterButton)
        
        self.addTab(self.lvWidget, 
            QIconSet(UI.PixmapCache.getPixmap("localVariables.png")), '')
        self.setTabToolTip(self.lvWidget, self.localsViewer.caption())
        
        self.connect(self.sourceButton, SIGNAL('clicked()'), 
                     self.handleShowSource)
        self.connect(self.stackComboBox, SIGNAL('activated(int)'), 
                     self.handleFrameSelected)
        self.connect(self.setGlobalsFilterButton, SIGNAL('clicked()'),
                     self.handleSetGlobalsFilter)
        self.connect(self.globalsFilterEdit, SIGNAL('returnPressed()'),
                     self.handleSetGlobalsFilter)
        self.connect(self.setLocalsFilterButton, SIGNAL('clicked()'),
                     self.handleSetLocalsFilter)
        self.connect(self.localsFilterEdit, SIGNAL('returnPressed()'),
                     self.handleSetLocalsFilter)
        
        # add the breakpoint viewer
        self.breakpointViewer = BreakPointViewer(self)
        self.addTab(self.breakpointViewer,
            QIconSet(UI.PixmapCache.getPixmap("breakpoints.png")), '')
        self.setTabToolTip(self.breakpointViewer, self.breakpointViewer.caption())
        
        # add the watchpoint viewer
        self.watchpointViewer = WatchPointViewer(self.dbs, self)
        self.addTab(self.watchpointViewer,
            QIconSet(UI.PixmapCache.getPixmap("watchpoints.png")), '')
        self.setTabToolTip(self.watchpointViewer, self.watchpointViewer.caption())
        self.dbs.setWatchpointViewer(self.watchpointViewer)
        
        # add the exception logger
        self.exceptionLogger = ExceptionLogger(self)
        self.addTab(self.exceptionLogger, 
            QIconSet(UI.PixmapCache.getPixmap("exceptions.png")), '')
        self.setTabToolTip(self.exceptionLogger, self.exceptionLogger.caption())
        
        if self.embeddedShell:
            self.showPage(self.shell)
        else:
            if self.embeddedBrowser:
                self.showPage(self.browser)
            else:
                self.showPage(self.lvWidget)
            
        self.currPage = None
        self.clientWD = ""
        self.currentStack = None
        self.framenr = 0
        
    def showEvent(self, evt):
        """
        Protected slot called when this widget is being shown.
        
        @param evt the event (QShowEvent)
        """
        self.breakpointViewer.showEvent(evt)
        
    def setDebugger(self, dbg):
        """
        Public method to set a reference to the Debug UI.
        
        @param dbg reference to the DebugUI objectTrees
        """
        self.dbg = dbg
        self.breakpointViewer.setDebugger(dbg)
        
    def handleResetUI(self):
        """
        Public method to reset the SBVviewer.
        """
        self.globalsViewer.handleResetUI()
        self.localsViewer.handleResetUI()
        self.stackComboBox.clear()
        self.sourceButton.setEnabled(0)
        self.clientWD = ""
        self.currentStack = None
        if self.embeddedShell:
            self.showPage(self.shell)
        else:
            if self.embeddedBrowser:
                self.showPage(self.browser)
            else:
                self.showPage(self.lvWidget)
        self.breakpointViewer.handleResetUI()
        
    def handleRawInput(self):
        """
        Pulic slot to handle the switch to the shell in raw input mode.
        """
        if self.embeddedShell:
            self.saveCurrentPage()
            self.showPage(self.shell)
            
    def showVariables(self, vlist, globals):
        """
        Public method to show the variables in the respective window.
        
        @param vlist list of variables to display
        @param globals flag indicating global/local state
        """
        if globals:
            self.globalsViewer.showVariables(vlist, self.framenr)
        else:
            self.localsViewer.showVariables(vlist, self.framenr)
            
    def showVariable(self, vlist, globals):
        """
        Public method to show the variables in the respective window.
        
        @param vlist list of variables to display
        @param globals flag indicating global/local state
        """
        if globals:
            self.globalsViewer.showVariable(vlist)
        else:
            self.localsViewer.showVariable(vlist)
            
    def showVariablesTab(self, globals):
        """
        Public method to make a variables tab visible.
        
        @param globals flag indicating global/local state
        """
        if globals:
            self.showPage(self.globalsViewer)
        else:
            self.showPage(self.lvWidget)
        
    def saveCurrentPage(self):
        """
        Public slot to save the current page.
        """
        self.currPage = self.currentPage()
        
    def restoreCurrentPage(self):
        """
        Public slot to restore the previously saved page.
        """
        if self.currPage is not None:
            self.showPage(self.currPage)
            
    def handleClientStack(self, stack):
        """
        Public slot to show the call stack of the program being debugged.
        """
        self.framenr = 0
        self.stackComboBox.clear()
        self.currentStack = stack
        self.sourceButton.setEnabled(len(stack))
        for s in stack:
            # just show base filename to make it readable
            s = (os.path.basename(s[0]), s[1], s[2])
            self.stackComboBox.insertItem('%s:%s:%s' % s)
            
    def setWD(self, wd):
        """
        Public slot to set the working directory of the program being debugged.
        
        @param wd working directory (string)
        """
        self.clientWD = wd
        
    def setVariablesFilter(self, globalsFilter, localsFilter):
        """
        Public slot to set the local variables filter.
        
        @param globalsFilter filter list for global variable types (list of int)
        @param localsFilter filter list for local variable types (list of int)
        """
        self.globalsFilter = globalsFilter
        self.localsFilter = localsFilter
        
    def handleShowSource(self):
        """
        Private slot to handle the source button press to show the selected file.
        """
        s = self.currentStack[self.stackComboBox.currentItem()]
        self.emit(PYSIGNAL('pythonFile'),(s[0], int(s[1])))
        
    def handleFrameSelected(self, frmnr):
        """
        Private slot to handle the selection of a new stack frame number.
        
        @param frmnr frame number (0 is the current frame) (int)
        """
        self.framenr = frmnr
        self.dbs.remoteClientVariables(0, self.localsFilter, frmnr)
        
    def handleSetGlobalsFilter(self):
        """
        Private slot to set the global variable filter
        """
        filter = unicode(self.globalsFilterEdit.text())
        self.dbs.remoteClientSetFilter(1, filter)
        if self.currentStack:
            self.dbs.remoteClientVariables(2, self.globalsFilter)
        
    def handleSetLocalsFilter(self):
        """
        Private slot to set the local variable filter
        """
        filter = unicode(self.localsFilterEdit.text())
        self.dbs.remoteClientSetFilter(0, filter)
        if self.currentStack:
            self.dbs.remoteClientVariables(0, self.localsFilter, self.framenr)
        
    def handleDebuggingStarted(self):
        """
        Public slot to handle the start of a debugging session.
        
        This slot sets the variables filter expressions.
        """
        self.handleSetGlobalsFilter()
        self.handleSetLocalsFilter()
