mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Enhancement 1984121: User category editor: Hide items not shown in tag browser
I cleaned up the code a lot, making it (I hope) easier to understand and more reliable.
This commit is contained in:
parent
3bae760705
commit
9a44efc431
@ -1,48 +1,43 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
from qt.core import (
|
from qt.core import (Qt, QApplication, QDialog, QIcon, QListWidgetItem)
|
||||||
Qt, QApplication, QDialog, QIcon, QListWidgetItem)
|
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories
|
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
|
||||||
from calibre.gui2 import error_dialog, warning_dialog
|
|
||||||
from calibre.constants import islinux
|
from calibre.constants import islinux
|
||||||
from calibre.utils.icu import sort_key, strcmp, primary_contains
|
from calibre.gui2 import error_dialog, warning_dialog
|
||||||
from polyglot.builtins import iteritems
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
|
from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories
|
||||||
|
from calibre.utils.icu import primary_sort_key, strcmp, primary_contains
|
||||||
class Item:
|
|
||||||
|
|
||||||
def __init__(self, name, label, index, icon, exists):
|
|
||||||
self.name = name
|
|
||||||
self.label = label
|
|
||||||
self.index = index
|
|
||||||
self.icon = icon
|
|
||||||
self.exists = exists
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return 'name=%s, label=%s, index=%s, exists=%s'%(self.name, self.label, self.index, self.exists)
|
|
||||||
|
|
||||||
|
|
||||||
class TagCategories(QDialog, Ui_TagCategories):
|
class TagCategories(QDialog, Ui_TagCategories):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
The structure of user_categories stored in preferences is
|
The structure of user_categories stored in preferences is
|
||||||
{cat_name: [ [name, category, v], [], []}, cat_name [ [name, cat, v] ...}
|
{cat_name: [ [name, category, v], [], [] ]}, cat_name: [ [name, cat, v] ...]}
|
||||||
where name is the item name, category is where it came from (series, etc),
|
where name is the item name, category is where it came from (series, etc),
|
||||||
and v is a scratch area that this editor uses to keep track of categories.
|
and v is a scratch area.
|
||||||
|
|
||||||
If you add a category, it is permissible to set v to zero. If you delete
|
If you add a category, set v to zero. If you delete a category, ensure that
|
||||||
a category, ensure that both the name and the category match.
|
both the name and the category match.
|
||||||
'''
|
'''
|
||||||
category_labels_orig = ['', 'authors', 'series', 'publisher', 'tags', 'languages']
|
|
||||||
|
category_icons = {'authors': QIcon.ic('user_profile.png'),
|
||||||
|
'series': QIcon.ic('series.png'),
|
||||||
|
'publisher': QIcon.ic('publisher.png'),
|
||||||
|
'tags': QIcon.ic('tags.png'),
|
||||||
|
'languages': QIcon.ic('languages.png')}
|
||||||
|
|
||||||
|
|
||||||
|
ItemTuple = namedtuple('ItemTuple', 'v k')
|
||||||
|
CategoryNameTuple = namedtuple('CategoryNameTuple', 'n k')
|
||||||
|
|
||||||
def __init__(self, window, db, on_category=None, book_ids=None):
|
def __init__(self, window, db, on_category=None, book_ids=None):
|
||||||
QDialog.__init__(self, window)
|
QDialog.__init__(self, window)
|
||||||
Ui_TagCategories.__init__(self)
|
Ui_TagCategories.__init__(self)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.blank.setText('\xa0')
|
|
||||||
|
|
||||||
# I can't figure out how to get these into the .ui file
|
# I can't figure out how to get these into the .ui file
|
||||||
self.gridLayout_2.setColumnMinimumWidth(0, 50)
|
self.gridLayout_2.setColumnMinimumWidth(0, 50)
|
||||||
@ -58,48 +53,41 @@ class TagCategories(QDialog, Ui_TagCategories):
|
|||||||
self.db = db
|
self.db = db
|
||||||
self.applied_items = []
|
self.applied_items = []
|
||||||
self.book_ids = book_ids
|
self.book_ids = book_ids
|
||||||
|
self.hide_hidden_categories = False
|
||||||
|
self.filter_by_vl = False
|
||||||
|
self.category_labels = [] # The label is the lookup key
|
||||||
|
|
||||||
if self.book_ids is None:
|
if self.book_ids is None:
|
||||||
self.apply_vl_checkbox.setEnabled(False)
|
self.apply_vl_checkbox.setEnabled(False)
|
||||||
|
|
||||||
cc_icon = QIcon.ic('column.png')
|
self.cc_icon = QIcon.ic('column.png')
|
||||||
|
|
||||||
self.category_labels = self.category_labels_orig[:]
|
|
||||||
self.category_icons = [None, QIcon.ic('user_profile.png'), QIcon.ic('series.png'),
|
|
||||||
QIcon.ic('publisher.png'), QIcon.ic('tags.png'),
|
|
||||||
QIcon.ic('languages.png')]
|
|
||||||
self.category_values = [None,
|
|
||||||
lambda: [t.original_name.replace('|', ',') for t in self.db_categories['authors']],
|
|
||||||
lambda: [t.original_name for t in self.db_categories['series']],
|
|
||||||
lambda: [t.original_name for t in self.db_categories['publisher']],
|
|
||||||
lambda: [t.original_name for t in self.db_categories['tags']],
|
|
||||||
lambda: [t.original_name for t in self.db_categories['languages']]
|
|
||||||
]
|
|
||||||
category_names = ['', _('Authors'), ngettext('Series', 'Series', 2),
|
|
||||||
_('Publishers'), _('Tags'), _('Languages')]
|
|
||||||
|
|
||||||
for key,cc in iteritems(self.db.custom_field_metadata()):
|
# Build a dict of all available items, used when checking and building user cats
|
||||||
if cc['datatype'] in ['text', 'series', 'enumeration']:
|
self.all_items = {}
|
||||||
self.category_labels.append(key)
|
db_categories = self.db.new_api.get_categories()
|
||||||
self.category_icons.append(cc_icon)
|
for key, tag in db_categories.items():
|
||||||
self.category_values.append(lambda col=key: [t.original_name for t in self.db_categories[col]])
|
self.all_items[key] = {'icon': self.category_icons.get(key, self.cc_icon),
|
||||||
category_names.append(cc['name'])
|
'name': self.db.field_metadata[key]['name'],
|
||||||
elif cc['datatype'] == 'composite' and \
|
'values': {t.original_name for t in tag}
|
||||||
cc['display'].get('make_category', False):
|
}
|
||||||
self.category_labels.append(key)
|
|
||||||
self.category_icons.append(cc_icon)
|
|
||||||
category_names.append(cc['name'])
|
|
||||||
self.category_values.append(lambda col=key: [t.original_name for t in self.db_categories[col]])
|
|
||||||
self.categories = dict.copy(db.new_api.pref('user_categories', {}))
|
|
||||||
if self.categories is None:
|
|
||||||
self.categories = {}
|
|
||||||
self.initialize_category_lists(book_ids=None)
|
|
||||||
|
|
||||||
self.display_filtered_categories(0)
|
# build the list of all user categories. Filter out keys that no longer exist
|
||||||
|
self.user_categories = {}
|
||||||
|
for cat_name, values in db.new_api.pref('user_categories', {}).items():
|
||||||
|
fv = set()
|
||||||
|
for v in values:
|
||||||
|
if v[1] in self.db.field_metadata:
|
||||||
|
fv.add(self.item_tuple(v[1], v[0]))
|
||||||
|
self.user_categories[cat_name] = fv
|
||||||
|
|
||||||
for v in category_names:
|
# get the hidden categories
|
||||||
self.category_filter_box.addItem(v)
|
hidden_cats = self.db.new_api.pref('tag_browser_hidden_categories', None)
|
||||||
self.current_cat_name = None
|
self.hidden_categories = set()
|
||||||
|
# strip non-existent field keys from hidden categories (just in case)
|
||||||
|
for cat in hidden_cats:
|
||||||
|
if cat in self.db.field_metadata:
|
||||||
|
self.hidden_categories.add(cat)
|
||||||
|
|
||||||
self.copy_category_name_to_clipboard.clicked.connect(self.copy_category_name_to_clipboard_clicked)
|
self.copy_category_name_to_clipboard.clicked.connect(self.copy_category_name_to_clipboard_clicked)
|
||||||
self.apply_button.clicked.connect(self.apply_button_clicked)
|
self.apply_button.clicked.connect(self.apply_button_clicked)
|
||||||
@ -109,20 +97,22 @@ class TagCategories(QDialog, Ui_TagCategories):
|
|||||||
self.category_box.currentIndexChanged.connect(self.select_category)
|
self.category_box.currentIndexChanged.connect(self.select_category)
|
||||||
self.category_filter_box.currentIndexChanged.connect(
|
self.category_filter_box.currentIndexChanged.connect(
|
||||||
self.display_filtered_categories)
|
self.display_filtered_categories)
|
||||||
self.item_filter_box.textEdited.connect(self.display_filtered_items)
|
self.item_filter_box.textEdited.connect(self.apply_filter)
|
||||||
self.delete_category_button.clicked.connect(self.del_category)
|
self.delete_category_button.clicked.connect(self.delete_category)
|
||||||
if islinux:
|
if islinux:
|
||||||
self.available_items_box.itemDoubleClicked.connect(self.apply_tags)
|
self.available_items_box.itemDoubleClicked.connect(self.apply_tags)
|
||||||
else:
|
else:
|
||||||
self.available_items_box.itemActivated.connect(self.apply_tags)
|
self.available_items_box.itemActivated.connect(self.apply_tags)
|
||||||
self.applied_items_box.itemActivated.connect(self.unapply_tags)
|
self.applied_items_box.itemActivated.connect(self.unapply_tags)
|
||||||
self.apply_vl_checkbox.clicked.connect(self.apply_vl)
|
self.apply_vl_checkbox.clicked.connect(self.apply_vl_clicked)
|
||||||
|
self.hide_hidden_categories_checkbox.clicked.connect(self.hide_hidden_categories_clicked)
|
||||||
|
|
||||||
|
self.current_cat_name = None
|
||||||
|
self.initialize_category_lists()
|
||||||
|
self.display_filtered_categories()
|
||||||
self.populate_category_list()
|
self.populate_category_list()
|
||||||
if on_category is not None:
|
if on_category is not None:
|
||||||
l = self.category_box.findText(on_category)
|
self.category_box.setCurrentIndex(self.category_box.findText(on_category))
|
||||||
if l >= 0:
|
|
||||||
self.category_box.setCurrentIndex(l)
|
|
||||||
if self.current_cat_name is None:
|
if self.current_cat_name is None:
|
||||||
self.category_box.setCurrentIndex(0)
|
self.category_box.setCurrentIndex(0)
|
||||||
self.select_category(0)
|
self.select_category(0)
|
||||||
@ -131,66 +121,114 @@ class TagCategories(QDialog, Ui_TagCategories):
|
|||||||
t = self.category_box.itemText(self.category_box.currentIndex())
|
t = self.category_box.itemText(self.category_box.currentIndex())
|
||||||
QApplication.clipboard().setText(t)
|
QApplication.clipboard().setText(t)
|
||||||
|
|
||||||
def initialize_category_lists(self, book_ids):
|
def item_tuple(self, key, val):
|
||||||
self.db_categories = self.db.new_api.get_categories(book_ids=book_ids)
|
return self.ItemTuple(val, key)
|
||||||
self.all_items = []
|
|
||||||
self.all_items_dict = {}
|
def category_name_tuple(self, key, name):
|
||||||
for idx,label in enumerate(self.category_labels):
|
return self.CategoryNameTuple(name, key)
|
||||||
if idx == 0:
|
|
||||||
|
def initialize_category_lists(self):
|
||||||
|
cfb = self.category_filter_box
|
||||||
|
current_cat_filter = (self.category_labels[cfb.currentIndex()]
|
||||||
|
if self.category_labels and cfb.currentIndex() > 0
|
||||||
|
else '')
|
||||||
|
|
||||||
|
# get the values for each category taking into account the VL, then
|
||||||
|
# populate the lists taking hidden and filtered categories into account
|
||||||
|
self.available_items = {}
|
||||||
|
self.sorted_items = []
|
||||||
|
sorted_categories = []
|
||||||
|
item_filter = self.item_filter_box.text()
|
||||||
|
db_categories = self.db.new_api.get_categories(book_ids=self.book_ids if
|
||||||
|
self.filter_by_vl else None)
|
||||||
|
for key, tags in db_categories.items():
|
||||||
|
if key == 'search' or key.startswith('@'):
|
||||||
continue
|
continue
|
||||||
for n in self.category_values[idx]():
|
if self.hide_hidden_categories and key in self.hidden_categories:
|
||||||
t = Item(name=n, label=label, index=len(self.all_items),
|
continue
|
||||||
icon=self.category_icons[idx], exists=True)
|
av = set()
|
||||||
self.all_items.append(t)
|
for t in tags:
|
||||||
self.all_items_dict[icu_lower(label+':'+n)] = t
|
if item_filter and not primary_contains(item_filter, t.original_name):
|
||||||
|
continue
|
||||||
|
av.add(t.original_name)
|
||||||
|
self.sorted_items.append(self.item_tuple(key, t.original_name))
|
||||||
|
self.available_items[key] = av
|
||||||
|
sorted_categories.append(self.category_name_tuple(key, self.all_items[key]['name']))
|
||||||
|
|
||||||
for cat in self.categories:
|
# Sort the items
|
||||||
for item,l in enumerate(self.categories[cat]):
|
self.sorted_items.sort(key=lambda v: primary_sort_key(v.v + v.k))
|
||||||
key = icu_lower(':'.join([l[1], l[0]]))
|
|
||||||
t = self.all_items_dict.get(key, None)
|
|
||||||
if l[1] in self.category_labels:
|
|
||||||
if t is None:
|
|
||||||
t = Item(name=l[0], label=l[1], index=len(self.all_items),
|
|
||||||
icon=self.category_icons[self.category_labels.index(l[1])],
|
|
||||||
exists=False)
|
|
||||||
self.all_items.append(t)
|
|
||||||
self.all_items_dict[key] = t
|
|
||||||
l[2] = t.index
|
|
||||||
else:
|
|
||||||
# remove any references to a category that no longer exists
|
|
||||||
del self.categories[cat][item]
|
|
||||||
|
|
||||||
self.all_items_sorted = sorted(self.all_items, key=lambda x: sort_key(x.name))
|
# Fill in the category names with visible (not hidden) lookup keys
|
||||||
|
sorted_categories.sort(key=lambda v: primary_sort_key(v.n + v.k))
|
||||||
|
cfb.blockSignals(True)
|
||||||
|
cfb.clear()
|
||||||
|
cfb.addItem('', '')
|
||||||
|
for i,v in enumerate(sorted_categories):
|
||||||
|
cfb.addItem(f'{v.n} ({v.k})', v.k)
|
||||||
|
if current_cat_filter == v.k:
|
||||||
|
cfb.setCurrentIndex(i+1)
|
||||||
|
cfb.blockSignals(False)
|
||||||
|
|
||||||
def apply_vl(self, checked):
|
def populate_category_list(self):
|
||||||
if checked:
|
self.category_box.blockSignals(True)
|
||||||
self.initialize_category_lists(self.book_ids)
|
self.category_box.clear()
|
||||||
else:
|
self.category_box.addItems(sorted(self.user_categories.keys(), key=primary_sort_key))
|
||||||
self.initialize_category_lists(None)
|
self.category_box.blockSignals(False)
|
||||||
self.fill_applied_items()
|
|
||||||
|
|
||||||
def make_list_widget(self, item):
|
def make_available_list_item(self, key, val):
|
||||||
n = item.name if item.exists else item.name + _(' (not on any book)')
|
w = QListWidgetItem(self.all_items[key]['icon'], val)
|
||||||
w = QListWidgetItem(item.icon, n)
|
w.setData(Qt.ItemDataRole.UserRole, self.item_tuple(key, val))
|
||||||
w.setData(Qt.ItemDataRole.UserRole, item.index)
|
w.setToolTip(_('Lookup name: {}').format(key))
|
||||||
w.setToolTip(_('Category lookup name: ') + item.label)
|
|
||||||
return w
|
return w
|
||||||
|
|
||||||
def display_filtered_items(self, text):
|
def make_applied_list_item(self, tup):
|
||||||
self.display_filtered_categories(None)
|
if tup.v not in self.all_items[tup.k]['values']:
|
||||||
|
t = tup.v + ' ' + _('(Not in library)')
|
||||||
|
elif tup.k not in self.available_items:
|
||||||
|
t = tup.v + ' ' + _('(Hidden in Tag browser)')
|
||||||
|
elif tup.v not in self.available_items[tup.k]:
|
||||||
|
t = tup.v + ' ' + _('(Hidden by Virtual library)')
|
||||||
|
else:
|
||||||
|
t = tup.v
|
||||||
|
w = QListWidgetItem(self.all_items[tup.k]['icon'], t)
|
||||||
|
w.setData(Qt.ItemDataRole.UserRole, tup)
|
||||||
|
w.setToolTip(_('Lookup name: {}').format(tup.k))
|
||||||
|
return w
|
||||||
|
|
||||||
def display_filtered_categories(self, idx):
|
def hide_hidden_categories_clicked(self, checked):
|
||||||
idx = idx if idx is not None else self.category_filter_box.currentIndex()
|
self.hide_hidden_categories = checked
|
||||||
|
self.initialize_category_lists()
|
||||||
|
self.display_filtered_categories()
|
||||||
|
self.fill_applied_items()
|
||||||
|
|
||||||
|
def apply_vl_clicked(self, checked):
|
||||||
|
self.filter_by_vl = checked
|
||||||
|
self.initialize_category_lists()
|
||||||
|
self.fill_applied_items()
|
||||||
|
|
||||||
|
def apply_filter(self, _):
|
||||||
|
self.initialize_category_lists()
|
||||||
|
self.display_filtered_categories()
|
||||||
|
|
||||||
|
def display_filtered_categories(self):
|
||||||
|
idx = self.category_filter_box.currentIndex()
|
||||||
|
filter_key = self.category_filter_box.itemData(idx)
|
||||||
self.available_items_box.clear()
|
self.available_items_box.clear()
|
||||||
|
for it in self.sorted_items:
|
||||||
|
if idx != 0 and it.k != filter_key:
|
||||||
|
continue
|
||||||
|
self.available_items_box.addItem(self.make_available_list_item(it.k, it.v))
|
||||||
|
|
||||||
|
def fill_applied_items(self):
|
||||||
|
ccn = self.current_cat_name
|
||||||
|
if ccn:
|
||||||
|
self.applied_items = [v for v in self.user_categories[ccn]]
|
||||||
|
self.applied_items.sort(key=lambda x:primary_sort_key(x.v + x.k))
|
||||||
|
else:
|
||||||
|
self.applied_items = []
|
||||||
self.applied_items_box.clear()
|
self.applied_items_box.clear()
|
||||||
item_filter = self.item_filter_box.text()
|
for tup in self.applied_items:
|
||||||
for item in self.all_items_sorted:
|
self.applied_items_box.addItem(self.make_applied_list_item(tup))
|
||||||
if idx == 0 or item.label == self.category_labels[idx]:
|
|
||||||
if item.index not in self.applied_items and item.exists:
|
|
||||||
if primary_contains(item_filter, item.name):
|
|
||||||
self.available_items_box.addItem(self.make_list_widget(item))
|
|
||||||
for index in self.applied_items:
|
|
||||||
self.applied_items_box.addItem(self.make_list_widget(self.all_items[index]))
|
|
||||||
|
|
||||||
def apply_button_clicked(self):
|
def apply_button_clicked(self):
|
||||||
self.apply_tags(node=None)
|
self.apply_tags(node=None)
|
||||||
@ -205,16 +243,16 @@ class TagCategories(QDialog, Ui_TagCategories):
|
|||||||
show=True, show_copy_button=False)
|
show=True, show_copy_button=False)
|
||||||
return
|
return
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
index = self.all_items[node.data(Qt.ItemDataRole.UserRole)].index
|
tup = node.data(Qt.ItemDataRole.UserRole)
|
||||||
if index not in self.applied_items:
|
self.user_categories[self.current_cat_name].add(tup)
|
||||||
self.applied_items.append(index)
|
self.fill_applied_items()
|
||||||
self.applied_items.sort(key=lambda x:sort_key(self.all_items[x].name))
|
|
||||||
self.display_filtered_categories(None)
|
|
||||||
|
|
||||||
def unapply_button_clicked(self):
|
def unapply_button_clicked(self):
|
||||||
self.unapply_tags(node=None)
|
self.unapply_tags(node=None)
|
||||||
|
|
||||||
def unapply_tags(self, node=None):
|
def unapply_tags(self, node=None):
|
||||||
|
if self.current_cat_name is None:
|
||||||
|
return
|
||||||
nodes = self.applied_items_box.selectedItems() if node is None else [node]
|
nodes = self.applied_items_box.selectedItems() if node is None else [node]
|
||||||
if len(nodes) == 0:
|
if len(nodes) == 0:
|
||||||
warning_dialog(self, _('No items selected'),
|
warning_dialog(self, _('No items selected'),
|
||||||
@ -222,15 +260,14 @@ class TagCategories(QDialog, Ui_TagCategories):
|
|||||||
show=True, show_copy_button=False)
|
show=True, show_copy_button=False)
|
||||||
return
|
return
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
index = self.all_items[node.data(Qt.ItemDataRole.UserRole)].index
|
tup = node.data(Qt.ItemDataRole.UserRole)
|
||||||
self.applied_items.remove(index)
|
self.user_categories[self.current_cat_name].discard(tup)
|
||||||
self.display_filtered_categories(None)
|
self.fill_applied_items()
|
||||||
|
|
||||||
def add_category(self):
|
def add_category(self):
|
||||||
self.save_category()
|
|
||||||
cat_name = str(self.input_box.text()).strip()
|
cat_name = str(self.input_box.text()).strip()
|
||||||
if cat_name == '':
|
if cat_name == '':
|
||||||
return False
|
return
|
||||||
comps = [c.strip() for c in cat_name.split('.') if c.strip()]
|
comps = [c.strip() for c in cat_name.split('.') if c.strip()]
|
||||||
if len(comps) == 0 or '.'.join(comps) != cat_name:
|
if len(comps) == 0 or '.'.join(comps) != cat_name:
|
||||||
error_dialog(self, _('Invalid name'),
|
error_dialog(self, _('Invalid name'),
|
||||||
@ -238,64 +275,66 @@ class TagCategories(QDialog, Ui_TagCategories):
|
|||||||
'multiple periods in a row or spaces before '
|
'multiple periods in a row or spaces before '
|
||||||
'or after periods.')).exec()
|
'or after periods.')).exec()
|
||||||
return False
|
return False
|
||||||
for c in sorted(self.categories.keys(), key=sort_key):
|
for c in sorted(self.user_categories.keys(), key=primary_sort_key):
|
||||||
if strcmp(c, cat_name) == 0 or \
|
if strcmp(c, cat_name) == 0 or \
|
||||||
(icu_lower(cat_name).startswith(icu_lower(c) + '.') and
|
(icu_lower(cat_name).startswith(icu_lower(c) + '.') and
|
||||||
not cat_name.startswith(c + '.')):
|
not cat_name.startswith(c + '.')):
|
||||||
error_dialog(self, _('Name already used'),
|
error_dialog(self, _('Name already used'),
|
||||||
_('That name is already used, perhaps with different case.')).exec()
|
_('That name is already used, perhaps with different case.')).exec()
|
||||||
return False
|
return False
|
||||||
if cat_name not in self.categories:
|
if cat_name not in self.user_categories:
|
||||||
|
self.user_categories[cat_name] = set()
|
||||||
self.category_box.clear()
|
self.category_box.clear()
|
||||||
self.current_cat_name = cat_name
|
self.current_cat_name = cat_name
|
||||||
self.categories[cat_name] = []
|
|
||||||
self.applied_items = []
|
|
||||||
self.populate_category_list()
|
self.populate_category_list()
|
||||||
|
self.fill_applied_items()
|
||||||
self.input_box.clear()
|
self.input_box.clear()
|
||||||
self.category_box.setCurrentIndex(self.category_box.findText(cat_name))
|
self.category_box.setCurrentIndex(self.category_box.findText(cat_name))
|
||||||
return True
|
|
||||||
|
|
||||||
def rename_category(self):
|
def rename_category(self):
|
||||||
self.save_category()
|
|
||||||
cat_name = str(self.input_box.text()).strip()
|
cat_name = str(self.input_box.text()).strip()
|
||||||
if cat_name == '':
|
if cat_name == '':
|
||||||
return False
|
return
|
||||||
if not self.current_cat_name:
|
if not self.current_cat_name:
|
||||||
return False
|
return
|
||||||
comps = [c.strip() for c in cat_name.split('.') if c.strip()]
|
comps = [c.strip() for c in cat_name.split('.') if c.strip()]
|
||||||
if len(comps) == 0 or '.'.join(comps) != cat_name:
|
if len(comps) == 0 or '.'.join(comps) != cat_name:
|
||||||
error_dialog(self, _('Invalid name'),
|
error_dialog(self, _('Invalid name'),
|
||||||
_('That name contains leading or trailing periods, '
|
_('That name contains leading or trailing periods, '
|
||||||
'multiple periods in a row or spaces before '
|
'multiple periods in a row or spaces before '
|
||||||
'or after periods.')).exec()
|
'or after periods.')).exec()
|
||||||
return False
|
return
|
||||||
|
|
||||||
for c in self.categories:
|
for c in self.user_categories:
|
||||||
if strcmp(c, cat_name) == 0:
|
if strcmp(c, cat_name) == 0:
|
||||||
error_dialog(self, _('Name already used'),
|
error_dialog(self, _('Name already used'),
|
||||||
_('That name is already used, perhaps with different case.')).exec()
|
_('That name is already used, perhaps with different case.')).exec()
|
||||||
return False
|
return
|
||||||
# The order below is important because of signals
|
# The order below is important because of signals
|
||||||
self.categories[cat_name] = self.categories[self.current_cat_name]
|
self.user_categories[cat_name] = self.user_categories[self.current_cat_name]
|
||||||
del self.categories[self.current_cat_name]
|
del self.user_categories[self.current_cat_name]
|
||||||
self.current_cat_name = None
|
self.current_cat_name = None
|
||||||
self.populate_category_list()
|
self.populate_category_list()
|
||||||
self.input_box.clear()
|
self.input_box.clear()
|
||||||
self.category_box.setCurrentIndex(self.category_box.findText(cat_name))
|
self.category_box.setCurrentIndex(self.category_box.findText(cat_name))
|
||||||
return True
|
return
|
||||||
|
|
||||||
def del_category(self):
|
def delete_category(self):
|
||||||
if self.current_cat_name is not None:
|
if self.current_cat_name is not None:
|
||||||
if not confirm('<p>'+_('The current User category will be '
|
if not confirm('<p>'+_('The current User category will be '
|
||||||
'<b>permanently deleted</b>. Are you sure?') +
|
'<b>permanently deleted</b>. Are you sure?') +
|
||||||
'</p>', 'tag_category_delete', self):
|
'</p>', 'tag_category_delete', self):
|
||||||
return
|
return
|
||||||
del self.categories[self.current_cat_name]
|
del self.user_categories[self.current_cat_name]
|
||||||
|
# self.category_box.removeItem(self.category_box.currentIndex())
|
||||||
|
self.populate_category_list()
|
||||||
|
if self.category_box.count():
|
||||||
|
self.current_cat_name = self.category_box.itemText(0)
|
||||||
|
else:
|
||||||
self.current_cat_name = None
|
self.current_cat_name = None
|
||||||
self.category_box.removeItem(self.category_box.currentIndex())
|
self.fill_applied_items()
|
||||||
|
|
||||||
def select_category(self, idx):
|
def select_category(self, idx):
|
||||||
self.save_category()
|
|
||||||
s = self.category_box.itemText(idx)
|
s = self.category_box.itemText(idx)
|
||||||
if s:
|
if s:
|
||||||
self.current_cat_name = str(s)
|
self.current_cat_name = str(s)
|
||||||
@ -303,34 +342,13 @@ class TagCategories(QDialog, Ui_TagCategories):
|
|||||||
self.current_cat_name = None
|
self.current_cat_name = None
|
||||||
self.fill_applied_items()
|
self.fill_applied_items()
|
||||||
|
|
||||||
def fill_applied_items(self):
|
|
||||||
if self.current_cat_name:
|
|
||||||
self.applied_items = [cat[2] for cat in self.categories.get(self.current_cat_name, [])]
|
|
||||||
else:
|
|
||||||
self.applied_items = []
|
|
||||||
self.applied_items.sort(key=lambda x:sort_key(self.all_items[x].name))
|
|
||||||
self.display_filtered_categories(None)
|
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
self.save_category()
|
# Reconstruct the pref value
|
||||||
for cat in sorted(self.categories.keys(), key=sort_key):
|
self.categories = {}
|
||||||
components = cat.split('.')
|
for cat in self.user_categories:
|
||||||
for i in range(0,len(components)):
|
cat_values = []
|
||||||
c = '.'.join(components[0:i+1])
|
for tup in self.user_categories[cat]:
|
||||||
if c not in self.categories:
|
cat_values.append([tup.v, tup.k, 0])
|
||||||
self.categories[c] = []
|
self.categories[cat] = cat_values
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
||||||
def save_category(self):
|
|
||||||
if self.current_cat_name is not None:
|
|
||||||
l = []
|
|
||||||
for index in self.applied_items:
|
|
||||||
item = self.all_items[index]
|
|
||||||
l.append([item.name, item.label, item.index])
|
|
||||||
self.categories[self.current_cat_name] = l
|
|
||||||
|
|
||||||
def populate_category_list(self):
|
|
||||||
self.category_box.blockSignals(True)
|
|
||||||
self.category_box.clear()
|
|
||||||
self.category_box.addItems(sorted(self.categories.keys(), key=sort_key))
|
|
||||||
self.category_box.blockSignals(False)
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Category &name: </string>
|
<string>&User category name: </string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
@ -177,19 +177,24 @@
|
|||||||
<item row="1" column="0" colspan="3">
|
<item row="1" column="0" colspan="3">
|
||||||
<widget class="QCheckBox" name="apply_vl_checkbox">
|
<widget class="QCheckBox" name="apply_vl_checkbox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><p>Show items in the Available items box only if they appear in the
|
<string><p>Only show items that are visible in current Virtual
|
||||||
current Virtual library. Applied items not in the Virtual library will be marked
|
library. Applied items not shown in the Virtual library will be
|
||||||
"not on any book".</p></string>
|
marked "Hidden by Virtual library".</p></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Show only available items in current Virtual library</string>
|
<string>&Only show items visible in current Virtual library</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0" colspan="3">
|
||||||
<widget class="QLabel" name="blank">
|
<widget class="QCheckBox" name="hide_hidden_categories_checkbox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>Don't show items that are hidden in the Tag browser.
|
||||||
|
Applied items not shown in the Tag browser will be marked
|
||||||
|
"Hidden in Tag browser".</p></string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string>&Don't show items hidden in the Tag browser</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user