66938ed44b
When a redirect occurs, the item is saved in history with a -r suffix now. When opening qutebrowser that's picked up and the item is hidden from completion.
196 lines
7.3 KiB
Python
196 lines
7.3 KiB
Python
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
|
|
|
# Copyright 2014-2016 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/>.
|
|
|
|
"""CompletionModels for URLs."""
|
|
|
|
import datetime
|
|
|
|
from PyQt5.QtCore import pyqtSlot, Qt
|
|
|
|
from qutebrowser.utils import objreg, utils, qtutils, log
|
|
from qutebrowser.completion.models import base
|
|
from qutebrowser.config import config
|
|
|
|
|
|
class UrlCompletionModel(base.BaseCompletionModel):
|
|
|
|
"""A model which combines bookmarks, quickmarks and web history URLs.
|
|
|
|
Used for the `open` command.
|
|
"""
|
|
|
|
# https://github.com/The-Compiler/qutebrowser/issues/545
|
|
# pylint: disable=abstract-method
|
|
|
|
URL_COLUMN = 0
|
|
TEXT_COLUMN = 1
|
|
TIME_COLUMN = 2
|
|
|
|
COLUMN_WIDTHS = (40, 50, 10)
|
|
DUMB_SORT = Qt.DescendingOrder
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
|
|
self.columns_to_filter = [self.URL_COLUMN, self.TEXT_COLUMN]
|
|
|
|
self._quickmark_cat = self.new_category("Quickmarks")
|
|
self._bookmark_cat = self.new_category("Bookmarks")
|
|
self._history_cat = self.new_category("History")
|
|
|
|
quickmark_manager = objreg.get('quickmark-manager')
|
|
quickmarks = quickmark_manager.marks.items()
|
|
for qm_name, qm_url in quickmarks:
|
|
self.new_item(self._quickmark_cat, qm_url, qm_name)
|
|
quickmark_manager.added.connect(
|
|
lambda name, url: self.new_item(self._quickmark_cat, url, name))
|
|
quickmark_manager.removed.connect(self.on_quickmark_removed)
|
|
|
|
bookmark_manager = objreg.get('bookmark-manager')
|
|
bookmarks = bookmark_manager.marks.items()
|
|
for bm_url, bm_title in bookmarks:
|
|
self.new_item(self._bookmark_cat, bm_url, bm_title)
|
|
bookmark_manager.added.connect(
|
|
lambda name, url: self.new_item(self._bookmark_cat, url, name))
|
|
bookmark_manager.removed.connect(self.on_bookmark_removed)
|
|
|
|
self._history = objreg.get('web-history')
|
|
self._max_history = config.get('completion', 'web-history-max-items')
|
|
history = utils.newest_slice(self._history, self._max_history)
|
|
for entry in history:
|
|
if not entry.redirect:
|
|
self._add_history_entry(entry)
|
|
self._history.add_completion_item.connect(self.on_history_item_added)
|
|
self._history.cleared.connect(self.on_history_cleared)
|
|
|
|
objreg.get('config').changed.connect(self.reformat_timestamps)
|
|
|
|
def _fmt_atime(self, atime):
|
|
"""Format an atime to a human-readable string."""
|
|
fmt = config.get('completion', 'timestamp-format')
|
|
if fmt is None:
|
|
return ''
|
|
try:
|
|
dt = datetime.datetime.fromtimestamp(atime)
|
|
except (ValueError, OSError, OverflowError):
|
|
# Different errors which can occur for too large values...
|
|
log.misc.error("Got invalid timestamp {}!".format(atime))
|
|
return '(invalid)'
|
|
else:
|
|
return dt.strftime(fmt)
|
|
|
|
def _remove_oldest_history(self):
|
|
"""Remove the oldest history entry."""
|
|
self._history_cat.removeRow(0)
|
|
|
|
def _add_history_entry(self, entry):
|
|
"""Add a new history entry to the completion."""
|
|
self.new_item(self._history_cat, entry.url.toDisplayString(),
|
|
entry.title,
|
|
self._fmt_atime(entry.atime), sort=int(entry.atime),
|
|
userdata=entry.url)
|
|
|
|
if (self._max_history != -1 and
|
|
self._history_cat.rowCount() > self._max_history):
|
|
self._remove_oldest_history()
|
|
|
|
@config.change_filter('completion', 'timestamp-format')
|
|
def reformat_timestamps(self):
|
|
"""Reformat the timestamps if the config option was changed."""
|
|
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)
|
|
atime = url_item.data(base.Role.sort)
|
|
atime_item.setText(self._fmt_atime(atime))
|
|
|
|
@pyqtSlot(object)
|
|
def on_history_item_added(self, entry):
|
|
"""Slot called when a new history item was added."""
|
|
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:
|
|
self._add_history_entry(entry)
|
|
|
|
@pyqtSlot()
|
|
def on_history_cleared(self):
|
|
self._history_cat.removeRows(0, self._history_cat.rowCount())
|
|
|
|
def _remove_item(self, data, category, column):
|
|
"""Helper function for on_quickmark_removed and on_bookmark_removed.
|
|
|
|
Args:
|
|
data: The item to search for.
|
|
category: The category to search in.
|
|
column: The column to use for matching.
|
|
"""
|
|
for i in range(category.rowCount()):
|
|
item = category.child(i, column)
|
|
if item.data(Qt.DisplayRole) == data:
|
|
category.removeRow(i)
|
|
break
|
|
|
|
@pyqtSlot(str)
|
|
def on_quickmark_removed(self, name):
|
|
"""Called when a quickmark has been removed by the user.
|
|
|
|
Args:
|
|
name: The name of the quickmark which has been removed.
|
|
"""
|
|
self._remove_item(name, self._quickmark_cat, self.TEXT_COLUMN)
|
|
|
|
@pyqtSlot(str)
|
|
def on_bookmark_removed(self, url):
|
|
"""Called when a bookmark has been removed by the user.
|
|
|
|
Args:
|
|
url: The url of the bookmark which has been removed.
|
|
"""
|
|
self._remove_item(url, self._bookmark_cat, self.URL_COLUMN)
|
|
|
|
def delete_cur_item(self, completion):
|
|
"""Delete the selected item.
|
|
|
|
Args:
|
|
completion: The Completion object to use.
|
|
"""
|
|
index = completion.currentIndex()
|
|
qtutils.ensure_valid(index)
|
|
category = index.parent()
|
|
index = category.child(index.row(), self.URL_COLUMN)
|
|
url = index.data()
|
|
qtutils.ensure_valid(category)
|
|
|
|
if category.data() == 'Bookmarks':
|
|
bookmark_manager = objreg.get('bookmark-manager')
|
|
bookmark_manager.delete(url)
|
|
elif category.data() == 'Quickmarks':
|
|
quickmark_manager = objreg.get('quickmark-manager')
|
|
sibling = index.sibling(index.row(), self.TEXT_COLUMN)
|
|
qtutils.ensure_valid(sibling)
|
|
name = sibling.data()
|
|
quickmark_manager.quickmark_del(name)
|