Refactor :undo and save/restore history.

This commit is contained in:
Florian Bruhin 2014-09-27 22:56:50 +02:00
parent 03e809a230
commit 4410536f69
3 changed files with 50 additions and 9 deletions

View File

@ -511,10 +511,9 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher')
def undo(self):
"""Re-open a closed tab (optionally skipping [count] closed tabs)."""
url_stack = objreg.get('url-stack', None)
if url_stack:
objreg.get('tabbed-browser').tabopen(url_stack.pop())
else:
try:
objreg.get('tabbed-browser').undo()
except IndexError:
raise cmdexc.CommandError("Nothing to undo!")
@cmdutils.register(instance='command-dispatcher')

View File

@ -32,7 +32,8 @@ import sys
import operator
from distutils.version import StrictVersion as Version
from PyQt5.QtCore import QEventLoop, qVersion
from PyQt5.QtCore import (qVersion, QEventLoop, QDataStream, QByteArray,
QIODevice)
MAXVALS = {
@ -128,6 +129,36 @@ def ensure_valid(obj):
raise QtValueError(obj)
def _check_qdatastream(stream):
"""Check the status of a QDataStream and raise IOError if it's not ok."""
status_to_str = {
QDataStream.Ok: "The data stream is operating normally.",
QDataStream.ReadPastEnd: ("The data stream has read past the end of "
"the data in the underlying device."),
QDataStream.ReadCorruptData: "The data stream has read corrupt data.",
QDataStream.WriteFailed: ("The data stream cannot write to the "
"underlying device."),
}
if stream.status() != QDataStream.Ok:
raise IOError(status_to_str[stream.status()])
def serialize(obj):
"""Serialize an object into a QByteArray."""
data = QByteArray()
stream = QDataStream(data, QIODevice.WriteOnly)
stream << obj
_check_qdatastream(stream)
return data
def deserialize(data, obj):
"""Deserialize an object from a QByteArray."""
stream = QDataStream(data, QIODevice.ReadOnly)
stream >> obj
_check_qdatastream(stream)
class QtValueError(ValueError):
"""Exception which gets raised by ensure_valid."""

View File

@ -20,6 +20,7 @@
"""The main tabbed browser widget."""
import functools
import collections
from PyQt5.QtWidgets import QSizePolicy
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QSize, QTimer, QUrl
@ -34,6 +35,9 @@ from qutebrowser.browser import signalfilter, commands
from qutebrowser.utils import log, message, usertypes, utils, qtutils, objreg
UndoEntry = collections.namedtuple('UndoEntry', ['url', 'history'])
class TabbedBrowser(tabwidget.TabWidget):
"""A TabWidget with QWebViews inside.
@ -53,7 +57,7 @@ class TabbedBrowser(tabwidget.TabWidget):
_tab_insert_idx_left: Where to insert a new tab with
tabbar -> new-tab-position set to 'left'.
_tab_insert_idx_right: Same as above, for 'right'.
_url_stack: Stack of URLs of closed tabs.
_undo_stack: List of UndoEntry namedtuples of closed tabs.
Signals:
cur_progress: Progress of the current tab changed (loadProgress).
@ -102,8 +106,7 @@ class TabbedBrowser(tabwidget.TabWidget):
self.cur_load_started.connect(self.on_cur_load_started)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self._tabs = []
self._url_stack = []
objreg.register('url-stack', self._url_stack)
self._undo_stack = []
self._filter = signalfilter.SignalFilter(self)
dispatcher = commands.CommandDispatcher()
objreg.register('command-dispatcher', dispatcher)
@ -244,12 +247,20 @@ class TabbedBrowser(tabwidget.TabWidget):
objreg.delete('last-focused-tab')
if not tab.cur_url.isEmpty():
qtutils.ensure_valid(tab.cur_url)
self._url_stack.append(tab.cur_url)
history_data = qtutils.serialize(tab.history())
entry = UndoEntry(tab.cur_url, history_data)
self._undo_stack.append(entry)
tab.shutdown()
self._tabs.remove(tab)
self.removeTab(idx)
tab.deleteLater()
def undo(self):
"""Undo removing of a tab."""
url, history_data = self._undo_stack.pop()
newtab = self.tabopen(url)
qtutils.deserialize(history_data, newtab.history())
@pyqtSlot('QUrl', bool)
def openurl(self, url, newtab):
"""Open a URL, used as a slot.