diff --git a/comictaggerlib/autotagmatchwindow.py b/comictaggerlib/autotagmatchwindow.py
index fe62cbe..449aeec 100644
--- a/comictaggerlib/autotagmatchwindow.py
+++ b/comictaggerlib/autotagmatchwindow.py
@@ -230,7 +230,15 @@ class AutoTagMatchWindow(QtWidgets.QDialog):
match = self.current_match()
ca = ComicArchive(self.current_match_set.original_path)
- md = ca.read_metadata(self.config.internal__load_data_style)
+ # TODO should this follow the same as CLI: filename (-f), read styles (-t), command line (-m)
+ # TODO Same is used for taggerwindow.py:~1734 Make a method?
+ md = GenericMetadata()
+ try:
+ for style in self.load_data_styles.keys():
+ md.overlay(ca.read_metadata(style))
+ except Exception as e:
+ logger.error("Failed to load metadata for %s: %s", ca.path, e)
+
if md.is_empty:
md = ca.metadata_from_filename(
self.config.Filename_Parsing__filename_parser,
@@ -265,4 +273,4 @@ class AutoTagMatchWindow(QtWidgets.QDialog):
)
break
- ca.load_cache(list(metadata_styles))
+ ca.load_cache(list(metadata_styles)) # TODO Should this be what the others do in taggerwindow.py etc.?
diff --git a/comictaggerlib/cli.py b/comictaggerlib/cli.py
index fe385a6..f6e7f37 100644
--- a/comictaggerlib/cli.py
+++ b/comictaggerlib/cli.py
@@ -249,12 +249,11 @@ class CLI:
md.overlay(f_md)
- for style in self.config.Runtime_Options__type:
+ for style in reversed(self.config.Runtime_Options__type):
if ca.has_metadata(style):
try:
t_md = ca.read_metadata(style)
md.overlay(t_md)
- break
except Exception as e:
logger.error("Failed to load metadata for %s: %s", ca.path, e)
diff --git a/comictaggerlib/ctsettings/commandline.py b/comictaggerlib/ctsettings/commandline.py
index 3920f3c..b56ee9c 100644
--- a/comictaggerlib/ctsettings/commandline.py
+++ b/comictaggerlib/ctsettings/commandline.py
@@ -160,14 +160,14 @@ def register_runtime(parser: settngs.Manager) -> None:
parser.add_setting(
"--json", "-j", action="store_true", help="Output json on stdout. Ignored in interactive mode.", file=False
)
-
+ # TODO Break read and write apart?
parser.add_setting(
"-t",
"--type",
metavar=f"{{{','.join(metadata_styles).upper()}}}",
default=[],
type=metadata_type,
- help="""Specify TYPE as either CR, CBL or COMET\n(as either ComicRack, ComicBookLover,\nor CoMet style tags, respectively).\nUse commas for multiple types.\nFor searching the metadata will use the first listed:\neg '-t cbl,cr' with no CBL tags, CR will be used if they exist\n\n""",
+ help="""Specify TYPE as either CR, CBL or COMET\n(as either ComicRack, ComicBookLover,\nor CoMet style tags, respectively).\nUse commas for multiple types.\nFor searching the metadata will be overlayed in reverse order (hierarchical):\ne.g. '-t cbl,cr' first CR tags are read, then CBL overlayed over the top.\n\n""",
file=False,
)
parser.add_setting(
diff --git a/comictaggerlib/ctsettings/file.py b/comictaggerlib/ctsettings/file.py
index d1bb276..b671001 100644
--- a/comictaggerlib/ctsettings/file.py
+++ b/comictaggerlib/ctsettings/file.py
@@ -32,7 +32,7 @@ def internal(parser: settngs.Manager) -> None:
# automatic settings
parser.add_setting("install_id", default=uuid.uuid4().hex, cmdline=False)
parser.add_setting("save_data_style", default=["cbi"], cmdline=False)
- parser.add_setting("load_data_style", default="cbi", cmdline=False)
+ parser.add_setting("load_data_style", default=[{"cbi": 0}], cmdline=False)
parser.add_setting("last_opened_folder", default="", cmdline=False)
parser.add_setting("window_width", default=0, cmdline=False)
parser.add_setting("window_height", default=0, cmdline=False)
diff --git a/comictaggerlib/ctsettings/settngs_namespace.py b/comictaggerlib/ctsettings/settngs_namespace.py
index 5f1aaf8..b5022e0 100644
--- a/comictaggerlib/ctsettings/settngs_namespace.py
+++ b/comictaggerlib/ctsettings/settngs_namespace.py
@@ -41,7 +41,7 @@ class SettngsNS(settngs.TypedNS):
internal__install_id: str
internal__save_data_style: list[str]
- internal__load_data_style: str
+ internal__load_data_style: dict[str, int]
internal__last_opened_folder: str
internal__window_width: int
internal__window_height: int
diff --git a/comictaggerlib/settingswindow.py b/comictaggerlib/settingswindow.py
index dc2d2bc..7c8d136 100644
--- a/comictaggerlib/settingswindow.py
+++ b/comictaggerlib/settingswindow.py
@@ -523,6 +523,7 @@ class SettingsWindow(QtWidgets.QDialog):
if self.cbxShortMetadataNames.isChecked() != self.config[0].General__use_short_metadata_names:
self.config[0].General__use_short_metadata_names = self.cbxShortMetadataNames.isChecked()
self.parent().populate_style_names()
+ self.parent().adjust_load_style_combo()
self.parent().adjust_save_style_combo()
self.config[0].Issue_Identifier__series_match_identify_thresh = self.sbNameMatchIdentifyThresh.value()
diff --git a/comictaggerlib/taggerwindow.py b/comictaggerlib/taggerwindow.py
index 8e37a93..8ceffe8 100644
--- a/comictaggerlib/taggerwindow.py
+++ b/comictaggerlib/taggerwindow.py
@@ -214,15 +214,20 @@ class TaggerWindow(QtWidgets.QMainWindow):
if config[0].Runtime_Options__type and isinstance(config[0].Runtime_Options__type[0], str):
# respect the command line option tag type
config[0].internal__save_data_style = config[0].Runtime_Options__type
- config[0].internal__load_data_style = config[0].Runtime_Options__type[0]
+ # TODO Should the command line have seperate options for read and write?
+ cmd_read_style = {}
+ for i, style in enumerate(config[0].Runtime_Options__type):
+ cmd_read_style.update({style: i})
+ config[0].internal__load_data_style = cmd_read_style
for style in config[0].internal__save_data_style:
if style not in metadata_styles:
config[0].internal__save_data_style.remove(style)
- if config[0].internal__load_data_style not in metadata_styles:
- config[0].internal__load_data_style = list(metadata_styles.keys())[0]
+ for style in config[0].internal__load_data_style.keys():
+ if style not in metadata_styles:
+ del config[0].internal__load_data_style[style]
self.save_data_styles: list[str] = config[0].internal__save_data_style
- self.load_data_style: str = config[0].internal__load_data_style
+ self.load_data_styles: dict[str, int] = config[0].internal__load_data_style
self.setAcceptDrops(True)
self.view_tag_actions, self.remove_tag_actions = self.tag_actions()
@@ -271,7 +276,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
self.cbMaturityRating.lineEdit().setAcceptDrops(False)
# hook up the callbacks
- self.cbLoadDataStyle.itemChecked.connect(self.set_load_data_style)
+ self.cbLoadDataStyle.itemChanged.connect(self.set_load_data_style)
self.cbSaveDataStyle.itemChecked.connect(self.set_save_data_style)
self.cbx_sources.currentIndexChanged.connect(self.set_source)
self.btnEditCredit.clicked.connect(self.edit_credit)
@@ -433,7 +438,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
self.actionAutoTag.triggered.connect(self.auto_tag)
self.actionCopyTags.setShortcut("Ctrl+C")
- self.actionCopyTags.setStatusTip("Copy one tag style to another")
+ self.actionCopyTags.setStatusTip("Copy first read style tags to enabled modify style(s)")
self.actionCopyTags.triggered.connect(self.copy_tags)
self.actionRemoveAuto.setShortcut("Ctrl+D")
@@ -1203,24 +1208,25 @@ class TaggerWindow(QtWidgets.QMainWindow):
self.update_menus()
self.fileSelectionList.update_current_row()
- self.metadata = self.comic_archive.read_metadata(self.load_data_style)
+ self.metadata = GenericMetadata()
+ for style in reversed(self.load_data_styles.keys()):
+ self.metadata.overlay(self.comic_archive.read_metadata(style))
self.update_ui_for_archive()
else:
QtWidgets.QMessageBox.information(self, "Whoops!", "No data to commit!")
- def set_load_data_style(self, s: str) -> None:
+ def set_load_data_style(self) -> None:
+ # TODO Should the message be changed? "manually entered data will be lost" Better desc for all 3 options?
+ # Save, Discard and Cancel - Cancel will keep the data in the form AND change the style. Explain each one?
if self.dirty_flag_verification(
- "Change Tag Read Style", "If you change read tag style now, data in the form will be lost. Are you sure?"
+ "Change Tag Read Style",
+ "If you change read tag style(s) now, data in the form will be lost. Are you sure?",
):
- self.load_data_style = self.cbLoadDataStyle.itemData(s)
- self.config[0].internal__load_data_style = self.load_data_style
+ self.load_data_styles = self.cbLoadDataStyle.currentData()
+ self.config[0].internal__load_data_style = self.load_data_styles
self.update_menus()
if self.comic_archive is not None:
self.load_archive(self.comic_archive)
- else:
- self.cbLoadDataStyle.currentIndexChanged.disconnect(self.set_load_data_style)
- self.adjust_load_style_combo()
- self.cbLoadDataStyle.currentIndexChanged.connect(self.set_load_data_style)
def set_save_data_style(self) -> None:
self.save_data_styles = self.cbSaveDataStyle.currentData()
@@ -1392,28 +1398,36 @@ class TaggerWindow(QtWidgets.QMainWindow):
self.cbx_sources.setCurrentIndex(self.cbx_sources.findData(self.config[0].Sources__source))
def adjust_load_style_combo(self) -> None:
- # select the current style
- self.cbLoadDataStyle.setCurrentIndex(self.cbLoadDataStyle.findData(self.load_data_style))
+ # select the enabled styles
+ unchecked = set(metadata_styles.keys()) - set(self.load_data_styles.keys())
+ for style, order in self.load_data_styles.items():
+ self.cbLoadDataStyle.setItemChecked(self.cbLoadDataStyle.findData(style), True, order)
+ for style in unchecked:
+ self.cbLoadDataStyle.setItemChecked(self.cbLoadDataStyle.findData(style), False)
def adjust_save_style_combo(self) -> None:
# select the current style
unchecked = set(metadata_styles.keys()) - set(self.save_data_styles)
for style in self.save_data_styles:
- self.cbSaveDataStyle.setItemChecked(self.cbLoadDataStyle.findData(style), True)
+ self.cbSaveDataStyle.setItemChecked(
+ self.cbSaveDataStyle.findData(style), True
+ ) # Why were these read style?
for style in unchecked:
- self.cbSaveDataStyle.setItemChecked(self.cbLoadDataStyle.findData(style), False)
+ self.cbSaveDataStyle.setItemChecked(self.cbSaveDataStyle.findData(style), False)
self.update_metadata_style_tweaks()
def populate_style_names(self) -> None:
# First clear all entries (called from settingswindow.py)
self.cbSaveDataStyle.clear()
+ self.cbLoadDataStyle.emptyTable()
# Add the entries to the tag style combobox
for style in metadata_styles.values():
- self.cbLoadDataStyle.addItem(style.name(), style.short_name)
if self.config[0].General__use_short_metadata_names:
self.cbSaveDataStyle.addItem(style.short_name.upper(), style.short_name)
+ self.cbLoadDataStyle.addItem(style.short_name.upper(), {style.short_name: -1})
else:
self.cbSaveDataStyle.addItem(style.name(), style.short_name)
+ self.cbLoadDataStyle.addItem(style.name(), {style.short_name: -1})
def populate_combo_boxes(self) -> None:
self.populate_style_names()
@@ -1604,7 +1618,8 @@ class TaggerWindow(QtWidgets.QMainWindow):
ca_list = self.fileSelectionList.get_selected_archive_list()
has_src_count = 0
- src_style = self.load_data_style
+ # TODO: Take first read style for now (make a better system later)
+ src_style, _ = next(iter(self.load_data_styles.items()))
dest_styles = self.save_data_styles
# Remove the read style from the write style
@@ -1683,7 +1698,8 @@ class TaggerWindow(QtWidgets.QMainWindow):
failed_list.append(ca.path)
ca.reset_cache()
- ca.load_cache([self.load_data_style, *self.save_data_styles])
+ # TODO Could result in dupes? Should only be read styles?
+ ca.load_cache([*self.load_data_styles.keys(), *self.save_data_styles])
prog_dialog.hide()
QtCore.QCoreApplication.processEvents()
@@ -1727,10 +1743,12 @@ class TaggerWindow(QtWidgets.QMainWindow):
ii = IssueIdentifier(ca, self.config[0], self.current_talker())
# read in metadata, and parse file name if not there
+ # TODO should this follow the same as CLI: filename (-f), read styles (-t), command line (-m)
+ md = GenericMetadata()
try:
- md = ca.read_metadata(self.load_data_style)
+ for style in self.load_data_styles.keys():
+ md.overlay(ca.read_metadata(style))
except Exception as e:
- md = GenericMetadata()
logger.error("Failed to load metadata for %s: %s", ca.path, e)
if md.is_empty:
md = ca.metadata_from_filename(
@@ -1888,7 +1906,8 @@ class TaggerWindow(QtWidgets.QMainWindow):
match_results.write_failures.append(res)
ca.reset_cache()
- ca.load_cache([self.load_data_style] + self.save_data_styles)
+ # TODO Only read styles required?
+ ca.load_cache([*self.load_data_styles.keys(), *self.save_data_styles])
return success, match_results
@@ -1937,7 +1956,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
self.auto_tag_log(f"Auto-Tagging {prog_idx} of {len(ca_list)}\n")
self.auto_tag_log(f"{ca.path}\n")
try:
- cover_idx = ca.read_metadata(self.load_data_style).get_cover_page_index_list()[0]
+ cover_idx = ca.read_metadata(list(self.load_data_styles.keys())[0]).get_cover_page_index_list()[0]
except Exception as e:
cover_idx = 0
logger.error("Failed to load metadata for %s: %s", ca.path, e)
@@ -2132,7 +2151,8 @@ class TaggerWindow(QtWidgets.QMainWindow):
if self.dirty_flag_verification(
"File Rename", "If you rename files now, unsaved data in the form will be lost. Are you sure?"
):
- dlg = RenameWindow(self, ca_list, self.load_data_style, self.config, self.talkers)
+ # dlg = RenameWindow(self, ca_list, self.load_data_styles, self.config, self.talkers)
+ dlg = RenameWindow(self, ca_list, "cr", self.config, self.talkers)
dlg.setModal(True)
if dlg.exec() and self.comic_archive is not None:
self.fileSelectionList.update_selected_rows()
@@ -2151,12 +2171,15 @@ class TaggerWindow(QtWidgets.QMainWindow):
self.config[0].internal__last_opened_folder = os.path.abspath(os.path.split(comic_archive.path)[0])
self.comic_archive = comic_archive
+
+ self.metadata = GenericMetadata()
try:
- self.metadata = self.comic_archive.read_metadata(self.load_data_style)
+ for style, order in reversed(self.load_data_styles.items()):
+ metadata = self.comic_archive.read_metadata(style)
+ self.metadata.overlay(metadata)
except Exception as e:
logger.error("Failed to load metadata for %s: %s", self.comic_archive.path, e)
self.exception(f"Failed to load metadata for {self.comic_archive.path}:\n\n{e}")
- self.metadata = GenericMetadata()
self.update_ui_for_archive()
diff --git a/comictaggerlib/ui/customwidgets.py b/comictaggerlib/ui/customwidgets.py
index 03d1984..0ad99c1 100644
--- a/comictaggerlib/ui/customwidgets.py
+++ b/comictaggerlib/ui/customwidgets.py
@@ -7,6 +7,8 @@ from typing import Any
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import QEvent, QModelIndex, QRect, Qt, pyqtSignal
+from comictaggerlib.graphics import graphics_path
+
# Multiselect combobox from: https://gis.stackexchange.com/a/351152 (with custom changes)
class CheckableComboBox(QtWidgets.QComboBox):
@@ -114,6 +116,16 @@ class CheckableComboBox(QtWidgets.QComboBox):
self.setItemChecked(index, True)
+class CheckBoxStyle(QtWidgets.QProxyStyle):
+ def subElementRect(
+ self, element: QtWidgets.QStyle.SubElement, option: QtWidgets.QStyleOption, widget: QtWidgets.QWidget = None
+ ) -> QRect:
+ r = super().subElementRect(element, option, widget)
+ if element == QtWidgets.QStyle.SE_ItemViewItemCheckIndicator:
+ r.moveCenter(option.rect.center())
+ return r
+
+
class SortLabelTableWidgetItem(QtWidgets.QTableWidgetItem):
"""Custom QTableWidgetItem to sort with '-' below numbers"""
@@ -126,30 +138,30 @@ class SortLabelTableWidgetItem(QtWidgets.QTableWidgetItem):
class HoverQLabel(QtWidgets.QLabel):
+ """A QLabel with two QButtons that appear on hover"""
+
def __init__(self, text: str, parent: TableComboBox):
super().__init__(text, parent=parent)
self.combobox = parent
- self.button_up = QtWidgets.QPushButton("Up", self)
+ self.button_up = QtWidgets.QPushButton(QtGui.QIcon(str(graphics_path / "up.png")), "", self)
self.button_up.clicked.connect(self.button_up_clicked)
+ self.button_up.setToolTip("Move style up in order")
self.button_up.hide()
- self.button_down = QtWidgets.QPushButton("Down", self)
+ self.button_down = QtWidgets.QPushButton(QtGui.QIcon(str(graphics_path / "down.png")), "", self)
self.button_down.clicked.connect(self.button_down_clicked)
+ self.button_down.setToolTip("Move style down in order")
self.button_down.hide()
# Place 'down' button on left side
- self.button_down.move(self.width() - self.button_down.width(), 0)
self.button_down.resize(self.button_down.sizeHint())
# Place 'up' button on right side
- self.button_up.move(self.width() - self.button_up.width() - self.button_down.width(), 0)
self.button_up.resize(self.button_up.sizeHint())
- # self.resizeEvent = self.adjustButton
-
def _showHideButtons(self, index: QModelIndex) -> None:
- # TODO Better to iterate over all?
+ # TODO Better to iterate over all? Send in check state too?
item = self.combobox.tableWidget.item(index.row(), 1)
item_checked = item.checkState()
if index.row() != self.combobox.tableWidget.currentRow():
@@ -164,6 +176,7 @@ class HoverQLabel(QtWidgets.QLabel):
self.button_down.hide()
def enterEvent(self, event: QEvent | None) -> None:
+ # Need to manually set the rest of the row highlighted
index: QModelIndex = self.combobox.tableWidget.indexAt(self.pos())
self.combobox.tableWidget.selectRow(index.row())
@@ -193,22 +206,35 @@ class HoverQLabel(QtWidgets.QLabel):
class TableComboBox(QtWidgets.QComboBox):
- itemChecked = pyqtSignal(str, bool)
+ itemChanged = pyqtSignal()
def __init__(self, *args: Any, **kwargs: Any):
super().__init__(*args, **kwargs)
+
+ # Longest width of read style label
+ self.longest = 0
+
self.tableWidget = QtWidgets.QTableWidget()
self.setModel(self.tableWidget.model())
self.setView(self.tableWidget)
+ centered_checkbox_style = CheckBoxStyle()
+ self.tableWidget.setStyle(centered_checkbox_style)
+
self.tableWidget.setColumnCount(3)
+ self.tableWidget.setHorizontalHeaderLabels([" # ", " Enabled ", "Read Style"])
+ self.tableWidget.horizontalHeaderItem(0).setToolTip("Order of overlay operations")
+ self.tableWidget.horizontalHeaderItem(1).setToolTip("Whether the style is enabled or not")
+ self.tableWidget.horizontalHeaderItem(2).setToolTip("Name of the read style")
+
+ self.tableWidget.horizontalHeader().setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
+ self.tableWidget.resizeColumnsToContents()
+
self.tableWidget.verticalHeader().setVisible(False)
- self.tableWidget.setHorizontalHeaderLabels(["Order", "Enabled", "Read Style"])
+
self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.tableWidget.setShowGrid(False)
- self.tableWidget.horizontalHeader().setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
- self.tableWidget.resizeColumnsToContents()
# Prevent popup from closing when clicking on an item
self.tableWidget.viewport().installEventFilter(self)
@@ -219,6 +245,9 @@ class TableComboBox(QtWidgets.QComboBox):
self.tableWidget.currentCellChanged.connect(self.current_cell_changed)
def current_cell_changed(self, cur_row: int, cur_col: int, prev_row: int, prev_col: int) -> None:
+ # When rebuilding, cur_row -1 will occur and cause a crash
+ if cur_row == -1:
+ return
if prev_row == -1:
# First time open
cur_index = self.tableWidget.indexFromItem(self.tableWidget.item(cur_row, 0))
@@ -231,6 +260,42 @@ class TableComboBox(QtWidgets.QComboBox):
cur_index = self.tableWidget.indexFromItem(self.tableWidget.item(cur_row, 0))
self.tableWidget.cellWidget(cur_row, 2)._showHideButtons(cur_index)
+ def _longest_label(self) -> None:
+ # Depending on "short" names for metadata, "Read Style" header or metadata name may be longer
+ style_header_width = 0
+ header_item = self.tableWidget.horizontalHeaderItem(2)
+ if header_item is not None:
+ font_metrics = QtGui.QFontMetrics(header_item.font())
+ style_header_width = font_metrics.width(header_item.text())
+
+ header_width = 0
+ for col in range(self.tableWidget.columnCount() - 1): # Skip "read style" as already done above
+ header_item = self.tableWidget.horizontalHeaderItem(col)
+ if header_item is not None:
+ font_metrics = QtGui.QFontMetrics(header_item.font())
+ text_width = font_metrics.width(header_item.text())
+ header_width += text_width
+
+ # Now check items
+ for i in range(self.count()):
+ hlabel = self.tableWidget.cellWidget(i, 2)
+ hlabel_width = (
+ style_header_width if style_header_width > hlabel.sizeHint().width() else hlabel.sizeHint().width()
+ )
+ # Get sizeHint of one button and double it
+ total_width = hlabel_width + header_width + (hlabel.button_up.sizeHint().width() * 2)
+
+ if total_width > self.longest:
+ self.longest = total_width
+
+ def _resizeTable(self) -> None:
+ self._longest_label()
+ self.tableWidget.setMinimumWidth(self.longest)
+
+ def resizeEvent(self, event: Any | None = None) -> None:
+ super().resizeEvent(event)
+ self._updateText()
+
def eventFilter(self, obj: Any, event: Any) -> bool:
# Allow events before the combobox list is shown
if obj == self.tableWidget.viewport():
@@ -258,7 +323,12 @@ class TableComboBox(QtWidgets.QComboBox):
return True
return False
+ def emptyTable(self) -> None:
+ self.tableWidget.setRowCount(0)
+ self.longest = 0
+
def _move_item(self, index: QModelIndex, up: bool) -> None:
+ """Move an item up or down in order"""
adjust = -1 if up else 1
cur_item = self.tableWidget.item(index.row(), 0)
cur_item_data = cur_item.data(Qt.UserRole)
@@ -274,26 +344,40 @@ class TableComboBox(QtWidgets.QComboBox):
swap_item.setData(Qt.UserRole, {swap_key: cur_value})
self._updateLabels()
+ self.itemChanged.emit()
# Selected (highlighted) row moves so is no longer under the mouse
self.tableWidget.selectRow(index.row())
- def addItem(self, label: str = "-", checked: bool = False, text: str = "", data: Any | None = None) -> None:
+ def addItem(self, text: str = "", data: Any | None = None) -> None:
rowPosition = self.tableWidget.rowCount()
self.tableWidget.insertRow(rowPosition)
- self.tableWidget.setItem(rowPosition, 0, SortLabelTableWidgetItem(label))
+ sortTblItem = SortLabelTableWidgetItem()
+ sortTblItem.setTextAlignment(Qt.AlignCenter)
+ self.tableWidget.setItem(rowPosition, 0, sortTblItem)
chkBoxItem = QtWidgets.QTableWidgetItem()
- chkBoxItem.setCheckState(Qt.Checked if checked else Qt.Unchecked)
+ # Set to true to get around the "one item must be checked" check for setItemChecked
+ chkBoxItem.setCheckState(Qt.Checked)
+
self.tableWidget.setItem(rowPosition, 1, chkBoxItem)
self.tableWidget.setCellWidget(rowPosition, 2, HoverQLabel(text, parent=self))
self.tableWidget.item(rowPosition, 0).setData(Qt.UserRole, data)
self._updateLabels()
self._updateText()
+ # Manual as resizeEvent doesn't trigger
+ self._resizeTable()
+
+ def findData(self, data: str, role: int = Qt.UserRole) -> QModelIndex | None:
+ for i in range(self.count()):
+ item = self.itemData(i)
+ k = list(item.keys())[0]
+ if k == data:
+ return self.tableWidget.indexFromItem(self.tableWidget.item(i, 0))
+ return None
def currentData(self) -> dict[str, int]:
- # Return the list of all checked items data
res = {}
for i in range(self.count()):
item = self.tableWidget.item(i, 1)
@@ -332,7 +416,7 @@ class TableComboBox(QtWidgets.QComboBox):
# Disable top up button and bottom down button
if val == 1:
self.tableWidget.cellWidget(i, 2).button_up.setEnabled(False)
- # Disable the down button if single item. Show buttons as a sign it is checked
+ # Disable the down button if single item. Show buttons even if disabled to indicate checked
if val == cur_data_len:
self.tableWidget.cellWidget(i, 2).button_down.setEnabled(False)
elif val == cur_data_len:
@@ -369,33 +453,35 @@ class TableComboBox(QtWidgets.QComboBox):
self.setCurrentIndex(-1)
self.setPlaceholderText(elidedText)
- def setItemChecked(self, index: QModelIndex, state: bool) -> None:
+ def setItemChecked(self, index: QModelIndex, state: bool, order: int = -1) -> None:
+ if index is None:
+ return
qt_state = Qt.Checked if state else Qt.Unchecked
item = self.tableWidget.item(index.row(), 1)
- current = self.currentData()
- # If we have at least one item checked emit itemChecked with the current check state and update text
+ current_len = len(self.currentData())
+
# Require at least one item to be checked and provide a tooltip
- if len(current) == 1 and not state and item.checkState() == Qt.Checked:
+ if current_len == 1 and not state and item.checkState() == Qt.Checked:
QtWidgets.QToolTip.showText(QtGui.QCursor.pos(), self.toolTip(), self, QRect(), 3000)
return
- if len(current) > 0:
+ if current_len > 0:
item.setCheckState(qt_state)
item_data: dict[str, int] = self.itemData(index.row())
key_name = list(item_data.keys())[0]
if state:
- next_num = self._nextOrderNumber()
- data = {key_name: next_num}
- self.tableWidget.item(index.row(), 0).setText(str(next_num + 1))
+ order_num = order if order != -1 else self._nextOrderNumber()
+ data = {key_name: order_num}
+ self.tableWidget.item(index.row(), 0).setText(str(order_num + 1))
self.tableWidget.item(index.row(), 0).setData(Qt.UserRole, data)
else:
data = {key_name: -1}
self.tableWidget.item(index.row(), 0).setText("-")
self.tableWidget.item(index.row(), 0).setData(Qt.UserRole, data)
- # We need to check the order numbers as any number could have been removed
+ # Any number may have been removed so reevaluate all
self._setOrderNumbers()
- self.itemChecked.emit(key_name, state)
+ self.itemChanged.emit()
self._updateText()
self._updateLabels()
# Check if buttons need to be shown or hidden
diff --git a/comictaggerlib/ui/taggerwindow.ui b/comictaggerlib/ui/taggerwindow.ui
index 2601888..d071c0a 100644
--- a/comictaggerlib/ui/taggerwindow.ui
+++ b/comictaggerlib/ui/taggerwindow.ui
@@ -76,7 +76,11 @@
-
-
+
+
+ At least one read style must be selected
+
+
-