Allow sorting of tags view by popularity

This commit is contained in:
Kovid Goyal 2008-10-04 15:55:41 -07:00
parent ab6a567334
commit 54bf6f0a7e
5 changed files with 53 additions and 16 deletions

View File

@ -37,6 +37,8 @@ def _config():
help=_('Notify when a new version is available')) help=_('Notify when a new version is available'))
c.add_opt('use_roman_numerals_for_series_number', default=True, c.add_opt('use_roman_numerals_for_series_number', default=True,
help=_('Use Roman numerals for series number')) help=_('Use Roman numerals for series number'))
c.add_opt('sort_by_popularity', default=False,
help=_('Sort tags list by popularity'))
c.add_opt('cover_flow_queue_length', default=6, c.add_opt('cover_flow_queue_length', default=6,
help=_('Number of covers to show in the cover browsing mode')) help=_('Number of covers to show in the cover browsing mode'))
c.add_opt('LRF_conversion_defaults', default=[], c.add_opt('LRF_conversion_defaults', default=[],

View File

@ -250,7 +250,8 @@ class Main(MainWindow, Ui_MainWindow):
self.tags_view.setVisible(False) self.tags_view.setVisible(False)
self.match_all.setVisible(False) self.match_all.setVisible(False)
self.match_any.setVisible(False) self.match_any.setVisible(False)
self.tags_view.set_database(db, self.match_all) self.popularity.setVisible(False)
self.tags_view.set_database(db, self.match_all, self.popularity)
self.connect(self.tags_view, SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'), self.connect(self.tags_view, SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'),
self.search.search_from_tokens) self.search.search_from_tokens)
self.connect(self.status_bar.tag_view_button, SIGNAL('toggled(bool)'), self.toggle_tags_view) self.connect(self.status_bar.tag_view_button, SIGNAL('toggled(bool)'), self.toggle_tags_view)
@ -300,11 +301,13 @@ class Main(MainWindow, Ui_MainWindow):
self.tags_view.setVisible(True) self.tags_view.setVisible(True)
self.match_all.setVisible(True) self.match_all.setVisible(True)
self.match_any.setVisible(True) self.match_any.setVisible(True)
self.popularity.setVisible(True)
self.tags_view.setFocus(Qt.OtherFocusReason) self.tags_view.setFocus(Qt.OtherFocusReason)
else: else:
self.tags_view.setVisible(False) self.tags_view.setVisible(False)
self.match_all.setVisible(False) self.match_all.setVisible(False)
self.match_any.setVisible(False) self.match_any.setVisible(False)
self.popularity.setVisible(False)
def sync_cf_to_listview(self, index, *args): def sync_cf_to_listview(self, index, *args):
if not hasattr(index, 'row') and self.library_view.currentIndex().row() != index: if not hasattr(index, 'row') and self.library_view.currentIndex().row() != index:

View File

@ -262,6 +262,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="popularity" >
<property name="text" >
<string>Sort by &amp;popularity</string>
</property>
</widget>
</item>
<item> <item>
<widget class="TagsView" name="tags_view" > <widget class="TagsView" name="tags_view" >
<property name="tabKeyNavigation" > <property name="tabKeyNavigation" >

View File

@ -8,7 +8,7 @@ Browsing book collection by tags.
''' '''
from PyQt4.Qt import QAbstractItemModel, Qt, QVariant, QTreeView, QModelIndex, \ from PyQt4.Qt import QAbstractItemModel, Qt, QVariant, QTreeView, QModelIndex, \
QFont, SIGNAL, QSize, QColor, QIcon QFont, SIGNAL, QSize, QColor, QIcon
from calibre.gui2 import config
NONE = QVariant() NONE = QVariant()
class TagsView(QTreeView): class TagsView(QTreeView):
@ -19,23 +19,24 @@ class TagsView(QTreeView):
self.setCursor(Qt.PointingHandCursor) self.setCursor(Qt.PointingHandCursor)
self.setIconSize(QSize(30, 30)) self.setIconSize(QSize(30, 30))
def set_database(self, db, match_all): def set_database(self, db, match_all, popularity):
self._model = TagsModel(db) self._model = TagsModel(db)
self.popularity = popularity
self.match_all = match_all self.match_all = match_all
self.setModel(self._model) self.setModel(self._model)
self.connect(self, SIGNAL('clicked(QModelIndex)'), self.toggle) self.connect(self, SIGNAL('clicked(QModelIndex)'), self.toggle)
self.popularity.setChecked(config['sort_by_popularity'])
self.connect(self.popularity, SIGNAL('stateChanged(int)'), self.sort_changed)
def sort_changed(self, state):
config.set('sort_by_popularity', state == Qt.Checked)
self.model().refresh()
def toggle(self, index): def toggle(self, index):
if self._model.toggle(index): if self._model.toggle(index):
self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'), self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'),
self._model.tokens(), self.match_all.isChecked()) self._model.tokens(), self.match_all.isChecked())
class Tag(unicode):
def __init__(self, name):
unicode.__init__(self, name)
self.state = 0
class TagsModel(QAbstractItemModel): class TagsModel(QAbstractItemModel):
categories = [_('Authors'), _('Series'), _('Formats'), _('Publishers'), _('Tags')] categories = [_('Authors'), _('Series'), _('Formats'), _('Publishers'), _('Tags')]
@ -61,9 +62,9 @@ class TagsModel(QAbstractItemModel):
def refresh(self): def refresh(self):
old_data = self._data old_data = self._data
self._data = self.db.get_categories() self._data = self.db.get_categories(config['sort_by_popularity'])
for key in self._data: for key in self._data:
self._data[key] = list(map(Tag, self._data[key])) self._data[key] = self._data[key]
for key in old_data.keys(): for key in old_data.keys():
for tag in old_data[key]: for tag in old_data[key]:
try: try:
@ -152,7 +153,7 @@ class TagsModel(QAbstractItemModel):
def tag_data(self, index, role): def tag_data(self, index, role):
category = self.row_map[index.parent().row()] category = self.row_map[index.parent().row()]
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
return QVariant(self._data[category][index.row()]) return QVariant(self._data[category][index.row()].as_string())
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
return self.status_map[self._data[category][index.row()].state] return self.status_map[self._data[category][index.row()].state]
return NONE return NONE

View File

@ -326,6 +326,16 @@ class ResultCache(object):
ans = (no_tags + ans) if order == 'ASC' else (ans + no_tags) ans = (no_tags + ans) if order == 'ASC' else (ans + no_tags)
return ans return ans
class Tag(unicode):
def __init__(self, name):
unicode.__init__(self, name)
self.count = 0
self.state = 0
def as_string(self):
return u'[%d] %s'%(self.count, self)
class LibraryDatabase2(LibraryDatabase): class LibraryDatabase2(LibraryDatabase):
''' '''
An ebook metadata database that stores references to ebook files on disk. An ebook metadata database that stores references to ebook files on disk.
@ -683,7 +693,7 @@ class LibraryDatabase2(LibraryDatabase):
self.conn.execute(st%dict(ltable='series', table='series', ltable_col='series')) self.conn.execute(st%dict(ltable='series', table='series', ltable_col='series'))
self.conn.commit() self.conn.commit()
def get_categories(self): def get_categories(self, sort_on_count=False):
categories = {} categories = {}
def get(name, category, field='name'): def get(name, category, field='name'):
ans = self.conn.execute('SELECT DISTINCT %s FROM %s'%(field, name)).fetchall() ans = self.conn.execute('SELECT DISTINCT %s FROM %s'%(field, name)).fetchall()
@ -691,9 +701,23 @@ class LibraryDatabase2(LibraryDatabase):
try: try:
ans.remove('') ans.remove('')
except ValueError: pass except ValueError: pass
ans.sort() categories[category] = list(map(Tag, ans))
categories[category] = ans tags = categories[category]
for x in (('authors', 'author'), ('tags', 'tag'), ('publishers', 'publisher'), ('series', 'series')): if name != 'data':
for tag in tags:
id = self.conn.execute('SELECT id FROM %s WHERE %s=?'%(name, field), (tag,)).fetchone()
if id:
id = id[0]
tag.id = id
for tag in tags:
if tag.id is not None:
tag.count = self.conn.execute('SELECT COUNT(id) FROM books_%s_link WHERE %s=?'%(name, category), (tag.id,)).fetchone()[0]
else:
for tag in tags:
tag.count = self.conn.execute('SELECT COUNT(format) FROM data WHERE format=?', (tag,)).fetchone()[0]
tags.sort(reverse=sort_on_count, cmp=(lambda x,y:cmp(x.count,y.count)) if sort_on_count else cmp)
for x in (('authors', 'author'), ('tags', 'tag'), ('publishers', 'publisher'),
('series', 'series')):
get(*x) get(*x)
get('data', 'format', 'format') get('data', 'format', 'format')
return categories return categories