コード例 #1
0
class Browser(QWidget):
    """LilyPond documentation browser widget."""
    def __init__(self, dockwidget):
        super(Browser, self).__init__(dockwidget)

        layout = QVBoxLayout(spacing=0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.toolbar = tb = QToolBar()
        self.webview = QWebEngineView(self,
                                      contextMenuPolicy=Qt.CustomContextMenu)
        self.webview.setPage(WebEnginePage(self.webview))
        self.chooser = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents)
        self.search = SearchEntry(maximumWidth=200, clearButtonEnabled=True)

        layout.addWidget(self.toolbar)
        layout.addWidget(self.webview)

        ac = dockwidget.actionCollection
        ac.help_back.triggered.connect(self.webview.back)
        ac.help_forward.triggered.connect(self.webview.forward)
        ac.help_home.triggered.connect(self.showHomePage)
        ac.help_print.triggered.connect(self.slotPrint)

        self.webview.urlChanged.connect(self.slotUrlChanged)
        self.webview.customContextMenuRequested.connect(
            self.slotShowContextMenu)

        tb.addAction(ac.help_back)
        tb.addAction(ac.help_forward)
        tb.addSeparator()
        tb.addAction(ac.help_home)
        tb.addAction(ac.help_print)
        tb.addSeparator()
        tb.addWidget(self.chooser)
        tb.addWidget(self.search)

        self.chooser.activated[int].connect(self.showHomePage)
        self.search.textChanged.connect(self.slotSearchChanged)
        self.search.returnPressed.connect(self.slotSearchReturnPressed)
        dockwidget.mainwindow().iconSizeChanged.connect(
            self.updateToolBarSettings)
        dockwidget.mainwindow().toolButtonStyleChanged.connect(
            self.updateToolBarSettings)

        app.settingsChanged.connect(self.readSettings)
        self.readSettings()
        self.loadDocumentation()
        self.showInitialPage()
        app.settingsChanged.connect(self.loadDocumentation)
        app.translateUI(self)

    def readSettings(self):
        s = QSettings()
        s.beginGroup("documentation")
        ws = self.webview.page().settings()
        family = s.value("fontfamily", self.font().family(), str)
        size = s.value("fontsize", 16, int)
        ws.setFontFamily(QWebEngineSettings.StandardFont, family)
        ws.setFontSize(QWebEngineSettings.DefaultFontSize, size)
        fixed = textformats.formatData('editor').font
        ws.setFontFamily(QWebEngineSettings.FixedFont, fixed.family())
        ws.setFontSize(QWebEngineSettings.DefaultFixedFontSize,
                       int(fixed.pointSizeF() * 96 / 72))
        self.webview.page().profile().setHttpAcceptLanguage(','.join(
            lilydoc.network.langs()))

    def keyPressEvent(self, ev):
        if ev.text() == "/":
            self.search.setFocus()
        else:
            super(Browser, self).keyPressEvent(ev)

    def translateUI(self):
        try:
            self.search.setPlaceholderText(_("Search..."))
        except AttributeError:
            pass  # not in Qt 4.6

    def showInitialPage(self):
        """Shows the preferred start page.

        If a local documentation instance already has a suitable version,
        just loads it. Otherwise connects to the allLoaded signal, that is
        emitted when all the documentation instances have loaded their version
        information and then shows the start page (if another page wasn't yet
        loaded).

        """
        if self.webview.url().isEmpty():
            docs = lilydoc.manager.docs()
            version = lilypondinfo.preferred().version()
            index = -1
            if version:
                for num, doc in enumerate(docs):
                    if doc.version() is not None and doc.version() >= version:
                        index = num  # a suitable documentation is found
                        break
            if index == -1:
                # nothing found (or LilyPond version not available),
                # wait for loading or show the most recent version
                if not lilydoc.manager.loaded():
                    lilydoc.manager.allLoaded.connect(self.showInitialPage)
                    return
                index = len(docs) - 1
            self.chooser.setCurrentIndex(index)
            self.showHomePage()

    def loadDocumentation(self):
        """Puts the available documentation instances in the combobox."""
        i = self.chooser.currentIndex()
        self.chooser.clear()
        for doc in lilydoc.manager.docs():
            v = doc.versionString()
            if doc.isLocal():
                t = _("(local)")
            else:
                t = _("({hostname})").format(hostname=doc.url().host())
            self.chooser.addItem("{0} {1}".format(v or _("<unknown>"), t))
        self.chooser.setCurrentIndex(i)
        if not lilydoc.manager.loaded():
            lilydoc.manager.allLoaded.connect(self.loadDocumentation, -1)
            return

    def updateToolBarSettings(self):
        mainwin = self.parentWidget().mainwindow()
        self.toolbar.setIconSize(mainwin.iconSize())
        self.toolbar.setToolButtonStyle(mainwin.toolButtonStyle())

    def showManual(self):
        """Invoked when the user presses F1."""
        self.slotHomeFrescobaldi()  # TEMP

    def slotUrlChanged(self):
        ac = self.parentWidget().actionCollection
        ac.help_back.setEnabled(self.webview.history().canGoBack())
        ac.help_forward.setEnabled(self.webview.history().canGoForward())

    def openUrl(self, url):
        if url.path().endswith(('.ily', '.lyi', '.ly')):
            self.sourceViewer().showReply(lilydoc.network.get(url))
        else:
            self.webview.load(url)

    def slotUnsupported(self, reply):
        helpers.openUrl(reply.url())

    def slotSearchChanged(self):
        text = self.search.text()
        if not text.startswith(':'):
            self.webview.page().findText(text)

    def slotSearchReturnPressed(self):
        text = self.search.text()
        if not text.startswith(':'):
            self.slotSearchChanged()
        else:
            pass  # TODO: implement full doc search

    def sourceViewer(self):
        try:
            return self._sourceviewer
        except AttributeError:
            from . import sourceviewer
            self._sourceviewer = sourceviewer.SourceViewer(self)
            return self._sourceviewer

    def showHomePage(self):
        """Shows the homepage of the LilyPond documentation."""
        i = self.chooser.currentIndex()
        if i < 0:
            i = 0
        doc = lilydoc.manager.docs()[i]

        url = doc.home()
        if doc.isLocal():
            path = url.toLocalFile()
            langs = lilydoc.network.langs()
            if langs:
                for lang in langs:
                    if os.path.exists(path + '.' + lang + '.html'):
                        path += '.' + lang
                        break
            url = QUrl.fromLocalFile(path + '.html')
        self.webview.load(url)

    def slotPrint(self):
        printer = self._printer = QPrinter()
        dlg = QPrintDialog(printer, self)
        dlg.setWindowTitle(app.caption(_("Print")))
        if dlg.exec_():
            self.webview.page().print(printer, self.slotPrintingDone)

    def slotPrintingDone(self, success):
        del self._printer

    def slotShowContextMenu(self, pos):
        d = self.webview.page().contextMenuData()
        menu = QMenu()
        if d.linkUrl().isValid():
            a = self.webview.pageAction(QWebEnginePage.CopyLinkToClipboard)
            a.setIcon(icons.get("edit-copy"))
            a.setText(_("Copy &Link"))
            menu.addAction(a)
            menu.addSeparator()
            a = menu.addAction(icons.get("window-new"),
                               _("Open Link in &New Window"))
            a.triggered.connect(
                (lambda url: lambda: self.slotNewWindow(url))(d.linkUrl()))
        else:
            if d.selectedText():
                a = self.webview.pageAction(QWebEnginePage.Copy)
                a.setIcon(icons.get("edit-copy"))
                a.setText(_("&Copy"))
                menu.addAction(a)
                menu.addSeparator()
            a = menu.addAction(icons.get("window-new"),
                               _("Open Document in &New Window"))
            a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(
                self.webview.url()))
        if menu.actions():
            menu.exec_(self.webview.mapToGlobal(pos))

    def slotNewWindow(self, url):
        helpers.openUrl(url)
コード例 #2
0
class Example(QMainWindow):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()


    def initUI(self):

        self.toolBar = QToolBar(self)
        self.addToolBar(self.toolBar)

        self.backBtn = QPushButton(self)
        self.backBtn.setEnabled(False)

        self.backBtn.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/left-32.png'))
        self.backBtn.clicked.connect(self.back)
        self.toolBar.addWidget(self.backBtn)

        self.forBtn = QPushButton(self)
        self.forBtn.setEnabled(False)
        self.forBtn.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/right-32.png'))

        self.forBtn.clicked.connect(self.forward)
        self.toolBar.addWidget(self.forBtn)

        self.address = QLineEdit(self)
        self.address.returnPressed.connect(self.load)
        self.toolBar.addWidget(self.address)

        self.webEngineView = QWebEngineView(self)
        self.setCentralWidget(self.webEngineView)

        self.webEngineView.page().urlChanged.connect(self.onLoadFinished)

        self.webEngineView.page().titleChanged.connect(self.setWindowTitle)
        self.webEngineView.page().urlChanged.connect(self.urlChanged)

        self.setGeometry(300, 300, 500, 400)
        self.setWindowTitle('QWebEnginePage')
        self.show()

    def onLoadFinished(self):

        if self.webEngineView.history().canGoBack():
            self.backBtn.setEnabled(True)
        else:
            self.backBtn.setEnabled(False)

        if self.webEngineView.history().canGoForward():
            self.forBtn.setEnabled(True)
        else:
            self.forBtn.setEnabled(False)


    def load(self):

        url = QUrl.fromUserInput(self.address.text())

        if url.isValid():
            self.webEngineView.load(url)

    def back(self):
        self.webEngineView.page().triggerAction(QWebEnginePage.Back)

    def forward(self):
        self.webEngineView.page().triggerAction(QWebEnginePage.Forward)

    def urlChanged(self, url):
        self.address.setText(url.toString())
コード例 #3
0
class QmMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.actionShow.triggered.connect(self.toggle_mode)
        self.ui.actionSave.triggered.connect(self.save_note)
        self.ui.actionLoadShelf.triggered.connect(self.download_shelf)
        self.ui.actionLoadHot.triggered.connect(self.show_hot_note)
        self.ui.actionLoadNotes.triggered.connect(self.download_notes)
        self.ui.statusBar.hide()
        self.pbar = QProgressBar(self)
        self.pbar.setFixedWidth(500)
        self.ui.statusBar.addWidget(self.pbar)
        icon = QtGui.QIcon()
        icon.addPixmap(
            QtGui.QPixmap(os.path.join(root_path, "static/icon.png")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.setWindowIcon(icon)

        self.browser = QWebEngineView(self)
        self.browser.setGeometry(
            0,
            self.ui.menubar.height(),
            self.width(),
            self.height() - self.ui.menubar.height(),
        )
        self.ui.actionback.triggered.connect(self.browser.back)
        self.ui.actionforward.triggered.connect(self.browser.forward)
        self.ui.actionShelf.triggered.connect(self.view_shelf)
        self.ui.actionLibrary.triggered.connect(self.view_library)

        # 加载外部的web页面
        self.cache_path = os.path.join(root_path, "cache")
        if not os.path.exists(self.cache_path):
            os.mkdir(self.cache_path)

        # 设置缓存目录
        default_profile = QWebEngineProfile.defaultProfile()
        default_profile.setCachePath(self.cache_path)
        default_profile.setPersistentStoragePath(self.cache_path)

        # 记录上次阅读位置
        self.history_url_file = os.path.join(self.cache_path,"history.txt")
        if not os.path.exists(self.history_url_file):
            url = QUrl("https://weread.qq.com/")
        else:
            with open(self.history_url_file,'r') as f:
                url = QUrl(f.read().strip())

        self.browser.urlChanged.connect(self.update_lastpage) # 每次改变都更新还是退出的时候更新

        self.browser.load(url)
        self.model = QStringListModel(self)
        self.item_model = QStandardItemModel(self)
        self.select_model = QItemSelectionModel(self.item_model)
        self.ui.tableView.setModel(self.item_model)
        self.ui.tableView.setSelectionModel(self.select_model)
        self.ui.tableView.setAlternatingRowColors(True)
        self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.is_reading_mode = True
        self.note_dir = os.path.join(root_path, "notes")
        if not os.path.exists(self.note_dir):
            os.mkdir(self.note_dir)

        try:
            self.update_cookies()
            self.booklist = wereader.get_bookshelf(self.cookies)
            self.books = itertools.cycle(self.booklist)
            self.curBook = self.booklist[0]
        except Exception:
            self.curBook = None
            self.booklist = None

    def update_cookies(self):
        self.cookies = read_cookie_from_path(self.cache_path + "/Cookies")

    def update_lastpage(self):
        with open(self.history_url_file,'w') as f:
            f.write(self.browser.history().currentItem().url().toString())

    def resizeEvent(self, a0):
        self.browser.resize(
            self.width(),
            self.height() - self.ui.menubar.height(),
        )
        self.ui.splitter_2.resize(
            self.width() - 10,
            self.height() - self.ui.menubar.height(),
        )

        self.ui.tableView.resize(
            self.ui.splitter.width(), self.ui.splitter.height() // 2
        )

    def on_listView_clicked(self, index):
        self.curBook = self.booklist[index.row()]
        self.on_curBook_changed()

    def on_tableView_clicked(self, index):
        self.curBook = self.booklist[index.row()]
        self.on_curBook_changed()

    def on_curBook_changed(self):
        self.ui.noteEdit.clear()
        note = self.get_note(self.curBook.bookId)
        self.ui.noteEdit.setText(note)

    def show_hot_note(self):
        self.ui.noteEdit.clear()
        note = self.get_hot_note(self.curBook.bookId)
        self.ui.noteEdit.setText(note)

    def get_note(self, id):
        note_name = os.path.join(self.note_dir, "%s.md" % id)
        if os.path.exists(note_name):
            with open(note_name, "r", encoding="utf-8") as f:
                return f.read()
        else:
            return wereader.get_bookmarklist(id, cookies=self.cookies)

    def get_hot_note(self, id):
        note_name = os.path.join(self.note_dir, "%s_hot.md" % id)
        if os.path.exists(note_name):
            with open(note_name, "r", encoding="utf-8") as f:
                return f.read()
        else:
            return wereader.get_bestbookmarks(id, cookies=self.cookies)

    def on_nextButton_clicked(self):
        self.curBook = next(self.books)
        self.on_curBook_changed()

    def save_note(self):
        text = self.ui.noteEdit.toPlainText()
        note_name = os.path.join(self.note_dir, "%s.md" % self.curBook.bookId)
        with open(note_name, "w", encoding="utf-8") as f:
            f.write(text)

    def toggle_mode(self):
        if self.is_reading_mode:
            self.browser.setVisible(False)
            self.ui.actionShow.setText("切换至阅读模式")
            self.is_reading_mode = False
        else:
            self.browser.setVisible(True)
            self.ui.actionShow.setText("切换至笔记模式")
            self.is_reading_mode = True

    def download_shelf(self):
        """加载书架时默认已经登录,重新获取cookie"""
        if not self.booklist:
            self.update_cookies()
            self.booklist = wereader.get_bookshelf(self.cookies)
            self.books = itertools.cycle(self.booklist)
        self.init_model()

    def init_model(self):
        self.model.setStringList([b.title for b in self.booklist])
        self.ui.listView.setModel(self.model)
        self.ui.listView.setEditTriggers(QAbstractItemView.NoEditTriggers)

        rows = len(self.booklist)
        cols = 3
        self.item_model.setRowCount(rows)
        self.item_model.setColumnCount(cols)
        for i in range(rows):
            try:
                self.item_model.setItem(i, 0,
                                        QStandardItem(self.booklist[i].bookId))
                self.item_model.setItem(i, 1,
                                        QStandardItem(self.booklist[i].title))
                self.item_model.setItem(i, 2,
                                        QStandardItem(self.booklist[i].author))
            except Exception as e:
                print(e)
        self.ui.tableView.setModel(self.item_model)
        w = self.ui.splitter.width() // 10
        self.ui.tableView.setColumnWidth(0, 1 * w)
        self.ui.tableView.setColumnWidth(1, 6 * w)
        self.ui.tableView.setColumnWidth(2, 3 * w)
        self.ui.tableView.setSelectionModel(self.select_model)

    # def view(self):
    #     img = cv2.imread(next(self.images))  # 读取图像
    #     img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换图像通道
    #     w, h = self.ui.graphicsView.width(), self.ui.graphicsView.height()
    #     img = cv2.resize(img, (w, h))
    #     frame = QImage(img, w, h, QImage.Format_RGB888)
    #     pix = QPixmap.fromImage(frame)
    #     self.item = QGraphicsPixmapItem(pix)  # 创建像素图元
    #     # self.item.setScale(self.zoomscale)
    #     self.scene = QGraphicsScene()  # 创建场景
    #     self.scene.addItem(self.item)
    #     self.ui.graphicsView.setScene(self.scene)  # 将场景添加至视图

    def download_notes(self):
        self.ui.actionLoadNotes.setDisabled(True)
        self.ui.statusBar.show()
        self.pbar.show()
        self.pbar.setMaximum(len(self.booklist))
        for i, book in enumerate(self.booklist):
            self.pbar.setValue(i)
            try:
                note_name = os.path.join(self.note_dir, "%s.md" % book.bookId)
                if os.path.exists(note_name):
                    continue
                note = self.get_note(book.bookId)
                if note.strip():
                    with open(note_name, 'w', encoding='utf-8') as f:
                        f.write(note)
            except Exception as e:
                print(e)

        self.pbar.hide()
        self.ui.statusBar.hide()

    def view_library(self):
        self.browser.load(QUrl("https://weread.qq.com/web/category"))

    def view_shelf(self):
        self.browser.load(QUrl("https://weread.qq.com/web/shelf"))
コード例 #4
0
ファイル: browser.py プロジェクト: GalaxyGroot/anki-plugins
class AwBrowser(QDialog):
    """
        Customization and configuration of a web browser to run within Anki
    """

    SINGLETON = None
    TITLE = 'Anki :: Web Browser Addon'

    _parent = None
    _fields = []
    _selectionHandler = None
    _web = None
    _context = None
    _lastAssignedField = None
    infoList = []
    providerList = []

    def __init__(self, myParent):
        QDialog.__init__(self, None)
        self._parent = myParent
        self.setupUI()

        if myParent:

            def wrapClose(fn):
                def clozeBrowser(evt):
                    self.close()
                    fn(evt)

                return clozeBrowser

            myParent.closeEvent = wrapClose(myParent.closeEvent)

    def setupUI(self):
        self.setWindowTitle(AwBrowser.TITLE)
        self.setWindowFlags(Qt.WindowMinMaxButtonsHint
                            | Qt.WindowCloseButtonHint)
        self.setGeometry(450, 200, 800, 450)
        self.setMinimumWidth(640)
        self.setMinimumHeight(450)
        self.setStyleSheet(Style.DARK_BG)

        mainLayout = QVBoxLayout()
        mainLayout.setContentsMargins(0, 0, 0, 0)
        mainLayout.setSpacing(0)
        self.setLayout(mainLayout)

        self._web = QWebEngineView(self)
        self._web.contextMenuEvent = self.contextMenuEvent
        self._web.page().loadStarted.connect(self.onStartLoading)
        self._web.page().loadFinished.connect(self.onLoadFinish)
        self._web.page().loadProgress.connect(self.onProgress)
        self._web.page().urlChanged.connect(self.onPageChange)

        # -------------------- Top / toolbar ----------------------
        navtbar = QToolBar("Navigation")
        navtbar.setIconSize(QSize(16, 16))
        mainLayout.addWidget(navtbar)

        backBtn = QAction(
            QtGui.QIcon(os.path.join(CWD, 'assets', 'arrow-back.png')), "Back",
            self)
        backBtn.setStatusTip("Back to previous page")
        backBtn.triggered.connect(self._web.back)
        navtbar.addAction(backBtn)

        self.forwardBtn = QAction(
            QtGui.QIcon(os.path.join(CWD, 'assets', 'arrow-forward.png')),
            "Forward", self)
        self.forwardBtn.setStatusTip("Next visited page")
        self.forwardBtn.triggered.connect(self._web.forward)
        navtbar.addAction(self.forwardBtn)

        refreshBtn = QAction(
            QtGui.QIcon(os.path.join(CWD, 'assets', 'reload.png')), "Reload",
            self)
        refreshBtn.setStatusTip("Reload")
        refreshBtn.triggered.connect(self._web.reload)
        navtbar.addAction(refreshBtn)

        self.createProvidersMenu(navtbar)

        self._itAddress = QtWidgets.QLineEdit(self)
        self._itAddress.setObjectName("itSite")
        self._itAddress.setStyleSheet('background-color: #F5F5F5;')
        self._itAddress.returnPressed.connect(self._goToAddress)
        navtbar.addWidget(self._itAddress)

        cbGo = QAction(QtGui.QIcon(os.path.join(CWD, 'assets', 'go-icon.png')),
                       "Go", self)
        cbGo.setObjectName("cbGo")
        navtbar.addAction(cbGo)
        cbGo.triggered.connect(self._goToAddress)

        self.stopBtn = QAction(
            QtGui.QIcon(os.path.join(CWD, 'assets', 'stop.png')), "Stop", self)
        self.stopBtn.setStatusTip("Stop loading")
        self.stopBtn.triggered.connect(self._web.stop)
        navtbar.addAction(self.stopBtn)
        # -------------------- Center ----------------------
        mainLayout.addWidget(self._web)
        # -------------------- Bottom bar ----------------------

        bottomWidget = QtWidgets.QWidget(self)
        bottomWidget.setFixedHeight(30)

        bottomLayout = QtWidgets.QHBoxLayout(bottomWidget)
        bottomLayout.setObjectName("bottomLayout")
        bottomWidget.setStyleSheet('color: #FFF;')

        lbSite = QtWidgets.QLabel(bottomWidget)
        lbSite.setObjectName("label")
        lbSite.setText("Context: ")
        lbSite.setFixedWidth(70)
        lbSite.setStyleSheet('font-weight: bold;')
        bottomLayout.addWidget(lbSite)

        self.ctxWidget = QtWidgets.QLabel(bottomWidget)
        self.ctxWidget.width = 300
        self.ctxWidget.setStyleSheet('text-align: left;')
        bottomLayout.addWidget(self.ctxWidget)

        self._loadingBar = QtWidgets.QProgressBar(bottomWidget)
        self._loadingBar.setFixedWidth(100)
        self._loadingBar.setProperty("value", 100)
        self._loadingBar.setObjectName("loadingBar")
        bottomLayout.addWidget(self._loadingBar)

        mainLayout.addWidget(bottomWidget)

        if cfg.getConfig().browserAlwaysOnTop:
            self.setWindowFlags(Qt.WindowStaysOnTopHint)

    @classmethod
    def singleton(cls, parent):
        if not cls.SINGLETON:
            cls.SINGLETON = AwBrowser(parent)
        return cls.SINGLETON

    def formatTargetURL(self, website: str, query: str = ''):
        return website.format(urllib.parse.quote(query, encoding='utf8'))

    @exceptionHandler
    def open(self, website, query: str):
        """
            Loads a given page with its replacing part with its query, and shows itself
        """

        self._context = query
        self._updateContextWidget()
        target = self.formatTargetURL(website, query)
        self._web.load(QUrl(target))
        self._itAddress.setText(target)

        self.show()
        self.raise_()
        return self._web

    def unload(self):
        try:
            self._web.setHtml(BLANK_PAGE)
            self._itAddress.setText('about:blank')
        except (RuntimeError) as err:
            pass

    def onClose(self):
        self._parent = None
        self._web.close()
        self.close()

    def onStartLoading(self):
        self.stopBtn.setEnabled(True)
        self._loadingBar.setProperty("value", 1)

    def onProgress(self, prog):
        self._loadingBar.setProperty("value", prog)

    def onLoadFinish(self, result):
        self.stopBtn.setDisabled(True)
        self._loadingBar.setProperty("value", 100)

        if not result:
            Feedback.log('No result on loading page! ')

    def _goToAddress(self):
        q = QUrl(self._itAddress.text())
        if q.scheme() == "":
            q.setScheme("http")

        self._web.load(q)
        self._web.show()

    def onPageChange(self, url):
        if url and url.toString().startswith('http'):
            self._itAddress.setText(url.toString())
        self.forwardBtn.setEnabled(self._web.history().canGoForward())

    def welcome(self):
        self._web.setHtml(WELCOME_PAGE)
        self._itAddress.setText('about:blank')
        self.show()
        self.raise_()

    def _updateContextWidget(self):
        self.ctxWidget.setText(self._context)

# ---------------------------------------------------------------------------------

    def createProvidersMenu(self, parentWidget):
        providerBtn = QAction(
            QtGui.QIcon(os.path.join(CWD, 'assets', 'gear-icon.png')),
            "Providers", parentWidget)
        providerBtn.setStatusTip("Search with Provider")
        providerBtn.triggered.connect(
            lambda: self.newProviderMenu(providerBtn))
        parentWidget.addAction(providerBtn)

    def newProviderMenu(self, parentBtn):
        ctx = ProviderSelectionController()
        ctx.showCustomMenu(parentBtn.parentWidget(), self.reOpenSameQuery)

    @exceptionHandler
    def reOpenSameQuery(self, website):
        self.open(website, self._context)

# ------------------------------------ Menu ---------------------------------------

    def _makeMenuAction(self, field, value, isLink):
        """
            Creates correct operations for the context menu selection.
            Only with lambda, it would repeat only the last element
        """
        def _processMenuSelection():
            self._lastAssignedField = field
            self._selectionHandler(field, value, isLink)

        return _processMenuSelection

    def contextMenuEvent(self, evt):
        """
            Handles the context menu in the web view. 
            Shows and handle options (from field list), only if in edit mode.
        """

        if not (self._fields and self._selectionHandler):
            return self.createInfoMenu(evt)

        isLink = False
        value = None
        if self._web.selectedText():
            isLink = False
            value = self._web.selectedText()
        else:
            if (self._web.page().contextMenuData().mediaType()
                    == QWebEngineContextMenuData.MediaTypeImage
                    and self._web.page().contextMenuData().mediaUrl()):
                isLink = True
                value = self._web.page().contextMenuData().mediaUrl()
                Feedback.log('Link: ' + value.toString())
                Feedback.log('toLocal: ' + value.toLocalFile())

                if not self._checkSuffix(value):
                    return

        if not value:
            Feedback.log('No value')
            return self.createInfoMenu(evt)

        if QApplication.keyboardModifiers() == Qt.ControlModifier:
            if self._assignToLastField(value, isLink):
                return

        self.createCtxMenu(value, isLink, evt)

    def _checkSuffix(self, value):
        if value and not value.toString().endswith(
            ("jpg", "jpeg", "png", "gif")):
            msgLink = value.toString()
            if len(value.toString()) < 80:
                msgLink = msgLink[:50] + '...' + msgLink[50:]
            answ = QMessageBox.question(
                self, 'Anki support',
                """This link may not be accepted by Anki: \n\n "%s" \n
Usually the suffix should be one of 
(jpg, jpeg, png, gif).
Try it anyway? """ % msgLink, QMessageBox.Yes | QMessageBox.No)

            if answ != QMessageBox.Yes:
                return False

        return True

    def createCtxMenu(self, value, isLink, evt):
        'Creates and configures the menu itself'

        m = QMenu(self)
        m.addAction(QAction('Copy', m, triggered=lambda: self._copy(value)))
        m.addSeparator()

        labelAct = QAction(Label.BROWSER_ASSIGN_TO, m)
        labelAct.setDisabled(True)
        m.addAction(labelAct)
        # sub = QMenu(Label.BROWSER_ASSIGN_TO, m)
        m.setTitle(Label.BROWSER_ASSIGN_TO)
        for index, label in self._fields.items():
            act = QAction(label,
                          m,
                          triggered=self._makeMenuAction(index, value, isLink))
            m.addAction(act)

        # m.addMenu(sub)
        action = m.exec_(self.mapToGlobal(evt.pos()))

    def createInfoMenu(self, evt):
        'Creates and configures a menu with only some information'
        m = QMenu(self)
        for item in self.infoList:
            act = QAction(item)
            act.setEnabled(False)
            m.addAction(act)
        action = m.exec_(self.mapToGlobal(evt.pos()))

    def _assignToLastField(self, value, isLink):
        'Tries to set the new value to the same field used before, if set...'

        if self._lastAssignedField:
            if self._lastAssignedField in self._fields:
                self._selectionHandler(self._lastAssignedField, value, isLink)
                return True
            else:
                self._lastAssignedField = None
        return False

    def _copy(self, value):
        if not value:
            return
        clip = QApplication.clipboard()
        clip.setText(value if isinstance(value, str) else value.toString())

    def load(self, qUrl):
        self._web.load(qUrl)

#   ----------------- getter / setter  -------------------

    def setFields(self, fList):
        self._fields = fList

    def setSelectionHandler(self, value):
        self._selectionHandler = value