mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
1) On tag pane editing of series, publisher, tags, search
2) a few cleanups, such as sorting the hidden category list
This commit is contained in:
parent
55c0f6f289
commit
07837f6d47
@ -26,7 +26,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
elif category == 'series':
|
elif category == 'series':
|
||||||
result = db.get_series_with_ids()
|
result = db.get_series_with_ids()
|
||||||
compare = (lambda x,y:cmp(title_sort(x).lower(), title_sort(y).lower()))
|
compare = (lambda x,y:cmp(title_sort(x).lower(), title_sort(y).lower()))
|
||||||
elif category == 'publishers':
|
elif category == 'publisher':
|
||||||
result = db.get_publishers_with_ids()
|
result = db.get_publishers_with_ids()
|
||||||
compare = (lambda x,y:cmp(x.lower(), y.lower()))
|
compare = (lambda x,y:cmp(x.lower(), y.lower()))
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
elif self.category == 'series':
|
elif self.category == 'series':
|
||||||
rename_func = self.db.rename_series
|
rename_func = self.db.rename_series
|
||||||
delete_func = self.db.delete_series_using_id
|
delete_func = self.db.delete_series_using_id
|
||||||
elif self.category == 'publishers':
|
elif self.category == 'publisher':
|
||||||
rename_func = self.db.rename_publisher
|
rename_func = self.db.rename_publisher
|
||||||
delete_func = self.db.delete_publisher_using_id
|
delete_func = self.db.delete_publisher_using_id
|
||||||
|
|
||||||
|
@ -20,12 +20,14 @@ from calibre.utils.search_query_parser import saved_searches
|
|||||||
|
|
||||||
class TagsView(QTreeView): # {{{
|
class TagsView(QTreeView): # {{{
|
||||||
|
|
||||||
need_refresh = pyqtSignal()
|
refresh_required = pyqtSignal()
|
||||||
restriction_set = pyqtSignal(object)
|
restriction_set = pyqtSignal(object)
|
||||||
tags_marked = pyqtSignal(object, object)
|
tags_marked = pyqtSignal(object, object)
|
||||||
user_category_edit = pyqtSignal(object)
|
user_category_edit = pyqtSignal(object)
|
||||||
tag_list_edit = pyqtSignal(object, object)
|
tag_list_edit = pyqtSignal(object, object)
|
||||||
saved_search_edit = pyqtSignal(object)
|
saved_search_edit = pyqtSignal(object)
|
||||||
|
tag_item_renamed = pyqtSignal()
|
||||||
|
search_item_renamed = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
QTreeView.__init__(self, *args)
|
QTreeView.__init__(self, *args)
|
||||||
@ -36,7 +38,8 @@ class TagsView(QTreeView): # {{{
|
|||||||
|
|
||||||
def set_database(self, db, tag_match, popularity, restriction):
|
def set_database(self, db, tag_match, popularity, restriction):
|
||||||
self.hidden_categories = config['tag_browser_hidden_categories']
|
self.hidden_categories = config['tag_browser_hidden_categories']
|
||||||
self._model = TagsModel(db, parent=self, hidden_categories=self.hidden_categories)
|
self._model = TagsModel(db, parent=self,
|
||||||
|
hidden_categories=self.hidden_categories)
|
||||||
self.popularity = popularity
|
self.popularity = popularity
|
||||||
self.restriction = restriction
|
self.restriction = restriction
|
||||||
self.tag_match = tag_match
|
self.tag_match = tag_match
|
||||||
@ -48,12 +51,12 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.popularity.setChecked(config['sort_by_popularity'])
|
self.popularity.setChecked(config['sort_by_popularity'])
|
||||||
self.popularity.stateChanged.connect(self.sort_changed)
|
self.popularity.stateChanged.connect(self.sort_changed)
|
||||||
self.restriction.activated[str].connect(self.search_restriction_set)
|
self.restriction.activated[str].connect(self.search_restriction_set)
|
||||||
self.need_refresh.connect(self.recount, type=Qt.QueuedConnection)
|
self.refresh_required.connect(self.recount, type=Qt.QueuedConnection)
|
||||||
db.add_listener(self.database_changed)
|
db.add_listener(self.database_changed)
|
||||||
self.saved_searches_changed(recount=False)
|
self.saved_searches_changed(recount=False)
|
||||||
|
|
||||||
def database_changed(self, event, ids):
|
def database_changed(self, event, ids):
|
||||||
self.need_refresh.emit()
|
self.refresh_required.emit()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def match_all(self):
|
def match_all(self):
|
||||||
@ -80,16 +83,23 @@ class TagsView(QTreeView): # {{{
|
|||||||
if event.button() == Qt.LeftButton:
|
if event.button() == Qt.LeftButton:
|
||||||
QTreeView.mouseReleaseEvent(self, event)
|
QTreeView.mouseReleaseEvent(self, event)
|
||||||
|
|
||||||
|
def mouseDoubleClickEvent(self, event):
|
||||||
|
# swallow these to avoid toggling and editing at the same time
|
||||||
|
pass
|
||||||
|
|
||||||
def toggle(self, index):
|
def toggle(self, index):
|
||||||
modifiers = int(QApplication.keyboardModifiers())
|
modifiers = int(QApplication.keyboardModifiers())
|
||||||
exclusive = modifiers not in (Qt.CTRL, Qt.SHIFT)
|
exclusive = modifiers not in (Qt.CTRL, Qt.SHIFT)
|
||||||
if self._model.toggle(index, exclusive):
|
if self._model.toggle(index, exclusive):
|
||||||
self.tags_marked.emit(self._model.tokens(), self.match_all)
|
self.tags_marked.emit(self._model.tokens(), self.match_all)
|
||||||
|
|
||||||
def context_menu_handler(self, action=None, category=None):
|
def context_menu_handler(self, action=None, category=None, index=None):
|
||||||
if not action:
|
if not action:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
if action == 'edit_item':
|
||||||
|
self.edit(index)
|
||||||
|
return
|
||||||
if action == 'manage_tags':
|
if action == 'manage_tags':
|
||||||
self.tag_list_edit.emit(category, 'tags')
|
self.tag_list_edit.emit(category, 'tags')
|
||||||
return
|
return
|
||||||
@ -97,7 +107,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.tag_list_edit.emit(category, 'series')
|
self.tag_list_edit.emit(category, 'series')
|
||||||
return
|
return
|
||||||
if action == 'manage_publishers':
|
if action == 'manage_publishers':
|
||||||
self.tag_list_edit.emit(category, 'publishers')
|
self.tag_list_edit.emit(category, 'publisher')
|
||||||
return
|
return
|
||||||
if action == 'manage_categories':
|
if action == 'manage_categories':
|
||||||
self.user_category_edit.emit(category)
|
self.user_category_edit.emit(category)
|
||||||
@ -123,24 +133,31 @@ class TagsView(QTreeView): # {{{
|
|||||||
item = index.internalPointer()
|
item = index.internalPointer()
|
||||||
tag_name = ''
|
tag_name = ''
|
||||||
if item.type == TagTreeItem.TAG:
|
if item.type == TagTreeItem.TAG:
|
||||||
|
tag_item = item
|
||||||
tag_name = item.tag.name
|
tag_name = item.tag.name
|
||||||
item = item.parent
|
item = item.parent
|
||||||
if item.type == TagTreeItem.CATEGORY:
|
if item.type == TagTreeItem.CATEGORY:
|
||||||
category = unicode(item.name.toString())
|
category = unicode(item.name.toString())
|
||||||
self.context_menu = QMenu(self)
|
self.context_menu = QMenu(self)
|
||||||
self.context_menu.addAction(_('Hide %s') % category,
|
# If the user right-clicked on a tag/series/publisher, then offer
|
||||||
partial(self.context_menu_handler, action='hide', category=category))
|
# the possibility of renaming that item
|
||||||
|
if tag_name and item.category_key in ['tags', 'series', 'publisher', 'search']:
|
||||||
if self.hidden_categories:
|
self.context_menu.addAction(_('Rename item') + " '" + tag_name + "'",
|
||||||
|
partial(self.context_menu_handler, action='edit_item',
|
||||||
|
category=tag_item, index=index))
|
||||||
self.context_menu.addSeparator()
|
self.context_menu.addSeparator()
|
||||||
|
# Hide/Show/Restore categories
|
||||||
|
self.context_menu.addAction(_('Hide category %s') % category,
|
||||||
|
partial(self.context_menu_handler, action='hide', category=category))
|
||||||
|
if self.hidden_categories:
|
||||||
m = self.context_menu.addMenu(_('Show category'))
|
m = self.context_menu.addMenu(_('Show category'))
|
||||||
for col in self.hidden_categories:
|
for col in sorted(self.hidden_categories, cmp=lambda x,y: cmp(x.lower(), y.lower())):
|
||||||
m.addAction(col,
|
m.addAction(col,
|
||||||
partial(self.context_menu_handler, action='show', category=col))
|
partial(self.context_menu_handler, action='show', category=col))
|
||||||
self.context_menu.addSeparator()
|
self.context_menu.addAction(_('Show all categories'),
|
||||||
self.context_menu.addAction(_('Restore defaults'),
|
|
||||||
partial(self.context_menu_handler, action='defaults'))
|
partial(self.context_menu_handler, action='defaults'))
|
||||||
|
|
||||||
|
# Offer specific editors for tags/series/publishers/saved searches
|
||||||
self.context_menu.addSeparator()
|
self.context_menu.addSeparator()
|
||||||
if category == _('Tags'):
|
if category == _('Tags'):
|
||||||
self.context_menu.addAction(_('Manage Tags'),
|
self.context_menu.addAction(_('Manage Tags'),
|
||||||
@ -159,6 +176,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
partial(self.context_menu_handler, action='manage_series',
|
partial(self.context_menu_handler, action='manage_series',
|
||||||
category=tag_name))
|
category=tag_name))
|
||||||
|
|
||||||
|
# Always show the user categories editor
|
||||||
self.context_menu.addSeparator()
|
self.context_menu.addSeparator()
|
||||||
if category in prefs['user_categories'].keys():
|
if category in prefs['user_categories'].keys():
|
||||||
self.context_menu.addAction(_('Manage User Categories'),
|
self.context_menu.addAction(_('Manage User Categories'),
|
||||||
@ -219,7 +237,8 @@ class TagTreeItem(object): # {{{
|
|||||||
TAG = 1
|
TAG = 1
|
||||||
ROOT = 2
|
ROOT = 2
|
||||||
|
|
||||||
def __init__(self, data=None, category_icon=None, icon_map=None, parent=None, tooltip=None):
|
def __init__(self, data=None, category_icon=None, icon_map=None,
|
||||||
|
parent=None, tooltip=None, category_key=None):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.children = []
|
self.children = []
|
||||||
if self.parent is not None:
|
if self.parent is not None:
|
||||||
@ -234,6 +253,7 @@ class TagTreeItem(object): # {{{
|
|||||||
self.bold_font = QFont()
|
self.bold_font = QFont()
|
||||||
self.bold_font.setBold(True)
|
self.bold_font.setBold(True)
|
||||||
self.bold_font = QVariant(self.bold_font)
|
self.bold_font = QVariant(self.bold_font)
|
||||||
|
self.category_key = category_key
|
||||||
elif self.type == self.TAG:
|
elif self.type == self.TAG:
|
||||||
icon_map[0] = data.icon
|
icon_map[0] = data.icon
|
||||||
self.tag, self.icon_state_map = data, list(map(QVariant, icon_map))
|
self.tag, self.icon_state_map = data, list(map(QVariant, icon_map))
|
||||||
@ -279,6 +299,8 @@ class TagTreeItem(object): # {{{
|
|||||||
return QVariant('%s'%(self.tag.name))
|
return QVariant('%s'%(self.tag.name))
|
||||||
else:
|
else:
|
||||||
return QVariant('[%d] %s'%(self.tag.count, self.tag.name))
|
return QVariant('[%d] %s'%(self.tag.count, self.tag.name))
|
||||||
|
if role == Qt.EditRole:
|
||||||
|
return QVariant(self.tag.name)
|
||||||
if role == Qt.DecorationRole:
|
if role == Qt.DecorationRole:
|
||||||
return self.icon_state_map[self.tag.state]
|
return self.icon_state_map[self.tag.state]
|
||||||
if role == Qt.ToolTipRole and self.tag.tooltip is not None:
|
if role == Qt.ToolTipRole and self.tag.tooltip is not None:
|
||||||
@ -293,7 +315,7 @@ class TagTreeItem(object): # {{{
|
|||||||
|
|
||||||
class TagsModel(QAbstractItemModel): # {{{
|
class TagsModel(QAbstractItemModel): # {{{
|
||||||
|
|
||||||
def __init__(self, db, parent=None, hidden_categories=None):
|
def __init__(self, db, parent, hidden_categories=None):
|
||||||
QAbstractItemModel.__init__(self, parent)
|
QAbstractItemModel.__init__(self, parent)
|
||||||
|
|
||||||
# must do this here because 'QPixmap: Must construct a QApplication
|
# must do this here because 'QPixmap: Must construct a QApplication
|
||||||
@ -313,6 +335,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
|
|
||||||
self.icon_state_map = [None, QIcon(I('plus.svg')), QIcon(I('minus.svg'))]
|
self.icon_state_map = [None, QIcon(I('plus.svg')), QIcon(I('minus.svg'))]
|
||||||
self.db = db
|
self.db = db
|
||||||
|
self.tags_view = parent
|
||||||
self.hidden_categories = hidden_categories
|
self.hidden_categories = hidden_categories
|
||||||
self.search_restriction = ''
|
self.search_restriction = ''
|
||||||
self.ignore_next_search = 0
|
self.ignore_next_search = 0
|
||||||
@ -340,7 +363,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
c = TagTreeItem(parent=self.root_item,
|
c = TagTreeItem(parent=self.root_item,
|
||||||
data=self.categories[i],
|
data=self.categories[i],
|
||||||
category_icon=self.category_icon_map[r],
|
category_icon=self.category_icon_map[r],
|
||||||
tooltip=tt)
|
tooltip=tt, category_key=r)
|
||||||
for tag in data[r]:
|
for tag in data[r]:
|
||||||
TagTreeItem(parent=c, data=tag, icon_map=self.icon_state_map)
|
TagTreeItem(parent=c, data=tag, icon_map=self.icon_state_map)
|
||||||
|
|
||||||
@ -398,11 +421,35 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
item = index.internalPointer()
|
item = index.internalPointer()
|
||||||
return item.data(role)
|
return item.data(role)
|
||||||
|
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
if not index.isValid():
|
||||||
|
return NONE
|
||||||
|
val = unicode(value.toString())
|
||||||
|
item = index.internalPointer()
|
||||||
|
if item.parent.category_key == 'series':
|
||||||
|
self.db.rename_series(item.tag.id, val)
|
||||||
|
item.tag.name = val
|
||||||
|
self.tags_view.tag_item_renamed.emit()
|
||||||
|
elif item.parent.category_key == 'publisher':
|
||||||
|
self.db.rename_publisher(item.tag.id, val)
|
||||||
|
item.tag.name = val
|
||||||
|
self.tags_view.tag_item_renamed.emit()
|
||||||
|
elif item.parent.category_key == 'tags':
|
||||||
|
self.db.rename_tag(item.tag.id, val)
|
||||||
|
item.tag.name = val
|
||||||
|
self.tags_view.tag_item_renamed.emit()
|
||||||
|
elif item.parent.category_key == 'search':
|
||||||
|
saved_searches.rename(unicode(item.data(role).toString()), val)
|
||||||
|
item.tag.name = val
|
||||||
|
self.tags_view.search_item_renamed.emit()
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
|
return True
|
||||||
|
|
||||||
def headerData(self, *args):
|
def headerData(self, *args):
|
||||||
return NONE
|
return NONE
|
||||||
|
|
||||||
def flags(self, *args):
|
def flags(self, *args):
|
||||||
return Qt.ItemIsEnabled|Qt.ItemIsSelectable
|
return Qt.ItemIsEnabled|Qt.ItemIsSelectable|Qt.ItemIsEditable
|
||||||
|
|
||||||
def path_for_index(self, index):
|
def path_for_index(self, index):
|
||||||
ans = []
|
ans = []
|
||||||
|
@ -553,6 +553,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
|
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
|
||||||
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
|
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
|
||||||
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
|
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
|
||||||
|
self.tags_view.tag_item_renamed.connect(self.library_view.model().refresh)
|
||||||
|
self.tags_view.search_item_renamed.connect(self.saved_search.clear_to_help)
|
||||||
self.search.search.connect(self.tags_view.model().reinit)
|
self.search.search.connect(self.tags_view.model().reinit)
|
||||||
for x in (self.location_view.count_changed, self.tags_view.recount,
|
for x in (self.location_view.count_changed, self.tags_view.recount,
|
||||||
self.restriction_count_changed):
|
self.restriction_count_changed):
|
||||||
|
@ -52,6 +52,12 @@ class SavedSearchQueries(object):
|
|||||||
self.queries.pop(self.force_unicode(name), False)
|
self.queries.pop(self.force_unicode(name), False)
|
||||||
prefs[self.opt_name] = self.queries
|
prefs[self.opt_name] = self.queries
|
||||||
|
|
||||||
|
def rename(self, old_name, new_name):
|
||||||
|
self.queries[self.force_unicode(new_name)] = \
|
||||||
|
self.queries.get(self.force_unicode(old_name), None)
|
||||||
|
self.queries.pop(self.force_unicode(old_name), False)
|
||||||
|
prefs[self.opt_name] = self.queries
|
||||||
|
|
||||||
def names(self):
|
def names(self):
|
||||||
return sorted(self.queries.keys(),
|
return sorted(self.queries.keys(),
|
||||||
cmp=lambda x,y: cmp(x.lower(), y.lower()))
|
cmp=lambda x,y: cmp(x.lower(), y.lower()))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user