mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Enhancement #2091139: Reordering Columns in Custom Column Editor
This commit is contained in:
parent
485e1a2d20
commit
f2c1274824
@ -19,6 +19,16 @@ from calibre.gui2.preferences.create_custom_column import CreateCustomColumn
|
||||
|
||||
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
|
||||
ORDER_COLUMN = 0
|
||||
HEADER_COLUMN = 1
|
||||
KEY_COLUMN = 2
|
||||
TYPE_COLUMN = 3
|
||||
DESCRIPTION_COLUMN = 4
|
||||
STATUS_COLUMN = 5
|
||||
|
||||
column_headings = (_('Order'), _('Column header'), _('Lookup name'),
|
||||
_('Type'), _('Description'), _('Status'))
|
||||
|
||||
restart_critical = True
|
||||
|
||||
def genesis(self, gui):
|
||||
@ -46,6 +56,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
signal.connect(self.columns_changed)
|
||||
self.show_all_button.clicked.connect(self.show_all)
|
||||
self.hide_all_button.clicked.connect(self.hide_all)
|
||||
self.column_positions = None
|
||||
|
||||
def initialize(self):
|
||||
ConfigWidgetBase.initialize(self)
|
||||
@ -57,10 +68,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
self.changed_signal.emit()
|
||||
|
||||
def commit(self):
|
||||
widths = []
|
||||
for i in range(0, self.opt_columns.columnCount()):
|
||||
widths.append(self.opt_columns.columnWidth(i))
|
||||
gprefs.set('custcol-prefs-table-geometry', widths)
|
||||
rr = ConfigWidgetBase.commit(self)
|
||||
return self.apply_custom_column_changes() or rr
|
||||
|
||||
@ -79,13 +86,24 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
self.field_metadata = db.field_metadata
|
||||
|
||||
self.opt_columns.setColumnCount(6)
|
||||
self.opt_columns.setHorizontalHeaderItem(0, QTableWidgetItem(_('Order')))
|
||||
self.opt_columns.setHorizontalHeaderItem(1, QTableWidgetItem(_('Column header')))
|
||||
self.opt_columns.setHorizontalHeaderItem(2, QTableWidgetItem(_('Lookup name')))
|
||||
self.opt_columns.setHorizontalHeaderItem(3, QTableWidgetItem(_('Type')))
|
||||
self.opt_columns.setHorizontalHeaderItem(4, QTableWidgetItem(_('Description')))
|
||||
self.opt_columns.setHorizontalHeaderItem(5, QTableWidgetItem(_('Status')))
|
||||
self.opt_columns.horizontalHeader().sectionClicked.connect(self.table_sorted)
|
||||
# Set up the columns in logical index order
|
||||
for p in range(0, len(self.column_headings)):
|
||||
self.opt_columns.setHorizontalHeaderItem(p, QTableWidgetItem(self.column_headings[p]))
|
||||
|
||||
# Now reorder the columns into the desired visual order. Note: ignore
|
||||
# visual order when looking at items. Qt automatically maps the visual
|
||||
# order onto the logical order.
|
||||
self.column_positions = gprefs.get('custcol-prefs-column_order', [0, 1, 2, 3, 4, 5])
|
||||
header = self.opt_columns.horizontalHeader()
|
||||
for dvi,li in enumerate(self.column_positions):
|
||||
cvi = header.visualIndex(li)
|
||||
if cvi != dvi:
|
||||
header.moveSection(cvi, dvi)
|
||||
header.sectionClicked.connect(self.table_sorted)
|
||||
header.setSectionsMovable(True)
|
||||
header.setFirstSectionMovable(False)
|
||||
header.sectionMoved.connect(self.header_moved)
|
||||
header.sectionResized.connect(self.save_geometry)
|
||||
self.opt_columns.verticalHeader().hide()
|
||||
|
||||
self.opt_columns.setRowCount(len(colmap))
|
||||
@ -104,6 +122,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
self.set_up_down_enabled(self.opt_columns.currentItem(), None)
|
||||
self.opt_columns.blockSignals(False)
|
||||
|
||||
def header_moved(self, log_index, old_v_index, new_v_index):
|
||||
self.column_positions = []
|
||||
for vi in range(0, self.opt_columns.columnCount()):
|
||||
self.column_positions.append(self.opt_columns.horizontalHeader().logicalIndex(vi))
|
||||
self.save_geometry()
|
||||
|
||||
def set_up_down_enabled(self, current_item, _):
|
||||
h = self.opt_columns.horizontalHeader()
|
||||
row = current_item.row()
|
||||
@ -130,7 +154,16 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
def row_double_clicked(self, r, c):
|
||||
self.edit_custcol()
|
||||
|
||||
def save_geometry(self):
|
||||
# Save both the column widths and the column order
|
||||
widths = []
|
||||
for i in range(0, self.opt_columns.columnCount()):
|
||||
widths.append(self.opt_columns.columnWidth(i))
|
||||
gprefs.set('custcol-prefs-table-geometry', widths)
|
||||
gprefs.set('custcol-prefs-column_order', self.column_positions)
|
||||
|
||||
def restore_geometry(self):
|
||||
# restore the column widths. Order is done when the table is created.
|
||||
geom = gprefs.get('custcol-prefs-table-geometry', None)
|
||||
if geom is not None and len(geom) == self.opt_columns.columnCount():
|
||||
with suppress(Exception):
|
||||
@ -141,14 +174,14 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
|
||||
def hide_all(self):
|
||||
for row in range(self.opt_columns.rowCount()):
|
||||
item = self.opt_columns.item(row, 0)
|
||||
item = self.opt_columns.item(row, self.ORDER_COLUMN)
|
||||
if item.checkState() != Qt.CheckState.PartiallyChecked:
|
||||
item.setCheckState(Qt.CheckState.Unchecked)
|
||||
self.changed_signal.emit()
|
||||
|
||||
def show_all(self):
|
||||
for row in range(self.opt_columns.rowCount()):
|
||||
item = self.opt_columns.item(row, 0)
|
||||
item = self.opt_columns.item(row, self.ORDER_COLUMN)
|
||||
if item.checkState() != Qt.CheckState.PartiallyChecked:
|
||||
item.setCheckState(Qt.CheckState.Checked)
|
||||
self.changed_signal.emit()
|
||||
@ -169,7 +202,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
item.setToolTip(str(order))
|
||||
item.setData(Qt.ItemDataRole.UserRole, key)
|
||||
item.setFlags(flags)
|
||||
self.opt_columns.setItem(row, 0, item)
|
||||
self.opt_columns.setItem(row, self.ORDER_COLUMN, item)
|
||||
|
||||
flags |= Qt.ItemFlag.ItemIsUserCheckable
|
||||
if key == 'ondevice':
|
||||
@ -182,17 +215,20 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
else:
|
||||
item.setCheckState(force_checked_to)
|
||||
|
||||
# The columns are added in logical index order, not visual index order,
|
||||
# so we can process them without a loop
|
||||
|
||||
item = QTableWidgetItem(cc['name'])
|
||||
item.setToolTip(cc['name'])
|
||||
item.setFlags(flags)
|
||||
if self.is_custom_key(key):
|
||||
item.setData(Qt.ItemDataRole.DecorationRole, (QIcon.ic('column.png')))
|
||||
self.opt_columns.setItem(row, 1, item)
|
||||
self.opt_columns.setItem(row, self.HEADER_COLUMN, item)
|
||||
|
||||
item = QTableWidgetItem(key)
|
||||
item.setToolTip(key)
|
||||
item.setFlags(flags)
|
||||
self.opt_columns.setItem(row, 2, item)
|
||||
self.opt_columns.setItem(row, self.KEY_COLUMN, item)
|
||||
|
||||
if key == 'title':
|
||||
coltype = _('Text')
|
||||
@ -210,13 +246,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
item = QTableWidgetItem(coltype)
|
||||
item.setToolTip(coltype)
|
||||
item.setFlags(flags)
|
||||
self.opt_columns.setItem(row, 3, item)
|
||||
self.opt_columns.setItem(row, self.TYPE_COLUMN, item)
|
||||
|
||||
desc = cc['display'].get('description', "")
|
||||
item = QTableWidgetItem(desc)
|
||||
item.setToolTip(desc)
|
||||
item.setFlags(flags)
|
||||
self.opt_columns.setItem(row, 4, item)
|
||||
self.opt_columns.setItem(row, self.DESCRIPTION_COLUMN, item)
|
||||
|
||||
if '*deleted' in cc:
|
||||
col_status = _('Deleted column. Double-click to undelete it')
|
||||
@ -231,13 +267,15 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
item = QTableWidgetItem(col_status)
|
||||
item.setToolTip(col_status)
|
||||
item.setFlags(flags)
|
||||
self.opt_columns.setItem(row, 5, item)
|
||||
self.opt_columns.setItem(row, self.STATUS_COLUMN, item)
|
||||
|
||||
self.opt_columns.setSortingEnabled(True)
|
||||
|
||||
def recreate_row(self, row):
|
||||
checked = self.opt_columns.item(row, 0).checkState()
|
||||
title = self.opt_columns.item(row, 2).text()
|
||||
self.setup_row(row, title, row, force_checked_to=checked)
|
||||
checked = self.opt_columns.item(row, self.ORDER_COLUMN).checkState()
|
||||
# Again, use the logical index, not the visual index
|
||||
key = self.opt_columns.item(row, self.KEY_COLUMN).text()
|
||||
self.setup_row(row, key, row, force_checked_to=checked)
|
||||
|
||||
def get_move_count(self):
|
||||
mods = QApplication.keyboardModifiers()
|
||||
@ -297,7 +335,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
if row < 0:
|
||||
return error_dialog(self, '', _('You must select a column to delete it'),
|
||||
show=True)
|
||||
key = str(self.opt_columns.item(row, 0).data(Qt.ItemDataRole.UserRole) or '')
|
||||
key = str(self.opt_columns.item(row, self.ORDER_COLUMN).data(Qt.ItemDataRole.UserRole) or '')
|
||||
if key not in self.custcols:
|
||||
return error_dialog(self, '',
|
||||
_('The selected column is not a custom column'), show=True)
|
||||
@ -340,13 +378,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
return key.startswith('#')
|
||||
|
||||
def column_order_val(self, row):
|
||||
return int(self.opt_columns.item(row, 0).text())
|
||||
return int(self.opt_columns.item(row, self.ORDER_COLUMN).text())
|
||||
|
||||
def edit_custcol(self):
|
||||
model = self.gui.library_view.model()
|
||||
row = self.opt_columns.currentRow()
|
||||
try:
|
||||
key = str(self.opt_columns.item(row, 0).data(Qt.ItemDataRole.UserRole))
|
||||
key = str(self.opt_columns.item(row, self.ORDER_COLUMN).data(Qt.ItemDataRole.UserRole))
|
||||
if key not in self.custcols:
|
||||
return error_dialog(self, '',
|
||||
_('The selected column is not a user-defined column'),
|
||||
@ -382,14 +420,14 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
model = self.gui.library_view.model()
|
||||
db = model.db
|
||||
self.opt_columns.sortItems(0, Qt.SortOrder.AscendingOrder)
|
||||
config_cols = [str(self.opt_columns.item(i, 0).data(Qt.ItemDataRole.UserRole) or '')
|
||||
config_cols = [str(self.opt_columns.item(i, self.ORDER_COLUMN).data(Qt.ItemDataRole.UserRole) or '')
|
||||
for i in range(self.opt_columns.rowCount())]
|
||||
if not config_cols:
|
||||
config_cols = ['title']
|
||||
removed_cols = set(model.column_map) - set(config_cols)
|
||||
hidden_cols = {str(self.opt_columns.item(i, 0).data(Qt.ItemDataRole.UserRole) or '')
|
||||
hidden_cols = {str(self.opt_columns.item(i, self.ORDER_COLUMN).data(Qt.ItemDataRole.UserRole) or '')
|
||||
for i in range(self.opt_columns.rowCount())
|
||||
if self.opt_columns.item(i, 0).checkState()==Qt.CheckState.Unchecked}
|
||||
if self.opt_columns.item(i, self.ORDER_COLUMN).checkState()==Qt.CheckState.Unchecked}
|
||||
hidden_cols = hidden_cols.union(removed_cols) # Hide removed cols
|
||||
hidden_cols = list(hidden_cols.intersection(set(model.column_map)))
|
||||
if 'ondevice' in hidden_cols:
|
||||
|
Loading…
x
Reference in New Issue
Block a user