Enhancement: allow sorting the columns in the create custom column dialog.

This commit is contained in:
Charles Haley 2022-01-06 13:25:30 +00:00
parent 6b10f5cc81
commit 843dc628c7

View File

@ -7,8 +7,9 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import copy, sys import copy, sys
from contextlib import suppress
from qt.core import Qt, QTableWidgetItem, QIcon from qt.core import Qt, QTableWidgetItem, QIcon, QVariant
from calibre.gui2 import gprefs, Application from calibre.gui2 import gprefs, Application
from calibre.gui2.preferences import ConfigWidgetBase, test_widget from calibre.gui2.preferences import ConfigWidgetBase, test_widget
@ -36,6 +37,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.add_custcol_button.clicked.connect(self.add_custcol) self.add_custcol_button.clicked.connect(self.add_custcol)
self.add_col_button.clicked.connect(self.add_custcol) self.add_col_button.clicked.connect(self.add_custcol)
self.edit_custcol_button.clicked.connect(self.edit_custcol) self.edit_custcol_button.clicked.connect(self.edit_custcol)
self.opt_columns.currentCellChanged.connect(self.current_cell_changed)
for signal in ('Activated', 'Changed', 'DoubleClicked', 'Clicked'): for signal in ('Activated', 'Changed', 'DoubleClicked', 'Clicked'):
signal = getattr(self.opt_columns, 'item'+signal) signal = getattr(self.opt_columns, 'item'+signal)
signal.connect(self.columns_changed) signal.connect(self.columns_changed)
@ -57,14 +59,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
rr = ConfigWidgetBase.commit(self) rr = ConfigWidgetBase.commit(self)
return self.apply_custom_column_changes() or rr return self.apply_custom_column_changes() or rr
def columns_changed(self, *args):
self.changed_signal.emit()
def columns_state(self, defaults=False):
if defaults:
return self.gui.library_view.get_default_state()
return self.gui.library_view.get_state()
def init_columns(self, defaults=False): def init_columns(self, defaults=False):
# Set up columns # Set up columns
self.opt_columns.blockSignals(True) self.opt_columns.blockSignals(True)
@ -79,17 +73,15 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
db = model.db db = model.db
self.field_metadata = db.field_metadata self.field_metadata = db.field_metadata
self.opt_columns.setColumnCount(5) self.opt_columns.setColumnCount(6)
item = QTableWidgetItem(_('Column header')) self.opt_columns.setHorizontalHeaderItem(0, QTableWidgetItem(_('Order')))
self.opt_columns.setHorizontalHeaderItem(0, item) self.opt_columns.setHorizontalHeaderItem(1, QTableWidgetItem(_('Column header')))
item = QTableWidgetItem(_('Lookup name')) self.opt_columns.setHorizontalHeaderItem(2, QTableWidgetItem(_('Lookup name')))
self.opt_columns.setHorizontalHeaderItem(1, item) self.opt_columns.setHorizontalHeaderItem(3, QTableWidgetItem(_('Type')))
item = QTableWidgetItem(_('Type')) self.opt_columns.setHorizontalHeaderItem(4, QTableWidgetItem(_('Description')))
self.opt_columns.setHorizontalHeaderItem(2, item) self.opt_columns.setHorizontalHeaderItem(5, QTableWidgetItem(_('Status')))
item = QTableWidgetItem(_('Status')) self.opt_columns.horizontalHeader().sectionClicked.connect(self.table_sorted)
self.opt_columns.setHorizontalHeaderItem(3, item) self.opt_columns.verticalHeader().hide()
item = QTableWidgetItem(_('Description'))
self.opt_columns.setHorizontalHeaderItem(4, item)
self.opt_columns.setRowCount(len(colmap)) self.opt_columns.setRowCount(len(colmap))
self.column_desc = dict(map(lambda x:(CreateCustomColumn.column_types[x]['datatype'], self.column_desc = dict(map(lambda x:(CreateCustomColumn.column_types[x]['datatype'],
@ -98,37 +90,46 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
for row, key in enumerate(colmap): for row, key in enumerate(colmap):
self.setup_row(row, key) self.setup_row(row, key)
self.initial_row_count = row
self.opt_columns.setSortingEnabled(True)
self.opt_columns.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder)
self.restore_geometry() self.restore_geometry()
self.opt_columns.cellDoubleClicked.connect(self.row_double_clicked) self.opt_columns.cellDoubleClicked.connect(self.row_double_clicked)
self.opt_columns.blockSignals(False) self.opt_columns.blockSignals(False)
def current_cell_changed(self, current_row, current_col, prev_row, prev_col):
if self.opt_columns.horizontalHeader().sortIndicatorSection() == 0:
self.column_up.setEnabled(current_row > 0 and current_row <= self.initial_row_count)
self.column_down.setEnabled(current_row < self.initial_row_count)
def columns_changed(self, *args):
self.changed_signal.emit()
def columns_state(self, defaults=False):
if defaults:
return self.gui.library_view.get_default_state()
return self.gui.library_view.get_state()
def table_sorted(self, column):
self.column_up.setEnabled(column == 0)
self.column_down.setEnabled(column == 0)
self.opt_columns.scrollTo(self.opt_columns.currentIndex())
def row_double_clicked(self, r, c): def row_double_clicked(self, r, c):
self.edit_custcol() self.edit_custcol()
def restore_geometry(self): def restore_geometry(self):
geom = gprefs.get('custcol-prefs-table-geometry', None) geom = gprefs.get('custcol-prefs-table-geometry', None)
if geom is not None and len(geom) == self.opt_columns.columnCount(): if geom is not None and len(geom) == self.opt_columns.columnCount():
try: with suppress(Exception):
for i in range(0, self.opt_columns.columnCount()): for i in range(0, self.opt_columns.columnCount()):
self.opt_columns.setColumnWidth(i, geom[i]) self.opt_columns.setColumnWidth(i, geom[i])
except: return
self.set_default_geometry()
else:
self.set_default_geometry()
def set_default_geometry(self):
self.opt_columns.resizeColumnsToContents() self.opt_columns.resizeColumnsToContents()
self.opt_columns.resizeRowsToContents()
def setup_row(self, row, key): def setup_row(self, row, key):
flags = Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable flags = Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable
item = QTableWidgetItem(key)
item.setToolTip(key)
item.setFlags(flags)
self.opt_columns.setItem(row, 1, item)
if self.is_custom_key(key): if self.is_custom_key(key):
cc = self.custcols[key] cc = self.custcols[key]
original_key = cc['original_key'] original_key = cc['original_key']
@ -136,6 +137,34 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
cc = self.field_metadata[key] cc = self.field_metadata[key]
original_key = key original_key = key
item = QTableWidgetItem()
item.setData(Qt.ItemDataRole.DisplayRole, QVariant(row))
item.setToolTip(str(row))
item.setData(Qt.ItemDataRole.UserRole, key)
item.setFlags(flags)
self.opt_columns.setItem(row, 0, item)
flags |= Qt.ItemFlag.ItemIsUserCheckable
if key == 'ondevice':
item.setFlags(flags & ~Qt.ItemFlag.ItemIsEnabled)
item.setCheckState(Qt.CheckState.PartiallyChecked)
else:
item.setFlags(flags)
item.setCheckState(Qt.CheckState.Unchecked if key in self.hidden_cols else
Qt.CheckState.Checked)
item = QTableWidgetItem(cc['name'])
item.setToolTip(cc['name'])
item.setFlags(flags)
if self.is_custom_key(key):
item.setData(Qt.ItemDataRole.DecorationRole, (QIcon(I('column.png'))))
self.opt_columns.setItem(row, 1, item)
item = QTableWidgetItem(key)
item.setToolTip(key)
item.setFlags(flags)
self.opt_columns.setItem(row, 2, item)
if key == 'title': if key == 'title':
coltype = _('Text') coltype = _('Text')
elif key == 'ondevice': elif key == 'ondevice':
@ -152,7 +181,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
item = QTableWidgetItem(coltype) item = QTableWidgetItem(coltype)
item.setToolTip(coltype) item.setToolTip(coltype)
item.setFlags(flags) item.setFlags(flags)
self.opt_columns.setItem(row, 2, item) self.opt_columns.setItem(row, 3, item)
desc = cc['display'].get('description', "")
item = QTableWidgetItem(desc)
item.setToolTip(desc)
item.setFlags(flags)
self.opt_columns.setItem(row, 4, item)
if '*deleted' in cc: if '*deleted' in cc:
col_status = _('Deleted column. Double-click to undelete it') col_status = _('Deleted column. Double-click to undelete it')
@ -167,49 +202,32 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
item = QTableWidgetItem(col_status) item = QTableWidgetItem(col_status)
item.setToolTip(col_status) item.setToolTip(col_status)
item.setFlags(flags) item.setFlags(flags)
self.opt_columns.setItem(row, 3, item) self.opt_columns.setItem(row, 5, item)
desc = cc['display'].get('description', "")
item = QTableWidgetItem(desc)
item.setToolTip(desc)
item.setFlags(flags)
self.opt_columns.setItem(row, 4, item)
item = QTableWidgetItem(cc['name'])
item.setToolTip(cc['name'])
item.setData(Qt.ItemDataRole.UserRole, key)
item.setFlags(flags)
self.opt_columns.setItem(row, 0, item)
if self.is_custom_key(key):
item.setData(Qt.ItemDataRole.DecorationRole, (QIcon(I('column.png'))))
if key != 'ondevice':
flags |= Qt.ItemFlag.ItemIsUserCheckable
item.setFlags(flags)
if key != 'ondevice':
item.setCheckState(Qt.CheckState.Unchecked if key in self.hidden_cols else
Qt.CheckState.Checked)
def up_column(self): def up_column(self):
idx = self.opt_columns.currentRow() row = self.opt_columns.currentRow()
if idx > 0: if row > 0:
for i in range(0, self.opt_columns.columnCount()): for i in range(0, self.opt_columns.columnCount()):
lower = self.opt_columns.takeItem(idx-1, i) lower = self.opt_columns.takeItem(row-1, i)
upper = self.opt_columns.takeItem(idx, i) upper = self.opt_columns.takeItem(row, i)
self.opt_columns.setItem(idx, i, lower) self.opt_columns.setItem(row, i, lower)
self.opt_columns.setItem(idx-1, i, upper) self.opt_columns.setItem(row-1, i, upper)
self.opt_columns.setCurrentCell(idx-1, 0) self.setup_row(row-1, self.opt_columns.item(row-1, 2).text())
self.setup_row(row, self.opt_columns.item(row, 2).text())
self.opt_columns.setCurrentCell(row-1, 0)
self.changed_signal.emit() self.changed_signal.emit()
def down_column(self): def down_column(self):
idx = self.opt_columns.currentRow() row = self.opt_columns.currentRow()
if idx < self.opt_columns.rowCount()-1: if row < self.opt_columns.rowCount()-1:
for i in range(0, self.opt_columns.columnCount()): for i in range(0, self.opt_columns.columnCount()):
lower = self.opt_columns.takeItem(idx, i) lower = self.opt_columns.takeItem(row, i)
upper = self.opt_columns.takeItem(idx+1, i) upper = self.opt_columns.takeItem(row+1, i)
self.opt_columns.setItem(idx+1, i, lower) self.opt_columns.setItem(row+1, i, lower)
self.opt_columns.setItem(idx, i, upper) self.opt_columns.setItem(row, i, upper)
self.opt_columns.setCurrentCell(idx+1, 0) self.setup_row(row+1, self.opt_columns.item(row+1, 2).text())
self.setup_row(row, self.opt_columns.item(row, 2).text())
self.opt_columns.setCurrentCell(row+1, 0)
self.changed_signal.emit() self.changed_signal.emit()
def is_new_custom_column(self, cc): def is_new_custom_column(self, cc):
@ -297,6 +315,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
def apply_custom_column_changes(self): def apply_custom_column_changes(self):
model = self.gui.library_view.model() model = self.gui.library_view.model()
db = model.db db = model.db
self.opt_columns.sortItems(0, Qt.AscendingOrder)
config_cols = [str(self.opt_columns.item(i, 0).data(Qt.ItemDataRole.UserRole) or '') config_cols = [str(self.opt_columns.item(i, 0).data(Qt.ItemDataRole.UserRole) or '')
for i in range(self.opt_columns.rowCount())] for i in range(self.opt_columns.rowCount())]
if not config_cols: if not config_cols: