mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Allow sorting of tags view by popularity
This commit is contained in:
parent
ab6a567334
commit
54bf6f0a7e
@ -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=[],
|
||||||
|
@ -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:
|
||||||
|
@ -262,6 +262,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="popularity" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Sort by &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" >
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user