From 0e42d2efc2d64efc1240f568ea5e453ec9fca0bb Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 13:06:09 +0100 Subject: [PATCH 1/9] Remove cli from mediacopier-qt --- mediacopier-cli/source/main.cpp | 6 +-- mediacopier-qt/lang/lang_de.ts | 15 ++---- mediacopier-qt/source/config.cpp | 13 ++--- mediacopier-qt/source/config.hpp | 8 +-- .../source/gui/MediaCopierParamWidget.cpp | 5 +- mediacopier-qt/source/main.cpp | 23 +++----- mediacopier-qt/source/worker.cpp | 54 +++++++++---------- 7 files changed, 46 insertions(+), 78 deletions(-) diff --git a/mediacopier-cli/source/main.cpp b/mediacopier-cli/source/main.cpp index 20e4a1d..c1fc15d 100644 --- a/mediacopier-cli/source/main.cpp +++ b/mediacopier-cli/source/main.cpp @@ -60,7 +60,7 @@ auto exec(const Config& config) -> void }); spdlog::info("Checking input directory.."); - auto reg = mc::FileRegister{config.outputDir, config.pattern}; + auto fileRegister = mc::FileRegister{config.outputDir, config.pattern}; std::optional dest; for (auto file : valid_media_files(config.inputDir)) { @@ -69,7 +69,7 @@ auto exec(const Config& config) -> void break; } try { - if ((dest = reg.add(file)).has_value()) { + if ((dest = fileRegister.add(file)).has_value()) { spdlog::info("Processing: {} -> {}", file->path().string(), dest.value().string()); @@ -82,7 +82,7 @@ auto exec(const Config& config) -> void } spdlog::info("Removing duplicates in destination directory.."); - reg.removeDuplicates(); + fileRegister.removeDuplicates(); spdlog::info("Done"); std::signal(SIGINT, SIG_DFL); diff --git a/mediacopier-qt/lang/lang_de.ts b/mediacopier-qt/lang/lang_de.ts index 0edaecf..6335f23 100644 --- a/mediacopier-qt/lang/lang_de.ts +++ b/mediacopier-qt/lang/lang_de.ts @@ -4,22 +4,15 @@ Command - - + Copy Kopieren - - + Move Verschieben - - - Simulate - Simulation - KMediaCopierJob @@ -74,12 +67,12 @@ QObject - + Source folder Quellverzeichnis - + Destination folder Zielverzeichnis diff --git a/mediacopier-qt/source/config.cpp b/mediacopier-qt/source/config.cpp index 50eb806..d1f33bb 100644 --- a/mediacopier-qt/source/config.cpp +++ b/mediacopier-qt/source/config.cpp @@ -26,17 +26,13 @@ namespace fs = std::filesystem; static constexpr const char* CONFIG_FILE = ".mediacopier"; static const std::map commands = { - {"copy", Config::Command::COPY_JPEG}, - {"move", Config::Command::MOVE_JPEG}, - {"sim", Config::Command::SIMULATE} + {"copy", Config::Command::COPY}, + {"move", Config::Command::MOVE} }; static const std::map commandStrings = { {Config::Command::COPY, QT_TRANSLATE_NOOP("Command", "Copy")}, - {Config::Command::COPY_JPEG, QT_TRANSLATE_NOOP("Command", "Copy")}, - {Config::Command::MOVE, QT_TRANSLATE_NOOP("Command", "Move")}, - {Config::Command::MOVE_JPEG, QT_TRANSLATE_NOOP("Command", "Move")}, - {Config::Command::SIMULATE, QT_TRANSLATE_NOOP("Command", "Simulate")} + {Config::Command::MOVE, QT_TRANSLATE_NOOP("Command", "Move")} }; Config::Config(const QApplication& app) @@ -88,9 +84,6 @@ Config::Config(const QApplication& app) if (parser.isSet("slim-gui")) m_ui = UI::SlimGui; - - if (parser.isSet("no-gui")) - m_ui = UI::NoGui; } bool Config::readConfigFile() noexcept diff --git a/mediacopier-qt/source/config.hpp b/mediacopier-qt/source/config.hpp index 66604a8..e221353 100644 --- a/mediacopier-qt/source/config.hpp +++ b/mediacopier-qt/source/config.hpp @@ -24,16 +24,12 @@ class Config { public: enum class Command { COPY, - MOVE, - COPY_JPEG, - MOVE_JPEG, - SIMULATE + MOVE }; enum class UI { FullGui, SlimGui, - NoGui }; Config(const QApplication& app); @@ -56,7 +52,7 @@ class Config { const std::filesystem::path& outputDir() const { return m_outputDir; } private: - Command m_command = Command::COPY_JPEG; + Command m_command = Command::COPY; UI m_ui = UI::FullGui; std::string m_pattern = "%Y/%W/IMG_%Y%m%d_%H%M%S"; std::filesystem::path m_inputDir; diff --git a/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp b/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp index ca78826..00f756f 100644 --- a/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp +++ b/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp @@ -33,9 +33,8 @@ const auto ask_for_directory = [](const QString& title) -> QString }; static const QList commands = { - Config::Command::COPY_JPEG, - Config::Command::MOVE_JPEG, - Config::Command::SIMULATE + Config::Command::COPY, + Config::Command::MOVE }; MediaCopierParamWidget::MediaCopierParamWidget(QWidget *parent) : diff --git a/mediacopier-qt/source/main.cpp b/mediacopier-qt/source/main.cpp index e295873..f9755d1 100644 --- a/mediacopier-qt/source/main.cpp +++ b/mediacopier-qt/source/main.cpp @@ -16,7 +16,6 @@ #include "gui/MediaCopierDialogFull.hpp" #include "gui/MediaCopierDialogSlim.hpp" -#include "worker.hpp" #include @@ -34,21 +33,6 @@ int run_gui(QApplication& app, std::shared_ptr config) return app.exec(); } -int run_cli(QApplication& app, std::shared_ptr config) -{ - Worker worker{*config}; - worker.start(); - return app.exec(); -} - -using UiFuncType = std::function)>; - -static const std::map uiFuncMap = { - {Config::UI::FullGui, &run_gui}, - {Config::UI::SlimGui, &run_gui}, - {Config::UI::NoGui, &run_cli}, -}; - int main(int argc, char *argv[]) { try { @@ -62,8 +46,13 @@ int main(int argc, char *argv[]) app.setApplicationVersion(mediacopier::MEDIACOPIER_VERSION); auto config = std::make_shared(app); - return uiFuncMap.at(config->ui())(app, config); + switch (config->ui()) { + case Config::UI::FullGui: + return run_gui(app, config); + case Config::UI::SlimGui: + return run_gui(app, config); + } } catch (const std::exception& err) { spdlog::error(err.what()); return 1; diff --git a/mediacopier-qt/source/worker.cpp b/mediacopier-qt/source/worker.cpp index 7b6e074..8ebef76 100644 --- a/mediacopier-qt/source/worker.cpp +++ b/mediacopier-qt/source/worker.cpp @@ -23,9 +23,7 @@ #include #include -#include #include -#include #include #include @@ -52,7 +50,7 @@ static volatile std::atomic operationSuspended(false); static constexpr const unsigned int DEFAULT_WAIT_MS = 200; -auto check_operation_state() +auto is_operation_cancelled() { while (true) { if (operationCancelled.load()) { @@ -100,14 +98,6 @@ auto execute(const fs::path& dest, mc::FileInfoPtr file) -> void typedef void (*ExecFuncPtr)(const fs::path&, mc::FileInfoPtr); -static const std::map execFuncMap = { - {Config::Command::COPY, &execute}, - {Config::Command::COPY_JPEG, &execute}, - {Config::Command::MOVE, &execute}, - {Config::Command::MOVE_JPEG, &execute}, - {Config::Command::SIMULATE, &execute} -}; - } // namespace Worker::Worker(Config config) : m_config{std::move(config)} @@ -174,37 +164,45 @@ void Worker::exec() m_fileCount = valid_media_file_count(m_config.inputDir()); m_progress = 0; - auto reg = mc::FileRegister{m_config.outputDir(), m_config.pattern()}; - auto execute = execFuncMap.at(m_config.command()); - std::optional dest; + auto fileRegister = mc::FileRegister{m_config.outputDir(), m_config.pattern()}; - try { - for (auto file : valid_media_files(m_config.inputDir())) { - if (check_operation_state()) { - spdlog::info("Operation was cancelled.."); - break; - } - ++m_progress; - if ((dest = reg.add(file)).has_value()) { + ExecFuncPtr execute; + switch (m_config.command()) { + case Config::Command::COPY: + execute = &::execute; + break; + case Config::Command::MOVE: + execute = &::execute; + break; + } + + std::optional dest; + for (auto file : valid_media_files(m_config.inputDir())) { + if (is_operation_cancelled()) { + spdlog::info("Operation was cancelled.."); + break; + } + ++m_progress; + try { + if ((dest = fileRegister.add(file)).has_value()) { Q_EMIT status({m_config.command(), file->path(), dest.value(), m_fileCount, m_progress}); execute(dest.value(), file); } else { Q_EMIT status({m_config.command(), file->path(), "", m_fileCount, m_progress}); } + } catch (const std::exception& err) { + spdlog::error(err.what()); } - } catch (const std::exception& err) { - spdlog::error(err.what()); } - spdlog::info("Removing duplicates.."); - reg.removeDuplicates(); + spdlog::info("Removing duplicates in destination directory.."); + fileRegister.removeDuplicates(); spdlog::info("Writing config.."); m_config.writeConfigFile(); - std::signal(SIGINT, SIG_DFL); - spdlog::info("Done"); + std::signal(SIGINT, SIG_DFL); Q_EMIT execDone(); } From d00367807e9369bf5c8fa729ffc33eccbe8069af Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 18:14:33 +0100 Subject: [PATCH 2/9] Improve handling of pattern configuration --- mediacopier-qt/lang/README.md | 5 + mediacopier-qt/lang/lang_de.ts | 25 ++-- mediacopier-qt/source/config.cpp | 55 ++++---- mediacopier-qt/source/config.hpp | 13 +- .../source/gui/MediaCopierParamWidget.cpp | 64 +++++---- .../source/gui/MediaCopierParamWidget.hpp | 6 +- .../source/gui/MediaCopierParamWidget.ui | 123 +++++++++++------- .../source/kde/mediacopier.desktop.in | 4 +- mediacopier-qt/source/main.cpp | 6 +- 9 files changed, 174 insertions(+), 127 deletions(-) create mode 100644 mediacopier-qt/lang/README.md diff --git a/mediacopier-qt/lang/README.md b/mediacopier-qt/lang/README.md new file mode 100644 index 0000000..609d6b3 --- /dev/null +++ b/mediacopier-qt/lang/README.md @@ -0,0 +1,5 @@ +You can update the translations via + +```sh +linguist-qt5 mediacopier-qt/lang/lang_de.ts +``` diff --git a/mediacopier-qt/lang/lang_de.ts b/mediacopier-qt/lang/lang_de.ts index 6335f23..33ee585 100644 --- a/mediacopier-qt/lang/lang_de.ts +++ b/mediacopier-qt/lang/lang_de.ts @@ -4,12 +4,12 @@ Command - + Copy Kopieren - + Move Verschieben @@ -38,28 +38,33 @@ MediaCopierParamWidget - + Operation - + Input Quellverzeichnis - + Pattern Schema - + Output Zielverzeichnis - - + + Update + + + + + ... @@ -67,12 +72,12 @@ QObject - + Source folder Quellverzeichnis - + Destination folder Zielverzeichnis diff --git a/mediacopier-qt/source/config.cpp b/mediacopier-qt/source/config.cpp index d1f33bb..ece0d4e 100644 --- a/mediacopier-qt/source/config.cpp +++ b/mediacopier-qt/source/config.cpp @@ -24,6 +24,7 @@ namespace fs = std::filesystem; static constexpr const char* CONFIG_FILE = ".mediacopier"; +static constexpr const char* DEFAULT_PATTERN = "%Y/%W/IMG_%Y%m%d_%H%M%S"; static const std::map commands = { {"copy", Config::Command::COPY}, @@ -41,49 +42,38 @@ Config::Config(const QApplication& app) parser.setApplicationDescription( app.applicationName() + - ", Copyright (C) 2020-2023 Patrick Ziegler"); - + ", Copyright (C) 2020-2024 Patrick Ziegler"); + parser.addPositionalArgument( + "CMD", "Available commands: copy (default), move", "[CMD"); parser.addPositionalArgument( "SRC", "Input directory", "[SRC"); - parser.addPositionalArgument( - "DST", "Output directory", "[DST]]"); - - QCommandLineOption optCommand( - "c", "Available commands: copy (default), move, sim", - "command"); - - QCommandLineOption optPattern( - "f", "Pattern to be used for creating new filenames", - "pattern"); - + "DST", "Output directory", "[DST]]]"); QCommandLineOption optSlimGui( "slim-gui", "Pattern to be used for creating new filenames"); - QCommandLineOption optNoGui( "no-gui", "Pattern to be used for creating new filenames"); - parser.addOptions({optCommand, optPattern, optSlimGui, optNoGui}); + parser.addOptions({optSlimGui, optNoGui}); parser.addVersionOption(); parser.addHelpOption(); parser.process(app); - if (parser.positionalArguments().length() > 0) - setInputDir(parser.positionalArguments().at(0)); - - if (parser.positionalArguments().length() > 1) - setOutputDir(parser.positionalArguments().at(1)); - - readConfigFile(); - - if (parser.isSet("f")) - setPattern(parser.value("f")); - - if (parser.isSet("c")) - setCommand(parser.value("c")); + if (parser.positionalArguments().length() > 0) { + setCommand(parser.positionalArguments().at(0)); + } + if (parser.positionalArguments().length() > 1) { + setInputDir(parser.positionalArguments().at(1)); + } + if (parser.positionalArguments().length() > 2) { + setOutputDir(parser.positionalArguments().at(2)); + readConfigFile(); + } + if (parser.isSet("slim-gui")) { + m_guiType = GuiType::Slim; + } - if (parser.isSet("slim-gui")) - m_ui = UI::SlimGui; + m_pattern = DEFAULT_PATTERN; } bool Config::readConfigFile() noexcept @@ -134,6 +124,11 @@ void Config::setPattern(const QString& pattern) m_pattern = pattern.toStdString(); } +void Config::resetPattern() +{ + m_pattern = DEFAULT_PATTERN; +} + void Config::setInputDir(const QString& inputDir) { m_inputDir = inputDir.toStdString(); diff --git a/mediacopier-qt/source/config.hpp b/mediacopier-qt/source/config.hpp index e221353..5d2998d 100644 --- a/mediacopier-qt/source/config.hpp +++ b/mediacopier-qt/source/config.hpp @@ -27,9 +27,9 @@ class Config { MOVE }; - enum class UI { - FullGui, - SlimGui, + enum class GuiType { + Full, + Slim, }; Config(const QApplication& app); @@ -40,21 +40,22 @@ class Config { void setCommand(const Command& command); void setCommand(const QString& command); void setPattern(const QString& pattern); + void resetPattern(); void setInputDir(const QString& inputDir); void setOutputDir(const QString& outputDir); static const QString commandString(const Command& command); const Command& command() const { return m_command; } - const UI& ui() const { return m_ui; } + const GuiType& guiType() const { return m_guiType; } const std::string& pattern() const { return m_pattern; } const std::filesystem::path& inputDir() const { return m_inputDir; } const std::filesystem::path& outputDir() const { return m_outputDir; } private: Command m_command = Command::COPY; - UI m_ui = UI::FullGui; - std::string m_pattern = "%Y/%W/IMG_%Y%m%d_%H%M%S"; + GuiType m_guiType = GuiType::Full; + std::string m_pattern; std::filesystem::path m_inputDir; std::filesystem::path m_outputDir; }; diff --git a/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp b/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp index 00f756f..218c08b 100644 --- a/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp +++ b/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp @@ -19,6 +19,7 @@ #include #include +#include #include @@ -46,6 +47,7 @@ MediaCopierParamWidget::MediaCopierParamWidget(QWidget *parent) : Q_FOREACH(Config::Command item, commands) { ui->paramCommand->addItem(Config::commandString(item)); } + ui->paramPattern->setEnabled(false); } MediaCopierParamWidget::~MediaCopierParamWidget() @@ -55,9 +57,17 @@ MediaCopierParamWidget::~MediaCopierParamWidget() void MediaCopierParamWidget::init(std::shared_ptr config) { - this->config = std::move(config); + m_config = std::move(config); - syncConfig(); + ui->dirsInputDirText->setText(QString::fromStdString(m_config->inputDir().string())); + ui->dirsOutputDirText->setText(QString::fromStdString(m_config->outputDir().string())); + ui->paramPattern->setText(m_config->pattern().c_str()); + for (int i = 0; i < commands.length(); ++i) { + if (commands.at(i) == m_config->command()) { + ui->paramCommand->setCurrentIndex(i); + break; + } + } connect(ui->dirsInputDirButton, &QToolButton::clicked, this, &MediaCopierParamWidget::onOpenInputDirClicked); @@ -65,6 +75,9 @@ void MediaCopierParamWidget::init(std::shared_ptr config) connect(ui->dirsOutputDirButton, &QToolButton::clicked, this, &MediaCopierParamWidget::onOpenOutputDirClicked); + connect(ui->paramPatternUpdate, &QCheckBox::clicked, + this, &MediaCopierParamWidget::onPatternUpdateClicked); + connect(ui->dirsInputDirText, &QLineEdit::textChanged, this, &MediaCopierParamWidget::onInputDirChanged); @@ -78,20 +91,6 @@ void MediaCopierParamWidget::init(std::shared_ptr config) this, &MediaCopierParamWidget::onCommandChanged); } -void MediaCopierParamWidget::syncConfig() -{ - ui->dirsInputDirText->setText(QString::fromStdString(config->inputDir().string())); - ui->dirsOutputDirText->setText(QString::fromStdString(config->outputDir().string())); - ui->paramPattern->setText(config->pattern().c_str()); - - for (int i = 0; i < commands.length(); ++i) { - if (commands.at(i) == config->command()) { - ui->paramCommand->setCurrentIndex(i); - break; - } - } -} - void MediaCopierParamWidget::onOpenInputDirClicked() { ui->dirsInputDirText->setText(ask_for_directory(QObject::tr("Source folder"))); @@ -102,28 +101,43 @@ void MediaCopierParamWidget::onOpenOutputDirClicked() ui->dirsOutputDirText->setText(ask_for_directory(QObject::tr("Destination folder"))); } +void MediaCopierParamWidget::onPatternUpdateClicked(bool checked) +{ + ui->paramPattern->setEnabled(checked); + if (!checked) { + m_config->resetPattern(); + m_config->readConfigFile(); + ui->paramPattern->setText(m_config->pattern().c_str()); + } +} + void MediaCopierParamWidget::onInputDirChanged(const QString& text) { - config->setInputDir(text); - spdlog::debug("Changed input dir to " + config->outputDir().string()); + m_config->setInputDir(text); + spdlog::debug("Changed input dir to " + m_config->outputDir().string()); } void MediaCopierParamWidget::onOutputDirChanged(const QString& text) { - config->setOutputDir(text); - spdlog::debug("Changed output dir to " + config->outputDir().string()); - config->readConfigFile(); - syncConfig(); + m_config->setOutputDir(text); + spdlog::debug("Changed output dir to " + m_config->outputDir().string()); + if (!ui->paramPattern->isEnabled()) { + m_config->resetPattern(); + if (QDir(text).exists()) { + m_config->readConfigFile(); + } + } + ui->paramPattern->setText(m_config->pattern().c_str()); } void MediaCopierParamWidget::onPatternChanged(const QString& text) { - config->setPattern(text); - spdlog::debug("Changed pattern to " + config->pattern()); + m_config->setPattern(text); + spdlog::debug("Changed pattern to " + m_config->pattern()); } void MediaCopierParamWidget::onCommandChanged(int index) { - config->setCommand(commands.at(index)); + m_config->setCommand(commands.at(index)); spdlog::debug("Changed command to " + Config::commandString(commands.at(index)).toStdString()); } diff --git a/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp b/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp index 0ef63fe..d005d96 100644 --- a/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp +++ b/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp @@ -33,12 +33,10 @@ class MediaCopierParamWidget : public QWidget ~MediaCopierParamWidget(); void init(std::shared_ptr config); -private: - void syncConfig(); - private Q_SLOTS: void onOpenInputDirClicked(); void onOpenOutputDirClicked(); + void onPatternUpdateClicked(bool checked); void onInputDirChanged(const QString& text); void onOutputDirChanged(const QString& text); void onPatternChanged(const QString& text); @@ -46,5 +44,5 @@ private Q_SLOTS: private: Ui::MediaCopierParamWidget *ui; - std::shared_ptr config; + std::shared_ptr m_config; }; diff --git a/mediacopier-qt/source/gui/MediaCopierParamWidget.ui b/mediacopier-qt/source/gui/MediaCopierParamWidget.ui index 96ac463..52f77f8 100644 --- a/mediacopier-qt/source/gui/MediaCopierParamWidget.ui +++ b/mediacopier-qt/source/gui/MediaCopierParamWidget.ui @@ -7,8 +7,8 @@ 0 0 - 160 - 150 + 187 + 122 @@ -24,33 +24,39 @@ 0 - - + + - Operation + Input Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + + + + + - Input - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + ... - - + + - Pattern + ... - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + QToolButton::DelayedPopup + + + Qt::NoArrow @@ -64,52 +70,75 @@ - - - - - + + - ... + Pattern + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + - - + + - ... - - - QToolButton::DelayedPopup + Operation - - Qt::NoArrow + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - + + + + QFrame::NoFrame + + + QFrame::Plain + + 0 + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + Update + + + + - - - - - dirsInputDirText - dirsInputDirButton - dirsOutputDirText - dirsOutputDirButton - paramPattern - paramCommand - diff --git a/mediacopier-qt/source/kde/mediacopier.desktop.in b/mediacopier-qt/source/kde/mediacopier.desktop.in index 89bda29..887c74d 100644 --- a/mediacopier-qt/source/kde/mediacopier.desktop.in +++ b/mediacopier-qt/source/kde/mediacopier.desktop.in @@ -12,10 +12,10 @@ X-KDE-Priority=TopLevel Name=Copy media files to ... Name[de]=Medien kopieren nach ... Icon=folder-copy -Exec=@CMAKE_INSTALL_PREFIX@/bin/@EXECUTABLE_NAME@ --slim-gui -c copy "%U" +Exec=@CMAKE_INSTALL_PREFIX@/bin/@EXECUTABLE_NAME@ --slim-gui copy "%U" [Desktop Action mediacopier-move] Name=Move media files to ... Name[de]=Medien verschieben nach ... Icon=folder-move -Exec=@CMAKE_INSTALL_PREFIX@/bin/@EXECUTABLE_NAME@ --slim-gui -c move "%U" +Exec=@CMAKE_INSTALL_PREFIX@/bin/@EXECUTABLE_NAME@ --slim-gui move "%U" diff --git a/mediacopier-qt/source/main.cpp b/mediacopier-qt/source/main.cpp index f9755d1..f3ec7ea 100644 --- a/mediacopier-qt/source/main.cpp +++ b/mediacopier-qt/source/main.cpp @@ -47,10 +47,10 @@ int main(int argc, char *argv[]) auto config = std::make_shared(app); - switch (config->ui()) { - case Config::UI::FullGui: + switch (config->guiType()) { + case Config::GuiType::Full: return run_gui(app, config); - case Config::UI::SlimGui: + case Config::GuiType::Slim: return run_gui(app, config); } } catch (const std::exception& err) { From e3acbe643ea159a5d3ed1e3b88ec54b100084106 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 18:32:53 +0100 Subject: [PATCH 3/9] Clear logs and progress on re-run --- mediacopier-qt/source/gui/MediaCopierDialogFull.cpp | 1 + mediacopier-qt/source/gui/MediaCopierLogWidget.cpp | 6 ++++++ mediacopier-qt/source/gui/MediaCopierLogWidget.hpp | 1 + 3 files changed, 8 insertions(+) diff --git a/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp b/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp index 2359b34..9ff6e24 100644 --- a/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp +++ b/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp @@ -96,6 +96,7 @@ void MediaCopierDialogFull::aboutToQuit() void MediaCopierDialogFull::startOperation() { + this->ui->log->clear(); worker = std::make_shared(*config); QObject::connect(worker.get(), &Worker::status, this->ui->log, &MediaCopierLogWidget::update); QObject::connect(worker.get(), &Worker::finished, this, &MediaCopierDialogFull::operationDone); diff --git a/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp b/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp index 75e67ea..814994f 100644 --- a/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp +++ b/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp @@ -39,6 +39,12 @@ MediaCopierLogWidget::~MediaCopierLogWidget() delete ui; } +void MediaCopierLogWidget::clear() +{ + ui->logProgressBar->setValue(0); + ui->logText->clear(); +} + void MediaCopierLogWidget::update(Status info) { ui->logProgressBar->setMaximum(info.fileCount()); diff --git a/mediacopier-qt/source/gui/MediaCopierLogWidget.hpp b/mediacopier-qt/source/gui/MediaCopierLogWidget.hpp index 8c39645..63229a1 100644 --- a/mediacopier-qt/source/gui/MediaCopierLogWidget.hpp +++ b/mediacopier-qt/source/gui/MediaCopierLogWidget.hpp @@ -33,6 +33,7 @@ class MediaCopierLogWidget : public QWidget public: explicit MediaCopierLogWidget(QWidget *parent=nullptr); ~MediaCopierLogWidget(); + void clear(); public Q_SLOTS: void update(Status info); From fef6d94fe21686aaabb885011b867f813c833782 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 18:58:20 +0100 Subject: [PATCH 4/9] Show version info in log section --- CMakeLists.txt | 2 +- mediacopier-qt/source/gui/MediaCopierLogWidget.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 587c016..829acac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12) list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -project(mediacopier VERSION 2.1.0) +project(MediaCopier VERSION 2.1.0) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp b/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp index 814994f..1a54967 100644 --- a/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp +++ b/mediacopier-qt/source/gui/MediaCopierLogWidget.cpp @@ -29,7 +29,10 @@ MediaCopierLogWidget::MediaCopierLogWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MediaCopierLogWidget) { ui->setupUi(this); - + ui->logText->setPlainText( + QString("%1 v%2") + .arg(mediacopier::MEDIACOPIER_PROJECT_NAME) + .arg(mediacopier::MEDIACOPIER_VERSION)); auto sink = std::make_shared(ui->logText, "appendPlainText"); spdlog::default_logger()->sinks().push_back(std::move(sink)); } From 21a25567afcfd94d114e76f16e7643cd6a9ad128 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 22:25:54 +0100 Subject: [PATCH 5/9] Add some waiting time in simulation mode --- mediacopier-lib/source/operation_simulate.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mediacopier-lib/source/operation_simulate.cpp b/mediacopier-lib/source/operation_simulate.cpp index 535bef2..b015922 100644 --- a/mediacopier-lib/source/operation_simulate.cpp +++ b/mediacopier-lib/source/operation_simulate.cpp @@ -20,25 +20,31 @@ #include #include +#include +#include + namespace mediacopier { auto FileOperationSimulate::dumpFilePaths(const AbstractFileInfo& file) const -> void { - spdlog::info(m_destination.string() + " (from " + file.path().string() + ")"); + spdlog::info("{} -> {}", file.path().string(), m_destination.string()); } auto FileOperationSimulate::visit(const FileInfoImage& file) -> void { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); dumpFilePaths(file); } auto FileOperationSimulate::visit(const FileInfoImageJpeg& file) -> void { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); dumpFilePaths(file); } auto FileOperationSimulate::visit(const FileInfoVideo& file) -> void { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); dumpFilePaths(file); } From a9a74d0a0bf4da1d4e4736cbfb0006d0428ab082 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 22:26:42 +0100 Subject: [PATCH 6/9] Remove unused include --- mediacopier-qt/source/worker.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mediacopier-qt/source/worker.cpp b/mediacopier-qt/source/worker.cpp index 8ebef76..4768f4f 100644 --- a/mediacopier-qt/source/worker.cpp +++ b/mediacopier-qt/source/worker.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include From 93a59ed2077cb1fbca8e5e4a1d5a03ca8698e2e6 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 22:27:42 +0100 Subject: [PATCH 7/9] Add parameter validation checks --- CMakeLists.txt | 2 +- mediacopier-cli/source/config.cpp | 33 +++++++++++++++-- mediacopier-cli/source/config.hpp | 1 + mediacopier-cli/source/main.cpp | 5 +++ mediacopier-qt/lang/lang_de.ts | 4 +-- .../source/gui/MediaCopierDialogFull.cpp | 28 +++++++++------ .../source/gui/MediaCopierDialogSlim.cpp | 19 ++++++---- .../source/gui/MediaCopierParamWidget.cpp | 36 +++++++++++++++++++ .../source/gui/MediaCopierParamWidget.hpp | 5 +++ 9 files changed, 110 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 829acac..78e1f2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12) list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -project(MediaCopier VERSION 2.1.0) +project(MediaCopier VERSION 2.1.1) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/mediacopier-cli/source/config.cpp b/mediacopier-cli/source/config.cpp index 28ee0b1..b4e3104 100644 --- a/mediacopier-cli/source/config.cpp +++ b/mediacopier-cli/source/config.cpp @@ -16,13 +16,12 @@ #include "config.hpp" -#include +#include +#include #include #include -#include - #include #include @@ -96,3 +95,31 @@ void Config::finalize() noexcept pattern = DEFAULT_PATTERN; } } + +bool Config::validate() const noexcept +{ + bool result = false; + if (pattern.empty()) { + spdlog::error("No pattern specified!"); + result = true; + } + try { + if (fs::absolute(outputDir).empty() || !fs::is_directory(inputDir)) { + spdlog::error("Input directory does not exist!"); + result = true; + } + } catch(const fs::filesystem_error& err) { + spdlog::error("Failed to validate input directory path: " + std::string{err.what()}); + result = true; + } + try { + if (fs::absolute(outputDir).empty()) { + spdlog::error("No output directory specified"); + result = true; + } + } catch(const fs::filesystem_error& err) { + spdlog::error("Failed to validate output directory path: " + std::string{err.what()}); + result = true; + } + return result; +} diff --git a/mediacopier-cli/source/config.hpp b/mediacopier-cli/source/config.hpp index 8e16a26..e5d5ec6 100644 --- a/mediacopier-cli/source/config.hpp +++ b/mediacopier-cli/source/config.hpp @@ -32,6 +32,7 @@ struct Config void loadPersistentConfig(); void storePersistentConfig() const; void finalize() noexcept; + bool validate() const noexcept; Command cmd = Command::Copy; std::filesystem::path inputDir; diff --git a/mediacopier-cli/source/main.cpp b/mediacopier-cli/source/main.cpp index c1fc15d..86bdfd5 100644 --- a/mediacopier-cli/source/main.cpp +++ b/mediacopier-cli/source/main.cpp @@ -98,6 +98,11 @@ int main(int argc, char *argv[]) config.loadPersistentConfig(); config.finalize(); + if (config.validate()) { + spdlog::error("Invalid configuration"); + return 1; + } + switch (config.cmd) { case Config::Command::Copy: exec(config); diff --git a/mediacopier-qt/lang/lang_de.ts b/mediacopier-qt/lang/lang_de.ts index 33ee585..f72ad87 100644 --- a/mediacopier-qt/lang/lang_de.ts +++ b/mediacopier-qt/lang/lang_de.ts @@ -72,12 +72,12 @@ QObject - + Source folder Quellverzeichnis - + Destination folder Zielverzeichnis diff --git a/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp b/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp index 9ff6e24..9f91c0c 100644 --- a/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp +++ b/mediacopier-qt/source/gui/MediaCopierDialogFull.cpp @@ -56,16 +56,19 @@ void MediaCopierDialogFull::init(std::shared_ptr config, QApplication& a fsm = std::make_unique(); auto s1 = new QState(); // waiting for input - auto s2 = new QState(); // executing operation - auto s3 = new QState(); // aborting operation - auto s4 = new QFinalState(); // closing dialog + auto s2 = new QState(); // checking parameters + auto s3 = new QState(); // executing operation + auto s4 = new QState(); // aborting operation + auto s5 = new QFinalState(); // closing dialog s1->addTransition(ui->dialogButtonBox, &QDialogButtonBox::accepted, s2); - s1->addTransition(ui->dialogButtonBox, &QDialogButtonBox::rejected, s4); - s2->addTransition(ui->dialogButtonBox, &QDialogButtonBox::rejected, s3); - s2->addTransition(this, &MediaCopierDialogFull::rejected, s3); - s2->addTransition(this, &MediaCopierDialogFull::operationDone, s1); + s1->addTransition(ui->dialogButtonBox, &QDialogButtonBox::rejected, s5); + s2->addTransition(ui->param, &MediaCopierParamWidget::validParameters, s3); + s2->addTransition(ui->param, &MediaCopierParamWidget::invalidParameters, s1); + s3->addTransition(ui->dialogButtonBox, &QDialogButtonBox::rejected, s4); + s3->addTransition(this, &MediaCopierDialogFull::rejected, s4); s3->addTransition(this, &MediaCopierDialogFull::operationDone, s1); + s4->addTransition(this, &MediaCopierDialogFull::operationDone, s1); auto m_btnOk = ui->dialogButtonBox->button(QDialogButtonBox::Ok); auto m_btnCancel = ui->dialogButtonBox->button(QDialogButtonBox::Cancel); @@ -73,17 +76,22 @@ void MediaCopierDialogFull::init(std::shared_ptr config, QApplication& a s1->assignProperty(m_btnOk, "enabled", true); s1->assignProperty(m_btnCancel, "enabled", true); s2->assignProperty(m_btnOk, "enabled", false); - s3->assignProperty(m_btnCancel, "enabled", false); + s2->assignProperty(m_btnCancel, "enabled", false); + s3->assignProperty(m_btnOk, "enabled", false); + s3->assignProperty(m_btnCancel, "enabled", true); + s4->assignProperty(m_btnCancel, "enabled", false); QObject::connect(s1, &QState::entered, this, &MediaCopierDialogFull::awaitOperation); - QObject::connect(s2, &QState::entered, this, &MediaCopierDialogFull::startOperation); - QObject::connect(s3, &QState::entered, this, &MediaCopierDialogFull::cancelOperation); + QObject::connect(s2, &QState::entered, ui->param, &MediaCopierParamWidget::validate); + QObject::connect(s3, &QState::entered, this, &MediaCopierDialogFull::startOperation); + QObject::connect(s4, &QState::entered, this, &MediaCopierDialogFull::cancelOperation); QObject::connect(fsm.get(), &QStateMachine::finished, this, &MediaCopierDialogFull::close); fsm->addState(s1); fsm->addState(s2); fsm->addState(s3); fsm->addState(s4); + fsm->addState(s5); fsm->setInitialState(s1); fsm->start(); } diff --git a/mediacopier-qt/source/gui/MediaCopierDialogSlim.cpp b/mediacopier-qt/source/gui/MediaCopierDialogSlim.cpp index 482eb7d..c24fe47 100644 --- a/mediacopier-qt/source/gui/MediaCopierDialogSlim.cpp +++ b/mediacopier-qt/source/gui/MediaCopierDialogSlim.cpp @@ -55,20 +55,25 @@ void MediaCopierDialogSlim::init(std::shared_ptr config, QApplication& a fsm = std::make_unique(); auto s1 = new QState(); // waiting for input - auto s2 = new QState(); // executing operation - auto s3 = new QFinalState(); // closing dialog + auto s2 = new QState(); // checking parameters + auto s3 = new QState(); // executing operation + auto s4 = new QFinalState(); // closing dialog s1->addTransition(ui->dialogButtonBox, &QDialogButtonBox::accepted, s2); - s1->addTransition(ui->dialogButtonBox, &QDialogButtonBox::rejected, s3); - s2->addTransition(this, &MediaCopierDialogSlim::operationDone, s3); - - QObject::connect(s2, &QState::entered, this, &MediaCopierDialogSlim::hide); - QObject::connect(s2, &QState::entered, this, &MediaCopierDialogSlim::startOperation); + s1->addTransition(ui->dialogButtonBox, &QDialogButtonBox::rejected, s4); + s2->addTransition(ui->param, &MediaCopierParamWidget::validParameters, s3); + s2->addTransition(ui->param, &MediaCopierParamWidget::invalidParameters, s1); + s3->addTransition(this, &MediaCopierDialogSlim::operationDone, s4); + + QObject::connect(s2, &QState::entered, ui->param, &MediaCopierParamWidget::validate); + QObject::connect(s3, &QState::entered, this, &MediaCopierDialogSlim::hide); + QObject::connect(s3, &QState::entered, this, &MediaCopierDialogSlim::startOperation); QObject::connect(fsm.get(), &QStateMachine::finished, this, &MediaCopierDialogSlim::close); fsm->addState(s1); fsm->addState(s2); fsm->addState(s3); + fsm->addState(s4); fsm->setInitialState(s1); fsm->start(); } diff --git a/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp b/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp index 218c08b..467f764 100644 --- a/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp +++ b/mediacopier-qt/source/gui/MediaCopierParamWidget.cpp @@ -91,6 +91,42 @@ void MediaCopierParamWidget::init(std::shared_ptr config) this, &MediaCopierParamWidget::onCommandChanged); } +void MediaCopierParamWidget::validate() +{ + bool result = true; + + QPalette errorPalette; + errorPalette.setColor(QPalette::Base, QColor(255, 145, 145)); + errorPalette.setColor(QPalette::Text, Qt::white); + + if (ui->dirsInputDirText->text().isEmpty() || !QDir(ui->dirsInputDirText->text()).exists()) { + ui->dirsInputDirText->setPalette(errorPalette); + result = false; + } else { + ui->dirsInputDirText->setPalette(this->style()->standardPalette()); + } + + if (ui->dirsOutputDirText->text().isEmpty() || !QDir(ui->dirsOutputDirText->text()).makeAbsolute()) { + ui->dirsOutputDirText->setPalette(errorPalette); + result = false; + } else { + ui->dirsOutputDirText->setPalette(this->style()->standardPalette()); + } + + if (ui->paramPattern->text().isEmpty()) { + ui->paramPattern->setPalette(errorPalette); + result = false; + } else { + ui->paramPattern->setPalette(this->style()->standardPalette()); + } + + if (result) { + validParameters(); + } else { + invalidParameters(); + } +} + void MediaCopierParamWidget::onOpenInputDirClicked() { ui->dirsInputDirText->setText(ask_for_directory(QObject::tr("Source folder"))); diff --git a/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp b/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp index d005d96..77e93a9 100644 --- a/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp +++ b/mediacopier-qt/source/gui/MediaCopierParamWidget.hpp @@ -32,6 +32,11 @@ class MediaCopierParamWidget : public QWidget explicit MediaCopierParamWidget(QWidget *parent=nullptr); ~MediaCopierParamWidget(); void init(std::shared_ptr config); + void validate(); + +Q_SIGNALS: + void validParameters(); + void invalidParameters(); private Q_SLOTS: void onOpenInputDirClicked(); From 1d3083b902f7163a9c60e2b4ae83ef0df9d18c24 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 23:40:08 +0100 Subject: [PATCH 8/9] Update missing translation --- mediacopier-qt/lang/lang_de.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mediacopier-qt/lang/lang_de.ts b/mediacopier-qt/lang/lang_de.ts index f72ad87..46bb3ff 100644 --- a/mediacopier-qt/lang/lang_de.ts +++ b/mediacopier-qt/lang/lang_de.ts @@ -58,9 +58,10 @@ Zielverzeichnis - + Update - + Ändern + Ändern From a00ac1f09991259911feb15dfcecc0e47cfd00c8 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sun, 11 Feb 2024 23:40:41 +0100 Subject: [PATCH 9/9] Fix parameter widget size policy --- .../source/gui/MediaCopierParamWidget.ui | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mediacopier-qt/source/gui/MediaCopierParamWidget.ui b/mediacopier-qt/source/gui/MediaCopierParamWidget.ui index 52f77f8..5d4d124 100644 --- a/mediacopier-qt/source/gui/MediaCopierParamWidget.ui +++ b/mediacopier-qt/source/gui/MediaCopierParamWidget.ui @@ -95,6 +95,12 @@ + + + 0 + 0 + + QFrame::NoFrame @@ -139,6 +145,15 @@ + + dirsInputDirText + dirsInputDirButton + dirsOutputDirText + dirsOutputDirButton + paramPatternUpdate + paramPattern + paramCommand +