From 1524f29f71018ad1a5844c2c364e11b04d50493d Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 20 Mar 2016 13:03:14 +1300 Subject: [PATCH 1/4] Add titles to history entry. Adds a title to the HistoryEntry class and includes it in the serialization stuff. Not currently set from anywhere. Not sure if anything more needs to be done to support non-ascii characters. Everything works fine for me with unicode chars in url and title but everything in my stack is utf-8. --- qutebrowser/browser/history.py | 24 +++++++++++++---------- qutebrowser/completion/models/urlmodel.py | 5 ++++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index 1a4876a85..e68dc610a 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -40,18 +40,18 @@ class HistoryEntry: url_string: The URL which was accessed as string. """ - def __init__(self, atime, url): + def __init__(self, atime, url, title): self.atime = float(atime) self.url = QUrl(url) self.url_string = url + self.title = title def __repr__(self): return utils.get_repr(self, constructor=True, atime=self.atime, - url=self.url.toDisplayString()) + url=self.url.toDisplayString(), title=self.title) def __str__(self): - return '{} {}'.format(int(self.atime), self.url_string) - + return '{} {} {}'.format(int(self.atime), self.url_string, self.title) class WebHistory(QWebHistoryInterface): @@ -118,16 +118,20 @@ class WebHistory(QWebHistoryInterface): with self._lineparser.open(): for line in self._lineparser: yield - data = line.rstrip().split(maxsplit=1) + data = line.rstrip().split(maxsplit=2) if not data: # empty line continue - elif len(data) != 2: + elif len(data) == 2: + atime, url = data + title = "" + elif len(data) == 3: + atime, url, title = data + else: # other malformed line log.init.warning("Invalid history entry {!r}!".format( line)) continue - atime, url = data if atime.startswith('\0'): log.init.debug( "Removing NUL bytes from entry {!r} - see " @@ -139,7 +143,7 @@ class WebHistory(QWebHistoryInterface): # information about previous hits change the items in # old_urls to be lists or change HistoryEntry to have a # list of atimes. - entry = HistoryEntry(atime, url) + entry = HistoryEntry(atime, url, title) self._add_entry(entry) self._initial_read_done = True @@ -169,7 +173,7 @@ class WebHistory(QWebHistoryInterface): self._lineparser.save() self._saved_count = len(self._new_history) - def addHistoryEntry(self, url_string): + def addHistoryEntry(self, url_string, title=""): """Called by WebKit when an URL should be added to the history. Args: @@ -179,7 +183,7 @@ class WebHistory(QWebHistoryInterface): return if config.get('general', 'private-browsing'): return - entry = HistoryEntry(time.time(), url_string) + entry = HistoryEntry(time.time(), url_string, title) if self._initial_read_done: self.add_completion_item.emit(entry) self._new_history.append(entry) diff --git a/qutebrowser/completion/models/urlmodel.py b/qutebrowser/completion/models/urlmodel.py index 466dea65c..cec726355 100644 --- a/qutebrowser/completion/models/urlmodel.py +++ b/qutebrowser/completion/models/urlmodel.py @@ -99,7 +99,8 @@ class UrlCompletionModel(base.BaseCompletionModel): def _add_history_entry(self, entry): """Add a new history entry to the completion.""" - self.new_item(self._history_cat, entry.url.toDisplayString(), "", + self.new_item(self._history_cat, entry.url.toDisplayString(), + entry.title, self._fmt_atime(entry.atime), sort=int(entry.atime), userdata=entry.url) @@ -122,9 +123,11 @@ class UrlCompletionModel(base.BaseCompletionModel): for i in range(self._history_cat.rowCount()): url_item = self._history_cat.child(i, self.URL_COLUMN) atime_item = self._history_cat.child(i, self.TIME_COLUMN) + title_item = self._history_cat.child(i, self.TEXT_COLUMN) url = url_item.data(base.Role.userdata) if url == entry.url: atime_item.setText(self._fmt_atime(entry.atime)) + title_item.setText(entry.title) url_item.setData(int(entry.atime), base.Role.sort) break else: From 33fbe978638ed1804fca51277c74369392419abc Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 20 Mar 2016 13:14:10 +1300 Subject: [PATCH 2/4] Switch browsing history away from QWebHistoryInterface. Now adds a url to browser history once we have connected and got enough data to start rendering the page. The previous approach saved urls as soon as navigation was initiated, so upon encountering a redirect the final url wasn't saved. Using layout started rather than load finished means that pages whose contents manage to load minus one troublesome asset will still be saved. --- qutebrowser/browser/history.py | 1 - qutebrowser/browser/webview.py | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index e68dc610a..a0dedb468 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -212,4 +212,3 @@ def init(parent=None): """ history = WebHistory(parent) objreg.register('web-history', history) - QWebHistoryInterface.setDefaultInterface(history) diff --git a/qutebrowser/browser/webview.py b/qutebrowser/browser/webview.py index 3d2e80e4c..4166432af 100644 --- a/qutebrowser/browser/webview.py +++ b/qutebrowser/browser/webview.py @@ -145,6 +145,12 @@ class WebView(QWebView): self.loadProgress.connect(lambda p: setattr(self, 'progress', p)) objreg.get('config').changed.connect(self.on_config_changed) + @pyqtSlot() + def on_initial_layout_complete(self): + """Add url to history now that we have displayed something.""" + objreg.get('web-history').addHistoryEntry( + self.url().toDisplayString(), self.title()) + def _init_page(self): """Initialize the QWebPage used by this view.""" page = webpage.BrowserPage(self.win_id, self.tab_id, self) @@ -152,6 +158,8 @@ class WebView(QWebView): page.linkHovered.connect(self.linkHovered) page.mainFrame().loadStarted.connect(self.on_load_started) page.mainFrame().loadFinished.connect(self.on_load_finished) + page.mainFrame().initialLayoutCompleted.connect( + self.on_initial_layout_complete) page.statusBarMessage.connect( lambda msg: setattr(self, 'statusbar_message', msg)) page.networkAccessManager().sslErrors.connect( From b48b36a88dc4970e6880c4604644fcaea53dee43 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 4 Apr 2016 17:07:28 +1200 Subject: [PATCH 3/4] fixup! Switch browsing history away from QWebHistoryInterface. --- qutebrowser/browser/history.py | 7 ++++++- qutebrowser/browser/webview.py | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index a0dedb468..fb58d4fa5 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -173,7 +173,11 @@ class WebHistory(QWebHistoryInterface): self._lineparser.save() self._saved_count = len(self._new_history) - def addHistoryEntry(self, url_string, title=""): + def addHistoryEntry(self, url_string): + """Required for a QWebHistoryInterface impl, obseleted by add_url.""" + pass + + def add_url(self, url_string, title=""): """Called by WebKit when an URL should be added to the history. Args: @@ -212,3 +216,4 @@ def init(parent=None): """ history = WebHistory(parent) objreg.register('web-history', history) + QWebHistoryInterface.setDefaultInterface(history) diff --git a/qutebrowser/browser/webview.py b/qutebrowser/browser/webview.py index 4166432af..2512160e3 100644 --- a/qutebrowser/browser/webview.py +++ b/qutebrowser/browser/webview.py @@ -146,9 +146,9 @@ class WebView(QWebView): objreg.get('config').changed.connect(self.on_config_changed) @pyqtSlot() - def on_initial_layout_complete(self): + def on_initial_layout_completed(self): """Add url to history now that we have displayed something.""" - objreg.get('web-history').addHistoryEntry( + objreg.get('web-history').add_url( self.url().toDisplayString(), self.title()) def _init_page(self): @@ -159,7 +159,7 @@ class WebView(QWebView): page.mainFrame().loadStarted.connect(self.on_load_started) page.mainFrame().loadFinished.connect(self.on_load_finished) page.mainFrame().initialLayoutCompleted.connect( - self.on_initial_layout_complete) + self.on_initial_layout_completed) page.statusBarMessage.connect( lambda msg: setattr(self, 'statusbar_message', msg)) page.networkAccessManager().sslErrors.connect( From cd21f6326ed0c40f2b741f45ce579e71910400ac Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 4 Apr 2016 18:06:46 +1200 Subject: [PATCH 4/4] Save redirect links that are clicked on to history. This allows webkit to color links that are clicked on but never rendered as visited too. It also means if you get redirected from eg http://site.com to http://site.com/ you have essentially duplicates in your history. This makes the history completion a bit noisier. I suppose normalising paths before checking for duplicates might help. Also note that otter has an isTypedIn flag which might be used for dealing with this. --- qutebrowser/browser/webview.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/qutebrowser/browser/webview.py b/qutebrowser/browser/webview.py index 2512160e3..b05fc84ea 100644 --- a/qutebrowser/browser/webview.py +++ b/qutebrowser/browser/webview.py @@ -119,6 +119,7 @@ class WebView(QWebView): self.destroyed.connect(functools.partial( cfg.changed.disconnect, self.init_neighborlist)) self.cur_url = QUrl() + self._orig_url = QUrl() self.progress = 0 self.registry = objreg.ObjectRegistry() self.tab_id = next(tab_id_gen) @@ -148,8 +149,13 @@ class WebView(QWebView): @pyqtSlot() def on_initial_layout_completed(self): """Add url to history now that we have displayed something.""" - objreg.get('web-history').add_url( - self.url().toDisplayString(), self.title()) + history = objreg.get('web-history') + if not self._orig_url.matches(self.cur_url, + QUrl.UrlFormattingOption(0)): + # If the url of the page is different than the url of the link + # originally clicked, save them both. + history.add_url(self._orig_url.toDisplayString()) + history.add_url(self.cur_url.toDisplayString(), self.title()) def _init_page(self): """Initialize the QWebPage used by this view.""" @@ -190,6 +196,8 @@ class WebView(QWebView): log.webview.debug("load status for {}: {}".format(repr(self), val)) self.load_status = val self.load_status_changed.emit(val.name) + if val == LoadStatus.loading: + self._orig_url = self.cur_url def _set_bg_color(self): """Set the webpage background color as configured."""