From 0ac2ac45f54f49c180bbac94147a0d00cf4987bb Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Fri, 16 Aug 2024 15:17:50 +0400 Subject: [PATCH 1/8] wip: adding `InputMessageNotifier` --- src/plugins/preferences/CMakeLists.txt | 4 + .../common/inputmessagenotifier.cpp | 32 ++++++++ .../preferences/common/inputmessagenotifier.h | 79 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 src/plugins/preferences/common/inputmessagenotifier.cpp create mode 100644 src/plugins/preferences/common/inputmessagenotifier.h diff --git a/src/plugins/preferences/CMakeLists.txt b/src/plugins/preferences/CMakeLists.txt index 61b60c92c..79ceb7651 100644 --- a/src/plugins/preferences/CMakeLists.txt +++ b/src/plugins/preferences/CMakeLists.txt @@ -196,6 +196,8 @@ set(HEADERS common/preferencestreeproxymodel.h common/preferenceswidget.h + + common/inputmessagenotifier.h ) set(SOURCES @@ -378,6 +380,8 @@ set(SOURCES common/preferencestreeproxymodel.cpp common/preferenceswidget.cpp + + common/inputmessagenotifier.cpp ) set(UI_FORMS diff --git a/src/plugins/preferences/common/inputmessagenotifier.cpp b/src/plugins/preferences/common/inputmessagenotifier.cpp new file mode 100644 index 000000000..b185c818f --- /dev/null +++ b/src/plugins/preferences/common/inputmessagenotifier.cpp @@ -0,0 +1,32 @@ +/*********************************************************************************************************************** +** +** Copyright (C) 2021 BaseALT Ltd. +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +***********************************************************************************************************************/ + +#include "inputmessagenotifier.h" + +namespace preferences +{ + +InputMessageNotifier::InputMessageNotifier(QWidget *parent) + : QWidget(parent) +{ + +} + +} diff --git a/src/plugins/preferences/common/inputmessagenotifier.h b/src/plugins/preferences/common/inputmessagenotifier.h new file mode 100644 index 000000000..e3ced0ba7 --- /dev/null +++ b/src/plugins/preferences/common/inputmessagenotifier.h @@ -0,0 +1,79 @@ +/*********************************************************************************************************************** +** +** Copyright (C) 2021 BaseALT Ltd. +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +***********************************************************************************************************************/ + +#ifndef GPUI_INPUTMESSAGENOTIFIER_H +#define GPUI_INPUTMESSAGENOTIFIER_H + +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class InputMessageNotifier; } +QT_END_NAMESPACE + +namespace preferences +{ + +class InputMessageNotifier : public QWidget +{ +public: + Q_OBJECT +private: + typedef struct MessageNotifierInfoFields + { + bool invisibleSpace : 1; // example: ` /var/hello` + bool dots : 1; // example: `/var/./hello` | `/var/../hello` + bool folderPath : 1; // example: `/var/hello/` + bool windowsCompatibility : 1; // any path, that can't be Windows path or UNC path. + bool localPath : 1; // any path, that can't be local: `var/hello` + bool rootPath : 1; // any path, that can't be root: `/var/hello` + bool networkPath : 1; // any path, that can't be network: `smb://SMB.DOMAIN.TEST/Test/path` + } MessageNotifierInfoFields; + +public: + typedef union MessageNotifierInfo + { + MessageNotifierInfoFields fields; + uint32_t mask{0}; + } MessageNotifierInfo; + + typedef struct MessageInstance + { + MessageNotifierInfo trigger; + MessageNotifierInfo detected; + } MessageInstance; + +public: + explicit InputMessageNotifier(QWidget* parent = nullptr); + +private: + InputMessageNotifier(const InputMessageNotifier&) = delete; // copy ctor + InputMessageNotifier(InputMessageNotifier&&) = delete; // move ctor + InputMessageNotifier& operator=(const InputMessageNotifier&) = delete; // copy assignment + InputMessageNotifier& operator=(InputMessageNotifier&&) = delete; // move assignment + +private: + QMap m_instances{}; + QStaticArrayData m_messages{}; +}; + +} + +#endif //GPUI_INPUTMESSAGENOTIFIER_H From 3e5b5a347aabe14337e94b1f2b03e76ecd38436e Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Fri, 30 Aug 2024 15:46:41 +0400 Subject: [PATCH 2/8] wip: implement messages for `InputMessageNotifier` --- .../i18n/preferences_common_translation_en.ts | 38 +++++ .../i18n/preferences_common_translation_ru.ts | 38 +++++ .../common/inputmessagenotifier.cpp | 135 +++++++++++++++++- .../preferences/common/inputmessagenotifier.h | 109 +++++++++----- 4 files changed, 285 insertions(+), 35 deletions(-) diff --git a/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts b/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts index 63b6e6f58..43f145a94 100644 --- a/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts +++ b/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts @@ -764,6 +764,44 @@ context (user policy option) Common + + preferences::InputMessageNotifier + + + The input field has a space at the beginning or at the end + The input field has a space at the beginning or at the end + + + + There is a folder '.'/'..' in the path input field + There is a folder '.'/'..' in the path input field + + + + The path input field contains the path to the folder + The path input field contains the path to the folder + + + + The path input field contains a path that is not compatible with windows + The path input field contains a path that is not compatible with windows + + + + The path input field contains a relative path + The path input field contains a relative path + + + + The path input field contains a path from root + The path input field contains a path from root + + + + The path input field contains a network path + The path input field contains a network path + + preferences::PreferencesTreeView diff --git a/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts b/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts index 3f6734b73..fb4aeb72d 100644 --- a/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts +++ b/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts @@ -765,6 +765,44 @@ context (user policy option) Общие + + preferences::InputMessageNotifier + + + The input field has a space at the beginning or at the end + Поле ввода содержит пробел в начале или в конце + + + + There is a folder '.'/'..' in the path input field + В поле ввода пути есть папка "."/".." + + + + The path input field contains the path to the folder + Поле ввода пути содержит путь к папке + + + + The path input field contains a path that is not compatible with windows + Поле ввода path содержит путь, который несовместим с Windows + + + + The path input field contains a relative path + Поле ввода path содержит относительный путь + + + + The path input field contains a path from root + Поле ввода path содержит путь от корня + + + + The path input field contains a network path + Поле ввода path содержит сетевой путь + + preferences::PreferencesTreeView diff --git a/src/plugins/preferences/common/inputmessagenotifier.cpp b/src/plugins/preferences/common/inputmessagenotifier.cpp index b185c818f..7f68356e1 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.cpp +++ b/src/plugins/preferences/common/inputmessagenotifier.cpp @@ -20,13 +20,142 @@ #include "inputmessagenotifier.h" -namespace preferences +namespace preferences { + +QString InputMessageNotifier::invisibleSpaceMessage() +{ + return tr("The input field has a space at the beginning or at the end"); +} +QString InputMessageNotifier::dotsMessage() +{ + return tr("There is a folder '.'/'..' in the path input field"); +} +QString InputMessageNotifier::folderPathMessage() +{ + return tr("The path input field contains the path to the folder"); +} +QString InputMessageNotifier::windowsCompatibilityMessage() +{ + return tr("The path input field contains a path that is not compatible with windows"); +} +QString InputMessageNotifier::relativePathMessage() +{ + return tr("The path input field contains a relative path"); +} +QString InputMessageNotifier::rootPathMessage() +{ + return tr("The path input field contains a path from root"); +} +QString InputMessageNotifier::networkPathMessage() +{ + return tr("The path input field contains a network path"); +} + +bool InputMessageNotifier::checkInvisibleSpace(const QString &str) +{ + return str.trimmed() != str; +} +bool InputMessageNotifier::checkDots(const QString &str) +{ + // TODO: Write regex + return false; +} +bool InputMessageNotifier::checkFolderPath(const QString &str) +{ + // TODO: Write regex + return false; +} +bool InputMessageNotifier::checkWindowsCompatibility(const QString &str) +{ + // TODO: Write regex + return false; +} +bool InputMessageNotifier::checkRelativePath(const QString &str) +{ + // TODO: Write regex + return false; +} +bool InputMessageNotifier::checkRootPath(const QString &str) { + // TODO: Write regex + return false; +} +bool InputMessageNotifier::checkNetworkPath(const QString &str) +{ + // TODO: Write regex + return false; +} + +InputMessageNotifier::InputMessageNotifier(QWidget *parent) : QWidget(parent) +{ + this->m_layout = new QVBoxLayout; + this->setLayout(this->m_layout); + + for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { + this->m_messages[i] = new QLabel(this); + + this->m_messages[i]->setText(this->m_getMessages[i]()); + this->m_messages[i]->hide(); + this->m_messages[i]->setStyleSheet("background-color: rgb(249, 240, 107);\n" + "border-radius: 10px;\n" + "padding: 10px;"); + + this->m_layout->addWidget(this->m_messages[i]); + } +} + +void InputMessageNotifier::addInstance(const QString& name) +{ + this->m_instances[name] = {}; +} + +void InputMessageNotifier::setInstanceDetection(const QString& name, MessageNotifierType type, + bool detection) +{ + this->m_instances[name].trigger[static_cast(type)] = detection; + updateState(); +} -InputMessageNotifier::InputMessageNotifier(QWidget *parent) - : QWidget(parent) +void InputMessageNotifier::eraseInstance(const QString& name) { + this->m_instances.remove(name); + updateState(); +} +void InputMessageNotifier::updateInstance(const QString& name, const QString& content) +{ + auto &instance = this->m_instances[name]; + + for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { + instance.detected[i] = instance.trigger[i] && this->m_checkMessage[i](content); + } + + instance.content = std::move(content); + updateState(); } +void InputMessageNotifier::updateState() +{ + std::bitset<32> res{ 0 }; + + for (const auto &instance : this->m_instances) { + res |= instance.detected; + } + + for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { + if (res[i]) { + this->m_messages[i]->show(); + } else { + this->m_messages[i]->hide(); + } + } +} + +void InputMessageNotifier::retranslateUi() +{ + for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { + this->m_messages[i]->setText(this->m_getMessages[i]()); + } } + +} // namespace preferences diff --git a/src/plugins/preferences/common/inputmessagenotifier.h b/src/plugins/preferences/common/inputmessagenotifier.h index e3ced0ba7..08817de0d 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.h +++ b/src/plugins/preferences/common/inputmessagenotifier.h @@ -21,59 +21,104 @@ #ifndef GPUI_INPUTMESSAGENOTIFIER_H #define GPUI_INPUTMESSAGENOTIFIER_H -#include #include +#include +#include QT_BEGIN_NAMESPACE -namespace Ui { class InputMessageNotifier; } +namespace Ui { +class InputMessageNotifier; +} QT_END_NAMESPACE -namespace preferences -{ +namespace preferences { class InputMessageNotifier : public QWidget { public: Q_OBJECT -private: - typedef struct MessageNotifierInfoFields - { - bool invisibleSpace : 1; // example: ` /var/hello` - bool dots : 1; // example: `/var/./hello` | `/var/../hello` - bool folderPath : 1; // example: `/var/hello/` - bool windowsCompatibility : 1; // any path, that can't be Windows path or UNC path. - bool localPath : 1; // any path, that can't be local: `var/hello` - bool rootPath : 1; // any path, that can't be root: `/var/hello` - bool networkPath : 1; // any path, that can't be network: `smb://SMB.DOMAIN.TEST/Test/path` - } MessageNotifierInfoFields; public: - typedef union MessageNotifierInfo - { - MessageNotifierInfoFields fields; - uint32_t mask{0}; - } MessageNotifierInfo; + typedef enum class MessageNotifierType { + // Warns if one of the following regular expressions is executed for the entire string + INVISIBLE_SPACE = 0, // " .*|.* |.+ {2}.+" + DOTS = 1, // ".+\.{1,2}.*" + FOLDER_PATH = 2, // "*./" + WINDOWS_COMPATIBILITY = 3, // TODO: write regex + RELATIVE_PATH = 4, // TODO: write regex (for linux and windows) + ROOT_PATH = 5, // TODO: write regex (for linux and windows) + NETWORK_PATH = 6, // TODO: write regex (for linux and windows) + MESSAGE_NOTIFIER_LENGTH, + } MessageNotifierType; - typedef struct MessageInstance +private: + typedef std::bitset<32> MessageNotifierInfo; + + typedef struct MessageInstance { - MessageNotifierInfo trigger; - MessageNotifierInfo detected; + MessageNotifierInfo trigger{0}; + MessageNotifierInfo detected{0}; + QString content{}; } MessageInstance; + typedef QString (*MessageStringFunc)(); + typedef bool (*CheckStringFunc)(const QString &str); + +private: + static QString invisibleSpaceMessage(); + static QString dotsMessage(); + static QString folderPathMessage(); + static QString windowsCompatibilityMessage(); + static QString relativePathMessage(); + static QString rootPathMessage(); + static QString networkPathMessage(); + + static bool checkInvisibleSpace(const QString &str); + static bool checkDots(const QString &str); + static bool checkFolderPath(const QString &str); + static bool checkWindowsCompatibility(const QString &str); + static bool checkRelativePath(const QString &str); + static bool checkRootPath(const QString &str); + static bool checkNetworkPath(const QString &str); + + void updateState(); + +private: + static constexpr std::array(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH)> + m_getMessages = { &invisibleSpaceMessage, &dotsMessage, + &folderPathMessage, &windowsCompatibilityMessage, + &relativePathMessage, &rootPathMessage, + &networkPathMessage }; + static constexpr std::array(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH)> + m_checkMessage = { &checkInvisibleSpace, &checkDots, &checkFolderPath, + &checkWindowsCompatibility, &checkRelativePath, &checkRootPath, + &checkNetworkPath }; + public: - explicit InputMessageNotifier(QWidget* parent = nullptr); + explicit InputMessageNotifier(QWidget *parent = nullptr); + + void addInstance(const QString& name); + void setInstanceDetection(const QString& name, MessageNotifierType type, bool detection = true); + void eraseInstance(const QString& name); + void updateInstance(const QString& name, const QString &content); + + void retranslateUi(); private: - InputMessageNotifier(const InputMessageNotifier&) = delete; // copy ctor - InputMessageNotifier(InputMessageNotifier&&) = delete; // move ctor - InputMessageNotifier& operator=(const InputMessageNotifier&) = delete; // copy assignment - InputMessageNotifier& operator=(InputMessageNotifier&&) = delete; // move assignment + InputMessageNotifier(const InputMessageNotifier &) = delete; // copy ctor + InputMessageNotifier(InputMessageNotifier &&) = delete; // move ctor + InputMessageNotifier &operator=(const InputMessageNotifier &) = delete; // copy assignment + InputMessageNotifier &operator=(InputMessageNotifier &&) = delete; // move assignment private: QMap m_instances{}; - QStaticArrayData m_messages{}; -}; + QVBoxLayout* m_layout{ nullptr }; + std::array(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH)> + m_messages{ nullptr }; +}; -} +} // namespace preferences -#endif //GPUI_INPUTMESSAGENOTIFIER_H +#endif // GPUI_INPUTMESSAGENOTIFIER_H From 8c01066e5373298212fe122dca0408ab50ff13ee Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Fri, 30 Aug 2024 15:47:16 +0400 Subject: [PATCH 3/8] wip: add `InputMessageNotifier` into `FilesWidget` --- src/plugins/preferences/files/fileswidget.cpp | 6 ++++++ src/plugins/preferences/files/fileswidget.h | 1 + src/plugins/preferences/files/fileswidget.ui | 9 +++++++++ src/plugins/preferences/files/fileswidgetslots.cpp | 6 ++++++ 4 files changed, 22 insertions(+) diff --git a/src/plugins/preferences/files/fileswidget.cpp b/src/plugins/preferences/files/fileswidget.cpp index 3c1b71e82..a015bb2aa 100644 --- a/src/plugins/preferences/files/fileswidget.cpp +++ b/src/plugins/preferences/files/fileswidget.cpp @@ -40,6 +40,12 @@ FilesWidget::FilesWidget(QWidget *parent, FilesItem *item) { ui->setupUi(this); + ui->inputMessage->addInstance("source_file"); + ui->inputMessage->addInstance("destination"); + + ui->inputMessage->setInstanceDetection("source_file", InputMessageNotifier::MessageNotifierType::INVISIBLE_SPACE); + ui->inputMessage->setInstanceDetection("destination", InputMessageNotifier::MessageNotifierType::INVISIBLE_SPACE); + on_actionComboBox_currentIndexChanged(ui->actionComboBox->currentIndex()); } diff --git a/src/plugins/preferences/files/fileswidget.h b/src/plugins/preferences/files/fileswidget.h index 5a558a5d9..1a47cebcf 100644 --- a/src/plugins/preferences/files/fileswidget.h +++ b/src/plugins/preferences/files/fileswidget.h @@ -65,6 +65,7 @@ private slots: void on_actionComboBox_currentIndexChanged(int index); void on_destinationToolButton_clicked(); void on_sourceLineEdit_textChanged(const QString &text); + void on_destinationLineEdit_textChanged(const QString &text); void on_sourceToolButton_clicked(); private: diff --git a/src/plugins/preferences/files/fileswidget.ui b/src/plugins/preferences/files/fileswidget.ui index fe4c13970..b8c814c7c 100644 --- a/src/plugins/preferences/files/fileswidget.ui +++ b/src/plugins/preferences/files/fileswidget.ui @@ -117,6 +117,9 @@ + + + @@ -202,6 +205,12 @@ QLineEdit
common/shortcutlineedit.h
+ + preferences::InputMessageNotifier + QWidget +
common/inputmessagenotifier.h
+ 1 +
diff --git a/src/plugins/preferences/files/fileswidgetslots.cpp b/src/plugins/preferences/files/fileswidgetslots.cpp index 89c9aa5ae..0a7679141 100644 --- a/src/plugins/preferences/files/fileswidgetslots.cpp +++ b/src/plugins/preferences/files/fileswidgetslots.cpp @@ -103,6 +103,11 @@ void FilesWidget::on_destinationToolButton_clicked() } } +void FilesWidget::on_destinationLineEdit_textChanged(const QString &text) +{ + ui->inputMessage->updateInstance("destination", text); +} + void FilesWidget::on_sourceLineEdit_textChanged(const QString &text) { if (text.contains('*') || text.contains('?')) @@ -117,6 +122,7 @@ void FilesWidget::on_sourceLineEdit_textChanged(const QString &text) ui->destinationLabel->setText(tr("Destination file:")); } + ui->inputMessage->updateInstance("source_file", text); } } // namespace preferences From f5208052156cd5aad3d0a4ade3a9a0c87356fbe8 Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Wed, 25 Sep 2024 17:20:11 +0400 Subject: [PATCH 4/8] wip: begin of refactoring `InputMessageNotifier` --- .../common/inputmessagenotifier.cpp | 146 +++++++----------- .../preferences/common/inputmessagenotifier.h | 94 +++++------ 2 files changed, 90 insertions(+), 150 deletions(-) diff --git a/src/plugins/preferences/common/inputmessagenotifier.cpp b/src/plugins/preferences/common/inputmessagenotifier.cpp index 7f68356e1..df145ce05 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.cpp +++ b/src/plugins/preferences/common/inputmessagenotifier.cpp @@ -19,78 +19,16 @@ ***********************************************************************************************************************/ #include "inputmessagenotifier.h" +#include +#include namespace preferences { -QString InputMessageNotifier::invisibleSpaceMessage() -{ - return tr("The input field has a space at the beginning or at the end"); -} -QString InputMessageNotifier::dotsMessage() -{ - return tr("There is a folder '.'/'..' in the path input field"); -} -QString InputMessageNotifier::folderPathMessage() -{ - return tr("The path input field contains the path to the folder"); -} -QString InputMessageNotifier::windowsCompatibilityMessage() -{ - return tr("The path input field contains a path that is not compatible with windows"); -} -QString InputMessageNotifier::relativePathMessage() -{ - return tr("The path input field contains a relative path"); -} -QString InputMessageNotifier::rootPathMessage() -{ - return tr("The path input field contains a path from root"); -} -QString InputMessageNotifier::networkPathMessage() -{ - return tr("The path input field contains a network path"); -} - -bool InputMessageNotifier::checkInvisibleSpace(const QString &str) -{ - return str.trimmed() != str; -} -bool InputMessageNotifier::checkDots(const QString &str) -{ - // TODO: Write regex - return false; -} -bool InputMessageNotifier::checkFolderPath(const QString &str) -{ - // TODO: Write regex - return false; -} -bool InputMessageNotifier::checkWindowsCompatibility(const QString &str) -{ - // TODO: Write regex - return false; -} -bool InputMessageNotifier::checkRelativePath(const QString &str) -{ - // TODO: Write regex - return false; -} -bool InputMessageNotifier::checkRootPath(const QString &str) -{ - // TODO: Write regex - return false; -} -bool InputMessageNotifier::checkNetworkPath(const QString &str) -{ - // TODO: Write regex - return false; -} - InputMessageNotifier::InputMessageNotifier(QWidget *parent) : QWidget(parent) { this->m_layout = new QVBoxLayout; this->setLayout(this->m_layout); - +/* for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { this->m_messages[i] = new QLabel(this); @@ -101,61 +39,85 @@ InputMessageNotifier::InputMessageNotifier(QWidget *parent) : QWidget(parent) "padding: 10px;"); this->m_layout->addWidget(this->m_messages[i]); - } + }*/ } -void InputMessageNotifier::addInstance(const QString& name) +size_t InputMessageNotifier::addDetector(std::unique_ptr detector) { - this->m_instances[name] = {}; + if (!detector) + { + throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__ + + ", Encountered with null pointer raither of detector.") + } + this->m_detectors[this->m_next_detector++] = std::move(detector); } -void InputMessageNotifier::setInstanceDetection(const QString& name, MessageNotifierType type, - bool detection) +void InputMessageNotifier::addInstance(const QString& name) { - this->m_instances[name].trigger[static_cast(type)] = detection; - updateState(); + this->m_instances[name] = MessageInstance(); } - void InputMessageNotifier::eraseInstance(const QString& name) { - this->m_instances.remove(name); - updateState(); + this->m_instances.erase(name); + updateState() } - -void InputMessageNotifier::updateInstance(const QString& name, const QString& content) +void InputMessageNotifier::setInstanceDetection(const QString& name, size_t type, bool detect = true) +{ + if (detect) + { + this->m_instances[name].mask.insert(type); + } + else + { + this->m_instances[name].mask.erase(type); + } +} +void InputMessageNotifier::updateInstance(const QString& name, const QString &content) { - auto &instance = this->m_instances[name]; + auto& instance = this->m_instances[name]; - for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { - instance.detected[i] = instance.trigger[i] && this->m_checkMessage[i](content); + instance.content = content; + + for(auto& detector : this->m_detectors) + { + if (instance.mask.find(detector.first) != instance.mask.end() && detector.second->detect(content)) + { + instance.detected.insert(detector.first); + } + else + { + instance.detected.erase(detector.first); + } } - instance.content = std::move(content); updateState(); } void InputMessageNotifier::updateState() { - std::bitset<32> res{ 0 }; + std::set types; - for (const auto &instance : this->m_instances) { - res |= instance.detected; + for (auto& instance : this->m_instances) + { + types.insert(instance.second.detected.begin(), instance.second.detected.end()); } - for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { - if (res[i]) { - this->m_messages[i]->show(); - } else { - this->m_messages[i]->hide(); + for (auto& detector : this->m_detectors) + { + if (types.find(detector.first) != types.end()) + { + this->m_detectors[detector.first]->raw()->show(); + } + else + { + this->m_detectors[detector.first]->raw()->hide(); } } } void InputMessageNotifier::retranslateUi() { - for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { - this->m_messages[i]->setText(this->m_getMessages[i]()); - } + } } // namespace preferences diff --git a/src/plugins/preferences/common/inputmessagenotifier.h b/src/plugins/preferences/common/inputmessagenotifier.h index 08817de0d..03debda77 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.h +++ b/src/plugins/preferences/common/inputmessagenotifier.h @@ -33,75 +33,50 @@ QT_END_NAMESPACE namespace preferences { -class InputMessageNotifier : public QWidget +class IInputMessageDetector : public QObject { public: Q_OBJECT public: - typedef enum class MessageNotifierType { - // Warns if one of the following regular expressions is executed for the entire string - INVISIBLE_SPACE = 0, // " .*|.* |.+ {2}.+" - DOTS = 1, // ".+\.{1,2}.*" - FOLDER_PATH = 2, // "*./" - WINDOWS_COMPATIBILITY = 3, // TODO: write regex - RELATIVE_PATH = 4, // TODO: write regex (for linux and windows) - ROOT_PATH = 5, // TODO: write regex (for linux and windows) - NETWORK_PATH = 6, // TODO: write regex (for linux and windows) - MESSAGE_NOTIFIER_LENGTH, - } MessageNotifierType; - -private: - typedef std::bitset<32> MessageNotifierInfo; + virtual bool detect(const QString& input) = 0; + virtual QWidget* raw() = 0; + virtual const QString& message() = 0; + virtual ~IInputMessageDetector() = 0; +}; - typedef struct MessageInstance - { - MessageNotifierInfo trigger{0}; - MessageNotifierInfo detected{0}; - QString content{}; - } MessageInstance; +class InputMessageWhitespaceDetector : public IInputMessageDetector +{ +public: + Q_OBJECT - typedef QString (*MessageStringFunc)(); - typedef bool (*CheckStringFunc)(const QString &str); +public: + bool detect(const QString& input) override; + QWidget* raw() override; + const QString& message() override; +}; +class InputMessageNotifier : public QWidget +{ +public: + Q_OBJECT private: - static QString invisibleSpaceMessage(); - static QString dotsMessage(); - static QString folderPathMessage(); - static QString windowsCompatibilityMessage(); - static QString relativePathMessage(); - static QString rootPathMessage(); - static QString networkPathMessage(); - - static bool checkInvisibleSpace(const QString &str); - static bool checkDots(const QString &str); - static bool checkFolderPath(const QString &str); - static bool checkWindowsCompatibility(const QString &str); - static bool checkRelativePath(const QString &str); - static bool checkRootPath(const QString &str); - static bool checkNetworkPath(const QString &str); - - void updateState(); -private: - static constexpr std::array(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH)> - m_getMessages = { &invisibleSpaceMessage, &dotsMessage, - &folderPathMessage, &windowsCompatibilityMessage, - &relativePathMessage, &rootPathMessage, - &networkPathMessage }; - static constexpr std::array(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH)> - m_checkMessage = { &checkInvisibleSpace, &checkDots, &checkFolderPath, - &checkWindowsCompatibility, &checkRelativePath, &checkRootPath, - &checkNetworkPath }; +typedef struct MessageInstance +{ + std::unordered_set mask{}; + std::unordered_set detected{}; + QString content; +} MessageInstance; public: explicit InputMessageNotifier(QWidget *parent = nullptr); + size_t addDetector(std::unique_ptr detector); + void addInstance(const QString& name); - void setInstanceDetection(const QString& name, MessageNotifierType type, bool detection = true); void eraseInstance(const QString& name); + void setInstanceDetection(const QString& name, size_t type, bool detect = true); void updateInstance(const QString& name, const QString &content); void retranslateUi(); @@ -110,13 +85,16 @@ class InputMessageNotifier : public QWidget InputMessageNotifier(const InputMessageNotifier &) = delete; // copy ctor InputMessageNotifier(InputMessageNotifier &&) = delete; // move ctor InputMessageNotifier &operator=(const InputMessageNotifier &) = delete; // copy assignment - InputMessageNotifier &operator=(InputMessageNotifier &&) = delete; // move assignment + InputMessageNotifier &operator=(InputMessageNotifier &&) = delete; // move assignment' + + void updateState(); private: - QMap m_instances{}; - QVBoxLayout* m_layout{ nullptr }; - std::array(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH)> - m_messages{ nullptr }; + QVBoxLayout* m_layout{nullptr}; + std::vector triggered{}; + std::unordered_map m_instances{}; + std::unordered_map> m_detectors{}; + size_t m_next_detector = 0; }; } // namespace preferences From e370bb18b145463e599a25409d23a25ee84d0294 Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Mon, 30 Sep 2024 17:30:32 +0400 Subject: [PATCH 5/8] wip: refactoring continue --- .../common/inputmessagenotifier.cpp | 213 +++++++++++++----- .../preferences/common/inputmessagenotifier.h | 150 +++++++++--- 2 files changed, 270 insertions(+), 93 deletions(-) diff --git a/src/plugins/preferences/common/inputmessagenotifier.cpp b/src/plugins/preferences/common/inputmessagenotifier.cpp index df145ce05..4399b3290 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.cpp +++ b/src/plugins/preferences/common/inputmessagenotifier.cpp @@ -24,100 +24,197 @@ namespace preferences { -InputMessageNotifier::InputMessageNotifier(QWidget *parent) : QWidget(parent) +bool WhitespaceDetector::detect(const QString& input) { - this->m_layout = new QVBoxLayout; - this->setLayout(this->m_layout); -/* - for (size_t i = 0; i < static_cast(MessageNotifierType::MESSAGE_NOTIFIER_LENGTH); ++i) { - this->m_messages[i] = new QLabel(this); + return input.trimmed() != input; +} +InputMessageNotifier::DetectElement::DetectElement(QWidget* parent, QLayout* layout, const QString& message, InputMessageNotifier::MessageLevel level) +{ + this->m_label = new QLabel(parent); + layout->addWidget(this->m_label); - this->m_messages[i]->setText(this->m_getMessages[i]()); - this->m_messages[i]->hide(); - this->m_messages[i]->setStyleSheet("background-color: rgb(249, 240, 107);\n" - "border-radius: 10px;\n" - "padding: 10px;"); + this->m_label->hide(); - this->m_layout->addWidget(this->m_messages[i]); - }*/ -} + this->m_label->setText(message); -size_t InputMessageNotifier::addDetector(std::unique_ptr detector) + switch(level) + { + case InputMessageNotifier::MessageLevel::Warning: + this->m_label->setStyleSheet("background-color: rgb(249, 240, 107);\n" + "color: rgb(0,0,0);\n" + "border-radius: 10px;\n" + "padding: 10px;"); + break; + + default: + case InputMessageNotifier::MessageLevel::Error: + this->m_label->setStyleSheet("background-color: rgb(246, 97, 81);\n" + "color: rgb(255, 255, 255);\n" + "border-radius: 10px;\n" + "padding: 10px;"); + break; + } + + this->m_level = level; +} +InputMessageNotifier::DetectElement::DetectElement(DetectElement&& element) { - if (!detector) + this->m_detected = element.m_detected; + this->m_label = element.m_label; + this->m_level = element.m_level; + element.m_label = nullptr; +} +InputMessageNotifier::DetectElement& InputMessageNotifier::DetectElement::operator=(DetectElement&& element) +{ + if (this->m_label) { - throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__ - + ", Encountered with null pointer raither of detector.") + delete this->m_label; } - this->m_detectors[this->m_next_detector++] = std::move(detector); + + this->m_detected = element.m_detected; + this->m_label = element.m_label; + this->m_level = element.m_level; + element.m_label = nullptr; + + return *this; } -void InputMessageNotifier::addInstance(const QString& name) +void InputMessageNotifier::DetectElement::detect() { - this->m_instances[name] = MessageInstance(); + this->m_label->show(); + this->m_detected = true; } -void InputMessageNotifier::eraseInstance(const QString& name) +void InputMessageNotifier::DetectElement::undetect() { - this->m_instances.erase(name); - updateState() + this->m_label->hide(); + this->m_detected = false; } -void InputMessageNotifier::setInstanceDetection(const QString& name, size_t type, bool detect = true) + +bool InputMessageNotifier::DetectElement::detected() { - if (detect) - { - this->m_instances[name].mask.insert(type); - } - else - { - this->m_instances[name].mask.erase(type); - } + return this->m_detected; } -void InputMessageNotifier::updateInstance(const QString& name, const QString &content) + +InputMessageNotifier::MessageLevel InputMessageNotifier::DetectElement::level() { - auto& instance = this->m_instances[name]; + return this->m_level; +} - instance.content = content; +void InputMessageNotifier::DetectElement::setMessage(const QString& message) +{ + this->m_label->setText(message); +} - for(auto& detector : this->m_detectors) +InputMessageNotifier::DetectElement::~DetectElement() +{ + if (this->m_label) { - if (instance.mask.find(detector.first) != instance.mask.end() && detector.second->detect(content)) - { - instance.detected.insert(detector.first); - } - else - { - instance.detected.erase(detector.first); - } + delete this->m_label; } +} - updateState(); +InputMessageNotifier::InputMessageNotifier(QWidget* widget) +: QWidget(widget) +{ + this->m_layout = new QVBoxLayout; + this->setLayout(this->m_layout); } -void InputMessageNotifier::updateState() +size_t InputMessageNotifier::addDetector(std::unique_ptr detector) { - std::set types; + this->m_detectors[this->m_nextDetector] = std::move(detector); + return this->m_nextDetector++; +} - for (auto& instance : this->m_instances) - { - types.insert(instance.second.detected.begin(), instance.second.detected.end()); - } +void InputMessageNotifier::removeDetector(size_t id) +{ + this->m_detectors.erase(id); +} + +void InputMessageNotifier::addInput(const QString& name) +{ + this->m_instances[name] = std::move(InputInstance()); +} + + +void InputMessageNotifier::removeInput(const QString& name) +{ + this->m_instances.erase(name); +} - for (auto& detector : this->m_detectors) +void InputMessageNotifier::updateInput(const QString& name, const QString& input) +{ + auto& instance = this->m_instances[name]; + + for (auto& detect : instance) { - if (types.find(detector.first) != types.end()) + bool detected = this->m_detectors[detect.first]->detect(input); + + if (detected && !detect.second.detected()) { - this->m_detectors[detector.first]->raw()->show(); + detect.second.detect(); + this->incCounter(detect.second.level()); } - else + else if(!detected && detect.second.detected()) { - this->m_detectors[detector.first]->raw()->hide(); + detect.second.undetect(); + this->decCounter(detect.second.level()); } } } -void InputMessageNotifier::retranslateUi() +void InputMessageNotifier::setMessage(const QString& name, size_t detector, const QString& message) +{ + auto entry = this->m_instances[name].find(detector); + if (entry != this->m_instances[name].end()) + { + entry->second.setMessage(message); + } +} + +void InputMessageNotifier::attachDetector(const QString& name, size_t detector, const QString& message, MessageLevel level) +{ + this->m_instances[name].insert(std::pair(detector, DetectElement(this, this->m_layout, message, level))); +} + +bool InputMessageNotifier::hasAnyError() +{ + return this->m_errorCount != 0; +} + +bool InputMessageNotifier::hasAnyWarning() +{ + return this->m_warningCount != 0; +} + +InputMessageNotifier::~InputMessageNotifier() { } +void InputMessageNotifier::incCounter(InputMessageNotifier::MessageLevel level) +{ + switch(level) + { + case InputMessageNotifier::MessageLevel::Warning: + ++this->m_warningCount; + break; + case InputMessageNotifier::MessageLevel::Error: + ++this->m_errorCount; + break; + } +} +void InputMessageNotifier::decCounter(MessageLevel level) +{ + switch(level) + { + case InputMessageNotifier::MessageLevel::Warning: + --this->m_warningCount; + break; + case InputMessageNotifier::MessageLevel::Error: + --this->m_errorCount; + break; + } +} + } // namespace preferences diff --git a/src/plugins/preferences/common/inputmessagenotifier.h b/src/plugins/preferences/common/inputmessagenotifier.h index 03debda77..3404ce7a5 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.h +++ b/src/plugins/preferences/common/inputmessagenotifier.h @@ -33,68 +33,148 @@ QT_END_NAMESPACE namespace preferences { -class IInputMessageDetector : public QObject +class InputDetector : public QObject { public: - Q_OBJECT - + Q_OBJECT public: virtual bool detect(const QString& input) = 0; - virtual QWidget* raw() = 0; - virtual const QString& message() = 0; - virtual ~IInputMessageDetector() = 0; + virtual ~InputDetector() = default; }; -class InputMessageWhitespaceDetector : public IInputMessageDetector +class WhitespaceDetector: public InputDetector { public: Q_OBJECT - public: bool detect(const QString& input) override; - QWidget* raw() override; - const QString& message() override; }; -class InputMessageNotifier : public QWidget +class InputMessageNotifier : public QWidget { public: + Q_OBJECT + +public: + + enum class MessageLevel + { + Warning, + Error, + }; + private: -typedef struct MessageInstance -{ - std::unordered_set mask{}; - std::unordered_set detected{}; - QString content; -} MessageInstance; + typedef struct DetectElement + { + public: + DetectElement(QWidget* parent, QLayout* layout, const QString& message, MessageLevel level); + DetectElement(DetectElement&& element); + DetectElement& operator=(DetectElement&& element); -public: - explicit InputMessageNotifier(QWidget *parent = nullptr); + void detect(); + void undetect(); - size_t addDetector(std::unique_ptr detector); + bool detected(); + MessageLevel level(); + void setMessage(const QString& message); - void addInstance(const QString& name); - void eraseInstance(const QString& name); - void setInstanceDetection(const QString& name, size_t type, bool detect = true); - void updateInstance(const QString& name, const QString &content); + ~DetectElement(); + private: + DetectElement(const DetectElement&) = delete; + void operator=(const DetectElement&) = delete; - void retranslateUi(); + private: + bool m_detected{false}; + QLabel* m_label{nullptr}; + MessageLevel m_level{MessageLevel::Warning}; + } DetectElement; + + typedef std::unordered_map InputInstance; + +public: + + InputMessageNotifier(QWidget* widget); + + /** + * @brief add detector. + * @param detector Detector. + * @return Detector id. + */ + size_t addDetector(std::unique_ptr detector); + + /** + * @brief remove detector. + * @param id Detector id. + */ + void removeDetector(size_t id); + + /** + * @brief registrate input. + * @param name Name of input to be registrated. + */ + void addInput(const QString& name); + + /** + * @brief unregistrate input. + * @param name Name of input to be unregistrated. + */ + void removeInput(const QString& name); + + /** + * @brief update input content and validate it. + * @param name Name of registrated input. + * @param input Input content. + */ + void updateInput(const QString& name, const QString& input); + + /** + * @brief update input content and validate it. + * @param name Name of registrated input. + * @param detector Detector id. + * @param message MessageNotifier message on detect. + */ + void setMessage(const QString& name, size_t detector, const QString& message); + + /** + * @brief attach detector to input. + * @param name Name of registrated input. + * @param detector Detector id. + * @param level Message level(visual and see hasAnyError() and hasAnyWarning()) + */ + void attachDetector(const QString& name, size_t detector, const QString& message, MessageLevel level = MessageLevel::Warning); + + /** + * @return true, if any error has been detected(on any input). + */ + bool hasAnyError(); + + /** + * @return true, if any warning has been detected(on any input). + */ + bool hasAnyWarning(); + + ~InputMessageNotifier(); private: - InputMessageNotifier(const InputMessageNotifier &) = delete; // copy ctor - InputMessageNotifier(InputMessageNotifier &&) = delete; // move ctor - InputMessageNotifier &operator=(const InputMessageNotifier &) = delete; // copy assignment - InputMessageNotifier &operator=(InputMessageNotifier &&) = delete; // move assignment' + InputMessageNotifier(const InputMessageNotifier&) = delete; + void operator=(const InputMessageNotifier&) = delete; - void updateState(); + void incCounter(MessageLevel level); + void decCounter(MessageLevel level); private: - QVBoxLayout* m_layout{nullptr}; - std::vector triggered{}; - std::unordered_map m_instances{}; - std::unordered_map> m_detectors{}; - size_t m_next_detector = 0; + + std::unordered_map> m_detectors{}; + std::unordered_map m_instances{}; + + size_t m_errorCount{0}; + size_t m_warningCount{0}; + + size_t m_nextDetector{0}; + + QLayout* m_layout{nullptr}; }; } // namespace preferences From ff0fdf539751a352a66031871f21116b0feb1d79 Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Mon, 30 Sep 2024 17:31:00 +0400 Subject: [PATCH 6/8] fix: update `InputMessageNotifier` in `FilesWidget` --- .../i18n/preferences_common_translation_en.ts | 21 +++------ .../i18n/preferences_common_translation_ru.ts | 21 +++------ src/plugins/preferences/files/fileswidget.cpp | 10 +++-- src/plugins/preferences/files/fileswidget.h | 2 + .../preferences/files/fileswidgetslots.cpp | 6 ++- .../files/i18n/files_translation_en.ts | 44 +++++++++++++------ .../files/i18n/files_translation_ru.ts | 44 +++++++++++++------ 7 files changed, 86 insertions(+), 62 deletions(-) diff --git a/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts b/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts index 43f145a94..3a06657eb 100644 --- a/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts +++ b/src/plugins/preferences/common/i18n/preferences_common_translation_en.ts @@ -767,39 +767,32 @@ context (user policy option) preferences::InputMessageNotifier - The input field has a space at the beginning or at the end - The input field has a space at the beginning or at the end + The input field has a space at the beginning or at the end - There is a folder '.'/'..' in the path input field - There is a folder '.'/'..' in the path input field + There is a folder '.'/'..' in the path input field - The path input field contains the path to the folder - The path input field contains the path to the folder + The path input field contains the path to the folder - The path input field contains a path that is not compatible with windows - The path input field contains a path that is not compatible with windows + The path input field contains a path that is not compatible with windows - The path input field contains a relative path - The path input field contains a relative path + The path input field contains a relative path - The path input field contains a path from root - The path input field contains a path from root + The path input field contains a path from root - The path input field contains a network path - The path input field contains a network path + The path input field contains a network path diff --git a/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts b/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts index fb4aeb72d..12e58cd79 100644 --- a/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts +++ b/src/plugins/preferences/common/i18n/preferences_common_translation_ru.ts @@ -768,39 +768,32 @@ context (user policy option) preferences::InputMessageNotifier - The input field has a space at the beginning or at the end - Поле ввода содержит пробел в начале или в конце + Поле ввода содержит пробел в начале или в конце - There is a folder '.'/'..' in the path input field - В поле ввода пути есть папка "."/".." + В поле ввода пути есть папка "."/".." - The path input field contains the path to the folder - Поле ввода пути содержит путь к папке + Поле ввода пути содержит путь к папке - The path input field contains a path that is not compatible with windows - Поле ввода path содержит путь, который несовместим с Windows + Поле ввода path содержит путь, который несовместим с Windows - The path input field contains a relative path - Поле ввода path содержит относительный путь + Поле ввода path содержит относительный путь - The path input field contains a path from root - Поле ввода path содержит путь от корня + Поле ввода path содержит путь от корня - The path input field contains a network path - Поле ввода path содержит сетевой путь + Поле ввода path содержит сетевой путь diff --git a/src/plugins/preferences/files/fileswidget.cpp b/src/plugins/preferences/files/fileswidget.cpp index a015bb2aa..0b75e77fa 100644 --- a/src/plugins/preferences/files/fileswidget.cpp +++ b/src/plugins/preferences/files/fileswidget.cpp @@ -40,11 +40,13 @@ FilesWidget::FilesWidget(QWidget *parent, FilesItem *item) { ui->setupUi(this); - ui->inputMessage->addInstance("source_file"); - ui->inputMessage->addInstance("destination"); + this->whitespaceDetector = ui->inputMessage->addDetector(std::unique_ptr(new WhitespaceDetector)); - ui->inputMessage->setInstanceDetection("source_file", InputMessageNotifier::MessageNotifierType::INVISIBLE_SPACE); - ui->inputMessage->setInstanceDetection("destination", InputMessageNotifier::MessageNotifierType::INVISIBLE_SPACE); + ui->inputMessage->addInput("source_file"); + ui->inputMessage->addInput("destination"); + + ui->inputMessage->attachDetector("source_file", whitespaceDetector, tr("source_file_whitespace")); + ui->inputMessage->attachDetector("destination", whitespaceDetector, tr("destination_whitespace")); on_actionComboBox_currentIndexChanged(ui->actionComboBox->currentIndex()); } diff --git a/src/plugins/preferences/files/fileswidget.h b/src/plugins/preferences/files/fileswidget.h index 1a47cebcf..ee2b40b45 100644 --- a/src/plugins/preferences/files/fileswidget.h +++ b/src/plugins/preferences/files/fileswidget.h @@ -83,6 +83,8 @@ private slots: bool fileMode {true}; + size_t whitespaceDetector{0}; + private: Ui::FilesWidget *ui {nullptr}; }; diff --git a/src/plugins/preferences/files/fileswidgetslots.cpp b/src/plugins/preferences/files/fileswidgetslots.cpp index 0a7679141..7b626db75 100644 --- a/src/plugins/preferences/files/fileswidgetslots.cpp +++ b/src/plugins/preferences/files/fileswidgetslots.cpp @@ -105,7 +105,7 @@ void FilesWidget::on_destinationToolButton_clicked() void FilesWidget::on_destinationLineEdit_textChanged(const QString &text) { - ui->inputMessage->updateInstance("destination", text); + ui->inputMessage->updateInput("destination", text); } void FilesWidget::on_sourceLineEdit_textChanged(const QString &text) @@ -115,14 +115,16 @@ void FilesWidget::on_sourceLineEdit_textChanged(const QString &text) fileMode = false; ui->destinationLabel->setText(tr("Destination folder:")); + ui->inputMessage->setMessage("destination", this->whitespaceDetector, tr("destination_folder_whitespace")); } else { fileMode = true; ui->destinationLabel->setText(tr("Destination file:")); + ui->inputMessage->setMessage("destination", this->whitespaceDetector, tr("destination_whitespace")); } - ui->inputMessage->updateInstance("source_file", text); + ui->inputMessage->updateInput("source_file", text); } } // namespace preferences diff --git a/src/plugins/preferences/files/i18n/files_translation_en.ts b/src/plugins/preferences/files/i18n/files_translation_en.ts index 482879400..8d8f83ae4 100644 --- a/src/plugins/preferences/files/i18n/files_translation_en.ts +++ b/src/plugins/preferences/files/i18n/files_translation_en.ts @@ -57,32 +57,32 @@ Destination:
- + Supress errors on individual file actions Supress errors on individual file actions - + Attributes Attributes - + Read-only Read-only - + Hidden Hidden - + Archive Archive - + Executable Executable @@ -120,13 +120,13 @@ Target - - + + All files (*) All files (*) - + All files (*.*) All files (*.*) @@ -134,17 +134,28 @@ preferences::FilesWidget - + + source_file_whitespace + The input field of the source file contains a space at the beginning or at the end + + + + + destination_whitespace + The input field of the destination file contains a space at the beginning or at the end + + + Please enter source file(s) value. Please enter source file(s) value. - + Please enter destination file(s) value. Please enter destination file(s) value. - + General General @@ -155,10 +166,15 @@ - + Destination file: Destination file: + + + destination_folder_whitespace + The input field of the destination folder contains a space at the beginning or at the end + Open Open @@ -184,7 +200,7 @@ Open Directory - + Destination folder: Destination folder: diff --git a/src/plugins/preferences/files/i18n/files_translation_ru.ts b/src/plugins/preferences/files/i18n/files_translation_ru.ts index e0ab08f8c..ad31c85b9 100644 --- a/src/plugins/preferences/files/i18n/files_translation_ru.ts +++ b/src/plugins/preferences/files/i18n/files_translation_ru.ts @@ -57,32 +57,32 @@ Назначение: - + Supress errors on individual file actions Подавление ошибок при действиях с отдельными файлами - + Attributes Атрибуты - + Read-only Только для чтения - + Hidden Скрытый - + Archive Архивный - + Executable Исполняемый @@ -120,13 +120,13 @@ Цель - - + + All files (*) Все файлы (*) - + All files (*.*) Все файлы (*.*) @@ -134,17 +134,28 @@ preferences::FilesWidget - + + source_file_whitespace + Поле ввода исходного файла содержит пробел в начале или в конце + + + + + destination_whitespace + Поле ввода целевого файла содержит пробел в начале или в конце + + + Please enter source file(s) value. Пожалуйста, введите источник файла(ов). - + Please enter destination file(s) value. Пожалуйста, введите место назначения файла(ов). - + General Основные настройки @@ -155,10 +166,15 @@ - + Destination file: Место назначения файлов: + + + destination_folder_whitespace + Поле ввода целевой папки содержит пробел в начале или в конце + Open Открыть @@ -184,7 +200,7 @@ Открыть Директорию - + Destination folder: Папка назначения: From ebd8fb9f78c0cc6fdfb809f2f71fc818717c0f33 Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Mon, 30 Sep 2024 17:38:18 +0400 Subject: [PATCH 7/8] fix: remove unnecessary inheritance --- src/plugins/preferences/common/inputmessagenotifier.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plugins/preferences/common/inputmessagenotifier.h b/src/plugins/preferences/common/inputmessagenotifier.h index 3404ce7a5..57cbd4f7d 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.h +++ b/src/plugins/preferences/common/inputmessagenotifier.h @@ -33,10 +33,8 @@ QT_END_NAMESPACE namespace preferences { -class InputDetector : public QObject +class InputDetector { -public: - Q_OBJECT public: virtual bool detect(const QString& input) = 0; virtual ~InputDetector() = default; @@ -44,8 +42,6 @@ class InputDetector : public QObject class WhitespaceDetector: public InputDetector { -public: - Q_OBJECT public: bool detect(const QString& input) override; }; From 84baa370a98e93f10cdaecfbf7a141f1181f7183 Mon Sep 17 00:00:00 2001 From: kiper220-alt Date: Tue, 1 Oct 2024 15:53:59 +0400 Subject: [PATCH 8/8] wip: end of refactoring --- src/plugins/preferences/CMakeLists.txt | 2 + .../preferences/common/inputdetectors.cpp | 15 +++ .../preferences/common/inputdetectors.h | 42 +++++++++ .../common/inputmessagenotifier.cpp | 92 ++++++++----------- .../preferences/common/inputmessagenotifier.h | 74 ++++++--------- src/plugins/preferences/files/fileswidget.cpp | 7 ++ src/plugins/preferences/files/fileswidget.h | 1 + .../preferences/files/fileswidgetslots.cpp | 2 + .../files/i18n/files_translation_en.ts | 30 ++++-- .../files/i18n/files_translation_ru.ts | 30 ++++-- 10 files changed, 184 insertions(+), 111 deletions(-) create mode 100644 src/plugins/preferences/common/inputdetectors.cpp create mode 100644 src/plugins/preferences/common/inputdetectors.h diff --git a/src/plugins/preferences/CMakeLists.txt b/src/plugins/preferences/CMakeLists.txt index 79ceb7651..ab355a0fb 100644 --- a/src/plugins/preferences/CMakeLists.txt +++ b/src/plugins/preferences/CMakeLists.txt @@ -198,6 +198,7 @@ set(HEADERS common/preferenceswidget.h common/inputmessagenotifier.h + common/inputdetectors.h ) set(SOURCES @@ -382,6 +383,7 @@ set(SOURCES common/preferenceswidget.cpp common/inputmessagenotifier.cpp + common/inputdetectors.cpp ) set(UI_FORMS diff --git a/src/plugins/preferences/common/inputdetectors.cpp b/src/plugins/preferences/common/inputdetectors.cpp new file mode 100644 index 000000000..80f7ff337 --- /dev/null +++ b/src/plugins/preferences/common/inputdetectors.cpp @@ -0,0 +1,15 @@ +#include "inputdetectors.h" + +namespace preferences { + +bool WhitespaceDetector::detect(const QString &input) +{ + return input.trimmed() != input; +} + +bool EmptyDetector::detect(const QString &input) +{ + return input.length() == 0; +} + +} // namespace preferences diff --git a/src/plugins/preferences/common/inputdetectors.h b/src/plugins/preferences/common/inputdetectors.h new file mode 100644 index 000000000..d66a0382c --- /dev/null +++ b/src/plugins/preferences/common/inputdetectors.h @@ -0,0 +1,42 @@ +/*********************************************************************************************************************** +** +** Copyright (C) 2021 BaseALT Ltd. +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +***********************************************************************************************************************/ + +#ifndef GPUI_INPUTDETECTORS_H +#define GPUI_INPUTDETECTORS_H + +#include "inputmessagenotifier.h" + +namespace preferences { + +class WhitespaceDetector : public InputDetector +{ +public: + bool detect(const QString &input) override; +}; + +class EmptyDetector : public InputDetector +{ +public: + bool detect(const QString &input) override; +}; + +} // namespace preferences + +#endif // GPUI_INPUTDETECTORS_H diff --git a/src/plugins/preferences/common/inputmessagenotifier.cpp b/src/plugins/preferences/common/inputmessagenotifier.cpp index 4399b3290..8c3769d3e 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.cpp +++ b/src/plugins/preferences/common/inputmessagenotifier.cpp @@ -19,16 +19,14 @@ ***********************************************************************************************************************/ #include "inputmessagenotifier.h" -#include #include +#include namespace preferences { -bool WhitespaceDetector::detect(const QString& input) -{ - return input.trimmed() != input; -} -InputMessageNotifier::DetectElement::DetectElement(QWidget* parent, QLayout* layout, const QString& message, InputMessageNotifier::MessageLevel level) +InputMessageNotifier::DetectElement::DetectElement(QWidget *parent, QLayout *layout, + const QString &message, + InputMessageNotifier::MessageLevel level) { this->m_label = new QLabel(parent); layout->addWidget(this->m_label); @@ -37,37 +35,36 @@ InputMessageNotifier::DetectElement::DetectElement(QWidget* parent, QLayout* lay this->m_label->setText(message); - switch(level) - { - case InputMessageNotifier::MessageLevel::Warning: - this->m_label->setStyleSheet("background-color: rgb(249, 240, 107);\n" - "color: rgb(0,0,0);\n" - "border-radius: 10px;\n" - "padding: 10px;"); + switch (level) { + case InputMessageNotifier::MessageLevel::Warning: + this->m_label->setStyleSheet("background-color: rgb(249, 240, 107);\n" + "color: rgb(0,0,0);\n" + "border-radius: 10px;\n" + "padding: 10px;"); break; - default: - case InputMessageNotifier::MessageLevel::Error: - this->m_label->setStyleSheet("background-color: rgb(246, 97, 81);\n" - "color: rgb(255, 255, 255);\n" - "border-radius: 10px;\n" - "padding: 10px;"); + default: + case InputMessageNotifier::MessageLevel::Error: + this->m_label->setStyleSheet("background-color: rgb(246, 97, 81);\n" + "color: rgb(255, 255, 255);\n" + "border-radius: 10px;\n" + "padding: 10px;"); break; } this->m_level = level; } -InputMessageNotifier::DetectElement::DetectElement(DetectElement&& element) +InputMessageNotifier::DetectElement::DetectElement(DetectElement &&element) { this->m_detected = element.m_detected; this->m_label = element.m_label; this->m_level = element.m_level; element.m_label = nullptr; } -InputMessageNotifier::DetectElement& InputMessageNotifier::DetectElement::operator=(DetectElement&& element) +InputMessageNotifier::DetectElement & +InputMessageNotifier::DetectElement::operator=(DetectElement &&element) { - if (this->m_label) - { + if (this->m_label) { delete this->m_label; } @@ -100,21 +97,19 @@ InputMessageNotifier::MessageLevel InputMessageNotifier::DetectElement::level() return this->m_level; } -void InputMessageNotifier::DetectElement::setMessage(const QString& message) +void InputMessageNotifier::DetectElement::setMessage(const QString &message) { this->m_label->setText(message); } InputMessageNotifier::DetectElement::~DetectElement() { - if (this->m_label) - { + if (this->m_label) { delete this->m_label; } } -InputMessageNotifier::InputMessageNotifier(QWidget* widget) -: QWidget(widget) +InputMessageNotifier::InputMessageNotifier(QWidget *widget) : QWidget(widget) { this->m_layout = new QVBoxLayout; this->setLayout(this->m_layout); @@ -131,50 +126,46 @@ void InputMessageNotifier::removeDetector(size_t id) this->m_detectors.erase(id); } -void InputMessageNotifier::addInput(const QString& name) +void InputMessageNotifier::addInput(const QString &name) { this->m_instances[name] = std::move(InputInstance()); } - -void InputMessageNotifier::removeInput(const QString& name) +void InputMessageNotifier::removeInput(const QString &name) { this->m_instances.erase(name); } -void InputMessageNotifier::updateInput(const QString& name, const QString& input) +void InputMessageNotifier::updateInput(const QString &name, const QString &input) { - auto& instance = this->m_instances[name]; + auto &instance = this->m_instances[name]; - for (auto& detect : instance) - { + for (auto &detect : instance) { bool detected = this->m_detectors[detect.first]->detect(input); - if (detected && !detect.second.detected()) - { + if (detected && !detect.second.detected()) { detect.second.detect(); this->incCounter(detect.second.level()); - } - else if(!detected && detect.second.detected()) - { + } else if (!detected && detect.second.detected()) { detect.second.undetect(); this->decCounter(detect.second.level()); } } } -void InputMessageNotifier::setMessage(const QString& name, size_t detector, const QString& message) +void InputMessageNotifier::setMessage(const QString &name, size_t detector, const QString &message) { auto entry = this->m_instances[name].find(detector); - if (entry != this->m_instances[name].end()) - { + if (entry != this->m_instances[name].end()) { entry->second.setMessage(message); } } -void InputMessageNotifier::attachDetector(const QString& name, size_t detector, const QString& message, MessageLevel level) +void InputMessageNotifier::attachDetector(const QString &name, size_t detector, + const QString &message, MessageLevel level) { - this->m_instances[name].insert(std::pair(detector, DetectElement(this, this->m_layout, message, level))); + this->m_instances[name].insert(std::pair( + detector, DetectElement(this, this->m_layout, message, level))); } bool InputMessageNotifier::hasAnyError() @@ -187,15 +178,11 @@ bool InputMessageNotifier::hasAnyWarning() return this->m_warningCount != 0; } -InputMessageNotifier::~InputMessageNotifier() -{ - -} +InputMessageNotifier::~InputMessageNotifier() { } void InputMessageNotifier::incCounter(InputMessageNotifier::MessageLevel level) { - switch(level) - { + switch (level) { case InputMessageNotifier::MessageLevel::Warning: ++this->m_warningCount; break; @@ -206,8 +193,7 @@ void InputMessageNotifier::incCounter(InputMessageNotifier::MessageLevel level) } void InputMessageNotifier::decCounter(MessageLevel level) { - switch(level) - { + switch (level) { case InputMessageNotifier::MessageLevel::Warning: --this->m_warningCount; break; diff --git a/src/plugins/preferences/common/inputmessagenotifier.h b/src/plugins/preferences/common/inputmessagenotifier.h index 57cbd4f7d..23b06a7a9 100644 --- a/src/plugins/preferences/common/inputmessagenotifier.h +++ b/src/plugins/preferences/common/inputmessagenotifier.h @@ -25,73 +25,57 @@ #include #include -QT_BEGIN_NAMESPACE -namespace Ui { -class InputMessageNotifier; -} -QT_END_NAMESPACE - namespace preferences { -class InputDetector +class InputDetector { public: - virtual bool detect(const QString& input) = 0; + virtual bool detect(const QString &input) = 0; virtual ~InputDetector() = default; }; -class WhitespaceDetector: public InputDetector +class InputMessageNotifier : public QWidget { public: - bool detect(const QString& input) override; -}; - -class InputMessageNotifier : public QWidget -{ -public: - Q_OBJECT -public: - - enum class MessageLevel - { +public: + enum class MessageLevel { Warning, Error, }; private: - typedef struct DetectElement { public: - DetectElement(QWidget* parent, QLayout* layout, const QString& message, MessageLevel level); - DetectElement(DetectElement&& element); - DetectElement& operator=(DetectElement&& element); + DetectElement(QWidget *parent, QLayout *layout, const QString &message, MessageLevel level); + DetectElement(DetectElement &&element); + DetectElement &operator=(DetectElement &&element); void detect(); void undetect(); bool detected(); MessageLevel level(); - void setMessage(const QString& message); + void setMessage(const QString &message); ~DetectElement(); + private: - DetectElement(const DetectElement&) = delete; - void operator=(const DetectElement&) = delete; + DetectElement(const DetectElement &) = delete; // copy ctor + DetectElement &operator=(const DetectElement &) = delete; // copy assignment private: - bool m_detected{false}; - QLabel* m_label{nullptr}; - MessageLevel m_level{MessageLevel::Warning}; + bool m_detected{ false }; + QLabel *m_label{ nullptr }; + MessageLevel m_level{ MessageLevel::Warning }; } DetectElement; typedef std::unordered_map InputInstance; public: - - InputMessageNotifier(QWidget* widget); + InputMessageNotifier(QWidget *widget); /** * @brief add detector. @@ -110,20 +94,20 @@ class InputMessageNotifier : public QWidget * @brief registrate input. * @param name Name of input to be registrated. */ - void addInput(const QString& name); + void addInput(const QString &name); /** * @brief unregistrate input. * @param name Name of input to be unregistrated. */ - void removeInput(const QString& name); + void removeInput(const QString &name); /** * @brief update input content and validate it. * @param name Name of registrated input. * @param input Input content. */ - void updateInput(const QString& name, const QString& input); + void updateInput(const QString &name, const QString &input); /** * @brief update input content and validate it. @@ -131,7 +115,7 @@ class InputMessageNotifier : public QWidget * @param detector Detector id. * @param message MessageNotifier message on detect. */ - void setMessage(const QString& name, size_t detector, const QString& message); + void setMessage(const QString &name, size_t detector, const QString &message); /** * @brief attach detector to input. @@ -139,7 +123,8 @@ class InputMessageNotifier : public QWidget * @param detector Detector id. * @param level Message level(visual and see hasAnyError() and hasAnyWarning()) */ - void attachDetector(const QString& name, size_t detector, const QString& message, MessageLevel level = MessageLevel::Warning); + void attachDetector(const QString &name, size_t detector, const QString &message, + MessageLevel level = MessageLevel::Warning); /** * @return true, if any error has been detected(on any input). @@ -154,23 +139,24 @@ class InputMessageNotifier : public QWidget ~InputMessageNotifier(); private: - InputMessageNotifier(const InputMessageNotifier&) = delete; - void operator=(const InputMessageNotifier&) = delete; + InputMessageNotifier(const InputMessageNotifier &) = delete; // copy ctor + InputMessageNotifier(InputMessageNotifier &&) = delete; // move ctor + InputMessageNotifier &operator=(const InputMessageNotifier &) = delete; // copy assignment + InputMessageNotifier &operator=(InputMessageNotifier &&) = delete; // move assignment void incCounter(MessageLevel level); void decCounter(MessageLevel level); private: - std::unordered_map> m_detectors{}; std::unordered_map m_instances{}; - size_t m_errorCount{0}; - size_t m_warningCount{0}; + size_t m_errorCount{ 0 }; + size_t m_warningCount{ 0 }; - size_t m_nextDetector{0}; + size_t m_nextDetector{ 0 }; - QLayout* m_layout{nullptr}; + QLayout *m_layout{ nullptr }; }; } // namespace preferences diff --git a/src/plugins/preferences/files/fileswidget.cpp b/src/plugins/preferences/files/fileswidget.cpp index 0b75e77fa..6490edbe0 100644 --- a/src/plugins/preferences/files/fileswidget.cpp +++ b/src/plugins/preferences/files/fileswidget.cpp @@ -20,6 +20,7 @@ #include "fileswidget.h" #include "ui_fileswidget.h" +#include "common/inputdetectors.h" #include "common/commonutils.h" #include "filesitem.h" @@ -41,12 +42,18 @@ FilesWidget::FilesWidget(QWidget *parent, FilesItem *item) ui->setupUi(this); this->whitespaceDetector = ui->inputMessage->addDetector(std::unique_ptr(new WhitespaceDetector)); + this->emptyDetector = ui->inputMessage->addDetector(std::unique_ptr(new EmptyDetector)); ui->inputMessage->addInput("source_file"); ui->inputMessage->addInput("destination"); ui->inputMessage->attachDetector("source_file", whitespaceDetector, tr("source_file_whitespace")); + ui->inputMessage->attachDetector("source_file", emptyDetector, tr("source_file_empty"), InputMessageNotifier::MessageLevel::Error); + ui->inputMessage->attachDetector("destination", whitespaceDetector, tr("destination_whitespace")); + ui->inputMessage->attachDetector("destination", emptyDetector, tr("destination_empty"), InputMessageNotifier::MessageLevel::Error); + + ui->sourceLineEdit->setToolTip("test"); on_actionComboBox_currentIndexChanged(ui->actionComboBox->currentIndex()); } diff --git a/src/plugins/preferences/files/fileswidget.h b/src/plugins/preferences/files/fileswidget.h index ee2b40b45..e7593134f 100644 --- a/src/plugins/preferences/files/fileswidget.h +++ b/src/plugins/preferences/files/fileswidget.h @@ -84,6 +84,7 @@ private slots: bool fileMode {true}; size_t whitespaceDetector{0}; + size_t emptyDetector{0}; private: Ui::FilesWidget *ui {nullptr}; diff --git a/src/plugins/preferences/files/fileswidgetslots.cpp b/src/plugins/preferences/files/fileswidgetslots.cpp index 7b626db75..41796dadf 100644 --- a/src/plugins/preferences/files/fileswidgetslots.cpp +++ b/src/plugins/preferences/files/fileswidgetslots.cpp @@ -116,6 +116,7 @@ void FilesWidget::on_sourceLineEdit_textChanged(const QString &text) ui->destinationLabel->setText(tr("Destination folder:")); ui->inputMessage->setMessage("destination", this->whitespaceDetector, tr("destination_folder_whitespace")); + ui->inputMessage->setMessage("destination", this->emptyDetector, tr("destination_folder_empty")); } else { @@ -123,6 +124,7 @@ void FilesWidget::on_sourceLineEdit_textChanged(const QString &text) ui->destinationLabel->setText(tr("Destination file:")); ui->inputMessage->setMessage("destination", this->whitespaceDetector, tr("destination_whitespace")); + ui->inputMessage->setMessage("destination", this->emptyDetector, tr("destination_empty")); } ui->inputMessage->updateInput("source_file", text); } diff --git a/src/plugins/preferences/files/i18n/files_translation_en.ts b/src/plugins/preferences/files/i18n/files_translation_en.ts index 8d8f83ae4..1f6e5f3f4 100644 --- a/src/plugins/preferences/files/i18n/files_translation_en.ts +++ b/src/plugins/preferences/files/i18n/files_translation_en.ts @@ -134,28 +134,39 @@ preferences::FilesWidget - + + source_file_whitespace The input field of the source file contains a space at the beginning or at the end - - + destination_whitespace The input field of the destination file contains a space at the beginning or at the end - + + source_file_empty + An empty input field for the source file + + + + + destination_empty + An empty input field for the destination file + + + Please enter source file(s) value. Please enter source file(s) value. - + Please enter destination file(s) value. Please enter destination file(s) value. - + General General @@ -166,7 +177,7 @@ - + Destination file: Destination file: @@ -175,6 +186,11 @@ destination_folder_whitespace The input field of the destination folder contains a space at the beginning or at the end + + + destination_folder_empty + An empty input field for the destination folder + Open Open diff --git a/src/plugins/preferences/files/i18n/files_translation_ru.ts b/src/plugins/preferences/files/i18n/files_translation_ru.ts index ad31c85b9..4f46080c4 100644 --- a/src/plugins/preferences/files/i18n/files_translation_ru.ts +++ b/src/plugins/preferences/files/i18n/files_translation_ru.ts @@ -134,28 +134,39 @@ preferences::FilesWidget - + + source_file_whitespace Поле ввода исходного файла содержит пробел в начале или в конце - - + destination_whitespace Поле ввода целевого файла содержит пробел в начале или в конце - + + source_file_empty + Пустое поле ввода исходного файла + + + + + destination_empty + Пустое поле ввода файла назначения + + + Please enter source file(s) value. Пожалуйста, введите источник файла(ов). - + Please enter destination file(s) value. Пожалуйста, введите место назначения файла(ов). - + General Основные настройки @@ -166,7 +177,7 @@ - + Destination file: Место назначения файлов: @@ -175,6 +186,11 @@ destination_folder_whitespace Поле ввода целевой папки содержит пробел в начале или в конце + + + destination_folder_empty + Пустое поле ввода папки назначения + Open Открыть