This commit is contained in:
Kovid Goyal 2025-01-31 19:59:58 +05:30
commit dce5f748ed
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 177 additions and 63 deletions

View File

@ -14,11 +14,13 @@ from qt.core import QAbstractItemView, QApplication, QDialog, QIcon, QMenu, QSiz
from calibre.constants import config_dir from calibre.constants import config_dir
from calibre.db.constants import TEMPLATE_ICON_INDICATOR from calibre.db.constants import TEMPLATE_ICON_INDICATOR
from calibre.gui2 import choose_files, gprefs, pixmap_to_data from calibre.gui2 import choose_files, gprefs, pixmap_to_data
from calibre.gui2.dialogs.tag_list_editor import block_signals
from calibre.gui2.dialogs.template_dialog import TemplateDialog from calibre.gui2.dialogs.template_dialog import TemplateDialog
from calibre.gui2.library.delegates import DelegateCB from calibre.gui2.library.delegates import DelegateCB
from calibre.gui2.preferences import LazyConfigWidgetBase from calibre.gui2.preferences import LazyConfigWidgetBase
from calibre.gui2.preferences.look_feel_tabs.tb_icon_rules_ui import Ui_Form from calibre.gui2.preferences.look_feel_tabs.tb_icon_rules_ui import Ui_Form
from calibre.utils.formatter import EvalFormatter from calibre.utils.formatter import EvalFormatter
from calibre.utils.icu import sort_key
DELETED_COLUMN = 0 DELETED_COLUMN = 0
CATEGORY_COLUMN = 1 CATEGORY_COLUMN = 1
@ -35,7 +37,7 @@ class StateTableWidgetItem(QTableWidgetItem):
def __init__(self, txt): def __init__(self, txt):
super().__init__(txt) super().__init__(txt)
self.setIcon(QIcon.cached_icon('blank.png')) self.setIcon(QIcon.cached_icon('blank.png'))
self.setFlags(Qt.ItemFlag.NoItemFlags) self.setFlags(Qt.ItemFlag.ItemIsEnabled)
def setText(self, txt): def setText(self, txt):
if txt: if txt:
@ -56,18 +58,18 @@ class CategoryTableWidgetItem(QTableWidgetItem):
super().__init__(txt) super().__init__(txt)
self._lookup_name = lookup_name self._lookup_name = lookup_name
self._table = table self._table = table
self._is_modified = False self._is_deleted = False
self.setIcon(category_icons.get(lookup_name) or QIcon.cached_icon('column.png')) self.setIcon(category_icons.get(lookup_name) or QIcon.cached_icon('column.png'))
self._txt = txt self._txt = txt
self.setFlags(self.flags() & ~Qt.ItemFlag.ItemIsEditable) self.setFlags(self.flags() & ~Qt.ItemFlag.ItemIsEditable)
@property @property
def is_modified(self): def is_deleted(self):
return self._is_modified return self._is_deleted
@is_modified.setter @is_deleted.setter
def is_modified(self, to_what): def is_deleted(self, to_what):
self._is_modified = to_what self._is_deleted = to_what
deleted_item = self._table.item(self.row(), DELETED_COLUMN) deleted_item = self._table.item(self.row(), DELETED_COLUMN)
deleted_item.setText(to_what) deleted_item.setText(to_what)
@ -76,18 +78,27 @@ class CategoryTableWidgetItem(QTableWidgetItem):
return self._lookup_name return self._lookup_name
def undo(self): def undo(self):
self.is_modified = False self.is_deleted = False
class ValueTableWidgetItem(QTableWidgetItem): class ValueTableWidgetItem(QTableWidgetItem):
def __init__(self, txt, table): def __init__(self, txt, table, all_values):
self._original_text = txt self._original_text = txt
self._table = table self._table = table
self._all_values = all_values
self._is_template = is_template = txt == TEMPLATE_ICON_INDICATOR self._is_template = is_template = txt == TEMPLATE_ICON_INDICATOR
self._is_modified = False
self._is_editable = False
super().__init__(('{' + _('template') + '}') if is_template else txt) super().__init__(('{' + _('template') + '}') if is_template else txt)
self.setIcon(QIcon.cached_icon('debug.png' if is_template else 'icon_choose.png')) if not is_template and txt not in all_values:
self.setFlags(self.flags() & ~Qt.ItemFlag.ItemIsEditable) icon = "dialog_error.png"
self.setToolTip(_("The value {} doesn't exist in the library").format(txt))
self._is_editable = True
else:
icon = 'debug.png' if is_template else 'icon_choose.png'
self.setFlags(self.flags() & ~Qt.ItemFlag.ItemIsEditable)
self.setIcon(QIcon.cached_icon(icon))
@property @property
def original_text(self): def original_text(self):
@ -97,9 +108,59 @@ class ValueTableWidgetItem(QTableWidgetItem):
def is_template(self): def is_template(self):
return self._is_template return self._is_template
@property
def is_deleted(self):
return self._table.item(self.row(), CATEGORY_COLUMN).is_deleted
@property @property
def is_modified(self): def is_modified(self):
return self._table.item(self.row(), CATEGORY_COLUMN).is_modified return self._is_modified
@is_modified.setter
def is_modified(self, to_what):
self._is_modified = to_what
self.setIcon(QIcon.cached_icon('modified.png'))
@property
def is_editable(self):
return self._is_editable
def undo(self):
self.is_modified = False
self.setText(self._original_text)
self.setIcon(QIcon.cached_icon('dialog_error.png'))
class ValueTableItemDelegate(QStyledItemDelegate):
def __init__(self, parent, table, changed_signal):
super().__init__(parent)
self._table = table
self._parent = parent
self._changed_signal = changed_signal
def createEditor(self, parent, option, index):
row = index.row()
item = self._table.item(row, VALUE_COLUMN)
if item.is_template:
return None
editor = DelegateCB(parent)
items = sorted(self._parent.all_values[self._table.item(row, CATEGORY_COLUMN).lookup_name], key=sort_key)
for text in items:
editor.addItem(text)
items_lower = [item.lower() for item in items]
try:
editor.setCurrentIndex(items_lower.index(item.original_text.lower()))
except:
pass
return editor
def setModelData(self, editor, model, index):
val = editor.currentText()
item = self._table.item(index.row(), index.column())
item.setText(val)
item.is_modified = True
self._changed_signal.emit()
class IconFileTableWidgetItem(QTableWidgetItem): class IconFileTableWidgetItem(QTableWidgetItem):
@ -155,11 +216,16 @@ class IconFileTableWidgetItem(QTableWidgetItem):
self.set_text(self._original_text) self.set_text(self._original_text)
self.setIcon(self._original_icon) self.setIcon(self._original_icon)
@property
def is_editable(self):
return True
class IconColumnDelegate(QStyledItemDelegate): class IconColumnDelegate(QStyledItemDelegate):
def __init__(self, parent, table, changed_signal): def __init__(self, parent, table, changed_signal):
super().__init__(parent) super().__init__(parent)
self._parent = parent
self._table = table self._table = table
self._changed_signal = changed_signal self._changed_signal = changed_signal
@ -189,6 +255,7 @@ class IconColumnDelegate(QStyledItemDelegate):
icon_item.setIcon(new_icon) icon_item.setIcon(new_icon)
icon_item.is_modified = True icon_item.is_modified = True
self._changed_signal.emit() self._changed_signal.emit()
self._parent.check_button_state(icon_item)
class ChildrenTableWidgetItem(QTableWidgetItem): class ChildrenTableWidgetItem(QTableWidgetItem):
@ -246,11 +313,16 @@ class ChildrenTableWidgetItem(QTableWidgetItem):
self.is_modified = False self.is_modified = False
self._set_text_and_icon(self._original_value) self._set_text_and_icon(self._original_value)
@property
def is_editable(self):
return True
class ChildrenColumnDelegate(QStyledItemDelegate): class ChildrenColumnDelegate(QStyledItemDelegate):
def __init__(self, parent, table, changed_signal): def __init__(self, parent, table, changed_signal):
super().__init__(parent) super().__init__(parent)
self._parent = parent
self._table = table self._table = table
self._changed_signal = changed_signal self._changed_signal = changed_signal
@ -264,13 +336,13 @@ class ChildrenColumnDelegate(QStyledItemDelegate):
self.longest_text = '' self.longest_text = ''
for icon, text in zip(icons, items): for icon, text in zip(icons, items):
editor.addItem(QIcon.cached_icon(icon), text) editor.addItem(QIcon.cached_icon(icon), text)
if len(text) > len(self.longest_text):
self.longest_text = text
return editor return editor
def setModelData(self, editor, model, index): def setModelData(self, editor, model, index):
val = {0:True, 1:False}[editor.currentIndex()] val = {0:True, 1:False}[editor.currentIndex()]
self._table.item(index.row(), index.column()).set_value(val) item = self._table.item(index.row(), index.column())
item.set_value(val)
self._parent.check_button_state(item)
self._changed_signal.emit() self._changed_signal.emit()
def setEditorData(self, editor, index): def setEditorData(self, editor, index):
@ -298,6 +370,9 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
self.rules_table.customContextMenuRequested.connect(self.show_context_menu) self.rules_table.customContextMenuRequested.connect(self.show_context_menu)
self.rules_table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.rules_table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.rules_table.itemClicked.connect(self.check_button_state)
self.rules_table.itemChanged.connect(self.check_button_state)
# Make the minimum section size smaller so the icon column icons don't # Make the minimum section size smaller so the icon column icons don't
# have a lot of space on the right # have a lot of space on the right
self.rules_table.horizontalHeader().setMinimumSectionSize(20) self.rules_table.horizontalHeader().setMinimumSectionSize(20)
@ -308,19 +383,23 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
item.setIcon(QIcon.cached_icon('trash.png')) item.setIcon(QIcon.cached_icon('trash.png'))
item.setToolTip(_('This icon shows in the row if the rule is deleted')) item.setToolTip(_('This icon shows in the row if the rule is deleted'))
elif i == CATEGORY_COLUMN: elif i == CATEGORY_COLUMN:
item.setToolTip(_('The name of the category')) item.setToolTip(_('The name of the category. Select a cell in this column to delete a row.'))
elif i == VALUE_COLUMN: elif i == VALUE_COLUMN:
item.setToolTip(_('The value in the category the rule is applied to')) item.setToolTip('<p>' +
_('The value in the category the rule is applied to. '
"If the value doesn't exist in the library then an "
"error icon is shown, in which case you can edit the "
"cell to pick the correct value."))
elif i == ICON_MODIFIED_COLUMN: elif i == ICON_MODIFIED_COLUMN:
item.setIcon(QIcon.cached_icon('modified.png')) item.setIcon(QIcon.cached_icon('modified.png'))
item.setToolTip(_('This icon shows in the row if the icon or template is modified')) item.setToolTip(_('This icon shows in the row if the icon or template is modified.'))
elif i == ICON_COLUMN: elif i == ICON_COLUMN:
item.setToolTip(_('The file name of the icon or the text of the template')) item.setToolTip(_('The file name of the icon or the text of the template.'))
elif i == FOR_CHILDREN_MODIFIED_COLUMN: elif i == FOR_CHILDREN_MODIFIED_COLUMN:
item.setIcon(QIcon.cached_icon('modified.png')) item.setIcon(QIcon.cached_icon('modified.png'))
item.setToolTip(_('This icon shows in the row if the "for children" setting is modified')) item.setToolTip(_('This icon shows in the row if the "for children" setting is modified.'))
elif i == FOR_CHILDREN_COLUMN: elif i == FOR_CHILDREN_COLUMN:
item.setToolTip(_('Indicates whether the rule applies to child values')) item.setToolTip(_('Indicates whether the rule applies to child values.'))
# Capture clicks on the horizontal header to sort the table columns # Capture clicks on the horizontal header to sort the table columns
hh = self.rules_table.horizontalHeader() hh = self.rules_table.horizontalHeader()
@ -330,6 +409,7 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
hh.setSortIndicatorShown(True) hh.setSortIndicatorShown(True)
self.delete_button.clicked.connect(self.delete_rule) self.delete_button.clicked.connect(self.delete_rule)
self.delete_button.setEnabled(False)
self.edit_button.clicked.connect(self.edit_column) self.edit_button.clicked.connect(self.edit_column)
self.undo_button.clicked.connect(self.undo_changes) self.undo_button.clicked.connect(self.undo_changes)
self.show_only_current_library.stateChanged.connect(self.change_filter_library) self.show_only_current_library.stateChanged.connect(self.change_filter_library)
@ -346,6 +426,8 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
self.rules_table.setItemDelegateForColumn(ICON_COLUMN, IconColumnDelegate(self, self.rules_table, self.changed_signal)) self.rules_table.setItemDelegateForColumn(ICON_COLUMN, IconColumnDelegate(self, self.rules_table, self.changed_signal))
self.rules_table.setItemDelegateForColumn(FOR_CHILDREN_COLUMN, self.rules_table.setItemDelegateForColumn(FOR_CHILDREN_COLUMN,
ChildrenColumnDelegate(self, self.rules_table, self.changed_signal)) ChildrenColumnDelegate(self, self.rules_table, self.changed_signal))
self.rules_table.setItemDelegateForColumn(VALUE_COLUMN,
ValueTableItemDelegate(self, self.rules_table, self.changed_signal))
self.populate_content() self.populate_content()
self.section_order = [0, 1, 1, 0, 0, 0, 0] self.section_order = [0, 1, 1, 0, 0, 0, 0]
self.last_section_sorted = 0 self.last_section_sorted = 0
@ -363,39 +445,42 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
t = self.rules_table t = self.rules_table
t.clearContents() t.clearContents()
all_values = {}
for category,vdict in v.items(): for category,vdict in v.items():
if category in field_metadata: if category in field_metadata:
display_name = field_metadata[category]['name'] display_name = field_metadata[category]['name']
all_values = self.gui.current_db.new_api.all_field_names(category) all_values[category] = set(self.gui.current_db.new_api.all_field_names(category))
if is_hierarchical_category(category): if is_hierarchical_category(category):
rslt = set()
for value in all_values: for value in all_values:
idx = 0 idx = 0
while idx >= 0: while idx >= 0:
rslt.add(value) all_values[category].add(value)
idx = value.rfind('.') idx = value.rfind('.')
value = value[:idx] value = value[:idx]
all_values = rslt
elif only_current_library: elif only_current_library:
continue continue
else: else:
display_name = category.removeprefix('#') display_name = category.removeprefix('#')
all_values = () all_values = {category: set()}
for item_value in vdict: self.all_values = all_values
if only_current_library and item_value != TEMPLATE_ICON_INDICATOR and item_value not in all_values:
continue with block_signals(self.rules_table):
t.setRowCount(row + 1) for item_value in vdict:
d = v[category][item_value] if (only_current_library and item_value != TEMPLATE_ICON_INDICATOR and
t.setItem(row, DELETED_COLUMN, StateTableWidgetItem('')) item_value not in all_values[category]):
t.setItem(row, CATEGORY_COLUMN, continue
CategoryTableWidgetItem(category, category_icons, display_name, t)) t.setRowCount(row + 1)
t.setItem(row, ICON_MODIFIED_COLUMN, StateTableWidgetItem('')) d = v[category][item_value]
t.setItem(row, VALUE_COLUMN, ValueTableWidgetItem(item_value, t)) t.setItem(row, DELETED_COLUMN, StateTableWidgetItem(''))
t.setItem(row, ICON_COLUMN, IconFileTableWidgetItem(d[0], item_value, t)) t.setItem(row, CATEGORY_COLUMN,
t.setItem(row, FOR_CHILDREN_MODIFIED_COLUMN, StateTableWidgetItem('')) CategoryTableWidgetItem(category, category_icons, display_name, t))
item = ChildrenTableWidgetItem(d[1], item_value, t) t.setItem(row, ICON_MODIFIED_COLUMN, StateTableWidgetItem(''))
t.setItem(row, FOR_CHILDREN_COLUMN, item) t.setItem(row, VALUE_COLUMN, ValueTableWidgetItem(item_value, t, all_values[category]))
row += 1 t.setItem(row, ICON_COLUMN, IconFileTableWidgetItem(d[0], item_value, t))
t.setItem(row, FOR_CHILDREN_MODIFIED_COLUMN, StateTableWidgetItem(''))
item = ChildrenTableWidgetItem(d[1], item_value, t)
t.setItem(row, FOR_CHILDREN_COLUMN, item)
row += 1
def show_context_menu(self, point): def show_context_menu(self, point):
item = self.rules_table.itemAt(point) item = self.rules_table.itemAt(point)
@ -405,10 +490,14 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
if column in (DELETED_COLUMN, ICON_MODIFIED_COLUMN, FOR_CHILDREN_MODIFIED_COLUMN): if column in (DELETED_COLUMN, ICON_MODIFIED_COLUMN, FOR_CHILDREN_MODIFIED_COLUMN):
return return
m = QMenu(self) m = QMenu(self)
if column in (CATEGORY_COLUMN, VALUE_COLUMN): if column == CATEGORY_COLUMN:
ac = m.addAction(_('Delete this rule'), partial(self.context_menu_handler, 'delete', item)) ac = m.addAction(_('Delete this rule'), partial(self.context_menu_handler, 'delete', item))
ac.setEnabled(not item.is_modified) ac.setEnabled(not item.is_deleted)
ac = m.addAction(_('Undo delete'), partial(self.context_menu_handler, 'undo_delete', item)) ac = m.addAction(_('Undo delete'), partial(self.context_menu_handler, 'undo_delete', item))
ac.setEnabled(item.is_deleted)
elif column == VALUE_COLUMN and item.is_editable:
ac = m.addAction(_('Modify this value'), partial(self.context_menu_handler, 'modify', item))
ac = m.addAction(_('Undo modification'), partial(self.context_menu_handler, 'undo_modification', item))
ac.setEnabled(item.is_modified) ac.setEnabled(item.is_modified)
elif column in (ICON_COLUMN, FOR_CHILDREN_COLUMN): elif column in (ICON_COLUMN, FOR_CHILDREN_COLUMN):
ac = m.addAction(_('Modify this value'), partial(self.context_menu_handler, 'modify', item)) ac = m.addAction(_('Modify this value'), partial(self.context_menu_handler, 'modify', item))
@ -440,6 +529,22 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
return return
return super().keyPressEvent(ev) return super().keyPressEvent(ev)
def check_button_state(self, item):
if item is None:
item = self.rules_table.currentItem()
self.delete_button.setEnabled(False)
self.edit_button.setEnabled(False)
self.undo_button.setEnabled(False)
column = item.column()
self.delete_button.setEnabled(column == CATEGORY_COLUMN)
if column == CATEGORY_COLUMN and item.is_deleted:
self.undo_button.setEnabled(True)
if column in (VALUE_COLUMN, ICON_COLUMN, FOR_CHILDREN_COLUMN):
if item.is_modified:
self.undo_button.setEnabled(True)
if item.is_editable:
self.edit_button.setEnabled(True)
def change_filter_library(self, state): def change_filter_library(self, state):
gprefs['tag_browser_rules_show_only_current_library'] = self.show_only_current_library.isChecked() gprefs['tag_browser_rules_show_only_current_library'] = self.show_only_current_library.isChecked()
self.populate_content() self.populate_content()
@ -449,14 +554,9 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
idx = self.rules_table.currentIndex() idx = self.rules_table.currentIndex()
if idx.isValid(): if idx.isValid():
column = idx.column() column = idx.column()
if column == DELETED_COLUMN: if column == VALUE_COLUMN and self.rules_table.item(idx.row(), column).is_modified:
column = CATEGORY_COLUMN self.undo_modification()
elif column == ICON_MODIFIED_COLUMN: elif column == CATEGORY_COLUMN:
column = ICON_COLUMN
elif column == FOR_CHILDREN_MODIFIED_COLUMN:
column = FOR_CHILDREN_COLUMN
if column in (CATEGORY_COLUMN, VALUE_COLUMN):
self.undo_delete() self.undo_delete()
elif column in (ICON_COLUMN, FOR_CHILDREN_COLUMN): elif column in (ICON_COLUMN, FOR_CHILDREN_COLUMN):
self.undo_modification() self.undo_modification()
@ -465,21 +565,25 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
idx = self.rules_table.currentIndex() idx = self.rules_table.currentIndex()
if idx.isValid(): if idx.isValid():
column = idx.column() column = idx.column()
if column in (ICON_COLUMN, FOR_CHILDREN_COLUMN): if column in (VALUE_COLUMN, ICON_COLUMN, FOR_CHILDREN_COLUMN):
self.rules_table.edit(idx) self.rules_table.edit(idx)
self.check_button_state(None) # Here to make buttons enabled/disabled
def delete_rule(self): def delete_rule(self):
idx = self.rules_table.currentIndex() idx = self.rules_table.currentIndex()
if idx.isValid(): if idx.isValid() and idx.column() == CATEGORY_COLUMN:
item = self.rules_table.item(idx.row(), CATEGORY_COLUMN) item = self.rules_table.item(idx.row(), idx.column())
item.is_modified = True item.is_deleted = True
self.changed_signal.emit() self.changed_signal.emit()
self.check_button_state(item)
def undo_delete(self): def undo_delete(self):
idx = self.rules_table.currentIndex() idx = self.rules_table.currentIndex()
if idx.isValid(): if idx.isValid():
self.rules_table.item(idx.row(), CATEGORY_COLUMN).undo() item = self.rules_table.item(idx.row(), CATEGORY_COLUMN)
item.undo()
self.changed_signal.emit() self.changed_signal.emit()
self.check_button_state(item)
def undo_modification(self): def undo_modification(self):
idx = self.rules_table.currentIndex() idx = self.rules_table.currentIndex()
@ -487,6 +591,7 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
item = self.rules_table.item(idx.row(), idx.column()) item = self.rules_table.item(idx.row(), idx.column())
item.undo() item.undo()
self.changed_signal.emit() self.changed_signal.emit()
self.check_button_state(item)
def table_column_resized(self, col, old, new): def table_column_resized(self, col, old, new):
self.table_column_widths = [] self.table_column_widths = []
@ -529,7 +634,7 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
value_item = self.rules_table.item(r, VALUE_COLUMN) value_item = self.rules_table.item(r, VALUE_COLUMN)
value_text = value_item._original_text value_text = value_item._original_text
if cat_item.is_modified: # deleted if cat_item.is_deleted:
if not value_item.is_template: if not value_item.is_template:
# Need to delete the icon file to clean up # Need to delete the icon file to clean up
icon_file = self.rules_table.item(r, ICON_COLUMN).text() icon_file = self.rules_table.item(r, ICON_COLUMN).text()
@ -541,9 +646,13 @@ class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
v[cat_item.lookup_name].pop(value_text, None) v[cat_item.lookup_name].pop(value_text, None)
continue continue
icon_item = self.rules_table.item(r, ICON_COLUMN)
d = list(v[cat_item.lookup_name][value_text]) d = list(v[cat_item.lookup_name][value_text])
if value_item.is_modified:
v[cat_item.lookup_name].pop(value_text)
v[cat_item.lookup_name][value_item.text()] = d
icon_item = self.rules_table.item(r, ICON_COLUMN)
if icon_item.is_modified: if icon_item.is_modified:
if value_item.is_template: if value_item.is_template:
d[0] = icon_item.text() d[0] = icon_item.text()

View File

@ -43,8 +43,8 @@
<property name="text"> <property name="text">
<string>&lt;p&gt;View all the defined value icon rules, including template rules. <string>&lt;p&gt;View all the defined value icon rules, including template rules.
Rules are defined and edited in the Tag browser context menus. Rules can be deleted in Rules are defined and edited in the Tag browser context menus. Rules can be deleted in
this dialog using the button, the delete key, or the context menu. The value icon rules this dialog by selecting the Category cell then using the button, the delete key,
are defined per-user, not per-library.&lt;/p&gt;</string> or the context menu. The value icon rules are defined per-user, not per-library.&lt;/p&gt;</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@ -70,7 +70,7 @@ are defined per-user, not per-library.&lt;/p&gt;</string>
<normaloff>:/images/trash.png</normaloff>:/images/trash.png</iconset> <normaloff>:/images/trash.png</normaloff>:/images/trash.png</iconset>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Delete the selected rule</string> <string>Delete the selected rule. The Category cell for the rule must be selected</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -81,7 +81,7 @@ are defined per-user, not per-library.&lt;/p&gt;</string>
<normaloff>:/images/edit_input.png</normaloff>:/images/edit_input.png</iconset> <normaloff>:/images/edit_input.png</normaloff>:/images/edit_input.png</iconset>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Edit the selected column</string> <string>Edit the selected cell</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -92,7 +92,7 @@ are defined per-user, not per-library.&lt;/p&gt;</string>
<normaloff>:/images/edit-undo.png</normaloff>:/images/edit-undo.png</iconset> <normaloff>:/images/edit-undo.png</normaloff>:/images/edit-undo.png</iconset>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Undelete the selected rule if it is deleted</string> <string>Undo changes in the selected cell, if any.</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -1611,6 +1611,11 @@ class TagsModel(QAbstractItemModel): # {{{
self.db.new_api.rename_items(lookup_key, {an_item.tag.id: new_name}, self.db.new_api.rename_items(lookup_key, {an_item.tag.id: new_name},
restrict_to_book_ids=restrict_to_books) restrict_to_book_ids=restrict_to_books)
self.tag_item_renamed.emit() self.tag_item_renamed.emit()
val_icon_data = self.value_icons.get(an_item.tag.category, {}).get(an_item.tag.original_name)
if val_icon_data:
# There is an icon for the old value. Rename it
self.value_icons[an_item.tag.category].pop(an_item.tag.original_name, None)
self.value_icons[an_item.tag.category][new_name] = val_icon_data
an_item.tag.name = new_name an_item.tag.name = new_name
an_item.tag.state = TAG_SEARCH_STATES['clear'] an_item.tag.state = TAG_SEARCH_STATES['clear']
self.use_position_based_index_on_next_recount = True self.use_position_based_index_on_next_recount = True