diff --git a/src/plugins/preferences/CMakeLists.txt b/src/plugins/preferences/CMakeLists.txt
index 61b60c92c..ab355a0fb 100644
--- a/src/plugins/preferences/CMakeLists.txt
+++ b/src/plugins/preferences/CMakeLists.txt
@@ -196,6 +196,9 @@ set(HEADERS
common/preferencestreeproxymodel.h
common/preferenceswidget.h
+
+ common/inputmessagenotifier.h
+ common/inputdetectors.h
)
set(SOURCES
@@ -378,6 +381,9 @@ set(SOURCES
common/preferencestreeproxymodel.cpp
common/preferenceswidget.cpp
+
+ common/inputmessagenotifier.cpp
+ common/inputdetectors.cpp
)
set(UI_FORMS
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..3a06657eb 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,37 @@ 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..12e58cd79 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,37 @@ 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/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
new file mode 100644
index 000000000..8c3769d3e
--- /dev/null
+++ b/src/plugins/preferences/common/inputmessagenotifier.cpp
@@ -0,0 +1,206 @@
+/***********************************************************************************************************************
+**
+** 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"
+#include
+#include
+
+namespace preferences {
+
+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_label->hide();
+
+ 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;");
+ 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)
+{
+ 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) {
+ delete this->m_label;
+ }
+
+ 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::DetectElement::detect()
+{
+ this->m_label->show();
+ this->m_detected = true;
+}
+void InputMessageNotifier::DetectElement::undetect()
+{
+ this->m_label->hide();
+ this->m_detected = false;
+}
+
+bool InputMessageNotifier::DetectElement::detected()
+{
+ return this->m_detected;
+}
+
+InputMessageNotifier::MessageLevel InputMessageNotifier::DetectElement::level()
+{
+ return this->m_level;
+}
+
+void InputMessageNotifier::DetectElement::setMessage(const QString &message)
+{
+ this->m_label->setText(message);
+}
+
+InputMessageNotifier::DetectElement::~DetectElement()
+{
+ if (this->m_label) {
+ delete this->m_label;
+ }
+}
+
+InputMessageNotifier::InputMessageNotifier(QWidget *widget) : QWidget(widget)
+{
+ this->m_layout = new QVBoxLayout;
+ this->setLayout(this->m_layout);
+}
+
+size_t InputMessageNotifier::addDetector(std::unique_ptr detector)
+{
+ this->m_detectors[this->m_nextDetector] = std::move(detector);
+ return this->m_nextDetector++;
+}
+
+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);
+}
+
+void InputMessageNotifier::updateInput(const QString &name, const QString &input)
+{
+ auto &instance = this->m_instances[name];
+
+ for (auto &detect : instance) {
+ bool detected = this->m_detectors[detect.first]->detect(input);
+
+ if (detected && !detect.second.detected()) {
+ detect.second.detect();
+ this->incCounter(detect.second.level());
+ } 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)
+{
+ 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
new file mode 100644
index 000000000..23b06a7a9
--- /dev/null
+++ b/src/plugins/preferences/common/inputmessagenotifier.h
@@ -0,0 +1,164 @@
+/***********************************************************************************************************************
+**
+** 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
+#include
+
+namespace preferences {
+
+class InputDetector
+{
+public:
+ virtual bool detect(const QString &input) = 0;
+ virtual ~InputDetector() = default;
+};
+
+class InputMessageNotifier : public QWidget
+{
+public:
+ Q_OBJECT
+
+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);
+
+ void detect();
+ void undetect();
+
+ bool detected();
+ MessageLevel level();
+ void setMessage(const QString &message);
+
+ ~DetectElement();
+
+ private:
+ 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 };
+ } 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
+
+ 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_nextDetector{ 0 };
+
+ QLayout *m_layout{ nullptr };
+};
+
+} // namespace preferences
+
+#endif // GPUI_INPUTMESSAGENOTIFIER_H
diff --git a/src/plugins/preferences/files/fileswidget.cpp b/src/plugins/preferences/files/fileswidget.cpp
index 3c1b71e82..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"
@@ -40,6 +41,20 @@ 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 5a558a5d9..e7593134f 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:
@@ -82,6 +83,9 @@ 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/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 @@
QLineEditcommon/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..41796dadf 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->updateInput("destination", text);
+}
+
void FilesWidget::on_sourceLineEdit_textChanged(const QString &text)
{
if (text.contains('*') || text.contains('?'))
@@ -110,13 +115,18 @@ 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"));
+ ui->inputMessage->setMessage("destination", this->emptyDetector, tr("destination_folder_empty"));
}
else
{
fileMode = true;
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);
}
} // 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..1f6e5f3f4 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 actionsSupress errors on individual file actions
-
+ AttributesAttributes
-
+ Read-onlyRead-only
-
+ HiddenHidden
-
+ ArchiveArchive
-
+ ExecutableExecutable
@@ -120,13 +120,13 @@
Target
-
-
+
+ All files (*)All files (*)
-
+ All files (*.*)All files (*.*)
@@ -134,17 +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.
-
+ GeneralGeneral
@@ -155,10 +177,20 @@
-
+ Destination file:Destination file:
+
+
+ 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
+ OpenOpen
@@ -184,7 +216,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..4f46080c4 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,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Основные настройки
@@ -155,10 +177,20 @@
-
+ Destination file:Место назначения файлов:
+
+
+ destination_folder_whitespace
+ Поле ввода целевой папки содержит пробел в начале или в конце
+
+
+
+ destination_folder_empty
+ Пустое поле ввода папки назначения
+ OpenОткрыть
@@ -184,7 +216,7 @@
Открыть Директорию
-
+ Destination folder:Папка назначения: