Refactor tab/browser widgets

This commit is contained in:
Florian Bruhin 2014-04-17 09:44:26 +02:00
parent 58ae1f7441
commit 4b1dcbd82a
8 changed files with 427 additions and 347 deletions

6
TODO
View File

@ -7,12 +7,6 @@ Weird font rendering
https://bugreports.qt-project.org/browse/QTBUG-21036
Changing completion models is awfully slow
Style
=====
Rename browsertab/tabbedbrowser/... widgets
Maybe move tabs.cur.* stuff to browsertab?
Major features
==============

View File

@ -0,0 +1,18 @@
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Classes related to the browser widgets."""

View File

@ -0,0 +1,294 @@
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""The main tabbed browser widget."""
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject
from PyQt5.QtGui import QClipboard
from PyQt5.QtPrintSupport import QPrintPreviewDialog
import qutebrowser.utils.url as urlutils
import qutebrowser.commands.utils as cmdutils
class CurCommandDispatcher(QObject):
"""Command dispatcher for TabbedBrowser.
Contains all commands which are related to the current tab.
We can't simply add these commands to BrowserTab directly and use
currentWidget() for TabbedBrowser.cur because at the time
cmdutils.register() decorators are run, currentWidget() will return None.
Attributes:
tabs: The TabbedBrowser object.
Signals:
temp_message: Connected to TabbedBrowser signal.
"""
# FIXME maybe subclassing would be more clean?
temp_message = pyqtSignal(str)
def __init__(self, parent):
"""Constructor.
Uses setattr to get some methods from parent.
Args:
parent: The TabbedBrowser for this dispatcher.
"""
super().__init__(parent)
self.tabs = parent
def _scroll_percent(self, perc=None, count=None, orientation=None):
"""Inner logic for scroll_percent_(x|y).
Args:
perc: How many percent to scroll, or None
count: How many percent to scroll, or None
orientation: Qt.Horizontal or Qt.Vertical
"""
if perc is None and count is None:
perc = 100
elif perc is None:
perc = int(count)
else:
perc = float(perc)
frame = self.tabs.currentWidget().page_.mainFrame()
m = frame.scrollBarMaximum(orientation)
if m == 0:
return
frame.setScrollBarValue(orientation, int(m * perc / 100))
@cmdutils.register(instance='mainwindow.tabs.cur', name='open',
split_args=False)
def openurl(self, url, count=None):
"""Open an url in the current/[count]th tab.
Command handler for :open.
Args:
url: The URL to open.
count: The tab index to open the URL in, or None.
"""
tab = self.tabs.cntwidget(count)
if tab is None:
if count is None:
# We want to open an URL in the current tab, but none exists
# yet.
self.tabs.tabopen(url)
else:
# Explicit count with a tab that doesn't exist.
return
else:
tab.openurl(url)
@cmdutils.register(instance='mainwindow.tabs.cur', name='reload')
def reloadpage(self, count=None):
"""Reload the current/[count]th tab.
Command handler for :reload.
Args:
count: The tab index to reload, or None.
"""
tab = self.tabs.cntwidget(count)
if tab is not None:
tab.reload()
@cmdutils.register(instance='mainwindow.tabs.cur')
def stop(self, count=None):
"""Stop loading in the current/[count]th tab.
Command handler for :stop.
Args:
count: The tab index to stop, or None.
"""
tab = self.tabs.cntwidget(count)
if tab is not None:
tab.stop()
@cmdutils.register(instance='mainwindow.tabs.cur', name='print')
def printpage(self, count=None):
"""Print the current/[count]th tab.
Command handler for :print.
Args:
count: The tab index to print, or None.
"""
# FIXME that does not what I expect
tab = self.tabs.cntwidget(count)
if tab is not None:
preview = QPrintPreviewDialog(self)
preview.paintRequested.connect(tab.print)
preview.exec_()
@cmdutils.register(instance='mainwindow.tabs.cur')
def back(self, count=1):
"""Go back in the history of the current tab.
Command handler for :back.
Args:
count: How many pages to go back.
"""
# FIXME display warning if beginning of history
for _ in range(count):
self.tabs.currentWidget().back()
@cmdutils.register(instance='mainwindow.tabs.cur')
def forward(self, count=1):
"""Go forward in the history of the current tab.
Command handler for :forward.
Args:
count: How many pages to go forward.
"""
# FIXME display warning if end of history
for _ in range(count):
self.tabs.currentWidget().forward()
@pyqtSlot(str, int)
def search(self, text, flags):
"""Search for text in the current page.
Args:
text: The text to search for.
flags: The QWebPage::FindFlags.
"""
self.tabs.currentWidget().findText(text, flags)
@cmdutils.register(instance='mainwindow.tabs.cur', hide=True)
def scroll(self, dx, dy, count=1):
"""Scroll the current tab by count * dx/dy.
Command handler for :scroll.
Args:
dx: How much to scroll in x-direction.
dy: How much to scroll in x-direction.
count: multiplier
"""
dx = int(count) * float(dx)
dy = int(count) * float(dy)
self.tabs.currentWidget().page_.mainFrame().scroll(dx, dy)
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_x',
hide=True)
def scroll_percent_x(self, perc=None, count=None):
"""Scroll the current tab to a specific percent of the page (horiz).
Command handler for :scroll_perc_x.
Args:
perc: Percentage to scroll.
count: Percentage to scroll.
"""
self._scroll_percent(perc, count, Qt.Horizontal)
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_y',
hide=True)
def scroll_percent_y(self, perc=None, count=None):
"""Scroll the current tab to a specific percent of the page (vert).
Command handler for :scroll_perc_y
Args:
perc: Percentage to scroll.
count: Percentage to scroll.
"""
self._scroll_percent(perc, count, Qt.Vertical)
@cmdutils.register(instance='mainwindow.tabs.cur', hide=True)
def scroll_page(self, mx, my, count=1):
"""Scroll the frame page-wise.
Args:
mx: How many pages to scroll to the right.
my: How many pages to scroll down.
count: multiplier
"""
# FIXME this might not work with HTML frames
page = self.tabs.currentWidget().page_
size = page.viewportSize()
page.mainFrame().scroll(int(count) * float(mx) * size.width(),
int(count) * float(my) * size.height())
@cmdutils.register(instance='mainwindow.tabs.cur')
def yank(self, sel=False):
"""Yank the current url to the clipboard or primary selection.
Command handler for :yank.
Args:
sel: True to use primary selection, False to use clipboard
Emit:
temp_message to display a temporary message.
"""
clip = QApplication.clipboard()
url = urlutils.urlstring(self.tabs.currentWidget().url())
mode = QClipboard.Selection if sel else QClipboard.Clipboard
clip.setText(url, mode)
self.temp_message.emit('URL yanked to {}'.format(
'primary selection' if sel else 'clipboard'))
@cmdutils.register(instance='mainwindow.tabs.cur', name='yanktitle')
def yank_title(self, sel=False):
"""Yank the current title to the clipboard or primary selection.
Command handler for :yanktitle.
Args:
sel: True to use primary selection, False to use clipboard
Emit:
temp_message to display a temporary message.
"""
clip = QApplication.clipboard()
title = self.tabs.tabText(self.tabs.currentIndex())
mode = QClipboard.Selection if sel else QClipboard.Clipboard
clip.setText(title, mode)
self.temp_message.emit('Title yanked to {}'.format(
'primary selection' if sel else 'clipboard'))
@cmdutils.register(instance='mainwindow.tabs.cur', name='zoomin')
def zoom_in(self, count=1):
"""Zoom in in the current tab.
Args:
count: How many steps to take.
"""
tab = self.tabs.currentWidget()
tab.zoom(count)
@cmdutils.register(instance='mainwindow.tabs.cur', name='zoomout')
def zoom_out(self, count=1):
"""Zoom out in the current tab.
Args:
count: How many steps to take.
"""
tab = self.tabs.currentWidget()
tab.zoom(-count)

View File

@ -0,0 +1,97 @@
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""A filter for signals which either filters or passes them."""
import logging
from functools import partial
from PyQt5.QtCore import QObject
from qutebrowser.utils.signals import dbg_signal
from qutebrowser.widgets.browsertab import BrowserTab
class SignalFilter(QObject):
"""A filter for signals.
Signals are only passed to the parent TabbedBrowser if they originated in
the currently shown widget.
Attributes:
_tabs: The QTabWidget associated with this SignalFilter.
"""
def __init__(self, tabs):
super().__init__(tabs)
self._tabs = tabs
def create(self, signal):
"""Factory for partial _filter_signals functions.
Args:
signal: The pyqtSignal to filter.
Return:
A partial functon calling _filter_signals with a signal.
"""
return partial(self._filter_signals, signal)
def _filter_signals(self, signal, *args):
"""Filter signals and trigger TabbedBrowser signals if needed.
Triggers signal if the original signal was sent from the _current_ tab
and not from any other one.
The original signal does not matter, since we get the new signal and
all args.
The current value of the signal is also stored in tab.signal_cache so
it can be emitted later when the tab changes to the current tab.
Args:
signal: The signal to emit if the sender was the current widget.
*args: The args to pass to the signal.
Emit:
The target signal if the sender was the current widget.
"""
# FIXME BUG the signal cache ordering seems to be weird sometimes.
# How to reproduce:
# - Open tab
# - While loading, open another tab
# - Switch back to #1 when loading finished
# - It seems loadingStarted is before loadingFinished
sender = self.sender()
log_signal = not signal.signal.startswith('2cur_progress')
if log_signal:
logging.debug('signal {} (tab {})'.format(
dbg_signal(signal, args), self._tabs.indexOf(sender)))
if not isinstance(sender, BrowserTab):
# FIXME why does this happen?
logging.warn('Got signal {} by {} which is no tab!'.format(
dbg_signal(signal, args), sender))
return
sender.signal_cache.add(signal, args)
if self._tabs.currentWidget() == sender:
if log_signal:
logging.debug(' emitting')
return signal.emit(*args)
else:
if log_signal:
logging.debug(' ignoring')

View File

@ -27,7 +27,7 @@ from PyQt5.QtWebKitWidgets import QWebView, QWebPage
import qutebrowser.utils.url as urlutils
import qutebrowser.config.config as config
import qutebrowser.utils.message as message
from qutebrowser.widgets.browserpage import BrowserPage
from qutebrowser.browser.webpage import BrowserPage
from qutebrowser.utils.signals import SignalCache
from qutebrowser.utils.usertypes import NeighborList

View File

@ -18,19 +18,19 @@
"""The main tabbed browser widget."""
import logging
import functools
from functools import partial
from PyQt5.QtWidgets import QApplication, QShortcut, QSizePolicy
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
from PyQt5.QtGui import QClipboard
from PyQt5.QtPrintSupport import QPrintPreviewDialog
import qutebrowser.utils.url as urlutils
import qutebrowser.config.config as config
import qutebrowser.commands.utils as cmdutils
from qutebrowser.widgets.tabbar import TabWidget
from qutebrowser.widgets.tabwidget import TabWidget
from qutebrowser.widgets.browsertab import BrowserTab
from qutebrowser.utils.signals import dbg_signal
from qutebrowser.browser.signalfilter import SignalFilter
from qutebrowser.browser.curcommand import CurCommandDispatcher
class TabbedBrowser(TabWidget):
@ -51,6 +51,7 @@ class TabbedBrowser(TabWidget):
_url_stack: Stack of URLs of closed tabs.
_space: Space QShortcut to avoid garbage collection
_tabs: A list of open tabs.
_filter: A SignalFilter instance.
cur: A CurCommandDispatcher instance to dispatch commands to the
current tab.
@ -100,6 +101,7 @@ class TabbedBrowser(TabWidget):
self._space.setKey(Qt.Key_Space)
self._space.setContext(Qt.WidgetWithChildrenShortcut)
self._space.activated.connect(lambda: self.cur.scroll_page(0, 1))
self._filter = SignalFilter(self)
self.cur = CurCommandDispatcher(self)
self.cur.temp_message.connect(self.cur_temp_message)
@ -160,61 +162,6 @@ class TabbedBrowser(TabWidget):
else:
logging.debug('ignoring title change')
def _filter_factory(self, signal):
"""Factory for partial _filter_signals functions.
Args:
signal: The pyqtSignal to filter.
Return:
A partial functon calling _filter_signals with a signal.
"""
return functools.partial(self._filter_signals, signal)
def _filter_signals(self, signal, *args):
"""Filter signals and trigger TabbedBrowser signals if needed.
Triggers signal if the original signal was sent from the _current_ tab
and not from any other one.
The original signal does not matter, since we get the new signal and
all args.
The current value of the signal is also stored in tab.signal_cache so
it can be emitted later when the tab changes to the current tab.
Args:
signal: The signal to emit if the sender was the current widget.
*args: The args to pass to the signal.
Emit:
The target signal if the sender was the current widget.
"""
# FIXME BUG the signal cache ordering seems to be weird sometimes.
# How to reproduce:
# - Open tab
# - While loading, open another tab
# - Switch back to #1 when loading finished
# - It seems loadingStarted is before loadingFinished
sender = self.sender()
log_signal = not signal.signal.startswith('2cur_progress')
if log_signal:
logging.debug('signal {} (tab {})'.format(dbg_signal(signal, args),
self.indexOf(sender)))
if not isinstance(sender, BrowserTab):
# FIXME why does this happen?
logging.warn('Got signal {} by {} which is no tab!'.format(
dbg_signal(signal, args), sender))
return
sender.signal_cache.add(signal, args)
if self.currentWidget() == sender:
if log_signal:
logging.debug(' emitting')
return signal.emit(*args)
else:
if log_signal:
logging.debug(' ignoring')
def shutdown(self):
"""Try to shut down all tabs cleanly.
@ -233,8 +180,7 @@ class TabbedBrowser(TabWidget):
for tabidx in range(tabcount):
logging.debug("Shutting down tab {}/{}".format(tabidx, tabcount))
tab = self.widget(tabidx)
tab.shutdown(callback=functools.partial(self._cb_tab_shutdown,
tab))
tab.shutdown(callback=partial(self._cb_tab_shutdown, tab))
@cmdutils.register(instance='mainwindow.tabs')
def tabclose(self, count=None):
@ -258,8 +204,7 @@ class TabbedBrowser(TabWidget):
# FIXME maybe we actually should store the webview objects here
self._url_stack.append(tab.url())
self.removeTab(idx)
tab.shutdown(callback=functools.partial(self._cb_tab_shutdown,
tab))
tab.shutdown(callback=partial(self._cb_tab_shutdown, tab))
elif last_close == 'quit':
self.quit.emit()
elif last_close == 'blank':
@ -280,18 +225,18 @@ class TabbedBrowser(TabWidget):
self._tabs.append(tab)
self.addTab(tab, urlutils.urlstring(url))
self.setCurrentWidget(tab)
tab.linkHovered.connect(self._filter_factory(self.cur_link_hovered))
tab.loadProgress.connect(self._filter_factory(self.cur_progress))
tab.loadFinished.connect(self._filter_factory(self.cur_load_finished))
tab.linkHovered.connect(self._filter.create(self.cur_link_hovered))
tab.loadProgress.connect(self._filter.create(self.cur_progress))
tab.loadFinished.connect(self._filter.create(self.cur_load_finished))
tab.loadStarted.connect(lambda: # pylint: disable=unnecessary-lambda
self.sender().signal_cache.clear())
tab.loadStarted.connect(self._filter_factory(self.cur_load_started))
tab.loadStarted.connect(self._filter.create(self.cur_load_started))
tab.statusBarMessage.connect(
self._filter_factory(self.cur_statusbar_message))
self._filter.create(self.cur_statusbar_message))
tab.scroll_pos_changed.connect(
self._filter_factory(self.cur_scroll_perc_changed))
tab.temp_message.connect(self._filter_factory(self.cur_temp_message))
tab.urlChanged.connect(self._filter_factory(self.cur_url_changed))
self._filter.create(self.cur_scroll_perc_changed))
tab.temp_message.connect(self._filter.create(self.cur_temp_message))
tab.urlChanged.connect(self._filter.create(self.cur_url_changed))
tab.titleChanged.connect(self._titleChanged_handler)
# FIXME sometimes this doesn't load
tab.show()
@ -414,271 +359,3 @@ class TabbedBrowser(TabWidget):
"""
super().resizeEvent(e)
self.resized.emit(self.geometry())
class CurCommandDispatcher(QObject):
"""Command dispatcher for TabbedBrowser.
Contains all commands which are related to the current tab.
We can't simply add these commands to BrowserTab directly and use
currentWidget() for TabbedBrowser.cur because at the time
cmdutils.register() decorators are run, currentWidget() will return None.
Attributes:
tabs: The TabbedBrowser object.
Signals:
temp_message: Connected to TabbedBrowser signal.
"""
# FIXME maybe subclassing would be more clean?
temp_message = pyqtSignal(str)
def __init__(self, parent):
"""Constructor.
Uses setattr to get some methods from parent.
Args:
parent: The TabbedBrowser for this dispatcher.
"""
super().__init__(parent)
self.tabs = parent
def _scroll_percent(self, perc=None, count=None, orientation=None):
"""Inner logic for scroll_percent_(x|y).
Args:
perc: How many percent to scroll, or None
count: How many percent to scroll, or None
orientation: Qt.Horizontal or Qt.Vertical
"""
if perc is None and count is None:
perc = 100
elif perc is None:
perc = int(count)
else:
perc = float(perc)
frame = self.tabs.currentWidget().page_.mainFrame()
m = frame.scrollBarMaximum(orientation)
if m == 0:
return
frame.setScrollBarValue(orientation, int(m * perc / 100))
@cmdutils.register(instance='mainwindow.tabs.cur', name='open',
split_args=False)
def openurl(self, url, count=None):
"""Open an url in the current/[count]th tab.
Command handler for :open.
Args:
url: The URL to open.
count: The tab index to open the URL in, or None.
"""
tab = self.tabs.cntwidget(count)
if tab is None:
if count is None:
# We want to open an URL in the current tab, but none exists
# yet.
self.tabs.tabopen(url)
else:
# Explicit count with a tab that doesn't exist.
return
else:
tab.openurl(url)
@cmdutils.register(instance='mainwindow.tabs.cur', name='reload')
def reloadpage(self, count=None):
"""Reload the current/[count]th tab.
Command handler for :reload.
Args:
count: The tab index to reload, or None.
"""
tab = self.tabs.cntwidget(count)
if tab is not None:
tab.reload()
@cmdutils.register(instance='mainwindow.tabs.cur')
def stop(self, count=None):
"""Stop loading in the current/[count]th tab.
Command handler for :stop.
Args:
count: The tab index to stop, or None.
"""
tab = self.tabs.cntwidget(count)
if tab is not None:
tab.stop()
@cmdutils.register(instance='mainwindow.tabs.cur', name='print')
def printpage(self, count=None):
"""Print the current/[count]th tab.
Command handler for :print.
Args:
count: The tab index to print, or None.
"""
# FIXME that does not what I expect
tab = self.tabs.cntwidget(count)
if tab is not None:
preview = QPrintPreviewDialog(self)
preview.paintRequested.connect(tab.print)
preview.exec_()
@cmdutils.register(instance='mainwindow.tabs.cur')
def back(self, count=1):
"""Go back in the history of the current tab.
Command handler for :back.
Args:
count: How many pages to go back.
"""
# FIXME display warning if beginning of history
for _ in range(count):
self.tabs.currentWidget().back()
@cmdutils.register(instance='mainwindow.tabs.cur')
def forward(self, count=1):
"""Go forward in the history of the current tab.
Command handler for :forward.
Args:
count: How many pages to go forward.
"""
# FIXME display warning if end of history
for _ in range(count):
self.tabs.currentWidget().forward()
@pyqtSlot(str, int)
def search(self, text, flags):
"""Search for text in the current page.
Args:
text: The text to search for.
flags: The QWebPage::FindFlags.
"""
self.tabs.currentWidget().findText(text, flags)
@cmdutils.register(instance='mainwindow.tabs.cur', hide=True)
def scroll(self, dx, dy, count=1):
"""Scroll the current tab by count * dx/dy.
Command handler for :scroll.
Args:
dx: How much to scroll in x-direction.
dy: How much to scroll in x-direction.
count: multiplier
"""
dx = int(count) * float(dx)
dy = int(count) * float(dy)
self.tabs.currentWidget().page_.mainFrame().scroll(dx, dy)
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_x',
hide=True)
def scroll_percent_x(self, perc=None, count=None):
"""Scroll the current tab to a specific percent of the page (horiz).
Command handler for :scroll_perc_x.
Args:
perc: Percentage to scroll.
count: Percentage to scroll.
"""
self._scroll_percent(perc, count, Qt.Horizontal)
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_y',
hide=True)
def scroll_percent_y(self, perc=None, count=None):
"""Scroll the current tab to a specific percent of the page (vert).
Command handler for :scroll_perc_y
Args:
perc: Percentage to scroll.
count: Percentage to scroll.
"""
self._scroll_percent(perc, count, Qt.Vertical)
@cmdutils.register(instance='mainwindow.tabs.cur', hide=True)
def scroll_page(self, mx, my, count=1):
"""Scroll the frame page-wise.
Args:
mx: How many pages to scroll to the right.
my: How many pages to scroll down.
count: multiplier
"""
# FIXME this might not work with HTML frames
page = self.tabs.currentWidget().page_
size = page.viewportSize()
page.mainFrame().scroll(int(count) * float(mx) * size.width(),
int(count) * float(my) * size.height())
@cmdutils.register(instance='mainwindow.tabs.cur')
def yank(self, sel=False):
"""Yank the current url to the clipboard or primary selection.
Command handler for :yank.
Args:
sel: True to use primary selection, False to use clipboard
Emit:
temp_message to display a temporary message.
"""
clip = QApplication.clipboard()
url = urlutils.urlstring(self.tabs.currentWidget().url())
mode = QClipboard.Selection if sel else QClipboard.Clipboard
clip.setText(url, mode)
self.temp_message.emit('URL yanked to {}'.format(
'primary selection' if sel else 'clipboard'))
@cmdutils.register(instance='mainwindow.tabs.cur', name='yanktitle')
def yank_title(self, sel=False):
"""Yank the current title to the clipboard or primary selection.
Command handler for :yanktitle.
Args:
sel: True to use primary selection, False to use clipboard
Emit:
temp_message to display a temporary message.
"""
clip = QApplication.clipboard()
title = self.tabs.tabText(self.tabs.currentIndex())
mode = QClipboard.Selection if sel else QClipboard.Clipboard
clip.setText(title, mode)
self.temp_message.emit('Title yanked to {}'.format(
'primary selection' if sel else 'clipboard'))
@cmdutils.register(instance='mainwindow.tabs.cur', name='zoomin')
def zoom_in(self, count=1):
"""Zoom in in the current tab.
Args:
count: How many steps to take.
"""
tab = self.tabs.currentWidget()
tab.zoom(count)
@cmdutils.register(instance='mainwindow.tabs.cur', name='zoomout')
def zoom_out(self, count=1):
"""Zoom out in the current tab.
Args:
count: How many steps to take.
"""
tab = self.tabs.currentWidget()
tab.zoom(-count)