Tooltips in Tag Browser and allow sorting of TB by average rating as well

This commit is contained in:
Kovid Goyal 2010-06-15 10:03:26 -06:00
commit b2cccd1281
4 changed files with 48 additions and 31 deletions

View File

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

View File

@ -10,7 +10,7 @@ Browsing book collection by tags.
from itertools import izip
from functools import partial
from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, QCheckBox, \
from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \
QFont, QSize, QIcon, QPoint, QVBoxLayout, QComboBox, \
QAbstractItemModel, QVariant, QModelIndex, QMenu, \
QPushButton, QWidget, QItemDelegate
@ -24,7 +24,7 @@ from calibre.gui2.dialogs.tag_categories import TagCategories
from calibre.gui2.dialogs.tag_list_editor import TagListEditor
from calibre.gui2.dialogs.edit_authors_dialog import EditAuthorsDialog
class TagDelegate(QItemDelegate):
class TagDelegate(QItemDelegate): # {{{
def paint(self, painter, option, index):
item = index.internalPointer()
@ -54,6 +54,8 @@ class TagDelegate(QItemDelegate):
model.data(index, Qt.DisplayRole).toString())
painter.restore()
# }}}
class TagsView(QTreeView): # {{{
refresh_required = pyqtSignal()
@ -77,12 +79,12 @@ class TagsView(QTreeView): # {{{
self.setHeaderHidden(True)
self.setItemDelegate(TagDelegate(self))
def set_database(self, db, tag_match, popularity):
def set_database(self, db, tag_match, sort_by):
self.hidden_categories = config['tag_browser_hidden_categories']
self._model = TagsModel(db, parent=self,
hidden_categories=self.hidden_categories,
search_restriction=None)
self.popularity = popularity
self.sort_by = sort_by
self.tag_match = tag_match
self.db = db
self.search_restriction = None
@ -90,8 +92,9 @@ class TagsView(QTreeView): # {{{
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.clicked.connect(self.toggle)
self.customContextMenuRequested.connect(self.show_context_menu)
self.popularity.setChecked(config['sort_by_popularity'])
self.popularity.stateChanged.connect(self.sort_changed)
pop = config['sort_tags_by']
self.sort_by.setCurrentIndex(self.db.CATEGORY_SORTS.index(pop))
self.sort_by.currentIndexChanged.connect(self.sort_changed)
self.refresh_required.connect(self.recount, type=Qt.QueuedConnection)
db.add_listener(self.database_changed)
@ -102,8 +105,8 @@ class TagsView(QTreeView): # {{{
def match_all(self):
return self.tag_match and self.tag_match.currentIndex() > 0
def sort_changed(self, state):
config.set('sort_by_popularity', state == Qt.Checked)
def sort_changed(self, pop):
config.set('sort_tags_by', self.db.CATEGORY_SORTS[pop])
self.recount()
def set_search_restriction(self, s):
@ -386,7 +389,7 @@ class TagsModel(QAbstractItemModel): # {{{
self.row_map = []
# get_node_tree cannot return None here, because row_map is empty
data = self.get_node_tree(config['sort_by_popularity'])
data = self.get_node_tree(config['sort_tags_by'])
self.root_item = TagTreeItem()
for i, r in enumerate(self.row_map):
if self.hidden_categories and self.categories[i] in self.hidden_categories:
@ -430,11 +433,11 @@ class TagsModel(QAbstractItemModel): # {{{
# Now get the categories
if self.search_restriction:
data = self.db.get_categories(sort_on_count=sort,
data = self.db.get_categories(sort=sort,
icon_map=self.category_icon_map,
ids=self.db.search('', return_matches=True))
else:
data = self.db.get_categories(sort_on_count=sort, icon_map=self.category_icon_map)
data = self.db.get_categories(sort=sort, icon_map=self.category_icon_map)
tb_categories = self.db.field_metadata
for category in tb_categories:
@ -448,7 +451,7 @@ class TagsModel(QAbstractItemModel): # {{{
return data
def refresh(self):
data = self.get_node_tree(config['sort_by_popularity']) # get category data
data = self.get_node_tree(config['sort_tags_by']) # get category data
if data is None:
return False
row_index = -1
@ -657,7 +660,7 @@ class TagBrowserMixin(object): # {{{
def __init__(self, db):
self.library_view.model().count_changed_signal.connect(self.tags_view.recount)
self.tags_view.set_database(self.library_view.model().db,
self.tag_match, self.popularity)
self.tag_match, self.sort_by)
self.tags_view.tags_marked.connect(self.search.search_from_tags)
self.tags_view.tags_marked.connect(self.saved_search.clear_to_help)
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
@ -718,9 +721,13 @@ class TagBrowserWidget(QWidget): # {{{
parent.tags_view = TagsView(parent)
self._layout.addWidget(parent.tags_view)
parent.popularity = QCheckBox(parent)
parent.popularity.setText(_('Sort by &popularity'))
self._layout.addWidget(parent.popularity)
parent.sort_by = QComboBox(parent)
# Must be in the same order as db2.CATEGORY_SORTS
for x in (_('Sort by name'), _('Sort by popularity'),
_('Sort by average rating')):
parent.sort_by.addItem(x)
parent.sort_by.setCurrentIndex(0)
self._layout.addWidget(parent.sort_by)
parent.tag_match = QComboBox(parent)
for x in (_('Match any'), _('Match all')):

View File

@ -430,7 +430,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{
self.book_on_device(None, reset=True)
db.set_book_on_device_func(self.book_on_device)
self.library_view.set_database(db)
self.tags_view.set_database(db, self.tag_match, self.popularity)
self.tags_view.set_database(db, self.tag_match, self.sort_by)
self.library_view.model().set_book_on_device_func(self.book_on_device)
self.status_bar.clear_message()
self.search.clear_to_help()

View File

@ -64,6 +64,10 @@ class Tag(object):
self.state = state
self.avg_rating = avg/2.0 if avg is not None else 0
self.sort = sort
if self.avg_rating > 0:
if tooltip:
tooltip = tooltip + ': '
tooltip = _('%sAverage rating is %3.1f')%(tooltip, self.avg_rating)
self.tooltip = tooltip
self.icon = icon
@ -687,7 +691,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
tn=field['table'], col=field['link_column']), (id_,))
return set(x[0] for x in ans)
def get_categories(self, sort_on_count=False, ids=None, icon_map=None):
CATEGORY_SORTS = ('name', 'popularity', 'rating')
def get_categories(self, sort='name', ids=None, icon_map=None):
self.books_list_filter.change([] if not ids else ids)
categories = {}
@ -711,10 +717,12 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
else:
query = '''SELECT id, {0}, count, avg_rating, sort
FROM tag_browser_filtered_{1}'''.format(cn, tn)
if sort_on_count:
query += ' ORDER BY count DESC'
else:
if sort == 'popularity':
query += ' ORDER BY count DESC, sort ASC'
elif sort == 'name':
query += ' ORDER BY sort ASC'
else:
query += ' ORDER BY avg_rating DESC, sort ASC'
data = self.conn.get(query)
# icon_map is not None if get_categories is to store an icon and
@ -770,11 +778,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if count > 0:
categories['formats'].append(Tag(fmt, count=count, icon=icon))
if sort_on_count:
categories['formats'].sort(cmp=lambda x,y:cmp(x.count, y.count),
reverse=True)
else:
categories['formats'].sort(cmp=lambda x,y:cmp(x.name, y.name))
if sort == 'popularity':
categories['formats'].sort(key=lambda x: x.count, reverse=True)
else: # no ratings exist to sort on
categories['formats'].sort(key = lambda x:x.name)
#### Now do the user-defined categories. ####
user_categories = prefs['user_categories']
@ -799,12 +806,15 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# Not a problem if we accumulate entries in the icon map
if icon_map is not None:
icon_map[cat_name] = icon_map[':user']
if sort_on_count:
if sort == 'popularity':
categories[cat_name] = \
sorted(items, cmp=(lambda x, y: cmp(y.count, x.count)))
sorted(items, key=lambda x: x.count, reverse=True)
elif sort == 'name':
categories[cat_name] = \
sorted(items, key=lambda x: x.sort.lower())
else:
categories[cat_name] = \
sorted(items, cmp=(lambda x, y: cmp(x.name.lower(), y.name.lower())))
sorted(items, key=lambda x:x.avg_rating, reverse=True)
#### Finally, the saved searches category ####
items = []