From 7e94861fa1c7a698ec0fc66b3d60b197d1ab7922 Mon Sep 17 00:00:00 2001
From: Alex Xu
Date: Sun, 14 Dec 2025 16:13:24 -0800
Subject: [PATCH] input folder multiselect (#1195)
---
gui/KCC.ui | 90 ++++++++++++---------
kindlecomicconverter/KCC_gui.py | 25 +++++-
kindlecomicconverter/KCC_ui.py | 135 +++++++++++++++++---------------
3 files changed, 149 insertions(+), 101 deletions(-)
diff --git a/gui/KCC.ui b/gui/KCC.ui
index cb9fccb..3bc01a5 100644
--- a/gui/KCC.ui
+++ b/gui/KCC.ui
@@ -348,6 +348,51 @@
+ -
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - next to source<br/></span>Place output files next to source files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - folder next to source<br/></span>Place output files in a folder next to source files</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Custom<br/></span>Place output files in custom directory specified by right button</p></body></html>
+
+
+ Output Folder
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 30
+
+
+
+ <html><head/><body><p>Use this to select the default output directory.</p></body></html>
+
+
+
+
+
+
+ :/Other/icons/folder_new.png:/Other/icons/folder_new.png
+
+
+
+
+
+
@@ -747,7 +792,7 @@
<html><head/><body><p style='white-space:pre'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>
- Add file(s)
+ Add input file(s)
@@ -755,19 +800,13 @@
- -
-
-
-
- 0
- 30
-
-
+
-
+
- <html><head/><body><p>Use this to select the default output directory.</p></body></html>
+ <html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=" font-weight:600;">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>
-
+ Add input folder(s)
@@ -775,26 +814,7 @@
- -
-
-
-
- 0
- 0
-
-
-
- <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - next to source<br/></span>Place output files next to source files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - folder next to source<br/></span>Place output files in a folder next to source files</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Custom<br/></span>Place output files in custom directory specified by right button</p></body></html>
-
-
- Output Folder
-
-
- true
-
-
-
- -
+
-
@@ -811,10 +831,9 @@
clearButton
deviceBox
convertButton
- formatBox
- defaultOutputFolderButton
fileButton
- defaultOutputFolderBox
+ directoryButton
+ formatBox
-
@@ -901,12 +920,9 @@
jobList
fileButton
clearButton
- defaultOutputFolderButton
- defaultOutputFolderBox
deviceBox
widthBox
heightBox
- formatBox
convertButton
mangaBox
rotateBox
diff --git a/kindlecomicconverter/KCC_gui.py b/kindlecomicconverter/KCC_gui.py
index 5ec3371..f86b02d 100644
--- a/kindlecomicconverter/KCC_gui.py
+++ b/kindlecomicconverter/KCC_gui.py
@@ -22,7 +22,7 @@ import itertools
from pathlib import Path
from PySide6.QtCore import (QSize, QUrl, Qt, Signal, QIODeviceBase, QEvent, QThread, QSettings)
from PySide6.QtGui import (QColor, QIcon, QPixmap, QDesktopServices)
-from PySide6.QtWidgets import (QApplication, QLabel, QListWidgetItem, QMainWindow, QSystemTrayIcon, QFileDialog, QMessageBox, QDialog)
+from PySide6.QtWidgets import (QApplication, QLabel, QListWidgetItem, QMainWindow, QSystemTrayIcon, QFileDialog, QMessageBox, QDialog, QTreeView, QAbstractItemView)
from PySide6.QtNetwork import (QLocalSocket, QLocalServer)
import os
@@ -610,12 +610,30 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'Comic (*.pdf);;All (*.*)')
for fname in fnames[0]:
if fname != '':
- if sys.platform.startswith('win'):
- fname = fname.replace('/', '\\')
self.lastPath = os.path.abspath(os.path.join(fname, os.pardir))
GUI.jobList.addItem(fname)
GUI.jobList.scrollToBottom()
+ def selectDir(self):
+ if self.needClean:
+ self.needClean = False
+ GUI.jobList.clear()
+
+ dialog = QFileDialog(MW, 'Select input folder(s)', self.lastPath)
+ dialog.setFileMode(QFileDialog.FileMode.Directory)
+ dialog.setOption(QFileDialog.Option.ShowDirsOnly, True)
+ dialog.setOption(QFileDialog.Option.DontUseNativeDialog, True)
+ dialog.findChild(QTreeView).setSelectionMode(QAbstractItemView.ExtendedSelection)
+
+ if dialog.exec():
+ dnames = dialog.selectedFiles()
+ for dname in dnames:
+ if dname != '':
+ self.lastPath = os.path.abspath(os.path.join(dname, os.pardir))
+ GUI.jobList.addItem(dname)
+ GUI.jobList.scrollToBottom()
+
+
def selectFileMetaEditor(self, sname):
if not sname:
if QApplication.keyboardModifiers() == Qt.ShiftModifier:
@@ -1319,6 +1337,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.defaultOutputFolderButton.clicked.connect(self.selectDefaultOutputFolder)
GUI.clearButton.clicked.connect(self.clearJobs)
GUI.fileButton.clicked.connect(self.selectFile)
+ GUI.directoryButton.clicked.connect(self.selectDir)
GUI.editorButton.clicked.connect(self.selectFileMetaEditor)
GUI.wikiButton.clicked.connect(self.openWiki)
GUI.kofiButton.clicked.connect(self.openKofi)
diff --git a/kindlecomicconverter/KCC_ui.py b/kindlecomicconverter/KCC_ui.py
index df16860..36f09d6 100644
--- a/kindlecomicconverter/KCC_ui.py
+++ b/kindlecomicconverter/KCC_ui.py
@@ -190,6 +190,33 @@ class Ui_mainWindow(object):
self.gridLayout_2.addWidget(self.autocontrastBox, 9, 2, 1, 1)
+ self.outputFolderWidget = QWidget(self.optionWidget)
+ self.outputFolderWidget.setObjectName(u"outputFolderWidget")
+ self.horizontalLayout_3 = QHBoxLayout(self.outputFolderWidget)
+ self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
+ self.defaultOutputFolderBox = QCheckBox(self.outputFolderWidget)
+ self.defaultOutputFolderBox.setObjectName(u"defaultOutputFolderBox")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
+ sizePolicy1.setHorizontalStretch(0)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.defaultOutputFolderBox.sizePolicy().hasHeightForWidth())
+ self.defaultOutputFolderBox.setSizePolicy(sizePolicy1)
+ self.defaultOutputFolderBox.setTristate(True)
+
+ self.horizontalLayout_3.addWidget(self.defaultOutputFolderBox)
+
+ self.defaultOutputFolderButton = QPushButton(self.outputFolderWidget)
+ self.defaultOutputFolderButton.setObjectName(u"defaultOutputFolderButton")
+ self.defaultOutputFolderButton.setMinimumSize(QSize(0, 30))
+ icon1 = QIcon()
+ icon1.addFile(u":/Other/icons/folder_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.defaultOutputFolderButton.setIcon(icon1)
+
+ self.horizontalLayout_3.addWidget(self.defaultOutputFolderButton)
+
+
+ self.gridLayout_2.addWidget(self.outputFolderWidget, 0, 2, 1, 1)
+
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
@@ -211,11 +238,11 @@ class Ui_mainWindow(object):
self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
self.hLabel = QLabel(self.customWidget)
self.hLabel.setObjectName(u"hLabel")
- sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
- sizePolicy1.setHorizontalStretch(0)
- sizePolicy1.setVerticalStretch(0)
- sizePolicy1.setHeightForWidth(self.hLabel.sizePolicy().hasHeightForWidth())
- self.hLabel.setSizePolicy(sizePolicy1)
+ sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
+ sizePolicy2.setHorizontalStretch(0)
+ sizePolicy2.setVerticalStretch(0)
+ sizePolicy2.setHeightForWidth(self.hLabel.sizePolicy().hasHeightForWidth())
+ self.hLabel.setSizePolicy(sizePolicy2)
self.gridLayout_3.addWidget(self.hLabel, 0, 2, 1, 1)
@@ -227,8 +254,8 @@ class Ui_mainWindow(object):
self.wLabel = QLabel(self.customWidget)
self.wLabel.setObjectName(u"wLabel")
- sizePolicy1.setHeightForWidth(self.wLabel.sizePolicy().hasHeightForWidth())
- self.wLabel.setSizePolicy(sizePolicy1)
+ sizePolicy2.setHeightForWidth(self.wLabel.sizePolicy().hasHeightForWidth())
+ self.wLabel.setSizePolicy(sizePolicy2)
self.gridLayout_3.addWidget(self.wLabel, 0, 0, 1, 1)
@@ -271,18 +298,18 @@ class Ui_mainWindow(object):
self.editorButton = QPushButton(self.toolWidget)
self.editorButton.setObjectName(u"editorButton")
self.editorButton.setMinimumSize(QSize(0, 30))
- icon1 = QIcon()
- icon1.addFile(u":/Other/icons/editor.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.editorButton.setIcon(icon1)
+ icon2 = QIcon()
+ icon2.addFile(u":/Other/icons/editor.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.editorButton.setIcon(icon2)
self.horizontalLayout.addWidget(self.editorButton)
self.kofiButton = QPushButton(self.toolWidget)
self.kofiButton.setObjectName(u"kofiButton")
self.kofiButton.setMinimumSize(QSize(0, 30))
- icon2 = QIcon()
- icon2.addFile(u":/Brand/icons/kofi_symbol.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.kofiButton.setIcon(icon2)
+ icon3 = QIcon()
+ icon3.addFile(u":/Brand/icons/kofi_symbol.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.kofiButton.setIcon(icon3)
self.kofiButton.setIconSize(QSize(19, 16))
self.horizontalLayout.addWidget(self.kofiButton)
@@ -290,9 +317,9 @@ class Ui_mainWindow(object):
self.wikiButton = QPushButton(self.toolWidget)
self.wikiButton.setObjectName(u"wikiButton")
self.wikiButton.setMinimumSize(QSize(0, 30))
- icon3 = QIcon()
- icon3.addFile(u":/Other/icons/wiki.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.wikiButton.setIcon(icon3)
+ icon4 = QIcon()
+ icon4.addFile(u":/Other/icons/wiki.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.wikiButton.setIcon(icon4)
self.horizontalLayout.addWidget(self.wikiButton)
@@ -336,11 +363,8 @@ class Ui_mainWindow(object):
self.preserveMarginBox = QSpinBox(self.croppingWidget)
self.preserveMarginBox.setObjectName(u"preserveMarginBox")
- sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
- sizePolicy2.setHorizontalStretch(0)
- sizePolicy2.setVerticalStretch(0)
- sizePolicy2.setHeightForWidth(self.preserveMarginBox.sizePolicy().hasHeightForWidth())
- self.preserveMarginBox.setSizePolicy(sizePolicy2)
+ sizePolicy1.setHeightForWidth(self.preserveMarginBox.sizePolicy().hasHeightForWidth())
+ self.preserveMarginBox.setSizePolicy(sizePolicy1)
self.preserveMarginBox.setMaximum(99)
self.preserveMarginBox.setSingleStep(5)
self.preserveMarginBox.setValue(0)
@@ -364,18 +388,18 @@ class Ui_mainWindow(object):
self.convertButton.setObjectName(u"convertButton")
self.convertButton.setMinimumSize(QSize(0, 30))
self.convertButton.setFont(font)
- icon4 = QIcon()
- icon4.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.convertButton.setIcon(icon4)
+ icon5 = QIcon()
+ icon5.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.convertButton.setIcon(icon5)
self.gridLayout_4.addWidget(self.convertButton, 1, 3, 1, 1)
self.clearButton = QPushButton(self.buttonWidget)
self.clearButton.setObjectName(u"clearButton")
self.clearButton.setMinimumSize(QSize(0, 30))
- icon5 = QIcon()
- icon5.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.clearButton.setIcon(icon5)
+ icon6 = QIcon()
+ icon6.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.clearButton.setIcon(icon6)
self.gridLayout_4.addWidget(self.clearButton, 0, 3, 1, 1)
@@ -388,42 +412,30 @@ class Ui_mainWindow(object):
self.fileButton = QPushButton(self.buttonWidget)
self.fileButton.setObjectName(u"fileButton")
self.fileButton.setMinimumSize(QSize(0, 30))
- icon6 = QIcon()
- icon6.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.fileButton.setIcon(icon6)
+ icon7 = QIcon()
+ icon7.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.fileButton.setIcon(icon7)
self.gridLayout_4.addWidget(self.fileButton, 0, 1, 1, 1)
- self.defaultOutputFolderButton = QPushButton(self.buttonWidget)
- self.defaultOutputFolderButton.setObjectName(u"defaultOutputFolderButton")
- self.defaultOutputFolderButton.setMinimumSize(QSize(0, 30))
- icon7 = QIcon()
- icon7.addFile(u":/Other/icons/folder_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.defaultOutputFolderButton.setIcon(icon7)
+ self.directoryButton = QPushButton(self.buttonWidget)
+ self.directoryButton.setObjectName(u"directoryButton")
+ self.directoryButton.setIcon(icon1)
- self.gridLayout_4.addWidget(self.defaultOutputFolderButton, 0, 5, 1, 1)
-
- self.defaultOutputFolderBox = QCheckBox(self.buttonWidget)
- self.defaultOutputFolderBox.setObjectName(u"defaultOutputFolderBox")
- sizePolicy2.setHeightForWidth(self.defaultOutputFolderBox.sizePolicy().hasHeightForWidth())
- self.defaultOutputFolderBox.setSizePolicy(sizePolicy2)
- self.defaultOutputFolderBox.setTristate(True)
-
- self.gridLayout_4.addWidget(self.defaultOutputFolderBox, 0, 4, 1, 1)
+ self.gridLayout_4.addWidget(self.directoryButton, 0, 4, 1, 1)
self.formatBox = QComboBox(self.buttonWidget)
self.formatBox.setObjectName(u"formatBox")
self.formatBox.setMinimumSize(QSize(0, 28))
- self.gridLayout_4.addWidget(self.formatBox, 1, 4, 1, 2)
+ self.gridLayout_4.addWidget(self.formatBox, 1, 4, 1, 1)
self.clearButton.raise_()
self.deviceBox.raise_()
self.convertButton.raise_()
- self.formatBox.raise_()
- self.defaultOutputFolderButton.raise_()
self.fileButton.raise_()
- self.defaultOutputFolderBox.raise_()
+ self.directoryButton.raise_()
+ self.formatBox.raise_()
self.gridLayout.addWidget(self.buttonWidget, 3, 0, 1, 2)
@@ -471,13 +483,10 @@ class Ui_mainWindow(object):
mainWindow.setStatusBar(self.statusBar)
QWidget.setTabOrder(self.jobList, self.fileButton)
QWidget.setTabOrder(self.fileButton, self.clearButton)
- QWidget.setTabOrder(self.clearButton, self.defaultOutputFolderButton)
- QWidget.setTabOrder(self.defaultOutputFolderButton, self.defaultOutputFolderBox)
- QWidget.setTabOrder(self.defaultOutputFolderBox, self.deviceBox)
+ QWidget.setTabOrder(self.clearButton, self.deviceBox)
QWidget.setTabOrder(self.deviceBox, self.widthBox)
QWidget.setTabOrder(self.widthBox, self.heightBox)
- QWidget.setTabOrder(self.heightBox, self.formatBox)
- QWidget.setTabOrder(self.formatBox, self.convertButton)
+ QWidget.setTabOrder(self.heightBox, self.convertButton)
QWidget.setTabOrder(self.convertButton, self.mangaBox)
QWidget.setTabOrder(self.mangaBox, self.rotateBox)
QWidget.setTabOrder(self.rotateBox, self.qualityBox)
@@ -621,6 +630,14 @@ class Ui_mainWindow(object):
self.autocontrastBox.setToolTip(QCoreApplication.translate("mainWindow", u"
Unchecked - BW only
Only autocontrast bw pages. Ignored for pages where near blacks or whites don't exist.
Indeterminate - Disabled
Disable autocontrast
Checked - BW and Color
BW and color images will be autocontrasted. Ignored for pages where near blacks or whites don't exist.
", None))
#endif // QT_CONFIG(tooltip)
self.autocontrastBox.setText(QCoreApplication.translate("mainWindow", u"Autocontrast", None))
+#if QT_CONFIG(tooltip)
+ self.defaultOutputFolderBox.setToolTip(QCoreApplication.translate("mainWindow", u" Unchecked - next to source
Place output files next to source files
Indeterminate - folder next to source
Place output files in a folder next to source files
Checked - Custom
Place output files in custom directory specified by right button
", None))
+#endif // QT_CONFIG(tooltip)
+ self.defaultOutputFolderBox.setText(QCoreApplication.translate("mainWindow", u"Output Folder", None))
+#if QT_CONFIG(tooltip)
+ self.defaultOutputFolderButton.setToolTip(QCoreApplication.translate("mainWindow", u"Use this to select the default output directory.
", None))
+#endif // QT_CONFIG(tooltip)
+ self.defaultOutputFolderButton.setText("")
#if QT_CONFIG(tooltip)
self.jobList.setToolTip(QCoreApplication.translate("mainWindow", u" Double click on source to open it in metadata editor.
", None))
#endif // QT_CONFIG(tooltip)
@@ -661,15 +678,11 @@ class Ui_mainWindow(object):
#if QT_CONFIG(tooltip)
self.fileButton.setToolTip(QCoreApplication.translate("mainWindow", u"
Add CBR, CBZ, CB7 or PDF file to queue.
", None))
#endif // QT_CONFIG(tooltip)
- self.fileButton.setText(QCoreApplication.translate("mainWindow", u"Add file(s)", None))
+ self.fileButton.setText(QCoreApplication.translate("mainWindow", u"Add input file(s)", None))
#if QT_CONFIG(tooltip)
- self.defaultOutputFolderButton.setToolTip(QCoreApplication.translate("mainWindow", u"Use this to select the default output directory.
", None))
+ self.directoryButton.setToolTip(QCoreApplication.translate("mainWindow", u"Add directory containing JPG, PNG or GIF files to queue.
CBR, CBZ and CB7 files inside will not be processed!
", None))
#endif // QT_CONFIG(tooltip)
- self.defaultOutputFolderButton.setText("")
-#if QT_CONFIG(tooltip)
- self.defaultOutputFolderBox.setToolTip(QCoreApplication.translate("mainWindow", u"Unchecked - next to source
Place output files next to source files
Indeterminate - folder next to source
Place output files in a folder next to source files
Checked - Custom
Place output files in custom directory specified by right button
", None))
-#endif // QT_CONFIG(tooltip)
- self.defaultOutputFolderBox.setText(QCoreApplication.translate("mainWindow", u"Output Folder", None))
+ self.directoryButton.setText(QCoreApplication.translate("mainWindow", u"Add input folder(s)", None))
#if QT_CONFIG(tooltip)
self.formatBox.setToolTip(QCoreApplication.translate("mainWindow", u"Output format.
", None))
#endif // QT_CONFIG(tooltip)