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

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

"""
Module implementing a compatability interface class to QextScintilla.
"""

import sys

from qt import Qt, QKeyEvent, QEvent, qApp, SIGNAL
from qtext import QextScintilla, \
    QSCINTILLA_VERSION as QextQSCINTILLA_VERSION, QSCINTILLA_VERSION_STR


def QSCINTILLA_VERSION():
    """
    Module function to return the QScintilla version.
    
    If the installed QScintilla is a snapshot version, then assume it is
    of the latest release and return a version number of 0x99999.
    
    @return QScintilla version (integer)
    """
    if QSCINTILLA_VERSION_STR.startswith('snapshot'):
        return 0x99999
    else:
        return QextQSCINTILLA_VERSION
    
class QextScintillaCompat(QextScintilla):
    """
    Class implementing a compatability interface to QextScintilla.
    
    This class implements all the functions, that were added to
    QextScintilla incrementally. This class ensures compatibility
    to older versions of QextScintilla.
    """
    def __init__(self, parent=None, name=None, flags=0):
        """
        Constructor
        
        @param parent parent widget (QWidget)
        @param name name of this instance (string or QString)
        @param flags window flags
        """
        QextScintilla.__init__(self, parent, name, flags)
        
        # workaround for a bug in version <= 1.5.1
        self._modified = 0
        self.connect(self, SIGNAL('modificationChanged(bool)'), 
                    self._handleModificationChanged)
        
        # workaround for an initialization bug in version <= 1.4
        self.clearStyles()
    
    # workaround for a bug in version <= 1.5.1
    def _handleModificationChanged(self, m):
        """
        Private slot to handle the modificationChanged signal. 
        
        It emits the signal modificationStatusChanged with parameters
        m and self.
        
        @param m modification status
        """
        self._modified = m
        
    def isModified(self):
        """
        Public method to retrieve the modification status.
        
        @return flag indicating the modification status (boolean)
        """
        return self._modified
        
    def setModified(self, m):
        """
        Public method to set the modification status.
        
        @param m flag indicating the new modification status
        """
        self._modified = m
        QextScintilla.setModified(self, m)
    
    # workaround for a bug in setLexer() in version <= 1.4
    def setLexer(self, lex = None):
        """
        Public method to set the lexer.
        
        @param lex the lexer to be set or None to reset it.
        """
        QextScintilla.setLexer(self, lex)
        if lex is None:
            self.clearStyles()
        
    def clearStyles(self):
        """
        Public method to set the styles according the selected Qt style.
        """
        colorGroup = qApp.palette().active()
        self.SendScintilla(QextScintilla.SCI_STYLESETFORE,
            QextScintilla.STYLE_DEFAULT, colorGroup.text())
        self.SendScintilla(QextScintilla.SCI_STYLESETBACK,
            QextScintilla.STYLE_DEFAULT, colorGroup.base())
        self.SendScintilla(QextScintilla.SCI_STYLECLEARALL)
        self.SendScintilla(QextScintilla.SCI_CLEARDOCUMENTSTYLE)
        
        self.setMarginsForegroundColor(colorGroup.foreground())
        self.setMarginsBackgroundColor(colorGroup.background())
        self.setFoldMarginColors(colorGroup.mid(),
                                 colorGroup.mid())
    
    def monospacedStyles(self, font):
        """
        Public method to set the current style to be monospaced.
        
        @param font font to be used (QFont)
        """
        try:
            rangeLow = range(self.STYLE_DEFAULT)
        except AttributeError:
            rangeLow = range(32)
        try:
            rangeHigh = range(self.STYLE_LASTPREDEFINED + 1,
                              self.STYLE_MAX + 1)
        except AttributeError:
            rangeHigh = range(40, 128)
            
        f = font.family().latin1()
        ps = font.pointSize()
        for style in rangeLow + rangeHigh:
            self.SendScintilla(QextScintilla.SCI_STYLESETFONT, style, f)
            self.SendScintilla(QextScintilla.SCI_STYLESETSIZE, style, ps)
        
    #####################################################################################
    # methods below are missing from QScintilla
    #####################################################################################

    def editorCommand(self, cmd):
        """
        Public method to perform a simple editor command.
        
        @param cmd the scintilla command to be performed
        """
        self.SendScintilla(cmd)
        
    def firstVisibleLine(self):
        """
        Public method to get the line number of the first visible line.
        
        @return number of the first visible line (integer)
        """
        return self.SendScintilla(QextScintilla.SCI_GETFIRSTVISIBLELINE)
        
    def textHeight(self):
        """
        Public method to get the text height.
        
        @return text height (integer)
        """
        return self.SendScintilla(QextScintilla.SCI_TEXTHEIGHT, 0)
        
    def scrollVertical(self, lines):
        """
        Public method to scroll the text area.
        
        @param lines number of lines to scroll (negative scrolls up,
            positive scrolls down) (integer)
        """
        self.SendScintilla(QextScintilla.SCI_LINESCROLL, 0, lines)
    
    def moveCursorToEOL(self):
        """
        Public method to move the cursor to the end of line.
        """
        self.SendScintilla(QextScintilla.SCI_LINEEND)
        
    def moveCursorLeft(self):
        """
        Public method to move the cursor left.
        """
        self.SendScintilla(QextScintilla.SCI_CHARLEFT)
        
    def moveCursorRight(self):
        """
        Public method to move the cursor left.
        """
        self.SendScintilla(QextScintilla.SCI_CHARRIGHT)
        
    def deleteLineRight(self):
        """
        Public method to delete the line to the right of the cursor.
        """
        self.SendScintilla(QextScintilla.SCI_DELLINERIGHT)
        
    def deleteBack(self):
        """
        Public method to delete the character to the left of the cursor.
        """
        self.SendScintilla(QextScintilla.SCI_DELETEBACK)
        
    def delete(self):
        """
        Public method to delete the character to the right of the cursor.
        """
        self.SendScintilla(QextScintilla.SCI_CLEAR)
        
    def isAutoCompletionActive(self):
        """
        Public method to check, if autocompletion is active.
        
        @return flag indicating autocompletion active state (boolean)
        """
        return self.SendScintilla(QextScintilla.SCI_AUTOCACTIVE)
        
    def showUserList(self, id, userlist):
        """
        Public method to show a user list.
        
        @param id id of the list to be shown (integer)
        @param userlist list of items to be shown (QStringList)
        """
        liststring = str(userlist.join(' '))
        self.SendScintilla(QextScintilla.SCI_USERLISTSHOW, 1, liststring)
        
    #####################################################################################
    # methods below have been added to QScintilla starting with version after 1.3
    #####################################################################################
    
    if "setEdgeMode" not in QextScintilla.__dict__:
        def setEdgeMode(self, edgeMode):
            """
            Public method to set the edge mode.
            
            @param edgeMode mode to be set
            """
            self.SendScintilla(QextScintilla.SCI_SETEDGEMODE, edgeMode)
            
    if "setEdgeColumn" not in QextScintilla.__dict__:
        def setEdgeColumn(self, column):
            """
            Public method to set the edge column.
            
            @param column column number to be set for the edge mode (integer)
            """
            self.SendScintilla(QextScintilla.SCI_SETEDGECOLUMN, column)
            
    if "setEdgeColor" not in QextScintilla.__dict__:
        def setEdgeColor(self, colour):
            """
            Public method to set the color of the edge mode highlight.
            
            @param colour colour to be set (QColor)
            """
            self.SendScintilla(QextScintilla.SCI_SETEDGECOLOUR, colour)
            
    if "setWrapMode" not in QextScintilla.__dict__:
        def setWrapMode(self, mode):
            """
            Public slot to set the wrap mode of the text display.
            
            @param mode wrap mode (QextScintilla.WrapNone or
                QextScintilla.WrapWord)
            """
            self.SendScintilla(QextScintilla.SCI_SETWRAPMODE, mode)
        
    if "resetSelectionForegroundColor" not in QextScintilla.__dict__:
        def resetSelectionForegroundColor(self):
            """
            Public method to reset the foreground color of the selection.
            """
            self.SendScintilla(QextScintilla.SCI_SETSELFORE, 0)
        
        # compatibility method to correct a bug under win32
        if sys.platform == "win32":
            def keyPressEvent(self, event):
                """
                Workaround for QScintilla <= 1.3 bug w/ keyboard layouts 
                having a AltGr key in win32: 
                AltGr is reported as state == Qt.ControlButton | Qt.AltButton,
                but QScintilla expects (Unix-style) Qt.MetaButton. Just 
                translate states for infected QScintilla versions.
        
                Reimplemented from QextScintilla.keyPressEvent
        
                @param event reference to the key press event (QKeyEvent)
                @author Torsten Marek, 2004-08-22
                """
                if event.state() == Qt.AltButton | Qt.ControlButton:
                    newevent = QKeyEvent(QEvent.KeyPress,
                                         event.key(),
                                         event.ascii(),
                                         Qt.MetaButton,
                                         event.text())
                    event = newevent
                QextScintilla.keyPressEvent(self, event)

    #####################################################################################
    # methods below have been added to QScintilla starting with version after 1.2
    #####################################################################################
    
    if "setSelectionBackgroundColor" not in QextScintilla.__dict__:
        def setSelectionBackgroundColor(self, colour):
            """
            Public method to set the background color of the selection.
            
            @param colour colour to be set (QColor)
            """
            self.SendScintilla(QextScintilla.SCI_SETSELBACK, 1, colour)
            
    if "setSelectionForegroundColor" not in QextScintilla.__dict__:
        def setSelectionForegroundColor(self, colour):
            """
            Public method to set the foreground color of the selection.
            
            @param colour colour to be set (QColor)
            """
            self.SendScintilla(QextScintilla.SCI_SETSELFORE, 1, colour)
            
    if "setCaretForegroundColor" not in QextScintilla.__dict__:
        def setCaretForegroundColor(self, colour):
            """
            Public method to set the foreground color of the caret.
            
            @param colour colour to be set (QColor)
            """
            self.SendScintilla(QextScintilla.SCI_SETCARETFORE, colour)
            
    if "setCaretLineBackgroundColor" not in QextScintilla.__dict__:
        def setCaretLineBackgroundColor(self, colour):
            """
            Public method to set the background color of the caret line.
            
            @param colour colour to be set (QColor)
            """
            self.SendScintilla(QextScintilla.SCI_SETCARETLINEBACK, colour)
            
    if "setCaretLineVisible" not in QextScintilla.__dict__:
        def setCaretLineVisible(self, enable):
            """
            Public method to enable the highlighting of the caret line.
            
            @param enable flag indicating the highlighting state to be set (boolean)
            """
            self.SendScintilla(QextScintilla.SCI_SETCARETLINEVISIBLE, enable)
            
    if "setCaretWidth" not in QextScintilla.__dict__:
        def setCaretWidth(self, width):
            """
            Public method to enable the highlighting of the caret line.
            
            @param width width of the caret (integer - 0, 1, 2 or 3)
            """
            if width < 0:
                width = 0
            elif width > 3:
                width = 3
            self.SendScintilla(QextScintilla.SCI_SETCARETWIDTH, width)
            
    if "recolor" not in QextScintilla.__dict__:
        def recolor(self, start = 0, end = -1):
            """
            Public method to recolor the given region.
            
            @param start linenumber where to start recolourisation (integer)
            @param end linenumber where to end recolourisation (integer)
            """
            self.SendScintilla(QextScintilla.SCI_COLOURISE, start, end)

    #####################################################################################
    # interface methods to the standard keyboard command set
    #####################################################################################
    
    def clearAlternateKeys(self):
        """
        Protected method to clear the alternate key commands.
        """
        if "clearAlternateKeys" not in self.standardCommands().__dict__:
            # clear each alternate key for QScintilla versions <= 1.3
            for cmd in self.standardCommands().commands():
                cmd.setAlternateKey(0)
        else:
            # call into the QextScintillaCommandSet
            self.standardCommands().clearAlternateKeys()
    
