mirror of
https://github.com/ciromattia/kcc
synced 2026-10-02 15:42:33 +00:00
Handle mixed metadata values in bulk editing
* In bulk mode, compare Series + Writer/Penciller/Inker/Colorist across all selected files (instead of using only the first file) * When values differ, show “(multiple values)” placeholder for that field * Add hover tooltip with overwrite warning and a File|Value table (or Value|Count summary when there are >20 files)
This commit is contained in:
@@ -1433,6 +1433,64 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
|
|
||||||
|
|
||||||
class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
||||||
|
def _buildBulkFieldToolTip(self, fieldLabel, valuesByFile):
|
||||||
|
"""Build HTML tooltip for bulk metadata mismatch fields.
|
||||||
|
|
||||||
|
valuesByFile: list of (file_path, value_str)
|
||||||
|
- if <= 20 rows: show File | Value
|
||||||
|
- else: show Value | Count
|
||||||
|
"""
|
||||||
|
note = '<p><em>Note: Changing this field will overwrite all values in all selected files.</em></p>'
|
||||||
|
|
||||||
|
if len(valuesByFile) <= 20:
|
||||||
|
rows = ''.join(
|
||||||
|
'<tr>'
|
||||||
|
f'<td style="padding:2px 6px; white-space:nowrap;">{escape(os.path.basename(f))}</td>'
|
||||||
|
f'<td style="padding:2px 6px;">{escape(v)}</td>'
|
||||||
|
'</tr>'
|
||||||
|
for f, v in valuesByFile
|
||||||
|
)
|
||||||
|
|
||||||
|
table = (
|
||||||
|
'<table border="1" cellspacing="0" cellpadding="0">'
|
||||||
|
'<tr>'
|
||||||
|
'<th style="padding:2px 6px; text-align:left;">File</th>'
|
||||||
|
'<th style="padding:2px 6px; text-align:left;">Value</th>'
|
||||||
|
'</tr>'
|
||||||
|
f'{rows}'
|
||||||
|
'</table>'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
counts = {}
|
||||||
|
for _, v in valuesByFile:
|
||||||
|
counts[v] = counts.get(v, 0) + 1
|
||||||
|
|
||||||
|
rows = ''.join(
|
||||||
|
'<tr>'
|
||||||
|
f'<td style="padding:2px 6px;">{escape(v)}</td>'
|
||||||
|
f'<td style="padding:2px 6px; text-align:right;">{c}</td>'
|
||||||
|
'</tr>'
|
||||||
|
for v, c in sorted(counts.items(), key=lambda t: (-t[1], t[0]))
|
||||||
|
)
|
||||||
|
|
||||||
|
table = (
|
||||||
|
'<table border="1" cellspacing="0" cellpadding="0">'
|
||||||
|
'<tr>'
|
||||||
|
'<th style="padding:2px 6px; text-align:left;">Value</th>'
|
||||||
|
'<th style="padding:2px 6px; text-align:right;">Count</th>'
|
||||||
|
'</tr>'
|
||||||
|
f'{rows}'
|
||||||
|
'</table>'
|
||||||
|
)
|
||||||
|
|
||||||
|
tooltipHTML = f'\
|
||||||
|
<b>{escape(fieldLabel)}</b>\
|
||||||
|
{note}\
|
||||||
|
{table}\
|
||||||
|
'
|
||||||
|
|
||||||
|
return tooltipHTML
|
||||||
|
|
||||||
def loadData(self, files):
|
def loadData(self, files):
|
||||||
self.files = files if isinstance(files, list) else [files]
|
self.files = files if isinstance(files, list) else [files]
|
||||||
self.bulkMode = len(self.files) > 1
|
self.bulkMode = len(self.files) > 1
|
||||||
@@ -1464,16 +1522,35 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
|||||||
field.setEnabled(False)
|
field.setEnabled(False)
|
||||||
field.setText('')
|
field.setText('')
|
||||||
field.setPlaceholderText('(multiple files)')
|
field.setPlaceholderText('(multiple files)')
|
||||||
|
field.setToolTip('')
|
||||||
|
|
||||||
for field in (self.seriesLine,):
|
# Load metadata for all files and show common values, or “(multiple values)” + tooltip.
|
||||||
field.setEnabled(True)
|
parsed = []
|
||||||
field.setPlaceholderText('')
|
for file in self.files:
|
||||||
field.setText(self.parser.data[field.objectName().capitalize()[:-4]])
|
parsed.append((file, metadata.MetadataParser(file)))
|
||||||
|
|
||||||
for field in (self.writerLine, self.pencillerLine, self.inkerLine, self.coloristLine):
|
field_specs = [
|
||||||
field.setEnabled(True)
|
(self.seriesLine, 'Series', lambda p: (p.data.get('Series', '') or '')),
|
||||||
field.setPlaceholderText('')
|
(self.writerLine, 'Writer', lambda p: ', '.join(p.data.get('Writers', []) or [])),
|
||||||
field.setText(', '.join(self.parser.data[field.objectName().capitalize()[:-4] + 's']))
|
(self.pencillerLine, 'Penciller', lambda p: ', '.join(p.data.get('Pencillers', []) or [])),
|
||||||
|
(self.inkerLine, 'Inker', lambda p: ', '.join(p.data.get('Inkers', []) or [])),
|
||||||
|
(self.coloristLine, 'Colorist', lambda p: ', '.join(p.data.get('Colorists', []) or [])),
|
||||||
|
]
|
||||||
|
|
||||||
|
for line, label, extractor in field_specs:
|
||||||
|
line.setEnabled(True)
|
||||||
|
valuesByFile = [(f, extractor(p)) for f, p in parsed]
|
||||||
|
uniqueValues = {v for _, v in valuesByFile}
|
||||||
|
|
||||||
|
if len(uniqueValues) == 1:
|
||||||
|
common_value = valuesByFile[0][1] if valuesByFile else ''
|
||||||
|
line.setPlaceholderText('')
|
||||||
|
line.setToolTip('')
|
||||||
|
line.setText(common_value)
|
||||||
|
else:
|
||||||
|
line.setText('')
|
||||||
|
line.setPlaceholderText('(multiple values)')
|
||||||
|
line.setToolTip(self._buildBulkFieldToolTip(label, valuesByFile))
|
||||||
else:
|
else:
|
||||||
file = self.files[0]
|
file = self.files[0]
|
||||||
self.parser = metadata.MetadataParser(file)
|
self.parser = metadata.MetadataParser(file)
|
||||||
|
|||||||
Reference in New Issue
Block a user