mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
c28d6f5423
@ -17,7 +17,8 @@ from qt.core import (
|
|||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
)
|
)
|
||||||
|
|
||||||
from calibre.gui2 import error_dialog, gprefs
|
from calibre.gui2 import error_dialog, gprefs, question_dialog
|
||||||
|
from calibre.utils.icu import lower
|
||||||
from calibre.utils.localization import ngettext
|
from calibre.utils.localization import ngettext
|
||||||
|
|
||||||
|
|
||||||
@ -35,6 +36,11 @@ class CountTableWidgetItem(QTableWidgetItem):
|
|||||||
|
|
||||||
class EnumValuesEdit(QDialog):
|
class EnumValuesEdit(QDialog):
|
||||||
|
|
||||||
|
VALUE_COLUMN = 0
|
||||||
|
WAS_COLUMN = 1
|
||||||
|
COLOR_COLUMN = 2
|
||||||
|
COUNT_COLUMN = 3
|
||||||
|
|
||||||
def __init__(self, parent, db, key):
|
def __init__(self, parent, db, key):
|
||||||
QDialog.__init__(self, parent)
|
QDialog.__init__(self, parent)
|
||||||
|
|
||||||
@ -46,8 +52,8 @@ class EnumValuesEdit(QDialog):
|
|||||||
bbox.addStretch(10)
|
bbox.addStretch(10)
|
||||||
self.del_button = QToolButton()
|
self.del_button = QToolButton()
|
||||||
self.del_button.setIcon(QIcon.ic('trash.png'))
|
self.del_button.setIcon(QIcon.ic('trash.png'))
|
||||||
self.del_button.setToolTip(_('Remove the currently selected value. Only '
|
self.del_button.setToolTip(_('Remove the currently selected value. The '
|
||||||
'values with a count of zero can be removed'))
|
'value will be removed from all books.'))
|
||||||
self.ins_button = QToolButton()
|
self.ins_button = QToolButton()
|
||||||
self.ins_button.setIcon(QIcon.ic('plus.png'))
|
self.ins_button.setIcon(QIcon.ic('plus.png'))
|
||||||
self.ins_button.setToolTip(_('Add a new permissible value'))
|
self.ins_button.setToolTip(_('Add a new permissible value'))
|
||||||
@ -65,6 +71,7 @@ class EnumValuesEdit(QDialog):
|
|||||||
bbox.addStretch(10)
|
bbox.addStretch(10)
|
||||||
l.addItem(bbox, 0, 0)
|
l.addItem(bbox, 0, 0)
|
||||||
|
|
||||||
|
self.deleted_values = {}
|
||||||
self.del_button.clicked.connect(self.del_line)
|
self.del_button.clicked.connect(self.del_line)
|
||||||
|
|
||||||
self.all_colors = {str(s) for s in list(QColor.colorNames())}
|
self.all_colors = {str(s) for s in list(QColor.colorNames())}
|
||||||
@ -72,14 +79,15 @@ class EnumValuesEdit(QDialog):
|
|||||||
tl = QVBoxLayout()
|
tl = QVBoxLayout()
|
||||||
l.addItem(tl, 0, 1)
|
l.addItem(tl, 0, 1)
|
||||||
self.table = t = QTableWidget(parent)
|
self.table = t = QTableWidget(parent)
|
||||||
t.setColumnCount(3)
|
t.setColumnCount(4)
|
||||||
t.setRowCount(1)
|
t.setRowCount(1)
|
||||||
t.setHorizontalHeaderLabels([_('Value'), _('Color'), _('Count')])
|
t.setHorizontalHeaderLabels([_('Value'), _('Was'), _('Color'), _('Count')])
|
||||||
t.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
t.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||||
tl.addWidget(t)
|
tl.addWidget(t)
|
||||||
|
|
||||||
counts = self.db.new_api.get_usage_count_by_id(key)
|
counts = self.db.new_api.get_usage_count_by_id(key)
|
||||||
self.name_to_count = {self.db.new_api.get_item_name(key, item_id):count for item_id,count in counts.items()}
|
self.name_to_count = {lower(self.db.new_api.get_item_name(key, item_id)):count
|
||||||
|
for item_id,count in counts.items()}
|
||||||
|
|
||||||
self.key = key
|
self.key = key
|
||||||
self.fm = fm = db.field_metadata[key]
|
self.fm = fm = db.field_metadata[key]
|
||||||
@ -93,6 +101,7 @@ class EnumValuesEdit(QDialog):
|
|||||||
c.setCurrentIndex(c.findText(colors[i]))
|
c.setCurrentIndex(c.findText(colors[i]))
|
||||||
else:
|
else:
|
||||||
c.setCurrentIndex(0)
|
c.setCurrentIndex(0)
|
||||||
|
self.make_was_item(i)
|
||||||
self.make_count_item(i, v)
|
self.make_count_item(i, v)
|
||||||
|
|
||||||
t.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
|
t.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
|
||||||
@ -112,10 +121,21 @@ class EnumValuesEdit(QDialog):
|
|||||||
|
|
||||||
def cell_changed(self, row, col):
|
def cell_changed(self, row, col):
|
||||||
if col == 0:
|
if col == 0:
|
||||||
item = self.table.item(row, 2)
|
val_item = self.table.item(row, self.VALUE_COLUMN)
|
||||||
if item is not None and self.table.item(row, 0) is not None:
|
if val_item is None:
|
||||||
count = self.name_to_count.get(self.table.item(row, 0).text())
|
return
|
||||||
|
item = self.table.item(row, self.COUNT_COLUMN)
|
||||||
|
if item is not None:
|
||||||
|
count = self.name_to_count.get(lower(self.table.item(row, self.VALUE_COLUMN).text()))
|
||||||
item.set_count(count)
|
item.set_count(count)
|
||||||
|
txt = val_item.text()
|
||||||
|
orig_txt = str(val_item.data(Qt.ItemDataRole.UserRole))
|
||||||
|
was_item = self.table.item(row, self.WAS_COLUMN)
|
||||||
|
if was_item is not None:
|
||||||
|
if txt != orig_txt:
|
||||||
|
was_item.setText(orig_txt)
|
||||||
|
else:
|
||||||
|
was_item.setText('')
|
||||||
|
|
||||||
def sizeHint(self):
|
def sizeHint(self):
|
||||||
sz = QDialog.sizeHint(self)
|
sz = QDialog.sizeHint(self)
|
||||||
@ -126,9 +146,8 @@ class EnumValuesEdit(QDialog):
|
|||||||
def make_name_item(self, row, txt):
|
def make_name_item(self, row, txt):
|
||||||
it = QTableWidgetItem(txt)
|
it = QTableWidgetItem(txt)
|
||||||
it.setData(Qt.ItemDataRole.UserRole, txt)
|
it.setData(Qt.ItemDataRole.UserRole, txt)
|
||||||
it.setCheckState(Qt.CheckState.Unchecked)
|
it.setToolTip(_('Changing the value will rename it in all books'))
|
||||||
it.setToolTip('<p>' + _('Check the box if you change the value and want it renamed in books where it is used') + '</p>')
|
self.table.setItem(row, self.VALUE_COLUMN, it)
|
||||||
self.table.setItem(row, 0, it)
|
|
||||||
|
|
||||||
def make_color_combobox(self, row, dex):
|
def make_color_combobox(self, row, dex):
|
||||||
c = QComboBox(self)
|
c = QComboBox(self)
|
||||||
@ -136,14 +155,18 @@ class EnumValuesEdit(QDialog):
|
|||||||
c.addItems(QColor.colorNames())
|
c.addItems(QColor.colorNames())
|
||||||
c.setToolTip('<p>' + _('Selects the color of the text when displayed in the book list. '
|
c.setToolTip('<p>' + _('Selects the color of the text when displayed in the book list. '
|
||||||
'Either all rows must have a color or no rows have a color') + '</p>')
|
'Either all rows must have a color or no rows have a color') + '</p>')
|
||||||
self.table.setCellWidget(row, 1, c)
|
self.table.setCellWidget(row, self.COLOR_COLUMN, c)
|
||||||
if dex >= 0:
|
if dex >= 0:
|
||||||
c.setCurrentIndex(dex)
|
c.setCurrentIndex(dex)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
def make_was_item(self, row):
|
||||||
|
it = QTableWidgetItem('')
|
||||||
|
self.table.setItem(row, self.WAS_COLUMN, it)
|
||||||
|
|
||||||
def make_count_item(self, row, txt):
|
def make_count_item(self, row, txt):
|
||||||
it = CountTableWidgetItem(self.name_to_count.get(txt))
|
it = CountTableWidgetItem(self.name_to_count.get(lower(txt)))
|
||||||
self.table.setItem(row, 2, it)
|
self.table.setItem(row, self.COUNT_COLUMN, it)
|
||||||
|
|
||||||
def move_up_clicked(self):
|
def move_up_clicked(self):
|
||||||
row = self.table.currentRow()
|
row = self.table.currentRow()
|
||||||
@ -156,15 +179,17 @@ class EnumValuesEdit(QDialog):
|
|||||||
self.move_row(row, -1)
|
self.move_row(row, -1)
|
||||||
|
|
||||||
def move_row(self, row, direction):
|
def move_row(self, row, direction):
|
||||||
t = self.table.takeItem(row, 0)
|
t = self.table.takeItem(row, self.VALUE_COLUMN)
|
||||||
c = self.table.cellWidget(row, 1).currentIndex()
|
c = self.table.cellWidget(row, self.COLOR_COLUMN).currentIndex()
|
||||||
count = self.table.takeItem(row, 2)
|
was = self.table.takeItem(row, self.WAS_COLUMN)
|
||||||
|
count = self.table.takeItem(row, self.COUNT_COLUMN)
|
||||||
self.table.removeRow(row)
|
self.table.removeRow(row)
|
||||||
row += direction
|
row += direction
|
||||||
self.table.insertRow(row)
|
self.table.insertRow(row)
|
||||||
self.table.setItem(row, 0, t)
|
self.table.setItem(row, self.VALUE_COLUMN, t)
|
||||||
self.make_color_combobox(row, c)
|
self.make_color_combobox(row, c)
|
||||||
self.table.setItem(row, 2, count)
|
self.table.setItem(row, self.WAS_COLUMN, was)
|
||||||
|
self.table.setItem(row, self.COUNT_COLUMN, count)
|
||||||
self.table.setCurrentCell(row, 0)
|
self.table.setCurrentCell(row, 0)
|
||||||
|
|
||||||
def move_down_clicked(self):
|
def move_down_clicked(self):
|
||||||
@ -180,16 +205,17 @@ class EnumValuesEdit(QDialog):
|
|||||||
def del_line(self):
|
def del_line(self):
|
||||||
row = self.table.currentRow()
|
row = self.table.currentRow()
|
||||||
if row >= 0:
|
if row >= 0:
|
||||||
txt = self.table.item(row, 0).text()
|
txt = self.table.item(row, self.VALUE_COLUMN).text()
|
||||||
count = self.name_to_count.get(txt, 0)
|
count = self.name_to_count.get(lower(txt), 0)
|
||||||
if count > 0:
|
if count > 0:
|
||||||
error_dialog(self,
|
r = question_dialog(self,
|
||||||
_('Cannot remove value "{}"').format(txt),
|
_('Value "{}" is used').format(txt),
|
||||||
ngettext('The value "{0}" is used in {1} book and cannot be removed.',
|
ngettext('The value "{0}" is used in {1} book. Do you really want to remove it?',
|
||||||
'The value "{0}" is used in {1} books and cannot be removed.',
|
'The value "{0}" is used in {1} books. Do you really want to remove it?',
|
||||||
count).format(txt, count),
|
count).format(txt, count))
|
||||||
show=True)
|
if r != QDialog.DialogCode.Accepted:
|
||||||
return
|
return
|
||||||
|
self.deleted_values[lower(txt)] = txt
|
||||||
self.table.removeRow(self.table.currentRow())
|
self.table.removeRow(self.table.currentRow())
|
||||||
|
|
||||||
def ins_button_clicked(self):
|
def ins_button_clicked(self):
|
||||||
@ -201,6 +227,7 @@ class EnumValuesEdit(QDialog):
|
|||||||
self.table.insertRow(row)
|
self.table.insertRow(row)
|
||||||
self.make_name_item(row, '')
|
self.make_name_item(row, '')
|
||||||
self.make_color_combobox(row, -1)
|
self.make_color_combobox(row, -1)
|
||||||
|
self.make_was_item(row)
|
||||||
self.make_count_item(row, '')
|
self.make_count_item(row, '')
|
||||||
|
|
||||||
def save_geometry(self):
|
def save_geometry(self):
|
||||||
@ -212,21 +239,20 @@ class EnumValuesEdit(QDialog):
|
|||||||
colors = []
|
colors = []
|
||||||
id_map = {}
|
id_map = {}
|
||||||
for i in range(0, self.table.rowCount()):
|
for i in range(0, self.table.rowCount()):
|
||||||
it = self.table.item(i, 0)
|
it = self.table.item(i, self.VALUE_COLUMN)
|
||||||
v = str(it.text())
|
v = str(it.text())
|
||||||
if not v:
|
if not v:
|
||||||
error_dialog(self, _('Empty value'),
|
error_dialog(self, _('Empty value'),
|
||||||
_('Empty values are not allowed'), show=True)
|
_('Empty values are not allowed'), show=True)
|
||||||
return
|
return
|
||||||
ov = str(it.data(Qt.ItemDataRole.UserRole))
|
ov = str(it.data(Qt.ItemDataRole.UserRole))
|
||||||
if v != ov and it.checkState() == Qt.CheckState.Checked:
|
if v != ov:
|
||||||
fid = self.db.new_api.get_item_id(self.key, ov)
|
fid = self.db.new_api.get_item_id(self.key, ov)
|
||||||
id_map[fid] = v
|
id_map[fid] = v
|
||||||
values.append(v)
|
values.append(v)
|
||||||
c = str(self.table.cellWidget(i, 1).currentText())
|
c = str(self.table.cellWidget(i, self.COLOR_COLUMN).currentText())
|
||||||
if c:
|
if c:
|
||||||
colors.append(c)
|
colors.append(c)
|
||||||
|
|
||||||
l_lower = [v.lower() for v in values]
|
l_lower = [v.lower() for v in values]
|
||||||
for i,v in enumerate(l_lower):
|
for i,v in enumerate(l_lower):
|
||||||
if v in l_lower[i+1:]:
|
if v in l_lower[i+1:]:
|
||||||
@ -241,6 +267,22 @@ class EnumValuesEdit(QDialog):
|
|||||||
'Either all values or no values must have colors'), show=True)
|
'Either all values or no values must have colors'), show=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Process deleted values. It is possible that a value was deleted then
|
||||||
|
# added back, possibly with a different case. If the case is the same then
|
||||||
|
# don't delete it. If the case is different then add it to the rename dict.
|
||||||
|
for v in values:
|
||||||
|
dv = self.deleted_values.get(lower(v))
|
||||||
|
if dv is None:
|
||||||
|
continue
|
||||||
|
self.deleted_values.pop(lower(v))
|
||||||
|
if v != dv:
|
||||||
|
fid = self.db.new_api.get_item_id(self.key, dv)
|
||||||
|
id_map[fid] = v
|
||||||
|
|
||||||
|
ids_to_delete = (self.db.new_api.get_item_id(self.key, v) for v in self.deleted_values.values())
|
||||||
|
if ids_to_delete:
|
||||||
|
self.db.new_api.remove_items(self.key, ids_to_delete)
|
||||||
|
|
||||||
disp['enum_values'] = values
|
disp['enum_values'] = values
|
||||||
disp['enum_colors'] = colors
|
disp['enum_colors'] = colors
|
||||||
self.db.set_custom_column_metadata(self.fm['colnum'], display=disp,
|
self.db.set_custom_column_metadata(self.fm['colnum'], display=disp,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user