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

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

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

import sys

from PyQt4.QtCore import Qt, SIGNAL
from PyQt4.QtGui import QApplication, QPalette
from PyQt4.Qsci import QsciScintilla, \
    QSCINTILLA_VERSION as QsciQSCINTILLA_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('2-snapshot'):
        return 0x99999
    else:
        return QsciQSCINTILLA_VERSION
    
#####################################################################################

class QsciScintillaCompat(QsciScintilla):
    """
    Class implementing a compatability interface to QsciScintilla.
    
    This class implements all the functions, that were added to
    QsciScintilla incrementally. This class ensures compatibility
    to older versions of QsciScintilla.
    """
    def __init__(self, parent = None):
        """
        Constructor
        
        @param parent parent widget (QWidget)
        @param name name of this instance (string or QString)
        @param flags window flags
        """
        try:
            QsciScintilla.__init__(self, parent)
        except TypeError:
            print type(parent)
            raise
        
        self.zoom = 0
    
    def setLexer(self, lex = None):
        """
        Public method to set the lexer.
        
        @param lex the lexer to be set or None to reset it.
        """
        QsciScintilla.setLexer(self, lex)
        if lex is None:
            self.clearStyles()
    
    def clearStyles(self):
        """
        Public method to set the styles according the selected Qt style.
        """
        palette = QApplication.palette()
        self.SendScintilla(QsciScintilla.SCI_STYLESETFORE,
            QsciScintilla.STYLE_DEFAULT, palette.color(QPalette.Text))
        self.SendScintilla(QsciScintilla.SCI_STYLESETBACK,
            QsciScintilla.STYLE_DEFAULT, palette.color(QPalette.Base))
        self.SendScintilla(QsciScintilla.SCI_STYLECLEARALL)
        self.SendScintilla(QsciScintilla.SCI_CLEARDOCUMENTSTYLE)
        
        self.setMarginsForegroundColor(palette.color(QPalette.WindowText))
        self.setMarginsBackgroundColor(palette.color(QPalette.Window))
        self.setFoldMarginColors(palette.color(QPalette.Mid),
                                 palette.color(QPalette.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 = str(font.family())
        ps = font.pointSize()
        for style in rangeLow + rangeHigh:
            self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, style, f)
            self.SendScintilla(QsciScintilla.SCI_STYLESETSIZE, style, ps)
    
    def lineAt(self, pos):
        """
        Public method to calculate the line at a position.
        
        This variant is able to calculate the line for positions in the
        margins and for empty lines.
        
        @param pos position to calculate the line for (QPoint)
        @return linenumber at position or -1, if there is no line at pos
            (integer, zero based)
        """
        scipos = self.SendScintilla(QsciScintilla.SCI_POSITIONFROMPOINT, pos.x(), pos.y())
        line = self.SendScintilla(QsciScintilla.SCI_LINEFROMPOSITION, scipos)
        if line >= self.lines():
            line = -1
        return line
    
    def currentPosition(self):
        """
        Public method to get the current position.
        
        @return absolute position of the cursor (integer)
        """
        return self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS)
    
    def styleAt(self, pos):
        """
        Public method to get the style at a position in the text.
        
        @param pos position in the text (integer)
        @return style at the requested position or 0 if the position
            is negative or past the end of the document (integer)
        """
        return self.SendScintilla(QsciScintilla.SCI_GETSTYLEAT, pos)
    
    def currentStyle(self):
        """
        Public method to get the style at the current position.
        
        @return style at the current position (integer)
        """
        return self.styleAt(self.currentPosition())
    
    #####################################################################################
    # methods below are missing from QScintilla
    #####################################################################################

    def zoomIn(self, zoom = 1):
        """
        Public method used to increase the zoom factor.
        
        @param zoom zoom factor increment
        """
        self.zoom += zoom
        QsciScintilla.zoomIn(self, zoom)
    
    def zoomOut(self, zoom = 1):
        """
        Public method used to decrease the zoom factor.
        
        @param zoom zoom factor decrement
        """
        self.zoom -= zoom
        QsciScintilla.zoomOut(self, zoom)
    
    def zoomTo(self, zoom):
        """
        Public method used to zoom to a specific zoom factor.
        
        @param zoom zoom factor
        """
        self.zoom = zoom
        QsciScintilla.zoomTo(self, zoom)
    
    def getZoom(self):
        """
        Public method used to retrieve the current zoom factor.
        
        @return zoom factor (int)
        """
        return self.zoom
    
    def editorCommand(self, cmd):
        """
        Public method to perform a simple editor command.
        
        @param cmd the scintilla command to be performed
        """
        self.SendScintilla(cmd)
    
    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(QsciScintilla.SCI_LINESCROLL, 0, lines)
    
    def moveCursorToEOL(self):
        """
        Public method to move the cursor to the end of line.
        """
        self.SendScintilla(QsciScintilla.SCI_LINEEND)
    
    def moveCursorLeft(self):
        """
        Public method to move the cursor left.
        """
        self.SendScintilla(QsciScintilla.SCI_CHARLEFT)
    
    def moveCursorRight(self):
        """
        Public method to move the cursor right.
        """
        self.SendScintilla(QsciScintilla.SCI_CHARRIGHT)
    
    def moveCursorWordLeft(self):
        """
        Public method to move the cursor left one word.
        """
        self.SendScintilla(QsciScintilla.SCI_WORDLEFT)
    
    def moveCursorWordRight(self):
        """
        Public method to move the cursor right one word.
        """
        self.SendScintilla(QsciScintilla.SCI_WORDRIGHT)
    
    def deleteBack(self):
        """
        Public method to delete the character to the left of the cursor.
        """
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
    
    def delete(self):
        """
        Public method to delete the character to the right of the cursor.
        """
        self.SendScintilla(QsciScintilla.SCI_CLEAR)
    
    def deleteWordLeft(self):
        """
        Public method to delete the word to the left of the cursor.
        """
        self.SendScintilla(QsciScintilla.SCI_DELWORDLEFT)
    
    def deleteWordRight(self):
        """
        Public method to delete the word to the right of the cursor.
        """
        self.SendScintilla(QsciScintilla.SCI_DELWORDRIGHT)
    
    def deleteLineLeft(self):
        """
        Public method to delete the line to the left of the cursor.
        """
        self.SendScintilla(QsciScintilla.SCI_DELLINELEFT)
    
    def deleteLineRight(self):
        """
        Public method to delete the line to the right of the cursor.
        """
        self.SendScintilla(QsciScintilla.SCI_DELLINERIGHT)
    
    def extendSelectionLeft(self):
        """
        Public method to extend the selection one character to the left.
        """
        self.SendScintilla(QsciScintilla.SCI_CHARLEFTEXTEND)
    
    def extendSelectionRight(self):
        """
        Public method to extend the selection one character to the right.
        """
        self.SendScintilla(QsciScintilla.SCI_CHARRIGHTEXTEND)
    
    def extendSelectionWordLeft(self):
        """
        Public method to extend the selection one word to the left.
        """
        self.SendScintilla(QsciScintilla.SCI_WORDLEFTEXTEND)
    
    def extendSelectionWordRight(self):
        """
        Public method to extend the selection one word to the right.
        """
        self.SendScintilla(QsciScintilla.SCI_WORDRIGHTEXTEND)
    
    def extendSelectionToBOL(self):
        """
        Public method to extend the selection to the beginning of the line.
        """
        self.SendScintilla(QsciScintilla.SCI_VCHOMEEXTEND)
    
    def extendSelectionToEOL(self):
        """
        Public method to extend the selection to the end of the line.
        """
        self.SendScintilla(QsciScintilla.SCI_LINEENDEXTEND)
    
    #####################################################################################
    # interface methods to the standard keyboard command set
    #####################################################################################
    
    def clearKeys(self):
        """
        Protected method to clear the key commands.
        """
        # call into the QsciCommandSet
        self.standardCommands().clearKeys()
        
    def clearAlternateKeys(self):
        """
        Protected method to clear the alternate key commands.
        """
        # call into the QsciCommandSet
        self.standardCommands().clearAlternateKeys()
    
##    #####################################################################################
##    # methods below have been added to QScintilla starting with version after 2.x
##    #####################################################################################
##    
##    if "newMethod" not in QsciScintilla.__dict__:
##        def newMethod(self, param):
##            """
##            Public method to do something.
##            
##            @param param parameter for method
##            """
##            pass
##
