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

# Copyright (c) 2002 - 2006 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

from UI.E3TabWidget import E3TabWidget

class SBVviewer(E3TabWidget):
    """
    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
        """
        E3TabWidget.__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()
