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

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

"""
Module implementing the helpbrowser.
"""

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from KdeQt import KQMessageBox

import Preferences

class HelpBrowser(QTextBrowser):
    """
    Class implementing the helpbrowser widget.
    
    This is a subclass of the Qt QTextBrowser to implement a
    custimized setSource method. The implementation was
    influenced by Qt Assistant, which is copyright by Trolltech AS.
    """
    def __init__(self, parent = None, name = QString("")):
        """
        Constructor
        
        @param parent parent widget of this window (QWidget)
        @param name name of this window (string or QString)
        """
        QTextBrowser.__init__(self, parent)
        self.setObjectName(name)
        self.setWhatsThis(self.trUtf8(
                """<b>Help Window</b>"""
                """<p>This window displays the selected help information."""
                """ Only local HTML help files will be displayed."""
                """ All other recognized help files will be shown in"""
                """ an external viewer.</p>"""
        ))
        
        self.mw = parent
        self.lastAnchor = QString()
        self.ctrlPressed = False
        
    def setSource(self, name):
        """
        Public method used to set the source to be displayed.
        
        This method is overridden from QTextBrowser.
        
        @param name filename to be shown (QUrl)
        """
        if not name.isValid():
            return
        
        if not name.scheme().isEmpty() and \
           not (name.scheme().length() == 1 or \
                name.scheme() == "file"):
            started = QDesktopServices.openUrl(name)
            if not started:
                KQMessageBox.critical(self,
                    self.trUtf8("Helpviewer"),
                    self.trUtf8("""<p>Could not start a viewer"""
                    """ for URL <b>%1</b>.</p>""").arg(name.toString()))
            return
        
        if self.ctrlPressed:
            # open in a new window
            self.mw.newTab(name)
            self.ctrlPressed = False
            return
        
        if not name.scheme().isEmpty() and \
           name.scheme().length() == 1:
                # it is a local path on win32 os
                name = QUrl.fromLocalFile(name.toString())
        
        if not QFileInfo(name.toLocalFile()).exists():
            QMessageBox.critical(None,
                self.trUtf8("Helpviewer"),
                self.trUtf8("""<p>The file <b>%1</b> does not exist.</p>""")\
                    .arg(name.toLocalFile()),
                QMessageBox.StandardButtons(\
                    QMessageBox.Ok))
            return

        if name.toLocalFile().endsWith(".pdf") or \
           name.toLocalFile().endsWith(".PDF") or \
           name.toLocalFile().endsWith(".chm") or \
           name.toLocalFile().endsWith(".CHM"):
            started = QDesktopServices.openUrl(name)
            if not started:
                KQMessageBox.critical(self,
                    self.trUtf8("Helpviewer"),
                    self.trUtf8("""<p>Could not start a viewer"""
                    """ for file <b>%1</b>.</p>""").arg(name.path()))
            return
        
        # now show it
        QTextBrowser.setSource(self, name)

    def contextMenuEvent(self, evt):
        """
        Protected method called to create a context menu.
        
        This method is overridden from QTextBrowser.
        
        @param evt reference to the context menu event object (QContextMenuEvent)
        """
        pos = evt.pos()
        menu = QMenu(self)
        
        self.lastAnchor = self.anchorAt(pos)
        if not self.lastAnchor.isEmpty():
            self.lastAnchor = self.source().resolved(QUrl(self.lastAnchor)).toString()
            if self.lastAnchor.at(0) == '#':
                src = self.source().toString()
                hsh = src.indexOf('#')
                self.lastAnchor = (hsh >= 0 and src.left(hsh) or src) + self.lastAnchor
            
            menu.addAction(self.trUtf8("Open Link in New Tab\tCtrl+LMB"),
                self.__openLinkInNewTab)
        
        menu.addAction(self.mw.newTabAct)
        menu.addAction(self.mw.newAct)
        menu.addSeparator()
        menu.addAction(self.mw.backAct)
        menu.addAction(self.mw.forwardAct)
        menu.addAction(self.mw.homeAct)
        menu.addSeparator()
        menu.addAction(self.mw.zoomInAct)
        menu.addAction(self.mw.zoomOutAct)
        menu.addSeparator()
        menu.addAction(self.mw.copyAct)
        menu.addAction(self.mw.findAct)
        
        menu.exec_(evt.globalPos())
        
    def __openLinkInNewTab(self):
        """
        Private method called by the context menu to open a link in a new window.
        """
        if self.lastAnchor.isEmpty():
            return
            
        oldCtrlPressed = self.ctrlPressed
        self.ctrlPressed = True
        self.setSource(QUrl(self.lastAnchor))
        self.ctrlPressed = oldCtrlPressed
        
    def keyPressEvent(self, evt):
        """
        Protected method called by a key press.
        
        This method is overridden from QTextBrowser.
        
        @param evt the key event (QKeyEvent)
        """
        self.ctrlPressed = (evt.key() == Qt.Key_Control)
        QTextBrowser.keyPressEvent(self, evt)
        
    def keyReleaseEvent(self, evt):
        """
        Protected method called by a key release.
        
        This method is overridden from QTextBrowser.
        
        @param evt the key event (QKeyEvent)
        """
        self.ctrlPressed = False
        QTextBrowser.keyReleaseEvent(self, evt)
        
    def hasSelection(self):
        """
        Public method to determine, if there is some text selected.
        
        @return flag indicating text has been selected (boolean)
        """
        return self.textCursor().hasSelection()
        
    def selectedText(self):
        """
        Public method to get the selected text.
        
        @return selected text (QString)
        """
        return self.textCursor().selectedText()
        
    def findNextPrev(self, txt, case, word, backwards):
        """
        Public slot to find the next occurrence of a text.
        
        @param txt text to search for (QString)
        @param case flag indicating a case sensitive search (boolean)
        @param word flag indicating a word based search (boolean)
        @param backwards flag indicating a backwards search (boolean)
        """
        doc = self.document()
        cur = self.textCursor()
        
        findFlags = QTextDocument.FindFlags()
        if case:
            findFlags |= QTextDocument.FindCaseSensitively
        if word:
            findFlags |= QTextDocument.FindWholeWords
        if backwards:
            findFlags |= QTextDocument.FindBackward
        
        if cur.hasSelection():
            cur.setPosition(backwards and cur.anchor() or cur.position(), 
                            QTextCursor.MoveAnchor)
        newCur = doc.find(txt, cur, findFlags)
        if newCur.isNull():
            return False
        else:
            self.setTextCursor(newCur)
            return True
        
    def supportsSearchWholeWord(self):
        """
        Public method to determine, if a word based search is supported.
        
        @return flag indicating support for word based search (boolean)
        """
        return True
