# -*- coding: utf-8 -*-
#
# Copyright © 2009-2010 Pierre Raybaut
# Licensed under the terms of the MIT License
# (see spyderlib/__init__.py for details)

"""Simple web browser widget"""

from spyderlib.qt.QtGui import (QHBoxLayout, QWidget, QVBoxLayout,
                                QProgressBar, QLabel, QMenu)
from spyderlib.qt.QtWebKit import QWebView, QWebPage, QWebSettings
from spyderlib.qt.QtCore import SIGNAL, QUrl

import sys

# Local imports
from spyderlib.utils.qthelpers import (get_icon, create_action, add_actions,
                                       create_toolbutton, action2button)
from spyderlib.baseconfig import DEV, _
from spyderlib.widgets.comboboxes import UrlComboBox
from spyderlib.widgets.findreplace import FindReplace
from spyderlib.py3compat import to_text_string, is_text_string


class WebView(QWebView):
    """Web page"""
    def __init__(self, parent):
        QWebView.__init__(self, parent)
        self.zoom_factor = 1.
        self.zoom_out_action = create_action(self, _("Zoom out"),
                                             icon=get_icon('zoom_out.png'),
                                             triggered=self.zoom_out)
        self.zoom_in_action = create_action(self, _("Zoom in"),
                                            icon=get_icon('zoom_in.png'),
                                            triggered=self.zoom_in)
        
    def find_text(self, text, changed=True,
                  forward=True, case=False, words=False,
                  regexp=False):
        """Find text"""
        findflag = QWebPage.FindWrapsAroundDocument
        if not forward:
            findflag = findflag | QWebPage.FindBackward
        if case:
            findflag = findflag | QWebPage.FindCaseSensitively
        return self.findText(text, findflag)
    
    def get_selected_text(self):
        """Return text selected by current text cursor"""
        return self.selectedText()
        
    def set_font(self, font, fixed_font=None):
        settings = self.page().settings()
        for fontfamily in (settings.StandardFont, settings.SerifFont,
                           settings.SansSerifFont, settings.CursiveFont,
                           settings.FantasyFont):
            settings.setFontFamily(fontfamily, font.family())
        if fixed_font is not None:
            settings.setFontFamily(settings.FixedFont, fixed_font.family())
        size = font.pointSize()
        settings.setFontSize(settings.DefaultFontSize, size)
        settings.setFontSize(settings.DefaultFixedFontSize, size)
        
    def apply_zoom_factor(self):
        """Apply zoom factor"""
        if hasattr(self, 'setZoomFactor'):
            # Assuming Qt >=v4.5
            self.setZoomFactor(self.zoom_factor)
        else:
            # Qt v4.4
            self.setTextSizeMultiplier(self.zoom_factor)
        
    def set_zoom_factor(self, zoom_factor):
        """Set zoom factor"""
        self.zoom_factor = zoom_factor
        self.apply_zoom_factor()
    
    def get_zoom_factor(self):
        """Return zoom factor"""
        return self.zoom_factor
            
    def zoom_out(self):
        """Zoom out"""
        self.zoom_factor = max(.1, self.zoom_factor-.1)
        self.apply_zoom_factor()
    
    def zoom_in(self):
        """Zoom in"""
        self.zoom_factor += .1
        self.apply_zoom_factor()
    
    #------ QWebView API -------------------------------------------------------
    def createWindow(self, webwindowtype):
        import webbrowser
        webbrowser.open(to_text_string(self.url().toString()))
        
    def contextMenuEvent(self, event):
        menu = QMenu(self)
        actions = [self.pageAction(QWebPage.Back),
                   self.pageAction(QWebPage.Forward), None,
                   self.pageAction(QWebPage.SelectAll),
                   self.pageAction(QWebPage.Copy), None,
                   self.zoom_in_action, self.zoom_out_action]
        if DEV:
            settings = self.page().settings()
            settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
            actions += [None, self.pageAction(QWebPage.InspectElement)]
        add_actions(menu, actions)
        menu.popup(event.globalPos())
        event.accept()
                

class WebBrowser(QWidget):
    """
    Web browser widget
    """
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        
        self.home_url = None
        
        self.webview = WebView(self)
        self.connect(self.webview, SIGNAL("loadFinished(bool)"),
                     self.load_finished)
        self.connect(self.webview, SIGNAL("titleChanged(QString)"),
                     self.setWindowTitle)
        self.connect(self.webview, SIGNAL("urlChanged(QUrl)"),
                     self.url_changed)
                
        home_button = create_toolbutton(self, icon=get_icon('home.png'),
                                        tip=_("Home"),
                                        triggered=self.go_home)
        
        zoom_out_button = action2button(self.webview.zoom_out_action)
        zoom_in_button = action2button(self.webview.zoom_in_action)
        
        pageact2btn = lambda prop: action2button(self.webview.pageAction(prop),
                                                 parent=self.webview)
        refresh_button = pageact2btn(QWebPage.Reload)
        stop_button = pageact2btn(QWebPage.Stop)
        previous_button = pageact2btn(QWebPage.Back)
        next_button = pageact2btn(QWebPage.Forward)
        
        stop_button.setEnabled(False)
        self.connect(self.webview, SIGNAL("loadStarted()"),
                     lambda: stop_button.setEnabled(True))
        self.connect(self.webview, SIGNAL("loadFinished(bool)"),
                     lambda: stop_button.setEnabled(False))
        
        progressbar = QProgressBar(self)
        progressbar.setTextVisible(False)
        progressbar.hide()
        self.connect(self.webview, SIGNAL("loadStarted()"), progressbar.show)
        self.connect(self.webview, SIGNAL("loadProgress(int)"),
                     progressbar.setValue)
        self.connect(self.webview, SIGNAL("loadFinished(bool)"),
                     lambda _state: progressbar.hide())
        
        label = QLabel(self.get_label())
        
        self.url_combo = UrlComboBox(self)
        self.connect(self.url_combo, SIGNAL('valid(bool)'),
                     self.url_combo_activated)
        self.connect(self.webview, SIGNAL("iconChanged()"), self.icon_changed)
        
        self.find_widget = FindReplace(self)
        self.find_widget.set_editor(self.webview)
        self.find_widget.hide()

        find_button = create_toolbutton(self, icon='find.png',
                                        tip=_("Find text"),
                                        toggled=self.toggle_find_widget)
        self.connect(self.find_widget, SIGNAL("visibility_changed(bool)"),
                     find_button.setChecked)

        hlayout = QHBoxLayout()
        for widget in (previous_button, next_button, home_button, find_button,
                       label, self.url_combo, zoom_out_button, zoom_in_button,
                       refresh_button, progressbar, stop_button):
            hlayout.addWidget(widget)
        
        layout = QVBoxLayout()
        layout.addLayout(hlayout)
        layout.addWidget(self.webview)
        layout.addWidget(self.find_widget)
        self.setLayout(layout)
                
    def get_label(self):
        """Return address label text"""
        return _("Address:")
            
    def set_home_url(self, text):
        """Set home URL"""
        self.home_url = QUrl(text)
        
    def set_url(self, url):
        """Set current URL"""
        self.url_changed(url)
        self.go_to(url)
        
    def go_to(self, url_or_text):
        """Go to page *address*"""
        if is_text_string(url_or_text):
            url = QUrl(url_or_text)
        else:
            url = url_or_text
        self.webview.load(url)
        
    def go_home(self):
        """Go to home page"""
        if self.home_url is not None:
            self.set_url(self.home_url)
        
    def text_to_url(self, text):
        """Convert text address into QUrl object"""
        return QUrl(text)
        
    def url_combo_activated(self, valid):
        """Load URL from combo box first item"""
        text = to_text_string(self.url_combo.currentText())
        self.go_to(self.text_to_url(text))
        
    def load_finished(self, ok):
        if not ok:
            self.webview.setHtml(_("Unable to load page"))
            
    def url_to_text(self, url):
        """Convert QUrl object to displayed text in combo box"""
        return url.toString()
            
    def url_changed(self, url):
        """Displayed URL has changed -> updating URL combo box"""
        self.url_combo.add_text(self.url_to_text(url))
            
    def icon_changed(self):
        self.url_combo.setItemIcon(self.url_combo.currentIndex(),
                                   self.webview.icon())
        self.setWindowIcon(self.webview.icon())
        
    def toggle_find_widget(self, state):
        if state:
            self.find_widget.show()
        else:
            self.find_widget.hide()


def main():
    """Run web browser"""
    from spyderlib.utils.qthelpers import qapplication
    app = qapplication()
    widget = WebBrowser()
    widget.show()
    widget.set_home_url('http://localhost:7464/')
    widget.go_home()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
