Refactored validation

This commit is contained in:
Borna Rajković committed 2022-06-14 00:53:46 +02:00
1 parent fe4a39803c
commit 7be3a1b5bc
29 files changed
+696 -545

No files matched your search

+180
View File
@@ -0,0 +1,180 @@
#include "attribute_dialog.h"
#include "mainwindow.h"
#include "application.h"
#include "error_dialog.h"
#include "warning_dialog.h"
namespace display {
long long int parseInt(std::string expression) {
try {
if (expression.size() > 2) {
if (expression.substr(0, 2) == "0x") {
return std::stoll(expression, nullptr, 16);
} else if (expression.substr(0, 2) == "0b") {
return std::stoll(expression, nullptr, 2);
} else {
return std::stoll(expression, nullptr, 10);
}
} else {
return std::stoll(expression, nullptr, 10);
}
} catch (std::exception &e) {
return 0;
}
}
AttributeDialog::AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute):
GenericDialog(title, action), attributeValue(attribute), value(attribute->value), popup(*attribute->attribute.getPopup()) {
auto *contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
contentLayout->addWidget(new QLabel(popup.getTitle().c_str()));
contentLayout->addWidget(new QLabel(popup.getText().c_str()));
auto type = attribute->value.getType();
if(popup.isEnumerated()) {
contentLayout->addWidget(setupEnumeration());
} else if(type == domain::Value::INT || type == domain::Value::STRING) {
contentLayout->addWidget(setupLineEdit(type));
} else if(type == domain::Value::BOOL) {
contentLayout->addWidget(setupBool());
}
}
bool AttributeDialog::onUpdate() {
auto validationErrors = validate();
if (validationErrors.empty()) {
attributeValue->value = value;
return true;
}
std::vector<domain::ValidationError> errors, warnings;
for (auto &err: validationErrors) {
if (err.type == domain::Action::ERROR) {
errors.push_back(err);
} else {
warnings.push_back(err);
}
}
if (!errors.empty()) {
auto errorDialog = new ErrorDialog(errors);
errorDialog->exec();
return false;
}
bool canAccept = true;
for (auto &warning: warnings) {
auto warningDialog = new WarningDialog(warning);
int response = warningDialog->exec();
if (response == QDialog::Rejected) {
canAccept = false;
}
}
if(canAccept) {
attributeValue->value = value;
}
return canAccept;
}
void AttributeDialog::onTextChanged(const QString &string) {
switch (value.getType()) {
case domain::Value::STRING:
value.setString(string.toStdString());
break;
case domain::Value::INT:
value = domain::Value::fromInt(parseInt(string.toStdString()));
break;
default:
throw std::exception();
}
}
void AttributeDialog::onEnumerationChanged(int index) {
value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue();
}
QComboBox *AttributeDialog::setupEnumeration() {
auto *combo = new QComboBox(this);
auto enumeration = popup.getEnumeration();
for (auto entry: enumeration) {
combo->addItem(QString::fromStdString(entry.getName()));
}
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&AttributeDialog::onEnumerationChanged);
for (int i = 0; i < enumeration.size(); i++) {
if (attributeValue->value.equals(enumeration[i].getValue())) {
combo->setCurrentIndex(i);
break;
}
}
return combo;
}
QLineEdit *AttributeDialog::setupLineEdit(domain::Value::ValueType type) {
auto edit = new QLineEdit(this);
connect(edit, &QLineEdit::textChanged, this, &AttributeDialog::onTextChanged);
switch (type) {
case domain::Value::ValueType::INT:
edit->setValidator(new QIntValidator(-10000000, 10000000, edit));
edit->insert(std::to_string(value.asInt()).c_str());
break;
case domain::Value::ValueType::STRING:
edit->insert(value.asString().c_str());
break;
}
return edit;
}
QGroupBox *AttributeDialog::setupBool() {
auto *group = new QGroupBox(this);
auto *radioLayout = new QHBoxLayout(group);
group->setLayout(radioLayout);
auto isTrue = new QRadioButton("da", group);
connect(isTrue, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(true);
});
auto isFalse = new QRadioButton("ne", group);
connect(isFalse, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(false);
});
if (value.asBool()) {
isTrue->setChecked(true);
} else {
isFalse->setChecked(true);
}
radioLayout->addWidget(isTrue);
radioLayout->addWidget(isFalse);
return group;
}
std::vector<domain::ValidationError> AttributeDialog::validate() {
domain::ComdelValidator validator(domain::getSupportedValidators());
auto currentValue = attributeValue->value;
attributeValue->value = value;
domain::ValidationContext context;
for (auto &addressSpace: Application::instance()->getLibrary()->getAddressSpaces()) {
context.addressSpaces.insert(std::make_pair(addressSpace.getName(), addressSpace));
}
auto errors = validator.validateAttribute(attributeValue, context);
attributeValue->value = currentValue;
return errors;
}
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef ATTRIBUTE_DIALOG_H
#define ATTRIBUTE_DIALOG_H
#include <QIntValidator>
#include <QPushButton>
#include <QComboBox>
#include <QGroupBox>
#include <QRadioButton>
#include <QDialog>
#include <QLineEdit>
#include <QLabel>
#include <QVBoxLayout>
#include <utility>
#include "comdel/domain/instance_attribute.h"
#include "comdel/domain/value.h"
#include "comdel/domain/comdel_validator.h"
#include "generic_dialog.h"
namespace display {
class AttributeDialog : public GenericDialog {
public:
AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute);
public slots:
void onTextChanged(const QString &string);
void onEnumerationChanged(int index);
protected:
bool onUpdate() override;
private:
QComboBox *setupEnumeration();
QLineEdit *setupLineEdit(domain::Value::ValueType type);
QGroupBox *setupBool();
std::vector<domain::ValidationError> validate();
domain::Value value;
domain::InstanceAttribute *attributeValue;
domain::Popup popup;
};
}
#endif //ATTRIBUTE_DIALOG_H
+34
View File
@@ -0,0 +1,34 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QPlainTextEdit>
#include "error_dialog.h"
namespace display {
ErrorDialog::ErrorDialog(std::vector<domain::ValidationError> errors)
: GenericDialog("Greške", "") {
auto contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
for (auto &err: errors) {
contentLayout->addWidget(new QLabel(QString::fromStdString(err.message), this));
}
}
ErrorDialog::ErrorDialog(std::ostringstream& errorStream)
: GenericDialog("Greške", "") {
auto contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
setMinimumWidth(1000);
auto log = new QPlainTextEdit();
log->setFont(QFont("Courier"));
log->appendPlainText(QString::fromStdString(errorStream.str()));
log->setReadOnly(true);
contentLayout->addWidget(log);
}
} // display
+22
View File
@@ -0,0 +1,22 @@
#ifndef SCHEMEEDITOR_ERROR_DIALOG_H
#define SCHEMEEDITOR_ERROR_DIALOG_H
#include "generic_dialog.h"
#include "comdel/domain/comdel_validator.h"
#include <sstream>
namespace display {
class ErrorDialog : public GenericDialog {
public:
ErrorDialog(std::vector<domain::ValidationError> errors);
ErrorDialog(std::ostringstream& errorStream);
protected:
bool onUpdate() override { return true; }
};
} // display
#endif //SCHEMEEDITOR_ERROR_DIALOG_H
+29
View File
@@ -0,0 +1,29 @@
#include <QVBoxLayout>
#include "generic_dialog.h"
display::GenericDialog::GenericDialog(std::string title, std::string action) {
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(QString::fromStdString(title));
setLayout(new QVBoxLayout());
content = new QWidget(this);
layout()->addWidget(content);
auto actionWidget = new QWidget(this);
auto actionBar = new QHBoxLayout(actionWidget);
layout()->addWidget(actionWidget);
// if action isn't defined only close button is offered
if(!action.empty()) {
okButton = new QPushButton(QString::fromStdString(action), this);
connect(okButton, &QPushButton::clicked, this, [this](){if(this->onUpdate()) this->accept();});
actionBar->addWidget(okButton);
}
cancelButton = new QPushButton("Odustani", this);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
actionBar->addWidget(cancelButton);
}
void display::GenericDialog::setOkButtonDisabled(bool disabled) {
okButton->setDisabled(disabled);
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef SCHEMEEDITOR_GENERIC_DIALOG_H
#define SCHEMEEDITOR_GENERIC_DIALOG_H
#include <QDialog>
#include <QWidget>
#include <QPushButton>
namespace display {
class GenericDialog: public QDialog {
public:
GenericDialog(std::string title, std::string action = "Ažuriraj");
protected:
void setOkButtonDisabled(bool disabled);
virtual bool onUpdate() = 0;
private:
QPushButton *okButton;
QPushButton *cancelButton;
protected:
QWidget *content;
};
}
#endif //SCHEMEEDITOR_GENERIC_DIALOG_H
+59
View File
@@ -0,0 +1,59 @@
#include <QVBoxLayout>
#include <QLabel>
#include "memory_dialog.h"
namespace display {
MemoryDialog::MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute,
std::vector<std::shared_ptr<domain::ComponentInstance>> instances)
: GenericDialog(title, action), value(attribute->value), attributeValue(attribute), popup(*attribute->attribute.getPopup()) {
for (auto &instance: instances) {
if (instance->component.getType() == domain::Component::MEMORY) {
memoryInstances.push_back(instance->name);
}
}
auto contentLayout = new QVBoxLayout(content);
content->setLayout(contentLayout);
contentLayout->addWidget(new QLabel(popup.getTitle().c_str()));
contentLayout->addWidget(new QLabel(popup.getText().c_str()));
contentLayout->addWidget(setupEnumeration());
}
bool MemoryDialog::onUpdate() {
attributeValue->value = value;
return true;
}
QComboBox *MemoryDialog::setupEnumeration() {
auto *combo = new QComboBox(this);
for (const auto& entry: memoryInstances) {
combo->addItem(QString::fromStdString(entry));
}
combo->addItem("null");
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
if(index == memoryInstances.size()) {
value = domain::Value::fromMemoryReference(std::nullopt);
} else {
value = domain::Value::fromMemoryReference(this->memoryInstances[index]);
}
});
combo->setCurrentIndex(memoryInstances.size());
for (int i = 0; i < memoryInstances.size(); i++) {
if (attributeValue->value.equals(domain::Value::fromMemoryReference(memoryInstances[i]))) {
combo->setCurrentIndex(i);
break;
}
}
return combo;
}
} // display
+33
View File
@@ -0,0 +1,33 @@
#ifndef SCHEMEEDITOR_MEMORY_DIALOG_H
#define SCHEMEEDITOR_MEMORY_DIALOG_H
#include <QComboBox>
#include "generic_dialog.h"
#include "comdel/domain/instance_attribute.h"
#include "comdel/domain/instance.h"
namespace display {
class MemoryDialog : public GenericDialog {
public:
MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute,
std::vector<std::shared_ptr<domain::ComponentInstance>> instances);
protected:
bool onUpdate() override;
private:
QComboBox *setupEnumeration();
domain::Value value;
domain::InstanceAttribute *attributeValue;
std::vector<std::string> memoryInstances;
domain::Popup popup;
};
} // display
#endif //SCHEMEEDITOR_MEMORY_DIALOG_H
+39
View File
@@ -0,0 +1,39 @@
#include <set>
#include "name_dialog.h"
namespace display {
NameDialog::NameDialog(std::string currentName, std::set<std::string> &names)
: GenericDialog("Izmjeni ime", "Izmjeni"), currentName(currentName), usedNames(names) {
usedNames.erase(currentName);
auto *contentLayout = new QVBoxLayout();
contentLayout->addWidget(new QLabel("Izmjeni ime", this));
edit = new QLineEdit(this);
edit->insert(currentName.c_str());
connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate);
contentLayout->addWidget(edit);
content->setLayout(contentLayout);
}
void NameDialog::onNameUpdate(const QString &text) {
if(usedNames.find(text.toStdString()) == usedNames.end()) {
setOkButtonDisabled(false);
} else {
setOkButtonDisabled(true);
}
}
std::string NameDialog::getName() {
return currentName;
}
bool NameDialog::onUpdate() {
currentName = edit->text().toStdString();
return true;
}
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef NAME_DIALOG_H
#define NAME_DIALOG_H
#include <QDialog>
#include <QLabel>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <set>
#include "comdel/domain/instance.h"
#include "generic_dialog.h"
namespace display {
class NameDialog : public GenericDialog {
public:
NameDialog(std::string currentName, std::set<std::string>& names);
std::string getName();
protected:
bool onUpdate() override;
public slots:
void onNameUpdate(const QString& text);
private:
std::set<std::string> usedNames;
QLineEdit *edit = nullptr;
std::string currentName;
};
}
#endif //NAME_DIALOG_H
@@ -0,0 +1,65 @@
#include "single_automatic_dialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QComboBox>
#include <QPushButton>
namespace display {
SingleAutomaticDialog::SingleAutomaticDialog(std::string title, std::string action,
std::vector<domain::InstanceAttribute> &values)
: GenericDialog(title, action), attributes(values) {
firstValue = values[0].value;
secondValue = values[1].value;
auto *contentLayout = new QHBoxLayout();
auto *firstLayout = new QVBoxLayout();
auto *secondLayout = new QVBoxLayout();
content->setLayout(contentLayout);
contentLayout->addLayout(firstLayout);
contentLayout->addLayout(secondLayout);
setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged);
setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged);
}
void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) {
auto popup = *attribute.attribute.getPopup();
layout->addWidget(new QLabel(popup.getTitle().c_str()));
layout->addWidget(new QLabel(popup.getText().c_str()));
auto *combo = new QComboBox(this);
auto enumeration = attribute.attribute.getPopup()->getEnumeration();
for (auto entry: enumeration) {
combo->addItem(QString::fromStdString(entry.getName()));
}
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,handler);
layout->addWidget(combo);
for (int i = 0; i < enumeration.size(); i++) {
if (attribute.value.equals(enumeration[i].getValue())) {
combo->setCurrentIndex(i);
break;
}
}
}
void SingleAutomaticDialog::onFirstEnumerationChanged(int index) {
firstValue = attributes[0].attribute.getPopup()->getEnumeration()[index].getValue();
}
void SingleAutomaticDialog::onSecondEnumerationChanged(int index) {
secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue();
}
bool SingleAutomaticDialog::onUpdate() {
attributes[0].value = firstValue;
attributes[1].value = secondValue;
return true;
}
} // display
@@ -0,0 +1,36 @@
#ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
#define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
#include <vector>
#include <QDialog>
#include <QVBoxLayout>
#include "comdel/domain/value.h"
#include "comdel/domain/instance_attribute.h"
#include "generic_dialog.h"
namespace display {
class SingleAutomaticDialog: public GenericDialog {
domain::Value firstValue;
domain::Value secondValue;
std::vector<domain::InstanceAttribute> &attributes;
public:
explicit SingleAutomaticDialog(
std::string title,
std::string action,
std::vector<domain::InstanceAttribute>& values);
protected:
bool onUpdate() override;
void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int));
public slots:
void onFirstEnumerationChanged(int index);
void onSecondEnumerationChanged(int index);
};
} // display
#endif //SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
+17
View File
@@ -0,0 +1,17 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include "success_dialog.h"
namespace display {
SuccessDialog::SuccessDialog(std::string message, std::string action) {
setLayout(new QVBoxLayout());
layout()->addWidget(new QLabel(QString::fromStdString(message)));
auto button = new QPushButton(QString::fromStdString(action));
connect(button, &QPushButton::clicked, [this]() {accept();});
layout()->addWidget(button);
}
} // display
+19
View File
@@ -0,0 +1,19 @@
//
// Created by bbr on 14.06.22..
//
#ifndef SCHEMEEDITOR_SUCCESS_DIALOG_H
#define SCHEMEEDITOR_SUCCESS_DIALOG_H
#include <QDialog>
namespace display {
class SuccessDialog: public QDialog {
public:
explicit SuccessDialog(std::string message, std::string action = "Ok");
};
} // display
#endif //SCHEMEEDITOR_SUCCESS_DIALOG_H
+16
View File
@@ -0,0 +1,16 @@
#include <QVBoxLayout>
#include <QLabel>
#include "warning_dialog.h"
namespace display {
WarningDialog::WarningDialog(domain::ValidationError error)
: GenericDialog("Upozorenje", "U redu") {
auto contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
contentLayout->addWidget(new QLabel(QString::fromStdString(error.message), this));
}
} // display
+20
View File
@@ -0,0 +1,20 @@
#ifndef SCHEMEEDITOR_WARNING_DIALOG_H
#define SCHEMEEDITOR_WARNING_DIALOG_H
#include "generic_dialog.h"
#include "comdel/domain/comdel_validator.h"
namespace display {
class WarningDialog : public GenericDialog {
public:
WarningDialog(domain::ValidationError error);
protected:
bool onUpdate() override { return true; };
};
} // display
#endif //SCHEMEEDITOR_WARNING_DIALOG_H