Ejemplo n.º 1
0
    def __init__(self, parent=None):
        super(NavigateInput, self).__init__(parent)

        set_shortcuts([("Ctrl+H", self, self.backspace),
                       ("Escape", self, self.exit)])

        self.hide()
Ejemplo n.º 2
0
    def __init__(self, parent=None):
        super(NavigateInput, self).__init__(parent)

        set_shortcuts([
            ("Ctrl+H", self, self.backspace),
            ("Escape", self, self.exit)
        ])

        self.hide()
Ejemplo n.º 3
0
    def __init__(self, parent=None):
        super(SearchFrame, self).__init__(parent)

        self.search_grid = QGridLayout(self)
        self.search_grid.setSpacing(0)
        self.search_grid.setContentsMargins(0, 0, 0, 0)
        self.label = QLabel("Find in page:")
        self.search_line = QLineEdit()
        self.search_grid.addWidget(self.label, 0, 0)
        self.search_grid.addWidget(self.search_line, 0, 1)
        self.setVisible(False)

        set_shortcuts([
            ("Ctrl+H", self, self.search_line.backspace),
            ])
Ejemplo n.º 4
0
    def __init__(self, parent=None):
        super(SearchFrame, self).__init__(parent)

        self.search_grid = QGridLayout(self)
        self.search_grid.setSpacing(0)
        self.search_grid.setContentsMargins(0, 0, 0, 0)
        self.label = QLabel("Find in page:")
        self.search_line = QLineEdit()
        self.search_grid.addWidget(self.label, 0, 0)
        self.search_grid.addWidget(self.search_line, 0, 1)
        self.setVisible(False)

        set_shortcuts([
            ("Ctrl+H", self, self.search_line.backspace),
        ])
Ejemplo n.º 5
0
    def __init__(self, parent=None):
        super(AddressBar, self).__init__(parent)

        self.__completer = None
        self.__model = None

        self.__stored_text = ''
        self.__stored_color = QColor(0, 0, 0)

        # This first assignation is to allow a blank tab, who hasn't chosen yet
        # an instance, to display completions for all sites
        self.set_model(None)

        set_shortcuts([
            ("Ctrl+H", self, self.backspace),
            # do not create a new tab when on the address bar;
            # popup related trouble BF001
            ("Ctrl+T", self, lambda: None),
            ("Ctrl+Shift+T", self, lambda: None)
        ])
Ejemplo n.º 6
0
    def __init__(self, parent=None):
        super(AddressBar, self).__init__(parent)

        self.__completer = None
        self.__model = None

        self.__stored_text = ''
        self.__stored_color = QColor(0, 0, 0)

        # This first assignation is to allow a blank tab, who hasn't chosen yet
        # an instance, to display completions for all sites
        self.set_model(None)

        set_shortcuts([
            ("Ctrl+H", self, self.backspace),
            # do not create a new tab when on the address bar;
            # popup related trouble BF001
            ("Ctrl+T", self, lambda: None),
            ("Ctrl+Shift+T", self, lambda: None)
        ])
Ejemplo n.º 7
0
    def __init__(self, parent=None):
        super(MainWin, self).__init__(parent)
        self.setWindowTitle("Eilat Browser")
        # gc.set_debug(gc.DEBUG_LEAK)

        self.last_closed = None

        self.tab_widget = QTabWidget(self)
        self.tab_widget.setTabBar(MidClickTabBar(self))
        self.tab_widget.tabBar().setMovable(True)
        self.tab_widget.setTabsClosable(True)

        # the right side of the tab already has the space for
        # a non-shown close button
        self.tab_widget.setStyleSheet(
            'QTabBar::tab {padding-top: 0px; padding-bottom: 0px; '
            'padding-left: 0.3em;} '
            'QTabBar::tab:selected {color: #00f;}')

        # tabCloseRequested carries int (index of a tab)
        self.tab_widget.tabCloseRequested.connect(self.del_tab)

        self.setCentralWidget(self.tab_widget)

        self.tooltip = NotifyLabel(parent=self)

        def restore_last_closed():
            """ One-use callback for QShortcut.
            Opens a fresh new tab with the url address of the last tab closed
            """
            if self.last_closed is not None:
                url = self.last_closed
                self.add_tab(url)
                self.last_closed = None

        def dump_gc():
            """ prints sizes for large memory collectable objects """
            objs = gc.get_objects()
            pairs = [(str(k)[:80], type(k).__name__, sys.getsizeof(k))
                     for k in objs if sys.getsizeof(k) > 1024*4*5]

            for pair in pairs:
                print(pair)

        def reload_disk_init():
            """ transfer options.yaml and the css directory to global maps """
            load_options()
            load_css()
            notify("reloaded disk config")

        set_shortcuts([
            ("F9", self, dump_gc),
            # reload configuration
            ("Ctrl+Shift+R", self, reload_disk_init),
            # new tabs
            ("Ctrl+T", self, self.add_tab),
            ("Ctrl+Shift+T", self, partial(self.add_tab, scripting=True)),
            ("Y", self, self.new_tab_from_clipboard),
            # movement
            ("M", self, self.inc_tab),
            ("N", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgUp", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgDown", self, self.inc_tab),
            # destroy/undestroy
            ("U", self, restore_last_closed),
            ("Ctrl+W", self, self.del_tab),
            ("Ctrl+Q", self, self.finalize)
            ])
Ejemplo n.º 8
0
    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)

        self.current = {
            'title': "[EMPTY]",
            'address': ""
        }

        # address bar
        self.address_bar = AddressBar(parent=self)

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        # set_prefix: app defined, carries str
        self.webkit.set_prefix.connect(self.address_bar.set_model)  # CFG02
        # javascript_state: app defined, carries bool
        self.webkit.javascript_state.connect(self.address_bar.set_bgcolor)

        # small label displaying instance ID and pending tab operations

        info_label = QLabel(parent=self)
        info_label.setText('?')  # CFG02

        # webkit_info: app defined, carries str
        self.webkit.attr.webkit_info.connect(info_label.setText)

        def update_address(qurl):
            """ The 'connect' gives a QUrl and setText receives a string;
            can't just connect setText

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            AB02 AB03

            """
            self.current['address'] = qurl.toString()
            self.address_bar.setText(self.current['address'])

        # urlChanged carries QUrl; loadStarted carries nothing;
        # loadFinished carries bool; titleChanged carries str;
        # loadProgress carries int
        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.load_started)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        def fill_notifier(message, request):
            """ sends a message to be displayed by the notifier

            """
            notify(message + " " + request.url().toString())

        # downloadRequested carries QNetworkRequest
        self.webkit.page().downloadRequested.connect(
            partial(fill_notifier, "download"))
        # unsupportedContent carries QNetworkReply
        self.webkit.page().unsupportedContent.connect(
            partial(fill_notifier, "unsupported"))

        # input area for access-key navigation

        self.nav_bar = NavigateInput(parent=self)
        # editingFinished carries nothing
        self.nav_bar.editingFinished.connect(self.webkit.clear_labels)

        # textEdited carries str
        self.nav_bar.textEdited.connect(self.webkit.akeynav)
        # nonvalid_tag (app defined) carries nothing
        self.webkit.nonvalid_tag.connect(self.nav_bar.clear)

        # 'corner' message and notification label, not on timer, smaller

        self.message_label = MessageLabel(self.webkit)

        def handle_hovered(link, title, content):
            """ When hovered, if ALT is pressed, show message label;
            hide otherwise

            """

            if ((QApplication.keyboardModifiers() & Qt.AltModifier) and
                    (link or title or content)):
                # ugly hack to ensure proper resizing; find a better way?
                self.message_label.hide()
                self.message_label.setText(
                    link + " " + title + " " + content)
                self.message_label.show()
            else:
                self.message_label.hide()

        # linkHovered carries str, str, str
        self.webkit.page().linkHovered.connect(handle_hovered)

        def handle_signaled(title):
            """ We received a string through a signal; display it on
            the message label

            """

            # if title:
            self.message_label.hide()
            self.message_label.setText(title)
            self.message_label.show()

        # show_message (app defined) carries str
        self.webkit.show_message.connect(handle_signaled)
        # loadStarted carries nothing
        self.webkit.loadStarted.connect(self.message_label.hide)

        # At the time navigation is requested load_requested is sent, and the
        # requested url is set as text in grey at the address bar. Once the
        # urlChanged signal is received, the actual url is set in black.

        # load_requested (app defined) carries str
        self.webkit.load_requested.connect(
            partial(self.address_bar.set_txt_color,
                    color=QColor(128, 128, 128)))

        def hide_message_label(*_):
            """ WARNING scrollRequested carries int, int, QRect;
            star swallows all

            """
            self.message_label.hide()

        self.webkit.page().scrollRequested.connect(hide_message_label)

        # focus_webkit (app defined) carries nothing
        self.webkit.hide_overlay.connect(self.message_label.hide)
        self.webkit.focus_webkit.connect(self.address_bar.restore)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)  # NAV20
        # textChanged carries str
        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        grid.setRowStretch(1, 1)

        grid.addWidget(info_label, 0, 0, 1, 1)
        grid.addWidget(self.address_bar, 0, 1, 1, 1)
        grid.addWidget(self.nav_bar, 0, 2, 1, 1)

        grid.addWidget(self.webkit, 1, 0, 1, 3)

        grid.addWidget(self.search_frame, 2, 0, 1, 3)
        grid.addWidget(self.pbar, 3, 0, 1, 3)

        def show_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            AB01

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        # the star swallows all arguments that aren't named 'store'
        def reset_addressbar(*, store=False):
            """ Restore the address bar to its original address and color (it
            could have changed because of a hover event).

            Optionally, store the original address in the clipboard.

            AB03

            """

            if self.current['address']:
                self.address_bar.set_txt_color(self.current['address'],
                                               color=QColor(0, 0, 0))

            if store:
                clipboard(self.current['address'])

        # urlChanged carries QUrl (ignored)
        self.webkit.urlChanged.connect(reset_addressbar)

        def enter_address_bar(clear=True):
            """ do not try entering the address bar if a load is in
            progress; do an 'stop' first

            AB00

            """

            if 'in_page_load' not in self.webkit.attr:
                if clear:
                    self.address_bar.clear_and_focus()
                else:
                    self.address_bar.setFocus()

        def cancel():
            """ if we're in the middle of loading the document, stop loading.
            Otherwise, hide the message label. The general concept is to reach
            a basic state.

            """

            if 'in_page_load' not in self.webkit.attr:
                self.message_label.hide()
                self.webkit.update()
            else:
                self.webkit.stop()

        set_shortcuts([
            # search NAV20
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page AB00
            ("Ctrl+J", self.address_bar, partial(
                self.webkit.navigate, self.address_bar)),
            ("Return", self.address_bar, partial(
                self.webkit.navigate, self.address_bar)),
            # address bar interaction
            ("A", self.webkit, cancel),
            ("Ctrl+L", self.webkit, enter_address_bar),  # AB00
            ("Ctrl+Shift+L", self.webkit, partial(
                enter_address_bar, clear=False)),
            ("Escape", self.address_bar, self.webkit.setFocus),  # AB00
            ("Ctrl+I", self.address_bar, navigate_completion),  # AB01
            ("Ctrl+P", self.address_bar, partial(
                navigate_completion, Qt.Key_Up)),
            # in-page element navigation
            ("Ñ", self, self.enter_nav),  # NAV11
            (";", self, self.enter_nav),
            # DOM01
            ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")),
            # toggle
            ("Q", self.webkit, self.toggle_script),  # TOG01
            # clipboard
            ("E", self, partial(reset_addressbar, store=True))  # CB05
            ])
Ejemplo n.º 9
0
    def __init__(self, parent=None):
        super(MainWin, self).__init__(parent)
        self.setWindowTitle("Eilat Browser")
        # gc.set_debug(gc.DEBUG_LEAK)

        self.last_closed = None

        self.tab_widget = QTabWidget(self)
        self.tab_widget.setTabBar(MidClickTabBar(self))
        self.tab_widget.tabBar().setMovable(True)
        self.tab_widget.setTabsClosable(True)

        # the right side of the tab already has the space for
        # a non-shown close button
        self.tab_widget.setStyleSheet(
            'QTabBar::tab {padding-top: 0px; padding-bottom: 0px; '
            'padding-left: 0.3em;} '
            'QTabBar::tab:selected {color: #00f;}')

        # tabCloseRequested carries int (index of a tab)
        self.tab_widget.tabCloseRequested.connect(self.del_tab)

        self.setCentralWidget(self.tab_widget)

        self.tooltip = NotifyLabel(parent=self)

        def restore_last_closed():
            """ One-use callback for QShortcut.
            Opens a fresh new tab with the url address of the last tab closed
            """
            if self.last_closed is not None:
                url = self.last_closed
                self.add_tab(url)
                self.last_closed = None

        def dump_gc():
            """ prints sizes for large memory collectable objects """
            objs = gc.get_objects()
            pairs = [(str(k)[:80], type(k).__name__, sys.getsizeof(k))
                     for k in objs if sys.getsizeof(k) > 1024 * 4 * 5]

            for pair in pairs:
                print(pair)

        def reload_disk_init():
            """ transfer options.yaml and the css directory to global maps """
            load_options()
            load_css()
            notify("reloaded disk config")

        set_shortcuts([
            ("F9", self, dump_gc),
            # reload configuration
            ("Ctrl+Shift+R", self, reload_disk_init),
            # new tabs
            ("Ctrl+T", self, self.add_tab),
            ("Ctrl+Shift+T", self, partial(self.add_tab, scripting=True)),
            ("Y", self, self.new_tab_from_clipboard),
            # movement
            ("M", self, self.inc_tab),
            ("N", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgUp", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgDown", self, self.inc_tab),
            # destroy/undestroy
            ("U", self, restore_last_closed),
            ("Ctrl+W", self, self.del_tab),
            ("Ctrl+Q", self, self.finalize)
        ])
Ejemplo n.º 10
0
    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)

        self.current = {'title': "[EMPTY]", 'address': ""}

        # address bar
        self.address_bar = AddressBar(parent=self)

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        # set_prefix: app defined, carries str
        self.webkit.set_prefix.connect(self.address_bar.set_model)  # CFG02
        # javascript_state: app defined, carries bool
        self.webkit.javascript_state.connect(self.address_bar.set_bgcolor)

        # small label displaying instance ID and pending tab operations

        info_label = QLabel(parent=self)
        info_label.setText('?')  # CFG02

        # webkit_info: app defined, carries str
        self.webkit.attr.webkit_info.connect(info_label.setText)

        def update_address(qurl):
            """ The 'connect' gives a QUrl and setText receives a string;
            can't just connect setText

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            AB02 AB03

            """
            self.current['address'] = qurl.toString()
            self.address_bar.setText(self.current['address'])

        # urlChanged carries QUrl; loadStarted carries nothing;
        # loadFinished carries bool; titleChanged carries str;
        # loadProgress carries int
        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.load_started)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        def fill_notifier(message, request):
            """ sends a message to be displayed by the notifier

            """
            notify(message + " " + request.url().toString())

        # downloadRequested carries QNetworkRequest
        self.webkit.page().downloadRequested.connect(
            partial(fill_notifier, "download"))
        # unsupportedContent carries QNetworkReply
        self.webkit.page().unsupportedContent.connect(
            partial(fill_notifier, "unsupported"))

        # input area for access-key navigation

        self.nav_bar = NavigateInput(parent=self)
        # editingFinished carries nothing
        self.nav_bar.editingFinished.connect(self.webkit.clear_labels)

        # textEdited carries str
        self.nav_bar.textEdited.connect(self.webkit.akeynav)
        # nonvalid_tag (app defined) carries nothing
        self.webkit.nonvalid_tag.connect(self.nav_bar.clear)

        # 'corner' message and notification label, not on timer, smaller

        self.message_label = MessageLabel(self.webkit)

        def handle_hovered(link, title, content):
            """ When hovered, if ALT is pressed, show message label;
            hide otherwise

            """

            if ((QApplication.keyboardModifiers() & Qt.AltModifier)
                    and (link or title or content)):
                # ugly hack to ensure proper resizing; find a better way?
                self.message_label.hide()
                self.message_label.setText(link + " " + title + " " + content)
                self.message_label.show()
            else:
                self.message_label.hide()

        # linkHovered carries str, str, str
        self.webkit.page().linkHovered.connect(handle_hovered)

        def handle_signaled(title):
            """ We received a string through a signal; display it on
            the message label

            """

            # if title:
            self.message_label.hide()
            self.message_label.setText(title)
            self.message_label.show()

        # show_message (app defined) carries str
        self.webkit.show_message.connect(handle_signaled)
        # loadStarted carries nothing
        self.webkit.loadStarted.connect(self.message_label.hide)

        # At the time navigation is requested load_requested is sent, and the
        # requested url is set as text in grey at the address bar. Once the
        # urlChanged signal is received, the actual url is set in black.

        # load_requested (app defined) carries str
        self.webkit.load_requested.connect(
            partial(self.address_bar.set_txt_color,
                    color=QColor(128, 128, 128)))

        def hide_message_label(*_):
            """ WARNING scrollRequested carries int, int, QRect;
            star swallows all

            """
            self.message_label.hide()

        self.webkit.page().scrollRequested.connect(hide_message_label)

        # focus_webkit (app defined) carries nothing
        self.webkit.hide_overlay.connect(self.message_label.hide)
        self.webkit.focus_webkit.connect(self.address_bar.restore)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)  # NAV20
        # textChanged carries str
        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        grid.setRowStretch(1, 1)

        grid.addWidget(info_label, 0, 0, 1, 1)
        grid.addWidget(self.address_bar, 0, 1, 1, 1)
        grid.addWidget(self.nav_bar, 0, 2, 1, 1)

        grid.addWidget(self.webkit, 1, 0, 1, 3)

        grid.addWidget(self.search_frame, 2, 0, 1, 3)
        grid.addWidget(self.pbar, 3, 0, 1, 3)

        def show_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            AB01

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        # the star swallows all arguments that aren't named 'store'
        def reset_addressbar(*, store=False):
            """ Restore the address bar to its original address and color (it
            could have changed because of a hover event).

            Optionally, store the original address in the clipboard.

            AB03

            """

            if self.current['address']:
                self.address_bar.set_txt_color(self.current['address'],
                                               color=QColor(0, 0, 0))

            if store:
                clipboard(self.current['address'])

        # urlChanged carries QUrl (ignored)
        self.webkit.urlChanged.connect(reset_addressbar)

        def enter_address_bar(clear=True):
            """ do not try entering the address bar if a load is in
            progress; do an 'stop' first

            AB00

            """

            if 'in_page_load' not in self.webkit.attr:
                if clear:
                    self.address_bar.clear_and_focus()
                else:
                    self.address_bar.setFocus()

        def cancel():
            """ if we're in the middle of loading the document, stop loading.
            Otherwise, hide the message label. The general concept is to reach
            a basic state.

            """

            if 'in_page_load' not in self.webkit.attr:
                self.message_label.hide()
                self.webkit.update()
            else:
                self.webkit.stop()

        set_shortcuts([
            # search NAV20
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page AB00
            ("Ctrl+J", self.address_bar,
             partial(self.webkit.navigate, self.address_bar)),
            ("Return", self.address_bar,
             partial(self.webkit.navigate, self.address_bar)),
            # address bar interaction
            ("A", self.webkit, cancel),
            ("Ctrl+L", self.webkit, enter_address_bar),  # AB00
            ("Ctrl+Shift+L", self.webkit,
             partial(enter_address_bar, clear=False)),
            ("Escape", self.address_bar, self.webkit.setFocus),  # AB00
            ("Ctrl+I", self.address_bar, navigate_completion),  # AB01
            ("Ctrl+P", self.address_bar, partial(navigate_completion,
                                                 Qt.Key_Up)),
            # in-page element navigation
            ("Ñ", self, self.enter_nav),  # NAV11
            (";", self, self.enter_nav),
            # DOM01
            ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")),
            # toggle
            ("Q", self.webkit, self.toggle_script),  # TOG01
            # clipboard
            ("E", self, partial(reset_addressbar, store=True))  # CB05
        ])
Ejemplo n.º 11
0
    def __init__(self, parent=None):
        super(WebView, self).__init__(parent)

        # hide the tooltips (they're still there, just with a height of zero)
        # see http://qt-project.org/doc/qt-4.8/stylesheet-reference.html
        self.setStyleSheet("QToolTip {max-height: 0px}")  # CFG11

        self.attr = Attributes(parent=self)
        self.attr.css_path = expanduser("~/.eilat/css/")  # CFG01

        self.started_at = None

        # a web element node
        self.__in_focus = None  # NAV11, NAV12

        # make_labels, clear_labels
        self.__labels = []

        # make_labels, clear_labels, akeynav
        self.map_tags = {}

        self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)  # CB04

        # self.settings().setFontFamily(
        #     QWebSettings.StandardFont, "Georgia")

        self.settings().setAttribute(
            QWebSettings.PluginsEnabled, False)

        # take care; if set to True, the address bar, that is not yet
        # connected, will not be able to set its color to "javascript on"
        self.javascript(False)

        self.settings().setAttribute(
            QWebSettings.FrameFlatteningEnabled, True)

        self.settings().setAttribute(
            QWebSettings.DeveloperExtrasEnabled, True)

        self.page().setForwardUnsupportedContent(True)  # CB04

        # connect (en constructor)
        def on_link_click(qurl):
            """ Callback for connection. Reads the 'paste' attribute
            to know if a middle click requested to open on a new tab.

            BRW01 BRW12 VID01 CB03

            """

            # required for 'open in new tab if not in this instance'
            qurl = do_redirect(qurl)  # BRW12

            # 'play' and 'save' should only happen from inside the webkit and
            # if the user started the action; handle here, not in 'navigate'

            if 'play' in self.attr:
                print("PLAYING")

                GLOBAL_VID_PLAY.play(qurl)  # VID01

                self.attr.clear('play')

                return

            if 'save' in self.attr:
                clipboard(qurl)  # CB02
                self.attr.clear('save')
                return

            instance = extract_instance(qurl.toString())

            target_prefix = get_options()['sites'][instance]['prefix']

            # if the prefixes don't match, we're requesting a new instance
            # TAB04 TAB05
            if 'paste' in self.attr or self.attr.prefix != target_prefix:
                mainwin().add_tab(qurl,
                                  scripting=('open_scripted' in self.attr))
                self.attr.clear('paste')
            else:
                self.navigate(qurl)  # BRW01

            if 'open_scripted' in self.attr:
                self.attr.clear('open_scripted')

        # linkClicked carries QUrl
        self.linkClicked.connect(on_link_click)

        def url_changed(qurl):
            """ One time callback for 'connect'
            Sets the user style sheet

            CFG01

            """

            print("CHGD ({}s)".format(time() - self.started_at))
            self.started_at = time()

            host_id = real_host(qurl.host())

            css_map = get_css()

            css_pseudo_file = css_map[host_id]
            self.settings().setUserStyleSheetUrl(QUrl(css_pseudo_file))

        # urlChanged carries QUrl
        self.urlChanged.connect(url_changed)

        # statusBarMessage carries str
        self.statusBarMessage.connect(notify)

        # downloadRequested carries QNetworkRequest
        self.page().downloadRequested.connect(clipboard)  # CB04
        # unsupportedContent carries QNetworkReply
        self.page().unsupportedContent.connect(clipboard)  # CB04

        # loadStarted carries nothing
        self.page().loadStarted.connect(partial(self.attr.insert,
                                                'in_page_load'))

        self.profiler = None

        def load_started():
            """ Clear __in_focus; we don't even know if the focused
            node still exists.

            Set the "we're starting to load" attribute.

            """

            self.attr.insert('in_page_load')
            self.__in_focus = None

            self.started_at = time()

            # profiling()

        self.page().loadStarted.connect(load_started)

        # the star swallows all arguments
        def load_finished(*_):
            """ if we kept javascript on to allow the load of the page, we
            may want to turn it off when it has finished.

            Remove the "we're starting to load" attribute.

            """

            print("DONE ({}s)".format(time() - self.started_at))

            if (not self.hasFocus() and
                    'in_page_load' not in self.attr and
                    self.javascript()):
                self.attr.insert('stored_scripting_on')
                self.javascript(False)  # JS01
                print("EXITING LOAD WITH JS WITHOUT FOCUS")

            self.attr.clear('in_page_load')

            # profiling(begin=False)

        # loadFinished carries bool (ignored)
        self.page().loadFinished.connect(load_finished)

        def dump_dom():
            """ saves the content of the current web page

            DOM04

            """
            data = self.page().currentFrame().documentElement().toInnerXml()
            print("SAVING...")
            with open('test.html', 'w') as file_handle:
                file_handle.write(data)

        def scroll(delta_x=0, delta_y=0):
            """ One-time callback for QShortcut

            NAV01

            """
            self.page().mainFrame().scroll(delta_x, delta_y)

        def zoom(lvl):
            """ One-time callback for QShortcut

            NAV02

            """
            factor = self.zoomFactor() + (lvl * 0.25)
            self.setZoomFactor(factor)

        def emit_message_info(title=False):
            """
            If requesting for the document's title, emit it. Otherwise,
            if a link is focused, emit its target to the message label

            """

            if title:
                self.show_message.emit(self.title())
            elif self.__in_focus is not None:
                qurl = QUrl(self.__in_focus.attribute('href'))
                qurl = do_redirect(qurl)
                self.show_message.emit(qurl.toString())

        set_shortcuts([
            # notifications
            ("Shift+D", self, partial(emit_message_info, title=True)),
            ("D", self, emit_message_info),
            # DOM actions DOM04 DOM03 DOM02
            ("Ctrl+M", self, dump_dom),
            ("F", self, self.__unembed_frames),
            ("F2", self, self.__delete_fixed),
            ("Shift+F2", self, partial(self.__delete_fixed, delete=False)),
            ("Ctrl+F2", self, partial(self.__delete_fixed, force=True)),
            # webkit interaction
            ("Alt+Left", self, self.back),
            ("Alt+Right", self, self.forward),
            ("F5", self, self.reload),
            ("R", self, self.reload),
            # view interaction NAV01 NAV02
            ("J", self, partial(scroll, delta_y=40)),
            #("Z", self, partial(scroll, delta_y=40)),
            ("K", self, partial(scroll, delta_y=-40)),
            #("X", self, partial(scroll, delta_y=-40)),
            ("H", self, partial(scroll, delta_x=-40)),
            ("L", self, partial(scroll, delta_x=40)),
            ("Ctrl+Up", self, partial(zoom, 1)),
            ("Ctrl+Down", self, partial(zoom, -1)),
            ("Ctrl+J", self, partial(fake_key, self, Qt.Key_Enter)),
            ("Ctrl+H", self, partial(fake_key, self, Qt.Key_Backspace)),
            ("Backspace", self, self.back),
            #("C", self, partial(fake_click, self)),
            (",", self, partial(fake_click, self)),
            # spatial navigation NAV12
            ("Shift+H", self, partial(self.__spatialnav, LEFT)),
            ("Shift+J", self, partial(self.__spatialnav, DOWN)),
            ("Shift+K", self, partial(self.__spatialnav, UP)),
            ("Shift+L", self, partial(self.__spatialnav, RIGHT)),
            # toggles TOG02 TOG03
            # lambda required because self.attr.prefix is updated
            # when the web view navigates the first time
            ("F11", self, lambda: toggle_show_logs(self.attr.prefix)),
            ("Shift+F11", self, lambda: toggle_load_fonts(self.attr.prefix)),
            ("Escape", self, self.focus_webkit.emit),  # FIXME ???
            # clipboard related behavior
            ("I", self, partial(self.attr.toggle, 'paste', 'I')),  # TAB04
            ("O", self, partial(self.attr.toggle, 'open_scripted', 'O')),
            ("S", self, partial(self.attr.toggle, 'save', 'S')),  # CB03
            ("V", self, partial(self.attr.toggle, 'play', 'V')),  # VID01
            # profiler
            # ("9", self, profiling),  # DEB02
            # ("0", self, partial(profiling, begin=False))  # DEB02
            ])