Compare commits
	
		
			No commits in common. "master" and "code_cleanup" have entirely different histories.
		
	
	
		
			master
			...
			code_clean
		
	
		
| @ -37,5 +37,5 @@ add_executable(SchemeEditor | ||||
|         comdel/parser/comdel_lexer.cpp | ||||
|   main.cpp | ||||
|   mainwindow.ui | ||||
|         comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/dialog/attribute_dialog.cpp comdel/display/dialog/attribute_dialog.h comdel/display/dialog/name_dialog.cpp comdel/display/dialog/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/dialog/single_automatic_dialog.cpp comdel/display/dialog/single_automatic_dialog.h comdel/parser/color.h comdel/display/dialog/generic_dialog.cpp comdel/display/dialog/generic_dialog.h comdel/display/dialog/warning_dialog.cpp comdel/display/dialog/warning_dialog.h comdel/display/dialog/error_dialog.cpp comdel/display/dialog/error_dialog.h comdel/display/dialog/memory_dialog.cpp comdel/display/dialog/memory_dialog.h comdel/display/dialog/success_dialog.cpp comdel/display/dialog/success_dialog.h message_source.cpp message_source.h) | ||||
|         comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h) | ||||
| target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets) | ||||
|  | ||||
| @ -9,18 +9,13 @@ CONFIG += c++17 | ||||
| #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0 | ||||
| 
 | ||||
| SOURCES += \ | ||||
|     comdel/display/dialog/attribute_dialog.cpp \ | ||||
|     comdel/display/dialog/error_dialog.cpp \ | ||||
|     comdel/display/dialog/generic_dialog.cpp \ | ||||
|     comdel/display/dialog/memory_dialog.cpp \ | ||||
|     comdel/display/dialog/name_dialog.cpp \ | ||||
|     comdel/display/dialog/single_automatic_dialog.cpp \ | ||||
|     comdel/display/dialog/success_dialog.cpp \ | ||||
|     comdel/display/dialog/warning_dialog.cpp \ | ||||
|     comdel/display/attribute_dialog.cpp \ | ||||
|     comdel/display/component_display.cpp \ | ||||
|     comdel/display/library_display.cpp \ | ||||
|     comdel/display/library_list.cpp \ | ||||
|     comdel/display/name_dialog.cpp \ | ||||
|     comdel/display/schema_display.cpp \ | ||||
|     comdel/display/single_automatic_dialog.cpp \ | ||||
|     comdel/domain/address_space.cpp \ | ||||
|     comdel/domain/attribute.cpp \ | ||||
|     comdel/domain/bus.cpp \ | ||||
| @ -49,22 +44,16 @@ SOURCES += \ | ||||
|     comdel/parser/tokens_type.cpp \ | ||||
|     application.cpp \ | ||||
|     main.cpp \ | ||||
|     message_source.cpp \ | ||||
|     mainwindow.cpp | ||||
| 
 | ||||
| HEADERS += \ | ||||
|     comdel/display/dialog/attribute_dialog.h \ | ||||
|     comdel/display/dialog/error_dialog.h \ | ||||
|     comdel/display/dialog/generic_dialog.h \ | ||||
|     comdel/display/dialog/memory_dialog.h \ | ||||
|     comdel/display/dialog/name_dialog.h \ | ||||
|     comdel/display/dialog/single_automatic_dialog.h \ | ||||
|     comdel/display/dialog/success_dialog.h \ | ||||
|     comdel/display/dialog/warning_dialog.h \ | ||||
|     comdel/display/attribute_dialog.h \ | ||||
|     comdel/display/component_display.h \ | ||||
|     comdel/display/library_display.h \ | ||||
|     comdel/display/library_list.h \ | ||||
|     comdel/display/name_dialog.h \ | ||||
|     comdel/display/schema_display.h \ | ||||
|     comdel/display/single_automatic_dialog.h \ | ||||
|     comdel/domain/address_space.h \ | ||||
|     comdel/domain/attribute.h \ | ||||
|     comdel/domain/bus.h \ | ||||
| @ -94,7 +83,6 @@ HEADERS += \ | ||||
|     comdel/parser/source_error.h \ | ||||
|     comdel/parser/token.h \ | ||||
|     comdel/parser/tokens_type.h \ | ||||
|     message_source.h \ | ||||
|     mainwindow.h | ||||
| 
 | ||||
| FORMS += \ | ||||
|  | ||||
| @ -90,7 +90,7 @@ std::pair<bool, std::vector<domain::ValidationError>> Application::loadSchema(st | ||||
|         } | ||||
| 
 | ||||
|     } else { | ||||
|         errorOutput << "Failed schema library" << std::endl; | ||||
|         errorOutput << "Failed parsing library" << std::endl; | ||||
|         return {false, errors}; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										283
									
								
								comdel/display/attribute_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								comdel/display/attribute_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,283 @@ | ||||
| //
 | ||||
| // Created by bbr on 18. 04. 2022..
 | ||||
| //
 | ||||
| 
 | ||||
| #include "attribute_dialog.h" | ||||
| #include "mainwindow.h" | ||||
| 
 | ||||
| #include "application.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     AttributeDialog::AttributeDialog(domain::InstanceAttribute *attribute, bool updating) { | ||||
| 
 | ||||
|         setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|         attributeValue = attribute; | ||||
| 
 | ||||
|         auto actionType = updating ? "Izmjeni " : "Postavi "; | ||||
| 
 | ||||
|         this->setWindowTitle(QString::fromStdString(actionType + attribute->attribute.getName())); | ||||
| 
 | ||||
|         auto layout = new QVBoxLayout(this); | ||||
|         this->setLayout(layout); | ||||
|         auto popup = *attribute->attribute.getPopup(); | ||||
| 
 | ||||
|         layout->addWidget(new QLabel(popup.getTitle().c_str())); | ||||
|         layout->addWidget(new QLabel(popup.getText().c_str())); | ||||
| 
 | ||||
|         auto type = attribute->attribute.getDefault().getType(); | ||||
|         value = attribute->value; | ||||
| 
 | ||||
|         if (attribute->attribute.getPopup()->isEnumerated()) { | ||||
|             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, | ||||
|                     &AttributeDialog::onEnumerationChanged); | ||||
|             layout->addWidget(combo); | ||||
| 
 | ||||
|             for (int i = 0; i < enumeration.size(); i++) { | ||||
|                 if (attributeValue->value.equals(enumeration[i].getValue())) { | ||||
|                     combo->setCurrentIndex(i); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } else if (!(type == domain::Value::ValueType::WIRE_REFERENCE || type == domain::Value::ValueType::BOOL)) { | ||||
| 
 | ||||
|             auto edit = new QLineEdit(this); | ||||
|             connect(edit, &QLineEdit::textChanged, this, &AttributeDialog::onTextChanged); | ||||
|             layout->addWidget(edit); | ||||
| 
 | ||||
|             switch (attribute->attribute.getDefault().getType()) { | ||||
|                 case domain::Value::ValueType::INT: | ||||
|                     edit->setValidator(new QIntValidator(-10000000, 10000000, edit)); | ||||
|                     edit->insert(std::to_string(attribute->value.asInt()).c_str()); | ||||
|                     break; | ||||
|                 case domain::Value::ValueType::STRING: | ||||
|                     edit->insert(attribute->value.asString().c_str()); | ||||
|                     break; | ||||
|                 default: | ||||
|                     throw std::exception(); | ||||
|             } | ||||
| 
 | ||||
|         } else if (type == domain::Value::ValueType::BOOL) { | ||||
|             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 (attribute->value.asBool()) { | ||||
|                 isTrue->setChecked(true); | ||||
|             } else { | ||||
|                 isFalse->setChecked(true); | ||||
|             } | ||||
| 
 | ||||
|             radioLayout->addWidget(isTrue); | ||||
|             radioLayout->addWidget(isFalse); | ||||
|             layout->addWidget(group); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         auto buttonLayout = new QHBoxLayout(this); | ||||
| 
 | ||||
|         auto okButton = new QPushButton(updating ? "Ažuriraj" : "Postavi", this); | ||||
|         auto cancelButton = new QPushButton("Odustani", this); | ||||
| 
 | ||||
|         connect(okButton, &QPushButton::clicked, this, &AttributeDialog::onUpdate); | ||||
|         connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
| 
 | ||||
|         buttonLayout->addWidget(okButton); | ||||
|         buttonLayout->addWidget(cancelButton); | ||||
| 
 | ||||
|         layout->addLayout(buttonLayout); | ||||
|     } | ||||
| 
 | ||||
|     void AttributeDialog::onUpdate() { | ||||
|         auto oldValue = attributeValue->value; | ||||
| 
 | ||||
|         attributeValue->value = value; | ||||
|         domain::ComdelValidator validator(domain::getSupportedValidators()); | ||||
| 
 | ||||
|         domain::ValidationContext context; | ||||
| 
 | ||||
|         for (auto &addressSpace: Application::instance()->getLibrary()->getAddressSpaces()) { | ||||
|             context.addressSpaces.insert(std::make_pair(addressSpace.getName(), addressSpace)); | ||||
|         } | ||||
| 
 | ||||
|         auto validationErrors = validator.validateAttribute(attributeValue, context); | ||||
|         if (validationErrors.empty()) { | ||||
|             accept(); | ||||
|         } else { | ||||
|             bool canAccept = true; | ||||
| 
 | ||||
|             std::vector<domain::ValidationError> errors; | ||||
|             std::vector<domain::ValidationError> warnings; | ||||
|             for (auto &err: validationErrors) { | ||||
|                 if (err.type == domain::Action::ERROR) { | ||||
|                     errors.push_back(err); | ||||
|                 } else { | ||||
|                     warnings.push_back(err); | ||||
|                 } | ||||
|             } | ||||
|             if (!errors.empty()) { | ||||
|                 canAccept = false; | ||||
|                 auto errorDialog = new ErrorDialog(errors); | ||||
|                 errorDialog->exec(); | ||||
|             } | ||||
| 
 | ||||
|             for (auto &warning: warnings) { | ||||
|                 auto warningDialog = new WarningDialog(warning); | ||||
|                 int response = warningDialog->exec(); | ||||
|                 if (response == QDialog::Rejected) { | ||||
|                     canAccept = false; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (canAccept) { | ||||
|                 accept(); | ||||
|             } else { | ||||
|                 attributeValue->value = oldValue; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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(); | ||||
|     } | ||||
| 
 | ||||
|     MemoryDialog::MemoryDialog(domain::InstanceAttribute *attribute, | ||||
|                                std::vector<std::shared_ptr<domain::ComponentInstance>> instances, bool updating) { | ||||
|         memoryInstances = std::vector<std::string>(); | ||||
| 
 | ||||
|         setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|         attributeValue = attribute; | ||||
| 
 | ||||
|         auto actionType = updating ? "Izmjeni memoriju" : "Postavi memoriju"; | ||||
| 
 | ||||
|         this->setWindowTitle(QString::fromStdString(actionType)); | ||||
| 
 | ||||
|         for (auto &instance: instances) { | ||||
|             if (instance->component.getType() == domain::Component::MEMORY) { | ||||
|                 memoryInstances.push_back(instance->name); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         auto layout = new QVBoxLayout(this); | ||||
|         this->setLayout(layout); | ||||
|         auto popup = *attribute->attribute.getPopup(); | ||||
| 
 | ||||
|         layout->addWidget(new QLabel(popup.getTitle().c_str())); | ||||
|         layout->addWidget(new QLabel(popup.getText().c_str())); | ||||
| 
 | ||||
|         value = attribute->value; | ||||
| 
 | ||||
|         auto *combo = new QComboBox(this); | ||||
|         for (auto &entry: memoryInstances) { | ||||
|             combo->addItem(QString::fromStdString(entry)); | ||||
|         } | ||||
|         combo->addItem("null"); | ||||
| 
 | ||||
|         connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MemoryDialog::onMemoryChanged); | ||||
|         layout->addWidget(combo); | ||||
| 
 | ||||
|         combo->setCurrentIndex(memoryInstances.size()); | ||||
|         for (int i = 0; i < memoryInstances.size(); i++) { | ||||
|             if (attributeValue->value.asMemoryReference().has_value() && | ||||
|                 attributeValue->value.asMemoryReference() == memoryInstances[i]) { | ||||
|                 combo->setCurrentIndex(i); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         auto buttonLayout = new QHBoxLayout(this); | ||||
| 
 | ||||
|         auto okButton = new QPushButton(updating ? "Ažuriraj" : "Postavi"); | ||||
|         auto cancelButton = new QPushButton("Odustani", this); | ||||
| 
 | ||||
|         connect(okButton, &QPushButton::clicked, this, &MemoryDialog::onUpdate); | ||||
|         connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
| 
 | ||||
|         buttonLayout->addWidget(okButton); | ||||
|         buttonLayout->addWidget(cancelButton); | ||||
| 
 | ||||
|         layout->addLayout(buttonLayout); | ||||
|     } | ||||
| 
 | ||||
|     void MemoryDialog::onUpdate() { | ||||
|         attributeValue->value = value; | ||||
|         accept(); | ||||
|     } | ||||
| 
 | ||||
|     void MemoryDialog::onMemoryChanged(int index) { | ||||
|         if (index == memoryInstances.size()) { | ||||
|             value = domain::Value::fromMemoryReference(std::nullopt); | ||||
|         } else { | ||||
|             value = domain::Value::fromMemoryReference(memoryInstances[index]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ErrorDialog::ErrorDialog(std::vector<domain::ValidationError> errors) { | ||||
|         setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|         this->setWindowTitle("Greške"); | ||||
| 
 | ||||
|         auto layout = new QVBoxLayout(this); | ||||
|         this->setLayout(layout); | ||||
| 
 | ||||
|         for (auto &err: errors) { | ||||
|             layout->addWidget(new QLabel(QString::fromStdString(err.message), this)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     WarningDialog::WarningDialog(domain::ValidationError error) { | ||||
|         setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|         this->setWindowTitle("Upozorenje"); | ||||
| 
 | ||||
|         auto layout = new QVBoxLayout(this); | ||||
|         this->setLayout(layout); | ||||
| 
 | ||||
|         layout->addWidget(new QLabel(QString::fromStdString(error.message), this)); | ||||
| 
 | ||||
|         auto buttonLayout = new QHBoxLayout(this); | ||||
| 
 | ||||
|         auto okButton = new QPushButton("U redu", this); | ||||
|         auto cancelButton = new QPushButton("Odustani", this); | ||||
| 
 | ||||
|         connect(okButton, &QPushButton::clicked, [this]() { accept(); }); | ||||
|         connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
| 
 | ||||
|         buttonLayout->addWidget(okButton); | ||||
|         buttonLayout->addWidget(cancelButton); | ||||
| 
 | ||||
|         layout->addLayout(buttonLayout); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										89
									
								
								comdel/display/attribute_dialog.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								comdel/display/attribute_dialog.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | ||||
| #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" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class AttributeDialog : public QDialog { | ||||
|         domain::Value value; | ||||
| 
 | ||||
|         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; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         domain::InstanceAttribute *attributeValue; | ||||
| 
 | ||||
|     public: | ||||
|         AttributeDialog(domain::InstanceAttribute *attribute, bool updating = true); | ||||
| 
 | ||||
|     public slots: | ||||
| 
 | ||||
|         void onTextChanged(const QString &string); | ||||
| 
 | ||||
|         void onEnumerationChanged(int index); | ||||
| 
 | ||||
|         void onUpdate(); | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class MemoryDialog : public QDialog { | ||||
|         domain::Value value; | ||||
| 
 | ||||
|         domain::InstanceAttribute *attributeValue; | ||||
|         std::vector<std::string> memoryInstances; | ||||
| 
 | ||||
|     public: | ||||
|         MemoryDialog(domain::InstanceAttribute *attribute, | ||||
|                      std::vector<std::shared_ptr<domain::ComponentInstance>> instances, bool updating = true); | ||||
| 
 | ||||
|     public slots: | ||||
| 
 | ||||
|         void onMemoryChanged(int index); | ||||
| 
 | ||||
|         void onUpdate(); | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class ErrorDialog : public QDialog { | ||||
|     public: | ||||
|         ErrorDialog(std::vector<domain::ValidationError> errors); | ||||
|     }; | ||||
| 
 | ||||
|     class WarningDialog : public QDialog { | ||||
|     public: | ||||
|         WarningDialog(domain::ValidationError error); | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif //ATTRIBUTE_DIALOG_H
 | ||||
| @ -1,11 +1,9 @@ | ||||
| #include "component_display.h" | ||||
| #include "comdel/display/dialog/attribute_dialog.h" | ||||
| #include "comdel/display/dialog/name_dialog.h" | ||||
| #include "attribute_dialog.h" | ||||
| #include "name_dialog.h" | ||||
| #include "mainwindow.h" | ||||
| #include "application.h" | ||||
| #include "comdel/display/dialog/single_automatic_dialog.h" | ||||
| #include "comdel/display/dialog/memory_dialog.h" | ||||
| #include "message_source.h" | ||||
| #include "single_automatic_dialog.h" | ||||
| 
 | ||||
| #include <QMenu> | ||||
| #include <QLine> | ||||
| @ -20,13 +18,13 @@ namespace display { | ||||
| 
 | ||||
|     Component::Component(const std::shared_ptr<domain::ComponentInstance> &instance): instance(instance) { | ||||
|         setFlag(ItemSendsGeometryChanges, true); | ||||
|         setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName())); | ||||
|         instance->component.getDisplay().render(this, domain::ui::DisplayContext(instance.get())); | ||||
|         setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getName())); | ||||
|         instance->component.getDisplay().render(this); | ||||
|     } | ||||
| 
 | ||||
|     void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { | ||||
|         QMenu menu; | ||||
|         menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() { | ||||
|         menu.addAction("Izmjeni ime", [this]() { | ||||
|             std::set<std::string> names; | ||||
|             for(const auto &component: Application::instance()->getSchema()->componentInstances) { | ||||
|                 names.insert(component->name); | ||||
| @ -38,7 +36,7 @@ namespace display { | ||||
|             auto newName = dialog->getName(); | ||||
| 
 | ||||
|             Application::instance()->renameComponent(currentName, newName); | ||||
|             setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName())); | ||||
|             setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getName())); | ||||
|         }); | ||||
|         menu.addSeparator(); | ||||
|         for (int i = 0; i < this->instance->attributes.size(); i++) { | ||||
| @ -46,29 +44,22 @@ namespace display { | ||||
|             bool enabled = attr->attribute.getPopup().has_value(); | ||||
| 
 | ||||
|             if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) { | ||||
|                 menu.addAction(QMESSAGE("msg_dialog_memory_update"), [attr]() { | ||||
|                     auto dialog = new MemoryDialog(MESSAGE("msg_dialog_memory_update"), | ||||
|                                                    MESSAGE("msg_dialog_actions_update"), | ||||
|                                                    attr, | ||||
|                 menu.addAction("Izmjeni memoriju", [attr]() { | ||||
|                     auto dialog = new MemoryDialog(attr, | ||||
|                                                    Application::instance()->getSchema()->componentInstances); | ||||
|                     dialog->exec(); | ||||
|                 }); | ||||
|             } else { | ||||
|                 std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}}; | ||||
|                 auto action = menu.addAction(QMESSAGE_PARAM("msg_dialog_attribute_update", params), | ||||
|                     [attr]() { | ||||
|                         std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}}; | ||||
|                         auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_update", params), | ||||
|                                                           "msg_dialog_actions_update", | ||||
|                                                           attr); | ||||
|                         dialog->exec(); | ||||
|                 }); | ||||
|                 auto action = menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"), | ||||
|                                              [attr]() { | ||||
|                                                 auto dialog = new AttributeDialog(attr); | ||||
|                                                 dialog->exec(); | ||||
|                                              }); | ||||
|                 action->setEnabled(enabled); | ||||
|             } | ||||
|         } | ||||
|         menu.addSeparator(); | ||||
|         std::map<std::string, std::string> params = {{"name", instance->name}}; | ||||
|         menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() { | ||||
|         menu.addAction(QString::fromStdString("Ukloni " + this->instance->name), [this]() { | ||||
|             Application::instance()->removeComponent(this->instance->name); | ||||
|             auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|             view->refreshContent(); | ||||
| @ -83,28 +74,19 @@ namespace display { | ||||
|         auto pinConnections = Application::instance()->getSchema()->getConnections(componentInstance->name, pin.getName()); | ||||
| 
 | ||||
|         if(isSingleAutomatic(pinConnections)) { | ||||
|             auto *update = menu.addMenu(QMESSAGE("msg_pin_update")); | ||||
|             auto *remove = menu.addMenu(QMESSAGE("msg_pin_remove")); | ||||
|             auto *update = menu.addMenu("Izmjeni"); | ||||
|             auto *remove = menu.addMenu("Ukloni"); | ||||
|             for (auto pinConnection: pinConnections) { | ||||
|                 // this always must be true as only directConnections can be connected multiple times
 | ||||
|                 if (auto directConnection = dynamic_cast<domain::DirectConnectionInstance *>(pinConnection)) { | ||||
|                     if (directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC) { | ||||
|                         auto params = MessageSource::instance()->map( | ||||
|                                 {{"wire1", directConnection->attributes[0].value}, | ||||
|                                  {"wire2", directConnection->attributes[1].value}} | ||||
|                         ); | ||||
|                         update->addAction(QMESSAGE_PARAM("msg_sa_pin_update_title", params), | ||||
|                                           [directConnection]() { | ||||
|                             auto params = MessageSource::instance()->map( | ||||
|                                     {{"wire1", directConnection->attributes[0].value}, | ||||
|                                      {"wire2", directConnection->attributes[1].value}} | ||||
|                             ); | ||||
|                             auto dialog = new SingleAutomaticDialog(MESSAGE_PARAM("msg_sa_pin_update_title", params), | ||||
|                                                                     MESSAGE("msg_pin_update_action"), | ||||
|                                                                     directConnection->attributes); | ||||
|                         auto connectionName = directConnection->attributes[0].value.stringify() + "-" + | ||||
|                                               directConnection->attributes[1].value.stringify(); | ||||
|                         update->addAction(QString::fromStdString("Izmjeni " + connectionName), [directConnection]() { | ||||
|                             auto dialog = new SingleAutomaticDialog(directConnection->attributes); | ||||
|                             dialog->exec(); | ||||
|                         }); | ||||
|                         remove->addAction(QMESSAGE_PARAM("msg_sa_pin_remove_title", params), | ||||
|                         remove->addAction(QString::fromStdString("Ukloni " + connectionName), | ||||
|                                           [this, directConnection]() { | ||||
|                                               Application::instance()->removeConnection(directConnection); | ||||
|                                               auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
| @ -113,7 +95,7 @@ namespace display { | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } else if(!pinConnections.empty()) { | ||||
|         } else { | ||||
|             auto pinConnection = pinConnections[0]; | ||||
|             if(auto busConnection = dynamic_cast<domain::BusConnectionInstance*>(pinConnection)) { | ||||
|                 menu.addSection(QString::fromStdString(busConnection->bus->name)); | ||||
| @ -126,15 +108,12 @@ namespace display { | ||||
|             } | ||||
|             for (int i = 0; i < pinConnection->attributes.size(); i++) { | ||||
|                 auto *attr = &pinConnection->attributes[i]; | ||||
|                 std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}}; | ||||
|                 menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_update_named", params), | ||||
|                                [attr]() { | ||||
|                                    std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}}; | ||||
|                                    auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_actions_update_named", params), "msg_pin_update_action", attr); | ||||
|                                 dialog->exec(); | ||||
|                 menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"),[attr]() { | ||||
|                     auto dialog = new AttributeDialog(attr); | ||||
|                     dialog->exec(); | ||||
|                 }); | ||||
|             } | ||||
|             menu.addAction(QMESSAGE("msg_pin_remove_action"), [this, pinConnection]() { | ||||
|             menu.addAction("Ukloni poveznicu", [this, pinConnection]() { | ||||
|                 Application::instance()->removeConnection(pinConnection); | ||||
|                 auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|                 view->refreshContent(); | ||||
| @ -206,7 +185,7 @@ namespace display { | ||||
| 
 | ||||
|     void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { | ||||
|         QMenu menu; | ||||
|         menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() { | ||||
|         menu.addAction("Izmjeni ime", [this]() { | ||||
|             std::set<std::string> names; | ||||
|             for(const auto &component: Application::instance()->getSchema()->busInstances) { | ||||
|                 names.insert(component->name); | ||||
| @ -218,12 +197,10 @@ namespace display { | ||||
|             auto newName = dialog->getName(); | ||||
| 
 | ||||
|             Application::instance()->renameBus(currentName, newName); | ||||
|             setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getDisplayName())); | ||||
|             setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getName())); | ||||
|         }); | ||||
|         menu.addSeparator(); | ||||
| 
 | ||||
|         std::map<std::string, std::string> params = {{"name", busInstance->name}}; | ||||
|         menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() { | ||||
|         menu.addAction(QString::fromStdString("Ukloni " + this->busInstance->name), [this]() { | ||||
|             Application::instance()->removeBus(this->busInstance->name); | ||||
|             auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|             view->refreshContent(); | ||||
| @ -328,19 +305,10 @@ namespace display { | ||||
|     } | ||||
| 
 | ||||
|     void DirectConnection::updateConnection() { | ||||
|         domain::ui::Pin pin1, pin2; | ||||
|         if(connection->connection.getComponent().component == connection->instance->component.getName()) { | ||||
|             pin1 = connection->instance->component.getPin( | ||||
|                     connection->connection.getComponent().pin).getDisplayPin(); | ||||
|             pin2 = connection->secondInstance->component.getPin( | ||||
|                     connection->connection.getSecondComponent()->pin).getDisplayPin(); | ||||
| 
 | ||||
|         } else { | ||||
|             pin1 = connection->instance->component.getPin( | ||||
|                     connection->connection.getSecondComponent()->pin).getDisplayPin(); | ||||
|             pin2 = connection->secondInstance->component.getPin( | ||||
|                     connection->connection.getComponent().pin).getDisplayPin(); | ||||
|         } | ||||
|         auto pin1 = connection->instance->component.getPin( | ||||
|                 connection->connection.getComponent().pin).getDisplayPin(); | ||||
|         auto pin2 = connection->secondInstance->component.getPin( | ||||
|                 connection->connection.getSecondComponent()->pin).getDisplayPin(); | ||||
| 
 | ||||
|         setLine(connection->instance->position.first + pin1.getConnectionX(), | ||||
|                 connection->instance->position.second + pin1.getConnectionY(), | ||||
|  | ||||
| @ -1,182 +0,0 @@ | ||||
| #include "attribute_dialog.h" | ||||
| #include "mainwindow.h" | ||||
| 
 | ||||
| #include "application.h" | ||||
| #include "error_dialog.h" | ||||
| #include "warning_dialog.h" | ||||
| #include "message_source.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| 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::runtime_error("invalid value type in text change"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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(QMESSAGE("msg_boolean_true"), group); | ||||
|         connect(isTrue, &QRadioButton::clicked, [this]() { | ||||
|             this->value = domain::Value::fromBool(true); | ||||
|         }); | ||||
|         auto isFalse = new QRadioButton(QMESSAGE("msg_boolean_false"), 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,47 +0,0 @@ | ||||
| #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
 | ||||
| @ -1,34 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include <QPlainTextEdit> | ||||
| #include "error_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     ErrorDialog::ErrorDialog(std::vector<domain::ValidationError> errors) | ||||
|         : GenericDialog("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") { | ||||
| 
 | ||||
|         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("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") { | ||||
| 
 | ||||
|         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
 | ||||
| @ -1,22 +0,0 @@ | ||||
| #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
 | ||||
| @ -1,35 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include "generic_dialog.h" | ||||
| 
 | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| display::GenericDialog::GenericDialog(std::string title, std::optional<std::string> action, std::string cancel) { | ||||
|     setAttribute(Qt::WA_DeleteOnClose); | ||||
|     setWindowTitle(QMESSAGE(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.has_value()) { | ||||
|         okButton = new QPushButton(QMESSAGE(*action), this); | ||||
|         connect(okButton, &QPushButton::clicked, this, [this](){ | ||||
|             if(this->onUpdate()) { | ||||
|                 this->accept(); | ||||
|             } | ||||
|         }); | ||||
|         actionBar->addWidget(okButton); | ||||
|     } | ||||
|     cancelButton = new QPushButton(QMESSAGE(cancel), this); | ||||
|     connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
|     actionBar->addWidget(cancelButton); | ||||
| } | ||||
| 
 | ||||
| void display::GenericDialog::setOkButtonDisabled(bool disabled) { | ||||
|     okButton->setDisabled(disabled); | ||||
| } | ||||
| @ -1,33 +0,0 @@ | ||||
| #ifndef SCHEMEEDITOR_GENERIC_DIALOG_H | ||||
| #define SCHEMEEDITOR_GENERIC_DIALOG_H | ||||
| 
 | ||||
| #include <QDialog> | ||||
| #include <QWidget> | ||||
| #include <QPushButton> | ||||
| 
 | ||||
| #include <optional> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class GenericDialog: public QDialog { | ||||
|     public: | ||||
| 
 | ||||
|         explicit GenericDialog(std::string title, | ||||
|                                std::optional<std::string> action = "msg_dialog_actions_update", | ||||
|                                std::string cancel = "msg_dialog_actions_cancel"); | ||||
| 
 | ||||
|     protected: | ||||
|         void setOkButtonDisabled(bool disabled); | ||||
|         virtual bool onUpdate() = 0; | ||||
| 
 | ||||
|     private: | ||||
|         QPushButton *okButton; | ||||
|         QPushButton *cancelButton; | ||||
| 
 | ||||
|     protected: | ||||
|         QWidget *content; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_GENERIC_DIALOG_H
 | ||||
| @ -1,60 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include "memory_dialog.h" | ||||
| #include "message_source.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(QMESSAGE("msg_dialog_memory_default")); | ||||
| 
 | ||||
|         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
 | ||||
| @ -1,33 +0,0 @@ | ||||
| #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
 | ||||
| @ -1,40 +0,0 @@ | ||||
| #include <set> | ||||
| #include "name_dialog.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     NameDialog::NameDialog(std::string currentName, std::set<std::string> &names) | ||||
|         : GenericDialog("msg_dialog_name_update"), currentName(currentName), usedNames(names) { | ||||
| 
 | ||||
|         usedNames.erase(currentName); | ||||
| 
 | ||||
|         auto *contentLayout = new QVBoxLayout(); | ||||
|         contentLayout->addWidget(new QLabel(QMESSAGE("msg_dialog_name_update"), 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,19 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include <QPushButton> | ||||
| #include "success_dialog.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     SuccessDialog::SuccessDialog(std::string message) { | ||||
|         setLayout(new QVBoxLayout()); | ||||
|         setWindowTitle(QMESSAGE("msg_dialog_success_title")); | ||||
|         layout()->addWidget(new QLabel(QString::fromStdString(message))); | ||||
| 
 | ||||
|         auto button = new QPushButton(QMESSAGE("msg_dialog_actions_ok")); | ||||
|         connect(button, &QPushButton::clicked, [this]() {accept();}); | ||||
|         layout()->addWidget(button); | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,19 +0,0 @@ | ||||
| //
 | ||||
| // 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); | ||||
|     }; | ||||
| 
 | ||||
| } // display
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_SUCCESS_DIALOG_H
 | ||||
| @ -1,16 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include "warning_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     WarningDialog::WarningDialog(domain::ValidationError error) | ||||
|         : GenericDialog("msg_dialog_warning_title", "msg_dialog_actions_ok") { | ||||
| 
 | ||||
|         auto contentLayout = new QVBoxLayout(); | ||||
|         content->setLayout(contentLayout); | ||||
| 
 | ||||
|         contentLayout->addWidget(new QLabel(QString::fromStdString(error.message), this)); | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,20 +0,0 @@ | ||||
| #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
 | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "library_display.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| #include <QLabel> | ||||
| #include <QListWidget> | ||||
| @ -16,23 +15,16 @@ namespace display { | ||||
|         busList = new LibraryList(this); | ||||
| 
 | ||||
|         layout->setContentsMargins(4, 4, 4, 4); | ||||
| 
 | ||||
|         componentsLabel = new QLabel(QMESSAGE("msg_sidebar_components")); | ||||
|         busLabel = new QLabel(QMESSAGE("msg_sidebar_busses")); | ||||
| 
 | ||||
|         layout->addWidget(componentsLabel); | ||||
|         layout->addWidget(new QLabel("Komponente:")); | ||||
|         layout->addWidget(componentList, 1); | ||||
|         layout->addSpacing(8); | ||||
|         layout->addWidget(busLabel); | ||||
|         layout->addWidget(new QLabel("Sabirnice:")); | ||||
|         layout->addWidget(busList, 1); | ||||
|     } | ||||
| 
 | ||||
|     void Library::refreshContent() { | ||||
|         library = Application::instance()->getLibrary(); | ||||
| 
 | ||||
|         componentsLabel->setText(QMESSAGE("msg_sidebar_components")); | ||||
|         busLabel->setText(QMESSAGE("msg_sidebar_busses")); | ||||
| 
 | ||||
|         componentList->clear(); | ||||
|         busList->clear(); | ||||
| 
 | ||||
| @ -41,7 +33,7 @@ namespace display { | ||||
|         } | ||||
| 
 | ||||
|         for (auto &component: library->getComponents()) { | ||||
|             auto item = new LibraryListItem{component.getDisplayName(), "comdel/component", component.getName(), | ||||
|             auto item = new LibraryListItem{component.getName(), "comdel/component", component.getName(), | ||||
|                                             componentList}; | ||||
|             item->setToolTip(QString::fromStdString(component.getTooltip())); | ||||
|             componentList->addItem(item); | ||||
| @ -49,7 +41,7 @@ namespace display { | ||||
| 
 | ||||
|         for (auto &bus: library->getBuses()) { | ||||
|             if (bus.getType() == domain::Bus::REGULAR) { | ||||
|                 auto item = new LibraryListItem{bus.getDisplayName(), "comdel/bus", bus.getName(), busList}; | ||||
|                 auto item = new LibraryListItem{bus.getName(), "comdel/bus", bus.getName(), busList}; | ||||
|                 item->setToolTip(QString::fromStdString(bus.getTooltip())); | ||||
|                 busList->addItem(item); | ||||
|             } | ||||
|  | ||||
| @ -5,7 +5,6 @@ | ||||
| #include <QWidget> | ||||
| 
 | ||||
| #include <comdel/domain/library.h> | ||||
| #include <QLabel> | ||||
| #include "library_list.h" | ||||
| 
 | ||||
| namespace display { | ||||
| @ -22,8 +21,6 @@ namespace display { | ||||
|         LibraryList *componentList; | ||||
|         LibraryList *busList; | ||||
| 
 | ||||
|         QLabel *componentsLabel; | ||||
|         QLabel *busLabel; | ||||
|     }; | ||||
| 
 | ||||
| } // namespace display
 | ||||
|  | ||||
							
								
								
									
										50
									
								
								comdel/display/name_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								comdel/display/name_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| //
 | ||||
| // Created by bbr on 18. 04. 2022..
 | ||||
| //
 | ||||
| 
 | ||||
| #include <set> | ||||
| #include "name_dialog.h" | ||||
| 
 | ||||
| display::NameDialog::NameDialog(std::string currentName, std::set<std::string> &names): currentName(currentName) { | ||||
|     usedNames.erase(currentName); | ||||
| 
 | ||||
|     auto *layout = new QVBoxLayout(this); | ||||
|     layout->addWidget(new QLabel("Izmjeni ime", this)); | ||||
| 
 | ||||
|     edit = new QLineEdit(this); | ||||
|     edit->insert(currentName.c_str()); | ||||
|     connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate); | ||||
|     layout->addWidget(edit); | ||||
|     setWindowTitle("Izmjeni ime"); | ||||
|     setLayout(layout); | ||||
| 
 | ||||
|     auto buttonLayout = new QHBoxLayout(this); | ||||
| 
 | ||||
|     auto okButton = new QPushButton("Ažuriraj"); | ||||
|     auto cancelButton = new QPushButton("Odustani", this); | ||||
| 
 | ||||
|     connect(okButton, &QPushButton::clicked, this, &NameDialog::onNameChange); | ||||
|     connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
| 
 | ||||
|     buttonLayout->addWidget(okButton); | ||||
|     buttonLayout->addWidget(cancelButton); | ||||
| 
 | ||||
|     layout->addLayout(buttonLayout); | ||||
| } | ||||
| 
 | ||||
| void display::NameDialog::onNameUpdate(const QString &text) { | ||||
|     if(usedNames.find(text.toStdString()) == usedNames.end()) { | ||||
|         button->setDisabled(false); | ||||
|     } else { | ||||
|         button->setDisabled(true); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void display::NameDialog::onNameChange() { | ||||
|     currentName = edit->text().toStdString(); | ||||
|     close(); | ||||
| } | ||||
| 
 | ||||
| std::string display::NameDialog::getName() { | ||||
|     return currentName; | ||||
| } | ||||
| @ -9,29 +9,25 @@ | ||||
| 
 | ||||
| #include <set> | ||||
| 
 | ||||
| #include "comdel/domain/instance.h" | ||||
| #include "generic_dialog.h" | ||||
| #include <comdel/domain/instance.h> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class NameDialog : public GenericDialog { | ||||
|     class NameDialog : public QDialog { | ||||
| 
 | ||||
|         std::set<std::string> usedNames; | ||||
|         QLineEdit *edit = nullptr; | ||||
|         std::string currentName; | ||||
|         QPushButton *button; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|         void onNameChange(); | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| @ -1,23 +1,18 @@ | ||||
| #include "component_display.h" | ||||
| #include "schema_display.h" | ||||
| #include "application.h" | ||||
| #include "comdel/display/dialog/attribute_dialog.h" | ||||
| #include "comdel/display/dialog/single_automatic_dialog.h" | ||||
| #include "comdel/display/dialog/memory_dialog.h" | ||||
| #include "attribute_dialog.h" | ||||
| #include "single_automatic_dialog.h" | ||||
| 
 | ||||
| #include <QDrag> | ||||
| #include <QDragEnterEvent> | ||||
| #include <QMimeData> | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     Schema::Schema() { | ||||
|         schema = nullptr; | ||||
|         library = std::nullopt; | ||||
|         setRenderHint(QPainter::Antialiasing); | ||||
|         setAlignment(Qt::AlignCenter); | ||||
|         this->setScene(&scene); | ||||
|         this->setAcceptDrops(true); | ||||
|     } | ||||
| @ -178,14 +173,13 @@ namespace display { | ||||
|                 continue; | ||||
|             } | ||||
|             auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()}; | ||||
|             auto pin = pins[pinInstance]->getPin().getDisplayPin(); | ||||
|             auto position = pins[pinInstance]->getComponentInstance()->position; | ||||
| 
 | ||||
|             auto rect = QRectF(position.first + pin.x, position.second + pin.y, pin.w, pin.h); | ||||
|             auto rect = pins[pinInstance]->boundingRect(); | ||||
|             rect.setX(pins[pinInstance]->scenePos().x()); | ||||
|             rect.setY(pins[pinInstance]->scenePos().y()); | ||||
| 
 | ||||
|             if (rect.contains(endPoint)) { | ||||
|                 auto name = components[pinInstance.component]->getComponentInstance()->component.getName(); | ||||
|                 auto con = library->getConnection({instance->component.getName(), context.pin->getPin().getName()}, | ||||
|                 auto con = library->getConnection({instance->component.getName(), pin.getName()}, | ||||
|                                                   {name, pinInstance.pin}); | ||||
|                 if (con.has_value()) { | ||||
|                     auto busInstance = Application::instance()->addBus(library->getBus(con->getBus()), 0, 0); | ||||
| @ -201,22 +195,12 @@ namespace display { | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     std::shared_ptr<domain::DirectConnectionInstance> conInstance = nullptr; | ||||
|                     if(con->getComponent() == domain::ConnectionComponent{instance->component.getName(), context.pin->getPin().getName()}) { | ||||
|                         conInstance = std::make_shared<domain::DirectConnectionInstance>(instance, | ||||
|                                                                            components[pinInstance.component]->getComponentInstance().get(), | ||||
|                                                                            attributes, busInstance.get(), | ||||
|                                                                            *con); | ||||
|                     } else { | ||||
|                         conInstance = std::make_shared<domain::DirectConnectionInstance>(components[pinInstance.component]->getComponentInstance().get(), | ||||
|                                                                                          instance, | ||||
|                                                                                          attributes, busInstance.get(), | ||||
|                                                                                          *con); | ||||
|                     } | ||||
| 
 | ||||
|                     auto conInstance = std::make_shared<domain::DirectConnectionInstance>(instance, | ||||
|                                                                                           components[pinInstance.component]->getComponentInstance().get(), | ||||
|                                                                                           attributes, busInstance.get(), | ||||
|                                                                                           *con); | ||||
|                     schema->connections.push_back(conInstance); | ||||
| 
 | ||||
| 
 | ||||
|                     if (conInstance != nullptr) { | ||||
|                         auto c = new display::DirectConnection(conInstance.get(), | ||||
|                                                                components[conInstance->instance->name], | ||||
| @ -288,14 +272,13 @@ namespace display { | ||||
|             domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr); | ||||
|             if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) { | ||||
|                 if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) { | ||||
|                     auto dialog = new MemoryDialog("msg_dialog_memory_set", "msg_dialog_actions_set", &attribute, schema->componentInstances); | ||||
|                     auto dialog = new MemoryDialog(&attribute, schema->componentInstances, false); | ||||
|                     if(dialog->exec() == QDialog::Rejected) { | ||||
|                         // if any dialog isn't set, whole creation is rejected
 | ||||
|                         return {}; | ||||
|                     } | ||||
|                 } else { | ||||
|                     std::map<std::string, std::string> params = {{"attribute", attribute.attribute.getDisplayName()}}; | ||||
|                     auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_set", params), "msg_dialog_actions_set", &attribute); | ||||
|                     auto dialog = new AttributeDialog(&attribute, false); | ||||
|                     if(dialog->exec() == QDialog::Rejected) { | ||||
|                         // if any dialog isn't set, whole creation is rejected
 | ||||
|                         return {}; | ||||
| @ -314,7 +297,7 @@ namespace display { | ||||
|             instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr); | ||||
|         } | ||||
| 
 | ||||
|         auto dialog = new display::SingleAutomaticDialog("msg_dialog_sa_pin_set", "msg_dialog_actions_set", instanceAttributes); | ||||
|         auto dialog = new display::SingleAutomaticDialog(instanceAttributes, false); | ||||
|         if(dialog->exec() == QDialog::Rejected) { | ||||
|             // if dialog is rejected, whole creation is rejected
 | ||||
|             return {}; | ||||
|  | ||||
| @ -1,3 +1,7 @@ | ||||
| //
 | ||||
| // Created by bbr on 05.06.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #include "single_automatic_dialog.h" | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| @ -5,23 +9,38 @@ | ||||
| #include <QPushButton> | ||||
| 
 | ||||
| namespace display { | ||||
|     SingleAutomaticDialog::SingleAutomaticDialog(std::vector<domain::InstanceAttribute> &values, bool updating): attributes(values) { | ||||
|         setAttribute(Qt::WA_DeleteOnClose); | ||||
|         setWindowTitle(QString::fromStdString(updating ? "Ažuriraj poveznicu" : "Postavi poveznicu")); | ||||
| 
 | ||||
|     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(); | ||||
|         auto *parentLayout = new QVBoxLayout(this); | ||||
|         auto *contentLayout = new QHBoxLayout(this); | ||||
|         auto *firstLayout = new QVBoxLayout(this); | ||||
|         auto *secondLayout = new QVBoxLayout(this); | ||||
| 
 | ||||
|         content->setLayout(contentLayout); | ||||
|         parentLayout->addLayout(contentLayout); | ||||
|         contentLayout->addLayout(firstLayout); | ||||
|         contentLayout->addLayout(secondLayout); | ||||
|         this->setLayout(parentLayout); | ||||
| 
 | ||||
|         setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged); | ||||
|         setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged); | ||||
| 
 | ||||
|         auto buttonLayout = new QHBoxLayout(this); | ||||
| 
 | ||||
|         auto okButton = new QPushButton("U redu", this); | ||||
|         auto cancelButton = new QPushButton("Odustani", this); | ||||
| 
 | ||||
|         connect(okButton, &QPushButton::clicked, [this]() { accept(); }); | ||||
|         connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
| 
 | ||||
|         buttonLayout->addWidget(okButton); | ||||
|         buttonLayout->addWidget(cancelButton); | ||||
| 
 | ||||
|         parentLayout->addLayout(buttonLayout); | ||||
|     } | ||||
| 
 | ||||
|     void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) { | ||||
| @ -56,10 +75,10 @@ namespace display { | ||||
|         secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue(); | ||||
|     } | ||||
| 
 | ||||
|     bool SingleAutomaticDialog::onUpdate() { | ||||
|     void SingleAutomaticDialog::onUpdate() { | ||||
|         attributes[0].value = firstValue; | ||||
|         attributes[1].value = secondValue; | ||||
|         return true; | ||||
|         accept(); | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,3 +1,7 @@ | ||||
| //
 | ||||
| // Created by bbr on 05.06.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H | ||||
| #define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H | ||||
| 
 | ||||
| @ -6,29 +10,24 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include "comdel/domain/value.h" | ||||
| #include "comdel/domain/instance_attribute.h" | ||||
| #include "generic_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class SingleAutomaticDialog: public GenericDialog { | ||||
|     class SingleAutomaticDialog: public QDialog { | ||||
|         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); | ||||
|         explicit SingleAutomaticDialog(std::vector<domain::InstanceAttribute>& values, bool updating = true); | ||||
| 
 | ||||
|     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); | ||||
|         void onUpdate(); | ||||
|     }; | ||||
| 
 | ||||
| } // display
 | ||||
| @ -44,15 +44,8 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Attribute::Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup) | ||||
|             : name(name), displayName(displayName), defaultValue(defaultValue), popup(popup) {} | ||||
| 
 | ||||
|     std::string Attribute::getDisplayName() { | ||||
|         if(displayName.has_value()) { | ||||
|             return *displayName; | ||||
|         } | ||||
|         return name; | ||||
|     } | ||||
|     Attribute::Attribute(std::string name, Value defaultValue, std::optional<Popup> popup) | ||||
|             : name(name), defaultValue(defaultValue), popup(popup) {} | ||||
| 
 | ||||
|     std::string Attribute::getName() { | ||||
|         return name; | ||||
|  | ||||
| @ -61,16 +61,13 @@ namespace domain { | ||||
| 
 | ||||
|     class Attribute { | ||||
|         std::string name; | ||||
|         std::optional<std::string> displayName; | ||||
|         Value defaultValue; | ||||
|         std::optional<Popup> popup; | ||||
|     public: | ||||
|         Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup = std::nullopt); | ||||
|         Attribute(std::string name, Value defaultValue, std::optional<Popup> popup = std::nullopt); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         std::string getDisplayName(); | ||||
| 
 | ||||
|         Value getDefault(); | ||||
| 
 | ||||
|         std::optional<Popup> getPopup(); | ||||
|  | ||||
| @ -35,21 +35,14 @@ namespace domain { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     Bus::Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, | ||||
|     Bus::Bus(std::string name, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, | ||||
|              std::optional<ui::Bus> displayBus) | ||||
|             : name(name), displayName(displayName), instanceName(instanceName), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {} | ||||
|             : name(name), instanceName(instanceName), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {} | ||||
| 
 | ||||
|     std::string Bus::getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::string Bus::getDisplayName() { | ||||
|         if(displayName.has_value()) { | ||||
|             return *displayName; | ||||
|         } | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::string Bus::getTooltip() { | ||||
|         return tooltip; | ||||
|     } | ||||
| @ -69,5 +62,4 @@ namespace domain { | ||||
|     std::optional<ui::Bus> Bus::getDisplayBus() { | ||||
|         return displayBus; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -25,8 +25,8 @@ namespace domain { | ||||
|         std::string name; | ||||
|         WireType type; | ||||
|         int width; | ||||
|         bool hidden = false; | ||||
|         bool hasTerminate = false; | ||||
|         bool hidden; | ||||
|         bool hasTerminate; | ||||
|         Value terminateWith; | ||||
| 
 | ||||
|     public: | ||||
| @ -54,7 +54,6 @@ namespace domain { | ||||
|         }; | ||||
|     private: | ||||
|         std::string name; | ||||
|         std::optional<std::string> displayName; | ||||
|         std::string instanceName; | ||||
|         std::string tooltip; | ||||
|         BusType type; | ||||
| @ -64,13 +63,11 @@ namespace domain { | ||||
|         std::vector<Wire> wires; | ||||
| 
 | ||||
|     public: | ||||
|         Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, | ||||
|         Bus(std::string name, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, | ||||
|             std::optional<ui::Bus> display = std::nullopt); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         std::string getDisplayName(); | ||||
| 
 | ||||
|         std::string getInstanceName(); | ||||
| 
 | ||||
|         std::string getTooltip(); | ||||
|  | ||||
| @ -3,7 +3,6 @@ | ||||
| //
 | ||||
| 
 | ||||
| #include <set> | ||||
| #include <QLayout> | ||||
| #include "comdel_generator.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| @ -128,18 +127,8 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
|     void generateConnection(ConnectionInstance *connection, ostream &buffer) { | ||||
| 
 | ||||
|         auto x1 = connection->start.first; | ||||
|         auto y1 = connection->start.second; | ||||
|         auto x2 = connection->end.first; | ||||
|         auto y2 = connection->end.second; | ||||
| 
 | ||||
|         buffer << "\t\tpath {\n"; | ||||
|         buffer << "\t\t\tx:0; y:0;\n"; | ||||
|         buffer << "\t\t\tpoints: ("; | ||||
|         buffer << "(" << x1 << ", " << y1 << "),"; | ||||
|         buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n"; | ||||
|         buffer << "\t\t}" << std::endl; | ||||
|         buffer << "\t\tline {x1:" << connection->start.first << "; y1:" << connection->start.second << "; " << | ||||
|                "x2:" << connection->end.first << "; y2:" << connection->end.second << ";}" << "\n"; | ||||
|     } | ||||
| 
 | ||||
|     void generateBus(BusInstance *bus, ostream &buffer) { | ||||
| @ -159,10 +148,13 @@ namespace domain { | ||||
|         for (auto &bus: schema->busInstances) { | ||||
|             buffer << "\t//" << bus->name << std::endl; | ||||
|             for (auto &wire: bus->bus.getWires()) { | ||||
|                 auto name = wire.getName(); | ||||
|                 if (usedNames.count(name) > 0) { | ||||
|                 std::string name = wire.getName(); | ||||
|                 if (usedNames.count(wire.getName()) > 0) { | ||||
|                     name = bus->name + "__" + wire.getName(); | ||||
|                 } | ||||
|                 if (wire.isHidden()) { | ||||
|                     name = "--" + name; | ||||
|                 } | ||||
|                 usedNames.insert(name); | ||||
|                 usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name)); | ||||
| 
 | ||||
| @ -192,11 +184,7 @@ namespace domain { | ||||
|         if (wire.getWidth() != 1) { | ||||
|             buffer << "<" << wire.getWidth() << ">"; | ||||
|         } | ||||
|         buffer << " " << (wire.isHidden() ? "--" : "") << name; | ||||
|         if(wire.hasTerminateWith()) { | ||||
|             buffer << " = " << wire.getTerminateWith().asInt(); | ||||
|         } | ||||
|         buffer << ";" << std::endl; | ||||
|         buffer << " " << name << ";" << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     std::set<std::string> createImports(Schema *schema) { | ||||
| @ -215,9 +203,6 @@ namespace domain { | ||||
|                                     map<string, string> &wireNames, | ||||
|                                     stringstream &buffer); | ||||
| 
 | ||||
|     void generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin, | ||||
|                                     map<string, string> &wireNames, stringstream &buffer); | ||||
| 
 | ||||
|     void generateComponent(Schema *schema, map<string, string> &wires, ostream &buffer, | ||||
|                            shared_ptr<ComponentInstance> &component); | ||||
| 
 | ||||
| @ -265,42 +250,37 @@ namespace domain { | ||||
| 
 | ||||
|         for (auto &pin: component->component.getPins()) { | ||||
|             if (schema->hasConnection(component->name, pin.getName())) { | ||||
|                 auto connections = schema->getConnections(component->name, pin.getName()); | ||||
|                 if(connections.size() == 1) { | ||||
|                     auto conn = connections[0]; | ||||
|                     auto busConn = dynamic_cast<BusConnectionInstance *>(conn); | ||||
|                     if (busConn != nullptr) { | ||||
|                         for (auto wire: busConn->connection.getWires()) { | ||||
|                             if (wire.isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|                                 auto attribute = busConn->getAttribute(wire.asReference()); | ||||
|                                 if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                                     tempOutput << wires[busConn->bus->name + "." + attribute.value.asReference()] << ", "; | ||||
|                                 } else if (wire.isType(Value::NIL)) { | ||||
|                                     tempOutput << "*, "; | ||||
|                                 } else { | ||||
|                                     tempOutput << attribute.value.stringify() << ", "; | ||||
|                                 } | ||||
|                 auto conn = schema->getConnection(component->name, pin.getName()); | ||||
|                 auto busConn = dynamic_cast<BusConnectionInstance *>(conn); | ||||
|                 if (busConn != nullptr) { | ||||
|                     for (auto wire: busConn->connection.getWires()) { | ||||
|                         if (wire.isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|                             auto attribute = busConn->getAttribute(wire.asReference()); | ||||
|                             if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                                 tempOutput << wires[busConn->bus->name + "." + attribute.value.asReference()] << ", "; | ||||
|                             } else if (wire.isType(Value::NIL)) { | ||||
|                                 tempOutput << "*, "; | ||||
|                             } else { | ||||
|                                 if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                                     tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", "; | ||||
|                                 } else if (wire.isType(Value::NIL)) { | ||||
|                                     tempOutput << "*, "; | ||||
|                                 } else { | ||||
|                                     tempOutput << wire.stringify() << ", "; | ||||
|                                 } | ||||
|                                 tempOutput << attribute.value.stringify() << ", "; | ||||
|                             } | ||||
|                         } else { | ||||
|                             if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                                 tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", "; | ||||
|                             } else if (wire.isType(Value::NIL)) { | ||||
|                                 tempOutput << "*, "; | ||||
|                             } else { | ||||
|                                 tempOutput << wire.stringify() << ", "; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     auto dirConn = dynamic_cast<DirectConnectionInstance *>(conn); | ||||
|                     if (dirConn != nullptr) { | ||||
|                         if (dirConn->bus->bus.getType() == Bus::AUTOMATIC) { | ||||
|                             generateAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|                         } else { | ||||
|                             generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|                         } | ||||
|                 } | ||||
|                 auto dirConn = dynamic_cast<DirectConnectionInstance *>(conn); | ||||
|                 if (dirConn != nullptr) { | ||||
|                     if (dirConn->bus->bus.getType() == Bus::AUTOMATIC) { | ||||
|                         generateAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|                     } else { | ||||
|                         generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|                     } | ||||
|                 } else { | ||||
|                     generateSingleAutomaticPin(connections, component.get(), pin.getName(), wires, tempOutput); | ||||
|                 } | ||||
|             } else { | ||||
|                 // if no connection exists than defaults must exist
 | ||||
| @ -361,30 +341,8 @@ namespace domain { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin, | ||||
|                                     map<string, string> &wireNames, stringstream &buffer) { | ||||
|         std::map<int, BusInstance*> selectedValues; | ||||
|         for(auto conn: connections) { | ||||
|             auto dirConn = dynamic_cast<DirectConnectionInstance*>(conn); | ||||
|             auto index = dirConn->getSelected(ConnectionComponent{instance->name, pin}); | ||||
|             selectedValues.insert(std::make_pair(index, dirConn->bus)); | ||||
|         } | ||||
| 
 | ||||
|         std::vector<Value> defaultWires = instance->component.getPin(pin).getWires().value(); | ||||
| 
 | ||||
|         for (int i=0; i<defaultWires.size(); i++) { | ||||
|             if(selectedValues.count(i) > 0) { | ||||
|                 auto wireName = selectedValues[i]->name + "." + selectedValues[i]->bus.getWires()[0].getName(); | ||||
|                 buffer << wireNames[wireName] << ", "; | ||||
|             } else if(defaultWires[i].isType(Value::NIL)) { | ||||
|                 buffer << "*, "; | ||||
|             } else { | ||||
|                 buffer << defaultWires[i].stringify() << ", "; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, | ||||
|     void | ||||
|     generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, | ||||
|                          stringstream &buffer) { | ||||
|         std::vector<Value> wires; | ||||
|         if (connection->instance->name == name && connection->connection.getComponent().pin == pin) { | ||||
| @ -414,4 +372,4 @@ namespace domain { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } // domain
 | ||||
| } // domain
 | ||||
| @ -1,7 +1,6 @@ | ||||
| #include <set> | ||||
| #include "comdel_validator.h" | ||||
| #include "library.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| @ -31,20 +30,24 @@ namespace domain { | ||||
|         for (auto comp: library.getComponents()) { | ||||
|             int count = instanceMap[comp.getName()]; | ||||
| 
 | ||||
|             context.attributes["componentName"] = Value::fromString(comp.getDisplayName()); | ||||
|             context.attributes["componentName"] = Value::fromString(comp.getName()); | ||||
|             context.attributes["min"] = Value::fromInt(comp.getCount().first); | ||||
|             context.attributes["max"] = Value::fromInt(comp.getCount().second); | ||||
|             context.attributes["count"] = Value::fromInt(count); | ||||
| 
 | ||||
|             if (count < comp.getCount().first) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_component_min_count", context.map()); | ||||
|                 auto message = populateMessage( | ||||
|                         "Nedovoljno instanci komponente '{componentName}' potrebno barem {min}, pronađeno {count}", | ||||
|                         context); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } else if (count > comp.getCount().second) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_component_max_count", context.map()); | ||||
|                 auto message = populateMessage( | ||||
|                         "Previše insanci komponente '{componentName}' dozvoljeno najviše {max}, pronađeno {count}", context); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         // validate bus instance count
 | ||||
|         std::map<std::string, int> busInstanceMap; | ||||
|         for (auto &inst: schema.busInstances) { | ||||
| @ -54,16 +57,18 @@ namespace domain { | ||||
|         for (auto bus: library.getBuses()) { | ||||
|             int count = busInstanceMap[bus.getName()]; | ||||
| 
 | ||||
|             context.attributes["busName"] = Value::fromString(bus.getDisplayName()); | ||||
|             context.attributes["busName"] = Value::fromString(bus.getName()); | ||||
|             context.attributes["min"] = Value::fromInt(bus.getCount().first); | ||||
|             context.attributes["max"] = Value::fromInt(bus.getCount().second); | ||||
|             context.attributes["count"] = Value::fromInt(count); | ||||
| 
 | ||||
|             if (count < bus.getCount().first) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_bus_min_count", context.map()); | ||||
|                 auto message = populateMessage( | ||||
|                         "Nedovoljno instanci sabirnice '{busName}' potrebna barem jedna {min}, pronađeno {count}", context); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } else if (count > bus.getCount().second) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_bus_max_count", context.map()); | ||||
|                 auto message = populateMessage( | ||||
|                         "Previše instanci sabirnice '{busName}' dozvoljeno najviše {max}, pronašeno {count}", context); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } | ||||
|         } | ||||
| @ -77,11 +82,12 @@ namespace domain { | ||||
| 
 | ||||
|         for (auto &inst: schema.componentInstances) { | ||||
|             for (auto &pin: inst->component.getPins()) { | ||||
|                 if (pin.getConnection().has_value()) { | ||||
|                 if (pin.getConnection().getType() == PinConnection::REQUIRED) { | ||||
|                     if (!connectionExists(schema, inst, pin)) { | ||||
|                         context.instance = inst.get(); | ||||
|                         auto message = MESSAGE_PARAM(pin.getConnection().value(), context.map()); | ||||
|                         errors.emplace_back(context.instance, nullptr, Action::ERROR, message); | ||||
|                         context.attributes["instanceName"] = Value::fromString(inst->name); | ||||
|                         auto message = populateMessage(pin.getConnection().getMessage(), context); | ||||
|                         errors.emplace_back(Action::ERROR, message); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @ -141,7 +147,7 @@ namespace domain { | ||||
|         ruleContext.function = validators; | ||||
|         auto action = rule.evaluate(ruleContext); | ||||
|         if (action) { | ||||
|             auto message = MESSAGE_PARAM(action->getMessage(), context.map()); | ||||
|             std::string message = this->populateMessage(action->getMessage(), context); | ||||
|             return ValidationError{context.instance, context.attribute, action->getType(), message}; | ||||
|         } | ||||
|         return nullopt; | ||||
| @ -166,7 +172,7 @@ namespace domain { | ||||
|                         if(memoryReference != nullopt) { | ||||
|                             if(memoryInstances.count(*memoryReference) == 0) { | ||||
|                                 context.attributes["memoryReference"] = domain::Value::fromString(memoryReference.value()); | ||||
|                                 auto message = MESSAGE_PARAM("msg_validators_memory_not_found", context.map()); | ||||
|                                 auto message = populateMessage("Ne postoji memorijska komponenta '{memoryReference}'", context); | ||||
|                                 errors.emplace_back(component.get(), nullptr, Action::ERROR, message); | ||||
|                             } | ||||
|                         } | ||||
| @ -185,8 +191,9 @@ namespace domain { | ||||
| 
 | ||||
|         for(auto& component: schema.componentInstances) { | ||||
|             if(names.find(component->name) != names.end()) { | ||||
|                 context.instance = component.get(); | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_duplicates_found", context.map()); | ||||
|                 context.attributes["componentName"] = Value::fromString(component->name); | ||||
|                 auto message = populateMessage( | ||||
|                         "Pronađeno više instanci sa imenom '{componentName}'", context); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } | ||||
|             names.insert(component->name); | ||||
| @ -194,6 +201,26 @@ namespace domain { | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     std::string ComdelValidator::populateMessage(string source, ValidationContext context) { | ||||
|         for (auto &[key, value]: context.attributes) { | ||||
|             source = replacePlaceholder(source, key, value); | ||||
|         } | ||||
|         return source; | ||||
|     } | ||||
| 
 | ||||
|     string ComdelValidator::replacePlaceholder(string source, string key, Value value) { | ||||
|         key = "{" + key + "}"; | ||||
|         auto placeholderValue = value.string(); | ||||
| 
 | ||||
|         auto found = source.find(key); | ||||
|         while (found != string::npos) { | ||||
|             source.replace(found, key.length(), placeholderValue); | ||||
|             found = source.find(key); | ||||
|         } | ||||
|         return source; | ||||
|     } | ||||
| 
 | ||||
|     bool ComdelValidator::connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin) { | ||||
|         for (auto conn: schema.connections) { | ||||
|             auto busConnection = dynamic_cast<BusConnectionInstance *>(conn.get()); | ||||
| @ -206,9 +233,13 @@ namespace domain { | ||||
| 
 | ||||
|             auto directConnection = dynamic_cast<DirectConnectionInstance *>(conn.get()); | ||||
|             if (directConnection != nullptr) { | ||||
|                 if ((directConnection->instance->name == component->name && directConnection->connection.getComponent().pin == pin.getName()) || | ||||
|                     (directConnection->secondInstance->name == component->name) && directConnection->connection.getSecondComponent()->pin == pin.getName()) { | ||||
|                     return directConnection->connection.isConnecting({component->component.getName(), pin.getName()}); | ||||
|                 if (directConnection->instance->name == component->name && | ||||
|                     directConnection->connection.getComponent().pin == pin.getName()) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 if (directConnection->secondInstance->name == component->name && | ||||
|                     directConnection->connection.getSecondComponent()->pin == pin.getName()) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -221,20 +252,4 @@ namespace domain { | ||||
|             this->validators.insert(std::make_pair(validator->getName(), validator)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::map<std::string, std::string> ValidationContext::map() { | ||||
|         std::map<std::string, std::string> parametars; | ||||
|         if(instance != nullptr) { | ||||
|             parametars["instanceName"] = instance->name; | ||||
|             parametars["componentName"] = instance->component.getDisplayName(); | ||||
|         } | ||||
|         if(attribute != nullptr) { | ||||
|             parametars["attributeName"] = attribute->name; | ||||
|             parametars["attribute"] = attribute->value.string(); | ||||
|         } | ||||
|         for(auto [key, value]: attributes) { | ||||
|             parametars[key] = value.string(); | ||||
|         } | ||||
|         return parametars; | ||||
|     } | ||||
| } | ||||
| @ -23,8 +23,6 @@ namespace domain { | ||||
|         InstanceAttribute *attribute; | ||||
|         std::map<std::string, AddressSpace> addressSpaces; | ||||
|         std::map<std::string, Value> attributes; | ||||
| 
 | ||||
|         std::map<std::string, std::string> map(); | ||||
|     }; | ||||
| 
 | ||||
|     class ComdelValidator { | ||||
| @ -43,13 +41,18 @@ namespace domain { | ||||
| 
 | ||||
|         std::vector<ValidationError> validateInstanceCount(Schema &schema, Library &library, ValidationContext context); | ||||
| 
 | ||||
|         std::vector<ValidationError> validatePinConnections(Schema &schema, Library &library, ValidationContext context); | ||||
|         std::vector<ValidationError> | ||||
|         validatePinConnections(Schema &schema, Library &library, ValidationContext context); | ||||
| 
 | ||||
|         ComdelValidator(std::vector<FunctionValidator *> validators); | ||||
| 
 | ||||
|     private: | ||||
|         std::map<std::string, FunctionValidator *> validators; | ||||
| 
 | ||||
|         std::string populateMessage(string message, ValidationContext context); | ||||
| 
 | ||||
|         string replacePlaceholder(string message, const string name, Value value); | ||||
| 
 | ||||
|         bool connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin); | ||||
|     }; | ||||
| 
 | ||||
|  | ||||
| @ -1,25 +1,17 @@ | ||||
| #include "component.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Component::Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type, | ||||
|     Component::Component(string name, string tooltip, string source, ComponentType type, | ||||
|                          vector<Rule> rules, string instanceName, pair<int, int> count, Display display, | ||||
|                          vector<Pin> pins, vector<Attribute> attributes) | ||||
|             : name(name), displayName(displayName), tooltip(tooltip), source(source), type(type), rules(rules), instanceName(instanceName), | ||||
|             : name(name), tooltip(tooltip), source(source), type(type), rules(rules), instanceName(instanceName), | ||||
|               count(count), display(display), pins(pins), attributes(attributes) {} | ||||
| 
 | ||||
|     std::string Component::getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::string Component::getDisplayName() { | ||||
|         if(displayName.has_value()) { | ||||
|             return displayName.value(); | ||||
|         } | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::string Component::getTooltip() { | ||||
|         return tooltip; | ||||
|     } | ||||
| @ -58,7 +50,7 @@ namespace domain { | ||||
|                 return p; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no pin with name '" + pin + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     bool Component::hasPin(std::string name) { | ||||
| @ -80,7 +72,7 @@ namespace domain { | ||||
|                 return attr; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no attribute with name '" + attribute + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     bool Component::hasAttribute(std::string name, Value::ValueType type) { | ||||
| @ -102,4 +94,5 @@ namespace domain { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -23,7 +23,6 @@ namespace domain { | ||||
| 
 | ||||
|     private: | ||||
|         std::string name; | ||||
|         std::optional<std::string> displayName; | ||||
|         std::string tooltip; | ||||
|         std::string source; | ||||
|         ComponentType type; | ||||
| @ -37,14 +36,12 @@ namespace domain { | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type, | ||||
|         Component(string name, string tooltip, string source, ComponentType type, | ||||
|                   vector<Rule> rules, string instanceName, pair<int, int> count, Display display, | ||||
|                   vector<Pin> pins, vector<Attribute> attributes); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         std::string getDisplayName(); | ||||
| 
 | ||||
|         std::string getTooltip(); | ||||
| 
 | ||||
|         std::string getSource(); | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "connection.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| @ -39,7 +38,7 @@ namespace domain { | ||||
|                 return attributes[i]; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no attribute with name '" + name + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     bool Connection::hasAttribute(std::string name) { | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "connection_instance.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| @ -14,7 +13,7 @@ namespace domain { | ||||
|                 return attr; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no attribute with name '" + attribute + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| @ -27,23 +26,4 @@ namespace domain { | ||||
|                                                        Connection connection) | ||||
|             : ConnectionInstance(instance, attributes, connection), secondInstance(secondInstance), bus(bus) {} | ||||
| 
 | ||||
|     int DirectConnectionInstance::getSelected(ConnectionComponent conn) { | ||||
|         if(this->instance->name == conn.component) { | ||||
|             auto selected = attributes[0].value.asString(); | ||||
|             for(int i=0; i<connection.getWires().size(); i++) { | ||||
|                 if(connection.getWires()[i].isType(Value::STRING) && connection.getWires()[i].asString() == selected) { | ||||
|                     return i; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             auto selected = attributes[1].value.asString(); | ||||
|             for(int i=0; i<connection.getSecondWires()->size(); i++) { | ||||
|                 if(connection.getSecondWires().value()[i].isType(Value::STRING) && connection.getSecondWires().value()[i].asString() == selected) { | ||||
|                     return i; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -41,8 +41,6 @@ namespace domain { | ||||
| 
 | ||||
|         DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, | ||||
|                                  std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection); | ||||
| 
 | ||||
|         int getSelected(ConnectionComponent connection); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -2,17 +2,17 @@ | ||||
| 
 | ||||
| #include <QBrush> | ||||
| #include <QPen> | ||||
| #include <QFont> | ||||
| 
 | ||||
| #include "comdel/domain/instance.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     QBrush busBrush(QColor::fromRgb(200, 200, 200)); | ||||
|     QPen busPen(QColor::fromRgb(200, 200, 200)); | ||||
| 
 | ||||
|     Display::Display(std::vector<ui::Item> items) : items(items) {} | ||||
| 
 | ||||
|     void Display::render(QGraphicsItemGroup *group, ui::DisplayContext context) { | ||||
|     void Display::render(QGraphicsItemGroup *group) { | ||||
|         for (auto &item: items) { | ||||
|             item.render(group, context); | ||||
|             item.render(group); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -22,65 +22,26 @@ namespace domain { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void ui::Text::render(QGraphicsItemGroup *group, ui::DisplayContext context) { | ||||
|         auto formattedText = context.populateMessage(text); | ||||
| 
 | ||||
|         auto content = new QGraphicsTextItem(QString::fromStdString(formattedText)); | ||||
|         content->setDefaultTextColor(color); | ||||
|         content->setPos(x, y); | ||||
|         content->setFont(QFont("arial", 8)); | ||||
|         group->addToGroup(content); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Text::comdel(std::ostream &buffer, int x, int y) { | ||||
|         // TODO
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void ui::Rect::render(QGraphicsItemGroup *group) { | ||||
|         auto rect = new QGraphicsRectItem(x, y, w, h); | ||||
|         rect->setPen(QPen(config.lineColor)); | ||||
|         rect->setBrush(QBrush(config.fillColor)); | ||||
|         group->addToGroup(rect); | ||||
|         group->addToGroup(new QGraphicsRectItem(x, y, w, h)); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Rect::comdel(std::ostream &buffer, int x, int y) { | ||||
|         buffer << "\t\trectangle {\n"; | ||||
|         buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; | ||||
|         buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n"; | ||||
|         buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t\tw: " << w << "; h: " << h << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
|     void ui::Ellipse::render(QGraphicsItemGroup *group) { | ||||
|         auto ellipse = new QGraphicsEllipseItem(x, y, w, h); | ||||
|         ellipse->setPen(QPen(config.lineColor)); | ||||
|         ellipse->setBrush(QBrush(config.fillColor)); | ||||
|         group->addToGroup(ellipse); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Ellipse::comdel(std::ostream &buffer, int x, int y) { | ||||
|         buffer << "\t\tellipse {\n"; | ||||
|         buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; | ||||
|         buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void ui::Line::render(QGraphicsItemGroup *group) { | ||||
|         auto line = new QGraphicsLineItem(x1, y1, x2, y2); | ||||
|         line->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(line); | ||||
|         group->addToGroup(new QGraphicsLineItem(x1, y1, x2, y2)); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Line::comdel(std::ostream &buffer, int x, int y) { | ||||
|         buffer << "\t\tpath {\n"; | ||||
|         buffer << "\t\t\tx:0; y:0;\n"; | ||||
|         buffer << "\t\t\tpoints: ("; | ||||
|         buffer << "(" << (x1 + x) << ", " << (y1 + y) << "),"; | ||||
|         buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n"; | ||||
|         buffer << "\t\t}" << std::endl; | ||||
|         buffer << "\t\tline {\n"; | ||||
|         buffer << "\t\t\tx1: " << (x1 + x) << "; y1: " << (y1 + y) << ";\n"; | ||||
|         buffer << "\t\t\tx2: " << (x2 + x) << "; y2: " << (y2 + y) << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
|     void ui::Bus::render(QGraphicsItemGroup *group, int size) { | ||||
| @ -91,8 +52,8 @@ namespace domain { | ||||
|             _h = size; | ||||
|         } | ||||
|         auto rect = new QGraphicsRectItem(x, y, _w, _h); | ||||
|         rect->setBrush(QBrush(config.fillColor)); | ||||
|         rect->setPen(QPen(config.lineColor)); | ||||
|         rect->setBrush(busBrush); | ||||
|         rect->setPen(busPen); | ||||
|         group->addToGroup(rect); | ||||
|     } | ||||
| 
 | ||||
| @ -108,12 +69,10 @@ namespace domain { | ||||
|         buffer << "\t\trectangle {\n"; | ||||
|         buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; | ||||
|         if (orientation == HORIZONTAL) { | ||||
|             buffer << "\t\t\twidth: " << size << "; height: " << h << ";\n"; | ||||
|             buffer << "\t\t\tw: " << size << "; h: " << h << ";\n"; | ||||
|         } else { | ||||
|             buffer << "\t\t\twidth: " << w << "; height: " << size << ";\n"; | ||||
|             buffer << "\t\t\tw: " << w << "; h: " << size << ";\n"; | ||||
|         } | ||||
|         buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
| @ -138,11 +97,7 @@ namespace domain { | ||||
|                         << QPoint(x + w / 2, y + h / 2) << QPoint(x + w, y); | ||||
|                 break; | ||||
|         } | ||||
|         auto item = new QGraphicsPolygonItem(polygon); | ||||
|         item->setFillRule(Qt::OddEvenFill); | ||||
|         item->setBrush(QBrush(config.fillColor)); | ||||
|         item->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(item); | ||||
|         group->addToGroup(new QGraphicsPolygonItem(polygon)); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Pin::renderOut(QGraphicsItemGroup *group) { | ||||
| @ -166,18 +121,11 @@ namespace domain { | ||||
|                         << QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y); | ||||
|                 break; | ||||
|         } | ||||
|         auto item = new QGraphicsPolygonItem(polygon); | ||||
|         item->setFillRule(Qt::OddEvenFill); | ||||
|         item->setBrush(QBrush(config.fillColor)); | ||||
|         item->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(item); | ||||
|         group->addToGroup(new QGraphicsPolygonItem(polygon)); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Pin::renderInOut(QGraphicsItemGroup *group) { | ||||
|         auto rect = new QGraphicsRectItem(x, y, w, h); | ||||
|         rect->setBrush(QBrush(config.fillColor)); | ||||
|         rect->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(rect); | ||||
|         group->addToGroup(new QGraphicsRectItem(x, y, w, h)); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Pin::render(QGraphicsItemGroup *group) { | ||||
| @ -220,13 +168,11 @@ namespace domain { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     void ui::Item::render(QGraphicsItemGroup *group, ui::DisplayContext context, int size) { | ||||
|     void ui::Item::render(QGraphicsItemGroup *group, int size) { | ||||
|         if (rect) rect->render(group); | ||||
|         if (line) line->render(group); | ||||
|         if (pin) pin->render(group); | ||||
|         if (bus) bus->render(group, size); | ||||
|         if (text) text->render(group, context); | ||||
|         if (ellipse) ellipse->render(group); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Item::comdel(std::ostream &buffer, int x, int y, int size) { | ||||
| @ -234,32 +180,5 @@ namespace domain { | ||||
|         if (line) line->comdel(buffer, x, y); | ||||
|         // pins aren't exported
 | ||||
|         if (bus) bus->comdel(buffer, x, y, size); | ||||
|         // text currently isn't exported TODO
 | ||||
|     } | ||||
| 
 | ||||
|     ui::DisplayContext::DisplayContext(ComponentInstance *instance) { | ||||
|         for(auto attr: instance->attributes) { | ||||
|             this->values[attr.name] = attr.value; | ||||
|         } | ||||
|         this->values["instanceName"] = Value::fromString(instance->name); | ||||
|     } | ||||
| 
 | ||||
|     string replacePlaceholder(string source, string key, Value value) { | ||||
|         key = "{" + key + "}"; | ||||
|         auto placeholderValue = value.string(); | ||||
| 
 | ||||
|         auto found = source.find(key); | ||||
|         while (found != string::npos) { | ||||
|             source.replace(found, key.length(), placeholderValue); | ||||
|             found = source.find(key); | ||||
|         } | ||||
|         return source; | ||||
|     } | ||||
| 
 | ||||
|     std::string ui::DisplayContext::populateMessage(std::string source) { | ||||
|         for (auto &[key, value]: values) { | ||||
|             source = replacePlaceholder(source, key, value); | ||||
|         } | ||||
|         return source; | ||||
|     } | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -5,65 +5,16 @@ | ||||
| #include <optional> | ||||
| 
 | ||||
| #include <ostream> | ||||
| #include "comdel/parser/color.h" | ||||
| #include "value.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     namespace ui { | ||||
| 
 | ||||
|         class DisplayContext { | ||||
|             std::map<std::string, domain::Value> values; | ||||
| 
 | ||||
|         public: | ||||
|             explicit DisplayContext(ComponentInstance *instance); | ||||
|             std::string populateMessage(std::string message); | ||||
|         }; | ||||
| 
 | ||||
|         struct DisplayConfig { | ||||
|             QColor lineColor; | ||||
|             QColor fillColor; | ||||
| 
 | ||||
|             DisplayConfig(Color lineColor, Color fillColor) { | ||||
|                 this->lineColor = QColor::fromRgb(lineColor.r, lineColor.g, lineColor.b, lineColor.a); | ||||
|                 this->fillColor = QColor::fromRgb(fillColor.r, fillColor.g, fillColor.b, fillColor.a); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         class Text { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             QColor color; | ||||
|             std::string text; | ||||
| 
 | ||||
|             Text(int x, int y, int w, int h, std::string text, Color color) : x(x), y(y), w(w), h(h), text(text), | ||||
|                 color(QColor::fromRgb(color.r, color.g, color.b, color.a)) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group, ui::DisplayContext context); | ||||
| 
 | ||||
|             void comdel(std::ostream &buffer, int x, int y); | ||||
| 
 | ||||
|         }; | ||||
| 
 | ||||
|         class Rect { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Rect(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
|             void comdel(std::ostream &buffer, int x, int y); | ||||
| 
 | ||||
|         }; | ||||
| 
 | ||||
|         class Ellipse { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Ellipse(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {} | ||||
|             Rect(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
| @ -74,9 +25,8 @@ namespace domain { | ||||
|         class Line { | ||||
|         public: | ||||
|             int x1, y1, x2, y2; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Line(int x1, int y1, int x2, int y2, DisplayConfig config) : x1(x1), y1(y1), x2(x2), y2(y2), config(config) {} | ||||
|             Line(int x1, int y1, int x2, int y2) : x1(x1), y1(y1), x2(x2), y2(y2) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
| @ -97,11 +47,9 @@ namespace domain { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             BusOrientation orientation; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Bus(int x, int y, int w, int h, BusOrientation orientation, DisplayConfig config) : x(x), y(y), w(w), h(h), | ||||
|                                                                           orientation(orientation), | ||||
|                                                                           config(config) {} | ||||
|             Bus(int x, int y, int w, int h, BusOrientation orientation) : x(x), y(y), w(w), h(h), | ||||
|                                                                           orientation(orientation) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group, int size); | ||||
| 
 | ||||
| @ -116,12 +64,10 @@ namespace domain { | ||||
|             PinOrientation orientation; | ||||
|             PinType pinType; | ||||
|             int x, y, w, h; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType, DisplayConfig config) | ||||
|                 : x(x), y(y), w(w), h(h), orientation(orientation), pinType(pinType), config(config) {} | ||||
| 
 | ||||
|             Pin(): config(DisplayConfig(Color(), Color())) {}; | ||||
|             Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType) : x(x), y(y), w(w), h(h), | ||||
|                                                                                            orientation(orientation), | ||||
|                                                                                            pinType(pinType) {} | ||||
| 
 | ||||
|         public: | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| @ -144,10 +90,8 @@ namespace domain { | ||||
|             std::optional<Line> line = std::nullopt; | ||||
|             std::optional<Pin> pin = std::nullopt; | ||||
|             std::optional<Bus> bus = std::nullopt; | ||||
|             std::optional<Text> text = std::nullopt; | ||||
|             std::optional<Ellipse> ellipse = std::nullopt; | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group, ui::DisplayContext context, int size = 0); | ||||
|             void render(QGraphicsItemGroup *group, int size = 0); | ||||
|             void comdel(std::ostream &buffer, int x, int y, int size = 0); | ||||
|         }; | ||||
| 
 | ||||
| @ -158,7 +102,7 @@ namespace domain { | ||||
| 
 | ||||
|         Display(std::vector<ui::Item> items); | ||||
| 
 | ||||
|         void render(QGraphicsItemGroup *group, ui::DisplayContext context); | ||||
|         void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
|         void comdel(std::ostream &buffer, int x, int y, int size = 0); | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "library.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| @ -52,7 +51,7 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
|     bool Library::hasComponent(std::string name) { | ||||
|         for (unsigned int i = 0; i < components.size(); i++) { | ||||
|         for (uint i = 0; i < components.size(); i++) { | ||||
|             if (components[i].getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
| @ -61,7 +60,7 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
|     bool Library::hasBus(std::string name) { | ||||
|         for (unsigned int i = 0; i < buses.size(); i++) { | ||||
|         for (uint i = 0; i < buses.size(); i++) { | ||||
|             if (buses[i].getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
| @ -71,30 +70,30 @@ namespace domain { | ||||
| 
 | ||||
| 
 | ||||
|     AddressSpace &Library::getAddressSpace(std::string addressSpace) { | ||||
|         for (unsigned int i = 0; i < addressSpaces.size(); i++) { | ||||
|         for (uint i = 0; i < addressSpaces.size(); i++) { | ||||
|             if (addressSpaces[i].getName() == addressSpace) { | ||||
|                 return addressSpaces[i]; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no address space with name '" + addressSpace + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     Component &Library::getComponent(std::string component) { | ||||
|         for (unsigned int i = 0; i < components.size(); i++) { | ||||
|         for (uint i = 0; i < components.size(); i++) { | ||||
|             if (components[i].getName() == component) { | ||||
|                 return components[i]; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no component with name '" + component + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     Bus &Library::getBus(std::string bus) { | ||||
|         for (unsigned int i = 0; i < buses.size(); i++) { | ||||
|         for (uint i = 0; i < buses.size(); i++) { | ||||
|             if (buses[i].getName() == bus) { | ||||
|                 return buses[i]; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no bus with name '" + bus + "'"); | ||||
|         throw std::exception(); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| @ -103,7 +102,7 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus) { | ||||
|         for (unsigned int i = 0; i < connections.size(); i++) { | ||||
|         for (uint i = 0; i < connections.size(); i++) { | ||||
|             if (connections[i].isConnecting(component, bus)) { | ||||
|                 return connections[i]; | ||||
|             } | ||||
| @ -117,7 +116,7 @@ namespace domain { | ||||
| 
 | ||||
|     std::optional<Connection> | ||||
|     Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { | ||||
|         for (unsigned int i = 0; i < connections.size(); i++) { | ||||
|         for (uint i = 0; i < connections.size(); i++) { | ||||
|             if (connections[i].isConnecting(component, bus, secondComponent)) { | ||||
|                 return connections[i]; | ||||
|             } | ||||
|  | ||||
| @ -2,7 +2,19 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Pin::Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin, | ||||
|     PinConnection::PinConnection(std::string message, ConnectionType type) | ||||
|             : message(message), type(type) {} | ||||
| 
 | ||||
|     PinConnection::ConnectionType PinConnection::getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     std::string PinConnection::getMessage() { | ||||
|         return message; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, | ||||
|              std::optional<std::vector<Value>> wires) | ||||
|             : name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {} | ||||
| 
 | ||||
| @ -22,7 +34,7 @@ namespace domain { | ||||
|         return displayPin; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<std::string> Pin::getConnection() { | ||||
|     PinConnection &Pin::getConnection() { | ||||
|         return connection; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -9,6 +9,25 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class PinConnection { | ||||
|     public: | ||||
|         enum ConnectionType { | ||||
|             REQUIRED, | ||||
|             OPTIONAL | ||||
|         }; | ||||
| 
 | ||||
|     private: | ||||
|         std::string message; | ||||
|         ConnectionType type; | ||||
| 
 | ||||
|     public: | ||||
|         PinConnection(std::string message, ConnectionType type); | ||||
| 
 | ||||
|         ConnectionType getType(); | ||||
| 
 | ||||
|         std::string getMessage(); | ||||
|     }; | ||||
| 
 | ||||
|     class Pin { | ||||
|     public: | ||||
|         enum PinType { | ||||
| @ -21,13 +40,13 @@ namespace domain { | ||||
|         std::string name; | ||||
|         PinType type; | ||||
|         std::string tooltip; | ||||
|         std::optional<std::string> connection; | ||||
|         PinConnection connection; | ||||
|         domain::ui::Pin displayPin; | ||||
| 
 | ||||
|         std::optional<std::vector<Value>> wires; | ||||
| 
 | ||||
|     public: | ||||
|         Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin, | ||||
|         Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, | ||||
|             std::optional<std::vector<Value>> wires); | ||||
| 
 | ||||
|         std::string &getName(); | ||||
| @ -38,7 +57,7 @@ namespace domain { | ||||
| 
 | ||||
|         ui::Pin &getDisplayPin(); | ||||
| 
 | ||||
|         std::optional<std::string> getConnection(); | ||||
|         PinConnection &getConnection(); | ||||
| 
 | ||||
|         std::optional<std::vector<Value>> &getWires(); | ||||
|     }; | ||||
|  | ||||
| @ -57,10 +57,12 @@ namespace domain { | ||||
|         ConnectionComponent connectionComponent{instance->component.getName(), pinName}; | ||||
|         for(auto &conn: library.getConnections()) { | ||||
|             if(conn.isConnecting(connectionComponent)) { | ||||
|                 // if bus connection
 | ||||
|                 if(library.getBus(conn.getBus()).getType() == Bus::REGULAR) { | ||||
|                     for(auto& bus: busInstances) { | ||||
|                         if(bus->bus.getName() == conn.getBus()) { | ||||
|                             entries.push_back({ConnectionEntry::BUS, bus.get(), nullopt, nullopt, conn}); | ||||
|                             ConnectionEntry entry{ConnectionEntry::BUS, bus.get(), nullopt, nullopt, conn}; | ||||
|                             entries.emplace_back(entry); | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
| @ -90,16 +92,19 @@ namespace domain { | ||||
|                                 for(auto& conn: this->connections) { | ||||
|                                     if(conn->connection == entry.connection) { | ||||
|                                         if(bus.getType() == Bus::REGULAR) { | ||||
|                                             auto busConnection = dynamic_cast<BusConnectionInstance*>(conn.get()); | ||||
|                                             if(busConnection->instance == instance && busConnection->bus == entry.busInstance.value()) { | ||||
|                                             if(entry.busInstance.value()->bus.getName() == conn->connection.getBus()) { | ||||
|                                                 return true; | ||||
|                                             } | ||||
|                                         } else { | ||||
|                                             auto directConnection = dynamic_cast<DirectConnectionInstance*>(conn.get()); | ||||
|                                             if(directConnection->instance == instance && directConnection->secondInstance == entry.componentInstance.value() || | ||||
|                                                directConnection->secondInstance == instance && directConnection->instance == entry.componentInstance.value()) { | ||||
|                                                 return true; | ||||
|                                             auto *directInstance = dynamic_cast<DirectConnectionInstance*>(conn.get()); | ||||
|                                             ComponentInstance* secondInstance; | ||||
|                                             if(directInstance->instance == instance) { | ||||
|                                                 secondInstance = directInstance->secondInstance; | ||||
|                                             } else { | ||||
|                                                 secondInstance = directInstance->instance; | ||||
|                                             } | ||||
| 
 | ||||
|                                             return entry.componentInstance == secondInstance; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
| @ -108,8 +113,8 @@ namespace domain { | ||||
|                     entries.end() | ||||
|             ); | ||||
|         } | ||||
|         return entries; | ||||
| 
 | ||||
|         return entries; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -5,8 +5,9 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     ComdelContext::ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection) | ||||
|         : name(std::move(name)), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection) {} | ||||
| 
 | ||||
|     ComdelContext::ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus) | ||||
|         : name(std::move(name)), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection), inBus(inBus) {} | ||||
| 
 | ||||
|     bool ComdelContext::doesAttributeExists(std::string name, Value::ValueType type) { | ||||
|         for (auto &attribute: attributes) { | ||||
| @ -26,9 +27,7 @@ namespace domain { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /***********************************************************************
 | ||||
|      *                      ENUM CONVERSIONS                               * | ||||
|      ***********************************************************************/ | ||||
| 
 | ||||
|     Component::ComponentType toType(ComponentNode::ComponentType type) { | ||||
|         if (type == ComponentNode::MEMORY) { | ||||
|             return Component::MEMORY; | ||||
| @ -79,26 +78,29 @@ namespace domain { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) { | ||||
|         if (type == Value::MEMORY_REFERENCE) { | ||||
|             if (node.is(ValueNode::NIL)) { | ||||
|             if (node.getType() == ValueNode::NIL) { | ||||
|                 return Value::fromMemoryReference(nullopt); | ||||
|             } else { | ||||
|                 return Value::fromMemoryReference(node.asIdentifier()); | ||||
|             } | ||||
|         } | ||||
|         if (node.is(ValueNode::BOOL)) { | ||||
| 
 | ||||
|         if (node.getType() == ValueNode::BOOL) { | ||||
|             return Value::fromBool(node.asBool()); | ||||
|         } else if (node.is(ValueNode::INT)) { | ||||
|         } else if (node.getType() == ValueNode::INT) { | ||||
|             return Value::fromInt(node.asInt()); | ||||
|         } else if (node.is(ValueNode::STRING)) { | ||||
|         } else if (node.getType() == ValueNode::STRING) { | ||||
|             return Value::fromString(node.asString()); | ||||
|         } else if (node.is(ValueNode::NIL)) { | ||||
|         } else if (node.getType() == ValueNode::NIL) { | ||||
|             return Value::fromNull(); | ||||
|         } | ||||
|         return Value::fromReference(node.asIdentifier(), Value::UNDEFINED); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Bus::BusType toType(BusNode::BusType type) { | ||||
|         if (type == BusNode::AUTOMATIC) { | ||||
|             return Bus::AUTOMATIC; | ||||
| @ -108,6 +110,7 @@ namespace domain { | ||||
|         return Bus::REGULAR; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Pin::PinType toType(PinNode::PinType type) { | ||||
|         if (type == PinNode::IN) { | ||||
|             return Pin::IN; | ||||
| @ -117,6 +120,14 @@ namespace domain { | ||||
|         return Pin::IN_OUT; | ||||
|     } | ||||
| 
 | ||||
|     PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type) { | ||||
|         if (type == PinConnectionNode::OPTIONAL) { | ||||
|             return PinConnection::OPTIONAL; | ||||
|         } | ||||
|         return PinConnection::REQUIRED; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Popup::PopupType toType(PopupNode::PopupType type) { | ||||
|         if (type == PopupNode::AUTOMATIC) { | ||||
|             return Popup::AUTOMATIC; | ||||
| @ -124,11 +135,6 @@ namespace domain { | ||||
|         return Popup::ON_DEMAND; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /***********************************************************************
 | ||||
|      *                       SCHEMA CREATOR                                * | ||||
|      ***********************************************************************/ | ||||
| 
 | ||||
|     SchemaCreator::SchemaCreator(std::vector<FunctionValidator *> validators) | ||||
|             : validators(std::move(validators)) {} | ||||
| 
 | ||||
| @ -153,6 +159,7 @@ namespace domain { | ||||
|         } | ||||
| 
 | ||||
|         header = node.header ? node.header->asString() : ""; | ||||
| 
 | ||||
|         libraryInfo = node.libraryInfo ? node.libraryInfo->asString() : ""; | ||||
| 
 | ||||
|         for (auto &as: node.addressSpaces) { | ||||
| @ -194,16 +201,12 @@ namespace domain { | ||||
|         } else { | ||||
|             return nullopt; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Bus> SchemaCreator::loadBus(BusNode node) { | ||||
|         std::string busName = node.name.value; | ||||
| 
 | ||||
|         std::optional<std::string> displayName = nullopt; | ||||
|         if(node.displayName.has_value()) { | ||||
|             displayName = node.displayName->asString(); | ||||
|         } | ||||
| 
 | ||||
|         if (!node.instanceName) { | ||||
|             errors.emplace_back(node.span, "missing @instanceName"); | ||||
|             return nullopt; | ||||
| @ -266,15 +269,16 @@ namespace domain { | ||||
|             return nullopt; | ||||
|         } | ||||
| 
 | ||||
|         return Bus(busName, displayName, instanceName, tooltip, type, count, wires, displayBus); | ||||
|         return Bus(busName, instanceName, tooltip, type, count, wires, displayBus); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     std::optional<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode node) { | ||||
|         return AddressSpace(node.name.value, node.range.first.value, node.range.second.value); | ||||
|         return AddressSpace(node.name.value, node.start.value, node.end.value); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node) { | ||||
|         push(ComdelContext("connection", false, true, false)); | ||||
|         push(ComdelContext("connection", false, true, false, false)); | ||||
| 
 | ||||
|         std::string bus = node.bus.value; | ||||
|         auto busInstance = getBus(bus); | ||||
| @ -345,12 +349,10 @@ namespace domain { | ||||
| 
 | ||||
|             if (!node.second.has_value()) { | ||||
|                 errors.emplace_back(node.span, "missing second component"); | ||||
|                 return nullopt; | ||||
|             } | ||||
| 
 | ||||
|             ConnectionComponent second{node.second->component.value, node.second->pin.value}; | ||||
| 
 | ||||
| 
 | ||||
|             auto firstComponentInstance = getComponentPin(first.component, first.pin); | ||||
|             if (!firstComponentInstance) { | ||||
|                 errors.emplace_back(node.span, "pin does not exist"); | ||||
| @ -407,10 +409,7 @@ namespace domain { | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if(node.secondWires->empty()) { | ||||
|                 errors.emplace_back(node.span, "missing second @wires definition"); | ||||
|                 return nullopt; | ||||
|             } | ||||
| 
 | ||||
|             std::vector<Value> secondWires; | ||||
|             for (auto &secondWire: *node.secondWires) { | ||||
|                 if (secondWire.is(ValueNode::NIL)) { | ||||
| @ -454,6 +453,7 @@ namespace domain { | ||||
|                     attributes[1].setPupup(popup); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             pop(); | ||||
| 
 | ||||
|             return Connection(first, second, bus, attributes, firstWires, secondWires); | ||||
| @ -465,15 +465,10 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Component> SchemaCreator::loadComponent(ComponentNode node) { | ||||
|         push(ComdelContext(node.name.value, true, false, false)); | ||||
|         push(ComdelContext(node.name.value, true, false, false, false)); | ||||
| 
 | ||||
|         std::string componentName = node.name.value; | ||||
| 
 | ||||
|         std::optional<std::string> displayName = nullopt; | ||||
|         if (node.displayName.has_value()) { | ||||
|             displayName = node.displayName->asString(); | ||||
|         } | ||||
| 
 | ||||
|         if (!node.tooltip) { | ||||
|             errors.emplace_back(node.span, "missing @tooltip"); | ||||
|             pop(); | ||||
| @ -550,7 +545,7 @@ namespace domain { | ||||
|         } | ||||
| 
 | ||||
|         pop(); | ||||
|         return Component(componentName, displayName, tooltip, source, type, rules, instanceName, count, *display, pins, attributes); | ||||
|         return Component(componentName, tooltip, source, type, rules, instanceName, count, *display, pins, attributes); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Wire> SchemaCreator::loadWire(WireNode node) { | ||||
| @ -589,10 +584,12 @@ namespace domain { | ||||
|         } | ||||
|         ui::Pin displayPin = *display->getItems()[0].pin; | ||||
| 
 | ||||
|         std::optional<std::string> connection = std::nullopt; | ||||
|         if (node.connection) { | ||||
|             connection = node.connection->asString(); | ||||
| 
 | ||||
|         if (!node.connection) { | ||||
|             errors.emplace_back(node.span, "missing @connection"); | ||||
|             return nullopt; | ||||
|         } | ||||
|         auto connection = loadPinConnection(*node.connection); | ||||
| 
 | ||||
|         std::optional<std::vector<Value>> wiresOpt = std::nullopt; | ||||
|         if (node.wires.has_value()) { | ||||
| @ -613,81 +610,33 @@ namespace domain { | ||||
|         return Pin(pinName, type, tooltip, connection, displayPin, wiresOpt); | ||||
|     } | ||||
| 
 | ||||
|     Color readColor(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, Color _default) { | ||||
|         auto color = item.asColor(property, _default); | ||||
|         if(!color.has_value()) { | ||||
|             errors.emplace_back(item.span, "expected color"); | ||||
|             return _default; | ||||
|         } | ||||
|         return *color; | ||||
|     } | ||||
| 
 | ||||
|     std::string readString(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, std::string _default = "") { | ||||
|         auto value = item.asString(property, _default); | ||||
|         if(!value.has_value()) { | ||||
|             errors.emplace_back(item.span, "expected string"); | ||||
|             return _default; | ||||
|         } | ||||
|         return *value; | ||||
|     } | ||||
| 
 | ||||
|     long long int readInt(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, long long int _default = 0) { | ||||
|         auto value = item.asInt(property, _default); | ||||
|         if(!value.has_value()) { | ||||
|             errors.emplace_back(item.span, "expected int"); | ||||
|             return _default; | ||||
|         } | ||||
|         return *value; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node) { | ||||
|         std::vector<ui::Item> items; | ||||
|         for (auto &item: node.items) { | ||||
|             ui::Item displayItem; | ||||
|             std::string type = item.type.value; | ||||
| 
 | ||||
|             auto fillColor = readColor(errors, item, "fillColor", Color(255, 255, 255, 255)); | ||||
|             auto lineColor = readColor(errors, item, "lineColor", Color(0, 0, 0, 255)); | ||||
| 
 | ||||
|             if (type == "text") { | ||||
|             if (type == "rect") { | ||||
|                 long long int x, y, w, h; | ||||
|                 std::string text; | ||||
|                 auto color = readColor(errors, item, "color", Color(0, 0, 0, 255)); | ||||
|                 x = readInt(errors, item, "x"); | ||||
|                 y = readInt(errors, item, "y"); | ||||
|                 w = readInt(errors, item, "w"); | ||||
|                 h = readInt(errors, item, "h"); | ||||
|                 text = readString(errors, item, "text"); | ||||
|                 displayItem.text = ui::Text(x, y, w, h, text, color); | ||||
|             } else if (type == "ellipse") { | ||||
|                 long long int x, y, w, h; | ||||
|                 x = readInt(errors, item, "x"); | ||||
|                 y = readInt(errors, item, "y"); | ||||
|                 w = readInt(errors, item, "w"); | ||||
|                 h = readInt(errors, item, "h"); | ||||
|                 displayItem.ellipse = ui::Ellipse(x, y, w, h, {lineColor, fillColor}); | ||||
|             } else if (type == "rect") { | ||||
|                 long long int x, y, w, h; | ||||
|                 x = readInt(errors, item, "x"); | ||||
|                 y = readInt(errors, item, "y"); | ||||
|                 w = readInt(errors, item, "w"); | ||||
|                 h = readInt(errors, item, "h"); | ||||
|                 displayItem.rect = ui::Rect(x, y, w, h, {lineColor, fillColor}); | ||||
|                 x = item.asInt(&errors, "x"); | ||||
|                 y = item.asInt(&errors, "y"); | ||||
|                 w = item.asInt(&errors, "w"); | ||||
|                 h = item.asInt(&errors, "h"); | ||||
|                 displayItem.rect = ui::Rect(x, y, w, h); | ||||
|             } else if (type == "line") { | ||||
|                 long long int x1, y1, x2, y2; | ||||
|                 x1 = readInt(errors, item, "x1"); | ||||
|                 y1 = readInt(errors, item, "y1"); | ||||
|                 x2 = readInt(errors, item, "x2"); | ||||
|                 y2 = readInt(errors, item, "y2"); | ||||
|                 displayItem.line = ui::Line(x1, y1, x2, y2, {lineColor, fillColor}); | ||||
|                 x1 = item.asInt(&errors, "x1"); | ||||
|                 y1 = item.asInt(&errors, "y1"); | ||||
|                 x2 = item.asInt(&errors, "x2"); | ||||
|                 y2 = item.asInt(&errors, "y2"); | ||||
|                 displayItem.line = ui::Line(x1, y1, x2, y2); | ||||
|             } else if (type == "pin") { | ||||
|                 long long int x, y, w, h; | ||||
|                 x = readInt(errors, item, "x"); | ||||
|                 y = readInt(errors, item, "y"); | ||||
|                 w = readInt(errors, item, "w"); | ||||
|                 h = readInt(errors, item, "h"); | ||||
|                 std::string _orientation = readString(errors, item, "orientation", "bottom"); | ||||
|                 std::string _pinType = readString(errors, item, "type", "out"); | ||||
|                 x = item.asInt(&errors, "x"); | ||||
|                 y = item.asInt(&errors, "y"); | ||||
|                 w = item.asInt(&errors, "w"); | ||||
|                 h = item.asInt(&errors, "h"); | ||||
|                 std::string _orientation = item.asString(&errors, "orientation", "bottom"); | ||||
|                 std::string _pinType = item.asString(&errors, "type", "out"); | ||||
| 
 | ||||
|                 ui::PinOrientation orientation; | ||||
|                 if (_orientation == "left") { | ||||
| @ -713,14 +662,14 @@ namespace domain { | ||||
|                     errors.emplace_back(item.span, "unknown pin type '" + _pinType + "'"); | ||||
|                 } | ||||
| 
 | ||||
|                 displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType, {lineColor, fillColor}); | ||||
|                 displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType); | ||||
|             } else if (type == "bus") { | ||||
|                 long long int x, y, w, h; | ||||
|                 x = readInt(errors, item, "x"); | ||||
|                 y = readInt(errors, item, "y"); | ||||
|                 w = readInt(errors, item, "w"); | ||||
|                 h = readInt(errors, item, "h"); | ||||
|                 std::string _orientation = readString(errors, item, "orientation", "bottom"); | ||||
|                 x = item.asInt(&errors, "x"); | ||||
|                 y = item.asInt(&errors, "y"); | ||||
|                 w = item.asInt(&errors, "w"); | ||||
|                 h = item.asInt(&errors, "h"); | ||||
|                 std::string _orientation = item.asString(&errors, "orientation", "bottom"); | ||||
| 
 | ||||
|                 ui::BusOrientation orientation; | ||||
|                 if (_orientation == "horizontal") { | ||||
| @ -731,7 +680,7 @@ namespace domain { | ||||
|                     errors.emplace_back(item.span, "unknown bus orientation type '" + _orientation + "'"); | ||||
|                 } | ||||
| 
 | ||||
|                 displayItem.bus = ui::Bus(x, y, w, h, orientation, {lineColor, fillColor}); | ||||
|                 displayItem.bus = ui::Bus(x, y, w, h, orientation); | ||||
|             } else { | ||||
|                 errors.emplace_back(item.type.span, "unsupported display type"); | ||||
|             } | ||||
| @ -740,15 +689,16 @@ namespace domain { | ||||
|         return Display(items); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node) { | ||||
|         std::string message = node.message.asString(); | ||||
|         PinConnection::ConnectionType type = toType(node.type.value); | ||||
|         return {message, type}; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node) { | ||||
|         std::string name = node.name.value; | ||||
|         pushAdditional(name); | ||||
| 
 | ||||
|         std::optional<std::string> displayName = nullopt; | ||||
|         if (node.displayName.has_value()) { | ||||
|             displayName = node.displayName->asString(); | ||||
|         } | ||||
| 
 | ||||
|         Value value; | ||||
| 
 | ||||
|         if (current().inComponent) { | ||||
| @ -782,7 +732,7 @@ namespace domain { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         current().attributes.emplace_back(name, nullopt, value); | ||||
|         current().attributes.emplace_back(name, value); | ||||
| 
 | ||||
|         std::optional<Popup> popup; | ||||
|         if (node.popup) { | ||||
| @ -790,7 +740,7 @@ namespace domain { | ||||
|         } | ||||
| 
 | ||||
|         pop(); | ||||
|         return Attribute(name, displayName, value, popup); | ||||
|         return Attribute(name, value, popup); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Popup> SchemaCreator::loadPopup(PopupNode node, std::string name, Value::ValueType type) { | ||||
| @ -799,7 +749,7 @@ namespace domain { | ||||
|         pushAdditional(name); | ||||
| 
 | ||||
|         current().attributes.clear(); | ||||
|         current().attributes.emplace_back(name, nullopt, Value::ofType(type)); | ||||
|         current().attributes.emplace_back(name, Value::ofType(type)); | ||||
| 
 | ||||
|         if (!node.title) { | ||||
|             errors.emplace_back(node.span, "missing @title"); | ||||
| @ -882,7 +832,7 @@ namespace domain { | ||||
|             if (validator->getName() == function) { | ||||
|                 if (validator->getSignature().size() == node.params.size()) { | ||||
|                     std::vector<Value> params; | ||||
|                     for (unsigned int j = 0; j < validator->getSignature().size(); j++) { | ||||
|                     for (uint j = 0; j < validator->getSignature().size(); j++) { | ||||
|                         bool exists = false; | ||||
|                         auto type = toType(node.params[j]); | ||||
|                         if (type.getType() == Value::UNDEFINED) { | ||||
| @ -1034,6 +984,7 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
|     shared_ptr<ComponentInstance> SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) { | ||||
| 
 | ||||
|         auto componentInstanceName = instance.name.value; | ||||
|         auto position = std::make_pair(instance.position->first.value, instance.position->second.value); | ||||
| 
 | ||||
| @ -1056,7 +1007,7 @@ namespace domain { | ||||
|                 if (std::count_if(attributes.begin(), attributes.end(), | ||||
|                                   [&attr](InstanceAttribute &attribute) { return attr.getName() == attribute.name; }) == | ||||
|                     0) { | ||||
|                     errors.emplace_back(SourceError(instance.span, "missing attribute '" + attr.getDisplayName() + "'")); | ||||
|                     errors.emplace_back(SourceError(instance.span, "missing attribute '" + attr.getName() + "'")); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -1090,7 +1041,7 @@ namespace domain { | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Attribute> SchemaCreator::createMemoryAttribute() { | ||||
|         return Attribute("_memory", nullopt, Value::fromMemoryReference(std::nullopt), createMemoryPopup()); | ||||
|         return Attribute("_memory", Value::fromMemoryReference(std::nullopt), createMemoryPopup()); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Popup> SchemaCreator::createMemoryPopup() { | ||||
| @ -1138,7 +1089,7 @@ namespace domain { | ||||
|             this->context.push_back(current()); | ||||
|             current().name = name; | ||||
|         } else { | ||||
|             ComdelContext con(name, false, false, false); | ||||
|             ComdelContext con(name, false, false, false, false); | ||||
|             push(con); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -13,7 +13,6 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     /** Context used for loading model */ | ||||
|     struct ComdelContext { | ||||
|         std::vector<Attribute> attributes; | ||||
|         std::vector<std::string> wires; | ||||
| @ -21,8 +20,9 @@ namespace domain { | ||||
|         bool inComponent; | ||||
|         bool inConnection; | ||||
|         bool inSingleAutomaticConnection; | ||||
|         bool inBus; | ||||
| 
 | ||||
|         ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection); | ||||
|         ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus); | ||||
| 
 | ||||
|         bool doesAttributeExists(std::string name, Value::ValueType type); | ||||
|         bool doesWireExists(std::string name); | ||||
| @ -30,16 +30,6 @@ namespace domain { | ||||
|     }; | ||||
| 
 | ||||
|     class SchemaCreator { | ||||
| 
 | ||||
|     public: | ||||
|         explicit SchemaCreator(std::vector<FunctionValidator *> validators); | ||||
| 
 | ||||
|         std::vector<SourceError> getErrors(); | ||||
| 
 | ||||
|         std::optional<Library> loadLibrary(LibraryNode node); | ||||
|         Schema *loadSchema(SchemaNode node, Library &library); | ||||
| 
 | ||||
|     private: | ||||
|         std::vector<ComdelContext> context; | ||||
| 
 | ||||
|         std::string name; | ||||
| @ -53,6 +43,7 @@ namespace domain { | ||||
|         std::vector<Connection> connections; | ||||
|         std::map<std::string, std::string> messages; | ||||
| 
 | ||||
| 
 | ||||
|         std::vector<SourceError> errors; | ||||
|         std::vector<FunctionValidator *> validators; | ||||
| 
 | ||||
| @ -66,25 +57,35 @@ namespace domain { | ||||
|         std::optional<Display> loadDisplay(DisplayNode node); | ||||
|         std::optional<Wire> loadWire(WireNode node); | ||||
|         std::optional<Pin> loadPin(PinNode pins); | ||||
| 
 | ||||
|         PinConnection loadPinConnection(PinConnectionNode node); | ||||
| 
 | ||||
|         std::optional<Connection> loadConnection(ConnectionNode node); | ||||
|         std::optional<Bus> loadBus(BusNode node); | ||||
| 
 | ||||
|         std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library); | ||||
|         std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library); | ||||
| 
 | ||||
|         /** Utility classes */ | ||||
|         std::optional<Bus> getBus(std::string name); | ||||
|         std::optional<Pin> getComponentPin(std::string name, std::string pin); | ||||
|         bool hasAddressSpace(std::string name); | ||||
| 
 | ||||
|         void push(ComdelContext context); | ||||
|         void pushAdditional(std::string name); | ||||
|         ComdelContext ¤t(); | ||||
|         void pop(); | ||||
| 
 | ||||
|         std::optional<Attribute> createMemoryAttribute(); | ||||
|         vector<Enumeration> createWireEnumeration(vector<Value> enumeration); | ||||
|         std::optional<Popup> createMemoryPopup(); | ||||
| 
 | ||||
|         /** Context stack operations */ | ||||
|         void push(ComdelContext context); | ||||
|         void pushAdditional(std::string name); | ||||
|         ComdelContext ¤t(); | ||||
|         void pop(); | ||||
|     public: | ||||
|         explicit SchemaCreator(std::vector<FunctionValidator *> validators); | ||||
| 
 | ||||
|         std::vector<SourceError> getErrors(); | ||||
| 
 | ||||
|         std::optional<Library> loadLibrary(LibraryNode node); | ||||
|         Schema *loadSchema(SchemaNode node, Library &library); | ||||
|     }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| #include "value.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| @ -45,58 +44,32 @@ namespace domain { | ||||
|         return type == _type; | ||||
|     } | ||||
| 
 | ||||
|     std::string Value::getTypename() { | ||||
|         switch (type) { | ||||
|             case Value::BOOL: | ||||
|                 return "bool"; | ||||
|             case Value::INT: | ||||
|                 return "int"; | ||||
|             case Value::STRING: | ||||
|                 return "string"; | ||||
|             case Value::ADDRESS_SPACE: | ||||
|             case Value::ADDRESS_SPACE_REFERENCE: | ||||
|                 return "address space"; | ||||
|             case Value::WIRE_REFERENCE: | ||||
|                 return "wire reference"; | ||||
|             case Value::ATTRIBUTE_REFERENCE: | ||||
|                 return "attribute"; | ||||
|             case Value::NIL: | ||||
|                 return "null"; | ||||
|             case Value::MEMORY: | ||||
|             case Value::MEMORY_REFERENCE: | ||||
|                 return "memory"; | ||||
|             case Value::UNDEFINED: | ||||
|                 return "undefined"; | ||||
|         } | ||||
|         return "unknown"; | ||||
|     } | ||||
| 
 | ||||
|     long long Value::asInt() { | ||||
|         if (isType(Value::INT)) { | ||||
|             return intValue; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'int' but value contains '" + getTypename() + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     std::string Value::asString() { | ||||
|         if (isType(Value::STRING)) { | ||||
|             return stringValue; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'string' but value contains '" + getTypename() + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     bool Value::asBool() { | ||||
|         if (isType(Value::BOOL)) { | ||||
|             return boolValue; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'bool' but value contains '" + getTypename() + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     AddressSpace Value::asAddressSpace() { | ||||
|         if (isType(Value::ADDRESS_SPACE)) { | ||||
|             return *addressSpace; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'address space' but value contains '" + getTypename() + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     std::string Value::asReference() { | ||||
| @ -104,7 +77,7 @@ namespace domain { | ||||
|             isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) { | ||||
|             return reference; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'reference' but value contains '" + getTypename() + "'"); | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<std::string> Value::asMemoryReference() { | ||||
| @ -119,33 +92,29 @@ namespace domain { | ||||
|     void Value::setInt(long long value) { | ||||
|         if (isType(Value::INT)) { | ||||
|             this->intValue = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'int' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     void Value::setString(std::string value) { | ||||
|         if (isType(Value::STRING)) { | ||||
|             this->stringValue = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'string' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     void Value::setBool(bool value) { | ||||
|         if (isType(Value::BOOL)) { | ||||
|             this->boolValue = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'bool' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
|     void Value::setReference(std::string value) { | ||||
|         if (isType(Value::WIRE_REFERENCE)) { | ||||
|             this->reference = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'wire' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
|         throw std::exception(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| @ -218,7 +187,7 @@ namespace domain { | ||||
|                     return "null"; | ||||
|                 } | ||||
|             default: | ||||
|                 throw std::runtime_error("unknown type couldn't stringify '" + getTypename() + "'"); | ||||
|                 throw std::exception(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -228,31 +197,4 @@ namespace domain { | ||||
|         return val; | ||||
|     } | ||||
| 
 | ||||
|     bool Value::equals(Value value) { | ||||
|         if (value.getType() == type) { | ||||
|             switch (type) { | ||||
|                 case INT: | ||||
|                     return value.asInt() == intValue; | ||||
|                 case STRING: | ||||
|                     return value.asString() == stringValue; | ||||
|                 case NIL: | ||||
|                 case UNDEFINED: | ||||
|                     return true; | ||||
|                 case WIRE_REFERENCE: | ||||
|                 case ATTRIBUTE_REFERENCE: | ||||
|                 case ADDRESS_SPACE_REFERENCE: | ||||
|                     return value.asReference() == reference; | ||||
|                 case MEMORY_REFERENCE: | ||||
|                     return value.asMemoryReference() == memoryReference; | ||||
|                 case MEMORY: | ||||
|                     return value.asMemory() == memory; | ||||
|                 case BOOL: | ||||
|                     return value.asBool() == boolValue; | ||||
|                 default: | ||||
|                     return false; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -43,10 +43,34 @@ namespace domain { | ||||
| 
 | ||||
|         Value() = default; | ||||
| 
 | ||||
|         bool equals(Value value); | ||||
|         bool equals(Value value) { | ||||
|             if (value.getType() == type) { | ||||
|                 switch (type) { | ||||
|                     case INT: | ||||
|                         return value.asInt() == intValue; | ||||
|                     case STRING: | ||||
|                         return value.asString() == stringValue; | ||||
|                     case NIL: | ||||
|                     case UNDEFINED: | ||||
|                         return true; | ||||
|                     case WIRE_REFERENCE: | ||||
|                     case ATTRIBUTE_REFERENCE: | ||||
|                     case ADDRESS_SPACE_REFERENCE: | ||||
|                         return value.asReference() == reference; | ||||
|                     case MEMORY_REFERENCE: | ||||
|                         return value.asMemoryReference() == memoryReference; | ||||
|                     case MEMORY: | ||||
|                         return value.asMemory() == memory; | ||||
|                     case BOOL: | ||||
|                         return value.asBool() == boolValue; | ||||
|                     default: | ||||
|                         return false; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         std::string string(); | ||||
|         std::string getTypename(); | ||||
| 
 | ||||
|         ValueType getType(); | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,9 @@ | ||||
| #include "ast_nodes.h" | ||||
| 
 | ||||
| /*************************** AST NODE ********************************/ | ||||
| 
 | ||||
| AstNode::~AstNode() = default; | ||||
| 
 | ||||
| /*************************** NUMBER NODE ********************************/ | ||||
| 
 | ||||
| NumberNode::NumberNode(const std::string &expression) { | ||||
| @ -16,19 +20,6 @@ NumberNode::NumberNode(const std::string &expression) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*************************** COLOR NODE *********************************/ | ||||
| 
 | ||||
| ColorNode::ColorNode(const std::string &expression) { | ||||
|     auto value = expression.substr(1); | ||||
|     color.r = std::stoul(value.substr(0, 2), nullptr, 16); | ||||
|     color.g = std::stoul(value.substr(2, 4), nullptr, 16); | ||||
|     color.b = std::stoul(value.substr(4, 6), nullptr, 16); | ||||
|     color.a = 255; | ||||
|     if(value.length() == 8) { | ||||
|         color.a = std::stoul(value.substr(6,8), nullptr, 16); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*************************** STRING NODE ********************************/ | ||||
| 
 | ||||
| std::string StringNode::asString() { | ||||
| @ -37,11 +28,7 @@ std::string StringNode::asString() { | ||||
| 
 | ||||
| /*************************** VALUE NODE ********************************/ | ||||
| 
 | ||||
| ValueNode::ValueType ValueNode::getType() const { | ||||
|     return type.value; | ||||
| } | ||||
| 
 | ||||
| long long int ValueNode::asInt() { | ||||
| long long ValueNode::asInt() { | ||||
|     if (is(INT)) { | ||||
|         return intValue.value(); | ||||
|     } | ||||
| @ -62,14 +49,6 @@ std::string ValueNode::asIdentifier() { | ||||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| Color ValueNode::asColor() { | ||||
|     if (is(COLOR)) { | ||||
|         return colorValue.value(); | ||||
|     } | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool ValueNode::asBool() { | ||||
|     if (is(BOOL)) { | ||||
|         return boolValue.value(); | ||||
| @ -115,13 +94,6 @@ ValueNode ValueNode::ofNull() { | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofColor(Color color) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(COLOR); | ||||
|     value.colorValue = color; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofWire(std::optional<std::string> _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(WIRE); | ||||
| @ -135,38 +107,3 @@ ValueNode ValueNode::ofMemory(std::optional<std::string> _value) { | ||||
|     value.identifierValue = _value; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| /*************************** DisplayItem NODE ********************************/ | ||||
| 
 | ||||
| std::optional<long long int> DisplayItemNode::asInt(const std::string &property, long long int _default) { | ||||
|     auto prop = getProperty(property); | ||||
|     if(prop.has_value()) { | ||||
|         return prop->value.is(ValueNode::INT) ? std::optional(prop->value.asInt()) : std::nullopt; | ||||
|     } | ||||
|     return _default; | ||||
| } | ||||
| 
 | ||||
| std::optional<Color> DisplayItemNode::asColor(const std::string &property, Color _default) { | ||||
|     auto prop = getProperty(property); | ||||
|     if(prop.has_value()) { | ||||
|         return prop->value.is(ValueNode::COLOR) ? std::optional(prop->value.asColor()) : std::nullopt; | ||||
|     } | ||||
|     return _default; | ||||
| } | ||||
| 
 | ||||
| std::optional<std::string> DisplayItemNode::asString(const std::string &property, std::string _default) { | ||||
|     auto prop = getProperty(property); | ||||
|     if(prop.has_value()) { | ||||
|         return prop->value.is(ValueNode::STRING) ? std::optional(prop->value.asString()) : std::nullopt; | ||||
|     } | ||||
|     return _default; | ||||
| } | ||||
| 
 | ||||
| std::optional<PropertyNode> DisplayItemNode::getProperty(const std::string &property) { | ||||
|     for(auto &prop: values) { | ||||
|         if(prop.key.value == property) { | ||||
|             return prop; | ||||
|         } | ||||
|     } | ||||
|     return std::nullopt; | ||||
| } | ||||
| @ -2,36 +2,33 @@ | ||||
| #define AST_NODE_H | ||||
| 
 | ||||
| #include "token.h" | ||||
| #include "color.h" | ||||
| #include "source_error.h" | ||||
| #include <optional> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            BASE TYPES                                     * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| /**
 | ||||
|  * AST base class, all AST node classes extend this class. Class contains basic | ||||
|  * information about nodes location in file. | ||||
|  */ | ||||
| class AstNode { | ||||
| public: | ||||
|     /** Contains information about where in source file given node is located */ | ||||
| 
 | ||||
|     Span span; | ||||
| 
 | ||||
|     AstNode() = default; | ||||
| 
 | ||||
|     virtual ~AstNode(); | ||||
| 
 | ||||
|     AstNode(AstNode &&) = default; | ||||
| 
 | ||||
|     AstNode &operator=(AstNode &&) = default; | ||||
| 
 | ||||
|     AstNode(const AstNode &) = default; | ||||
| 
 | ||||
|     AstNode &operator=(const AstNode &) = default; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * AST base enum class, | ||||
|  * Used to represent AST enums | ||||
|  * */ | ||||
| template<typename T> | ||||
| struct EnumNode : public AstNode { | ||||
|     EnumNode() = default; | ||||
| @ -41,423 +38,254 @@ struct EnumNode : public AstNode { | ||||
|     T value; | ||||
| }; | ||||
| 
 | ||||
| /** Represents string
 | ||||
|  * value contains quote-marks ("" or '' depending on string type) | ||||
|  * */ | ||||
| struct StringNode : public AstNode { | ||||
|     /** String including quote-marks*/ | ||||
|     std::string value; | ||||
| 
 | ||||
|     /** Returns string without quote-marks */ | ||||
|     std::string asString(); | ||||
| }; | ||||
| 
 | ||||
| /** Represents identifiers */ | ||||
| struct IdentifierNode : public AstNode { | ||||
|     std::string value; | ||||
| }; | ||||
| 
 | ||||
| /** Represents all numbers used
 | ||||
|  * All numbers must fit into long long int | ||||
|  * */ | ||||
| struct NumberNode : public AstNode { | ||||
|     long long int value = 0; | ||||
|     long long int value; | ||||
| 
 | ||||
|     explicit NumberNode(const std::string &expression); | ||||
| 
 | ||||
|     NumberNode() = default; | ||||
|     NumberNode() : value(0) {} | ||||
| }; | ||||
| 
 | ||||
| /** Represents color
 | ||||
|  * color comes in two formats #RRGGBB or #RRGGBBAA (AA representing opacity) | ||||
|  * */ | ||||
| struct ColorNode : public AstNode { | ||||
|     Color color; | ||||
| 
 | ||||
|     explicit ColorNode(const std::string &expression); | ||||
| 
 | ||||
|     ColorNode() = default; | ||||
| }; | ||||
| 
 | ||||
| /** Represents ordered number pair */ | ||||
| struct NumberPairNode : public AstNode { | ||||
| struct CountNode : public AstNode { | ||||
|     NumberNode first; | ||||
|     NumberNode second; | ||||
| 
 | ||||
|     NumberPairNode(NumberNode first, NumberNode second) : first(first), second(second) {} | ||||
|     CountNode(NumberNode first, NumberNode second) : first(std::move(first)), second(std::move(second)) {} | ||||
| 
 | ||||
|     NumberPairNode() = default; | ||||
|     CountNode() = default; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct AddressSpaceNode : public AstNode { | ||||
|     IdentifierNode name; | ||||
|     NumberNode start; | ||||
|     NumberNode end; | ||||
| }; | ||||
| 
 | ||||
| /** Represents generic value
 | ||||
|  * Because attributes can contain different value types, | ||||
|  * this allows us to use one generic type for all attributes | ||||
|  * */ | ||||
| class ValueNode : public AstNode { | ||||
| public: | ||||
|     enum ValueType { | ||||
|         /** Stores same content as NumberNode */ | ||||
|         INT, | ||||
|         /** Stores same content as StringNode */ | ||||
|         STRING, | ||||
|         /** Stores true or false */ | ||||
|         BOOL, | ||||
|         /** Stores wire nam or null */ | ||||
|         WIRE, | ||||
|         /** Default type assigned when node value is of type IdentifierNode and more correct type is assigned later */ | ||||
|         IDENTIFIER, | ||||
|         /** Stores memory name or null */ | ||||
|         MEMORY, | ||||
|         /** Stores null */ | ||||
|         NIL, | ||||
|         /** Store same content as ColorNode */ | ||||
|         COLOR, | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     /** Type determines what is stored inside ValueNode */ | ||||
|     EnumNode<ValueType> type = EnumNode(NIL); | ||||
|     /** All possible values for ValueNode are stored inside optionals */ | ||||
|     std::optional<long long> intValue = std::nullopt; | ||||
|     std::optional<std::string> stringValue = std::nullopt; | ||||
|     std::optional<bool> boolValue = std::nullopt; | ||||
|     std::optional<std::string> identifierValue = std::nullopt; | ||||
|     std::optional<Color> colorValue = std::nullopt; | ||||
|     EnumNode<ValueType> type; | ||||
|     std::optional<long long> intValue; | ||||
|     std::optional<std::string> stringValue; | ||||
|     std::optional<bool> boolValue; | ||||
|     std::optional<std::string> identifierValue; | ||||
| 
 | ||||
| public: | ||||
|     ValueNode() = default; | ||||
| 
 | ||||
|     ValueType getType() const; | ||||
|     ValueType getType() const { | ||||
|         return type.value; | ||||
|     } | ||||
| 
 | ||||
|     long long asInt(); | ||||
| 
 | ||||
|     /** Checks ValueNode is of requested type and returns it or returns default value for given type*/ | ||||
|     long long int asInt(); | ||||
|     std::string asString(); | ||||
| 
 | ||||
|     std::string asIdentifier(); | ||||
|     Color asColor(); | ||||
| 
 | ||||
|     bool asBool(); | ||||
| 
 | ||||
|     /** Returns true if ValueNode is of given valueType */ | ||||
|     bool is(ValueType valueType); | ||||
| 
 | ||||
|     /** Static methods used to generate ValueNodes of requested type */ | ||||
|     static ValueNode ofBool(bool _value); | ||||
| 
 | ||||
|     static ValueNode ofInt(long long _value); | ||||
| 
 | ||||
|     static ValueNode ofString(std::string _value); | ||||
| 
 | ||||
|     static ValueNode ofIdentifier(std::string _value); | ||||
| 
 | ||||
|     static ValueNode ofMemory(std::optional<std::string> _value); | ||||
| 
 | ||||
|     static ValueNode ofNull(); | ||||
|     static ValueNode ofColor(Color color); | ||||
| 
 | ||||
|     static ValueNode ofWire(std::optional<std::string> _value); | ||||
| }; | ||||
| 
 | ||||
| /** Represents an identifier-value pair*/ | ||||
| struct PropertyNode : public AstNode { | ||||
|     IdentifierNode key; | ||||
|     ValueNode value; | ||||
| 
 | ||||
|     PropertyNode() = default; | ||||
|     PropertyNode(IdentifierNode key, ValueNode value): key(key), value(value) {} | ||||
| }; | ||||
| 
 | ||||
| /** Represents a string-value pair */ | ||||
| struct StringPropertyNode : public AstNode { | ||||
|     StringNode key; | ||||
|     ValueNode value; | ||||
| 
 | ||||
|     StringPropertyNode() = default; | ||||
|     StringPropertyNode(StringNode key, ValueNode value): key(key), value(value) {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            RULE TYPES                                     * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| struct IfStatementNode; | ||||
| 
 | ||||
| /** Represents validation rule
 | ||||
|  * Rules are made from a list of | ||||
|  * if - else if statements | ||||
|  * */ | ||||
| struct RuleNode : public AstNode { | ||||
|     std::vector<IfStatementNode> statements; | ||||
| }; | ||||
| 
 | ||||
| /** Represents condition inside if statement
 | ||||
|  * Every condition is made from optional negation operator ! | ||||
|  * Function called and list of function parameters | ||||
|  * */ | ||||
| struct ConditionNode { | ||||
|     bool negated; | ||||
|     IdentifierNode functionName; | ||||
|     std::vector<ValueNode> params; | ||||
| }; | ||||
| 
 | ||||
| /** Represents action executed inside if statement
 | ||||
|  * */ | ||||
| struct ActionNode : public AstNode { | ||||
|     /** There are two types of action determined by action type */ | ||||
| class ActionNode : public AstNode { | ||||
| public: | ||||
|     enum ActionType { | ||||
|         /** Error actions represent invalid state and cause validation to fail */ | ||||
|         ERROR, | ||||
|         /** Warning actions represent states that can cause issue when simulating
 | ||||
|          * model but models created with it are still valid | ||||
|          * */ | ||||
|         WARNING | ||||
|     }; | ||||
| 
 | ||||
|     EnumNode<ActionType> type; | ||||
|     /** Message used if condition is fulfilled */ | ||||
|     StringNode message; | ||||
| }; | ||||
| 
 | ||||
| /** If statements represents one validation check inside rule */ | ||||
| 
 | ||||
| struct IfStatementNode : public AstNode { | ||||
|     ConditionNode condition; | ||||
|     ActionNode action; | ||||
| }; | ||||
| 
 | ||||
| struct RuleNode : public AstNode { | ||||
|     std::vector<IfStatementNode> statements; | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            ATTRIBUTE TYPES                                * | ||||
|  *****************************************************************************/ | ||||
| struct EnumerationNode : public AstNode { | ||||
|     StringNode key; | ||||
|     ValueNode value; | ||||
| }; | ||||
| 
 | ||||
| /** Represents popup dialog used to modified attribute inside which it is defined
 | ||||
|  * */ | ||||
| struct PopupNode : public AstNode { | ||||
|     /** Determines type of popup*/ | ||||
|     enum PopupType { | ||||
|         /** Automatic popup is opened when component or connection containing it is defined */ | ||||
|         AUTOMATIC, | ||||
|         /** On demand popups are opened on user request usually from context menus*/ | ||||
|         ON_DEMAND | ||||
|     }; | ||||
| 
 | ||||
|     std::optional<EnumNode<PopupType>> type; | ||||
|     /** Title of popup */ | ||||
|     std::optional<StringNode> title; | ||||
|     /** Text of popup */ | ||||
|     std::optional<StringNode> text; | ||||
| 
 | ||||
|     /** If popup contains an enumeration*/ | ||||
|     bool enumerated; | ||||
|     std::vector<StringPropertyNode> enumeration; | ||||
|     std::vector<EnumerationNode> enumeration; | ||||
| 
 | ||||
|     /** Validation rules for given popup */ | ||||
|     std::vector<RuleNode> rules; | ||||
| }; | ||||
| 
 | ||||
| /** Represents component or connection attribute
 | ||||
|  * Attributes are values that can programmatically be changed | ||||
|  * if popup is defined | ||||
|  * */ | ||||
| struct AttributeNode : public AstNode { | ||||
|     /** Type of attribute */ | ||||
|     ValueNode::ValueType type; | ||||
|     /** Name of attribute */ | ||||
|     IdentifierNode name; | ||||
|     /** Display name */ | ||||
|     std::optional<StringNode> displayName; | ||||
|     /** Default type of attribute */ | ||||
|     std::optional<ValueNode> defaultValue; | ||||
|     /** Popup used to change attribute value */ | ||||
|     std::optional<PopupNode> popup; | ||||
| struct PropertyNode : public AstNode { | ||||
|     IdentifierNode key; | ||||
|     ValueNode value; | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            DISPLAY TYPES                                  * | ||||
|  *****************************************************************************/ | ||||
| struct DisplayItemNode : public AstNode { | ||||
|     IdentifierNode type; | ||||
|     std::vector<PropertyNode> values; | ||||
| 
 | ||||
| struct DisplayItemNode; | ||||
|     long long int asInt(std::vector<SourceError> *errors, const std::string &property, long long int _default = 0) { | ||||
|         for (auto &prop: values) { | ||||
|             if (prop.key.value == property) { | ||||
|                 if (prop.value.is(ValueNode::INT)) { | ||||
|                     return prop.value.asInt(); | ||||
|                 } else { | ||||
|                     if (errors != nullptr) { | ||||
|                         errors->emplace_back(prop.value.span, "expected number"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return _default; | ||||
|     } | ||||
| 
 | ||||
|     std::string asIdentifier(std::vector<SourceError> *errors, const std::string &property, std::string _default = "") { | ||||
|         for (auto &prop: values) { | ||||
|             if (prop.key.value == property) { | ||||
|                 if (prop.value.is(ValueNode::IDENTIFIER)) { | ||||
|                     return prop.value.asIdentifier(); | ||||
|                 } else { | ||||
|                     if (errors != nullptr) { | ||||
|                         errors->emplace_back(prop.value.span, "expected identifier"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return _default; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     std::string asString(std::vector<SourceError> *errors, const std::string &property, std::string _default = "") { | ||||
|         for (auto &prop: values) { | ||||
|             if (prop.key.value == property) { | ||||
|                 if (prop.value.is(ValueNode::STRING)) { | ||||
|                     return prop.value.asString(); | ||||
|                 } else { | ||||
|                     if (errors != nullptr) { | ||||
|                         errors->emplace_back(prop.value.span, "expected string"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return _default; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /** Represents how a component or bus is rendered
 | ||||
|  * Display is made from an list of display items | ||||
|  * */ | ||||
| struct DisplayNode : public AstNode { | ||||
|     std::vector<DisplayItemNode> items; | ||||
| }; | ||||
| 
 | ||||
| /** DisplayItem represents one rendered item
 | ||||
|  * in source code items are defined similar to json objects | ||||
|  * eg. | ||||
|  * @code rect { | ||||
|  *  x: 100; | ||||
|  *  y: 100; | ||||
|  *  w: 100; | ||||
|  *  h: 100; | ||||
|  *  fillColor: #123456 | ||||
|  * } | ||||
|  * */ | ||||
| struct DisplayItemNode : public AstNode { | ||||
|     /** Contains type of display item */ | ||||
|     IdentifierNode type; | ||||
|     /** Contains all property nodes */ | ||||
|     std::vector<PropertyNode> values; | ||||
| struct PinConnectionNode : public AstNode { | ||||
|     enum ConnectionType { | ||||
|         REQUIRED, | ||||
|         OPTIONAL | ||||
|     }; | ||||
| 
 | ||||
|     /** Returns value of requested property
 | ||||
|      * If requested property doesn't exists default value is returned (eg. asInt is called but PropertyNode contains string) | ||||
|      * If value of requested property is different than expected nullopt is retured | ||||
|      * */ | ||||
|     std::optional<long long int> asInt(const std::string &property, long long int _default = 0); | ||||
|     std::optional<Color> asColor(const std::string &property, Color _default = Color(0, 0, 0)); | ||||
|     std::optional<std::string> asString(const std::string &property, std::string _default = ""); | ||||
| 
 | ||||
| private: | ||||
|     std::optional<PropertyNode> getProperty(const std::string &property); | ||||
|     StringNode message; | ||||
|     EnumNode<ConnectionType> type; | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            LIBRARY TYPES                                  * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| /** Represents AddressSpaces
 | ||||
|  * Address spaces are defined with their name and address range | ||||
|  * */ | ||||
| struct AddressSpaceNode : public AstNode { | ||||
|     IdentifierNode name; | ||||
|     /** Range represent which addresses are available for components that use memory space [first, second> */ | ||||
|     NumberPairNode range; | ||||
| }; | ||||
| 
 | ||||
| /** Pins are used to create component-component or component-bus connections */ | ||||
| struct PinNode : public AstNode { | ||||
|     /** Determines pin type, pin types currently only affect how pins are rendered */ | ||||
|     enum PinType { | ||||
|         IN_OUT, | ||||
|         IN, | ||||
|         OUT | ||||
|     }; | ||||
| 
 | ||||
|     /** Name of pin */ | ||||
|     IdentifierNode name; | ||||
|     /** Type of pin */ | ||||
|     EnumNode<PinType> type; | ||||
|     /** Tooltip content displayed on hover over pin */ | ||||
|     std::optional<StringNode> tooltip; | ||||
|     /** If present this means pin must be connected to another component or bus to create connection
 | ||||
|      * Connection contains error message shown | ||||
|      * */ | ||||
|     std::optional<StringNode> connection; | ||||
|     /** Determines how the pin is displayed */ | ||||
|     std::optional<PinConnectionNode> connection; | ||||
|     std::optional<DisplayNode> display; | ||||
|     /** If pin connection is optional it requires list of wires used to populate comdel model */ | ||||
|     std::optional<std::vector<ValueNode>> wires; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Represents COMDEL component | ||||
|  * */ | ||||
| struct ComponentNode : public AstNode { | ||||
|     /** Determines type of component */ | ||||
|     enum ComponentType { | ||||
|         /** Generic component */ | ||||
|         OTHER, | ||||
|         /** Represents processor, all processors have implicit attribute _memory if type memory
 | ||||
|          * used when generating COMDEL model to connect memories and processors | ||||
|          */ | ||||
|         PROCESSOR, | ||||
|         /** Represents memory, all components of type memory can be selected in _memory attribute of processor */ | ||||
|         MEMORY | ||||
|     }; | ||||
| 
 | ||||
|     /** Component name */ | ||||
|     IdentifierNode name; | ||||
|     /** Component name */ | ||||
|     std::optional<StringNode> displayName; | ||||
|     /** Tooltip displayed on hover */ | ||||
|     std::optional<StringNode> tooltip; | ||||
|     /** Contains path to COMDEL source containing current component */ | ||||
|     std::optional<StringNode> source; | ||||
|     /** Type of component */ | ||||
|     EnumNode<ComponentType> type; | ||||
|     /** List of component level rules */ | ||||
|     std::vector<RuleNode> rules; | ||||
|     /** Default used to name instances */ | ||||
|     std::optional<IdentifierNode> instanceName; | ||||
|     /** Count determines number of instances allowed in a schema */ | ||||
|     std::optional<NumberPairNode> count; | ||||
|     /** Display determines how component is rendered */ | ||||
|     std::optional<DisplayNode> display; | ||||
|     /** List of all pins */ | ||||
|     std::vector<PinNode> pins; | ||||
|     /** List of all attributes */ | ||||
|     std::vector<AttributeNode> attributes; | ||||
| }; | ||||
| 
 | ||||
| /** WireNode represents COMDEL wire
 | ||||
|  * */ | ||||
| struct WireNode : public AstNode { | ||||
|     /** Determines type of wires */ | ||||
|     enum WireType { | ||||
|         /** Generic wire */ | ||||
|         WIRE, | ||||
|         /** wired_and can have multiple sources, that are ANDed together */ | ||||
|         WIRED_AND, | ||||
|         /** wired_and can have multiple sources, that are ORed together */ | ||||
|         WIRED_OR, | ||||
|         /** r_wire can remain unconnected */ | ||||
|         R_WIRE | ||||
|     }; | ||||
|     EnumNode<WireType> type; | ||||
|     /** Name of wire */ | ||||
|     IdentifierNode name; | ||||
|     /** Number of bits inside of a wire */ | ||||
|     NumberNode size; | ||||
| 
 | ||||
|     /** If wire is visible or hidden, this determines how wires are generated in COMDEL */ | ||||
|     bool hidden = false; | ||||
| 
 | ||||
|     /** If wire isn't connected to anything it is replaced with terminate with terminateWith value */ | ||||
|     bool hasTerminateWith = false; | ||||
|     bool hasTerminateWith; | ||||
|     ValueNode terminateWith; | ||||
| }; | ||||
| 
 | ||||
| /** Buses dont exist in COMDEL but they are useful
 | ||||
|  * as they allow us to connect multiple COMDEL wires together | ||||
|  * */ | ||||
| struct BusNode : public AstNode { | ||||
|     enum BusType { | ||||
|         /** This busses connect two components */ | ||||
|         AUTOMATIC, | ||||
|         /**
 | ||||
|          * This busses allow us to connect multiple component together using one bus | ||||
|          * */ | ||||
|         REGULAR, | ||||
|         /** This busses connect two components,
 | ||||
|          * they differ from automatic as they allow us to connect same pins multiple times */ | ||||
|         SINGLE_AUTOMATIC | ||||
|     }; | ||||
| 
 | ||||
|     EnumNode<BusType> type; | ||||
|     /** Bus name */ | ||||
| struct AttributeNode : public AstNode { | ||||
|     ValueNode::ValueType type; | ||||
|     IdentifierNode name; | ||||
|     /** Display name */ | ||||
|     std::optional<StringNode> displayName; | ||||
|     /** Default used to name instances */ | ||||
|     std::optional<IdentifierNode> instanceName; | ||||
|     /** Tooltip displayed on hover */ | ||||
|     std::optional<StringNode> tooltip; | ||||
|     /** Count determines number of instances allowed in a schema */ | ||||
|     std::optional<NumberPairNode> count; | ||||
|     /** Display determines how component is rendered */ | ||||
|     std::optional<DisplayNode> display; | ||||
| 
 | ||||
|     /** List of all COMDEL wires contained in bus */ | ||||
|     std::vector<WireNode> wires; | ||||
|     std::optional<ValueNode> defaultValue; | ||||
|     std::optional<PopupNode> popup; | ||||
| }; | ||||
| 
 | ||||
| /** Represents ComponentConnection key in Connection node
 | ||||
|  * (eg. componentName.pinName) | ||||
|  * */ | ||||
| struct ConnectionComponentNode : public AstNode { | ||||
|     IdentifierNode component; | ||||
|     IdentifierNode pin; | ||||
| }; | ||||
| 
 | ||||
| /** Represents Connection node
 | ||||
|  * Connection can be between component and bus in which second is null, | ||||
|  * or between two components | ||||
|  * */ | ||||
| struct ConnectionNode : public AstNode { | ||||
|     ConnectionComponentNode first; | ||||
|     std::optional<ConnectionComponentNode> second; | ||||
| @ -465,22 +293,51 @@ struct ConnectionNode : public AstNode { | ||||
|     IdentifierNode bus; | ||||
|     std::vector<AttributeNode> attributes; | ||||
| 
 | ||||
|     /** If connection is of type component-component it contains two pairs of wires */ | ||||
|     std::vector<ValueNode> firstWires; | ||||
|     std::optional<std::vector<ValueNode>> secondWires; | ||||
| }; | ||||
| 
 | ||||
| /** LibraryNode represent library instance */ | ||||
| struct ComponentNode : public AstNode { | ||||
|     enum ComponentType { | ||||
|         OTHER, | ||||
|         PROCESSOR, | ||||
|         MEMORY | ||||
|     }; | ||||
| 
 | ||||
|     IdentifierNode name; | ||||
|     std::optional<StringNode> tooltip; | ||||
|     std::optional<StringNode> source; | ||||
|     EnumNode<ComponentType> type; | ||||
|     std::vector<RuleNode> rules; | ||||
|     std::optional<IdentifierNode> instanceName; | ||||
|     std::optional<CountNode> count; | ||||
|     std::optional<DisplayNode> display; | ||||
|     std::vector<PinNode> pins; | ||||
|     std::vector<AttributeNode> attributes; | ||||
| }; | ||||
| 
 | ||||
| struct BusNode : public AstNode { | ||||
|     enum BusType { | ||||
|         AUTOMATIC, | ||||
|         REGULAR, | ||||
|         SINGLE_AUTOMATIC | ||||
|     }; | ||||
| 
 | ||||
|     EnumNode<BusType> type; | ||||
|     IdentifierNode name; | ||||
|     std::optional<IdentifierNode> instanceName; | ||||
|     std::optional<StringNode> tooltip; | ||||
|     std::optional<CountNode> count; | ||||
|     std::optional<DisplayNode> display; | ||||
| 
 | ||||
|     std::vector<WireNode> wires; | ||||
| }; | ||||
| 
 | ||||
| struct LibraryNode : public AstNode { | ||||
|     /** Name of library */ | ||||
|     std::optional<StringNode> name; | ||||
|     /** Library info contains generic information about library */ | ||||
|     std::optional<StringNode> libraryInfo; | ||||
|     /** Contains text that is added to top of COMDEL file */ | ||||
|     std::optional<StringNode> header; | ||||
|     /** Contains path to component directory */ | ||||
|     std::optional<StringNode> componentDirectory; | ||||
|     /** Contains text that is added to top of System component in COMDEL file */ | ||||
|     std::optional<StringNode> componentHeader; | ||||
| 
 | ||||
|     std::vector<AddressSpaceNode> addressSpaces; | ||||
| @ -489,64 +346,46 @@ struct LibraryNode : public AstNode { | ||||
|     std::vector<BusNode> buses; | ||||
|     std::vector<ConnectionNode> connections; | ||||
| 
 | ||||
|     /** Contains properties used to translate dialog and error messages */ | ||||
|     std::vector<PropertyNode> messages; | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            LIBRARY TYPES                                  * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| /** Represents instance of attribute in component or connection instance */ | ||||
| // SCHEMA models
 | ||||
| struct InstanceAttributeNode : public AstNode { | ||||
|     IdentifierNode name; | ||||
|     ValueNode value; | ||||
| }; | ||||
| 
 | ||||
| /** Represents instance of a component or a bus */ | ||||
| struct InstanceNode : public AstNode { | ||||
|     /** Contains instance name */ | ||||
|     IdentifierNode name; | ||||
|     /** Contains component name */ | ||||
|     IdentifierNode component; | ||||
| 
 | ||||
|     /** Contains position of component instance */ | ||||
|     std::optional<NumberPairNode> position; | ||||
|     std::optional<CountNode> position; | ||||
|     std::vector<InstanceAttributeNode> attributes; | ||||
| 
 | ||||
|     /** Contains size of bus instances */ | ||||
|     std::optional<NumberNode> size; | ||||
| }; | ||||
| 
 | ||||
| /** Represents ComponentConnection of a selected instance */ | ||||
| struct ConnectionComponentInstanceNode : public AstNode { | ||||
|     /** Name of component instance */ | ||||
| struct ConnectionComponentInstance : public AstNode { | ||||
|     IdentifierNode instance; | ||||
|     /** Name of pin */ | ||||
|     IdentifierNode pin; | ||||
| }; | ||||
| 
 | ||||
| /** Represents Connection instance */ | ||||
| struct ConnectionInstanceNode : public AstNode { | ||||
|     ConnectionComponentInstanceNode first; | ||||
|     std::optional<ConnectionComponentInstanceNode> second; | ||||
|     ConnectionComponentInstance first; | ||||
|     std::optional<ConnectionComponentInstance> second; | ||||
| 
 | ||||
|     IdentifierNode bus; | ||||
| 
 | ||||
|     std::vector<InstanceAttributeNode> attributes; | ||||
| }; | ||||
| 
 | ||||
| /** Represent schema instance */ | ||||
| 
 | ||||
| struct SchemaNode : public AstNode { | ||||
|     /** Contains path to library source */ | ||||
|     std::optional<StringNode> source; | ||||
| 
 | ||||
|     /** Contains list of instances */ | ||||
|     std::vector<InstanceNode> instances; | ||||
|     /** Contains list of connection */ | ||||
|     std::vector<ConnectionInstanceNode> connections; | ||||
| 
 | ||||
|     /** Contains library */ | ||||
|     std::optional<LibraryNode> library; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -1,21 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 12.06.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef SCHEMEEDITOR_COLOR_H | ||||
| #define SCHEMEEDITOR_COLOR_H | ||||
| 
 | ||||
| 
 | ||||
| struct Color { | ||||
|     unsigned char r = 0; | ||||
|     unsigned char g = 0; | ||||
|     unsigned char b = 0; | ||||
|     unsigned char a = 255; | ||||
| 
 | ||||
|     Color() = default; | ||||
| 
 | ||||
|     Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_COLOR_H
 | ||||
| @ -11,14 +11,11 @@ | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| /** Contains results of tokenizing,
 | ||||
|  * if errors isn't empty tokenizing has failed */ | ||||
| struct LexerResult { | ||||
|     std::vector<Token> tokens; | ||||
|     std::vector<SourceError> errors; | ||||
| }; | ||||
| 
 | ||||
| /** Used to tokenize input string */ | ||||
| class ComdelLexer { | ||||
| 
 | ||||
|     enum Radix { | ||||
| @ -27,11 +24,9 @@ class ComdelLexer { | ||||
|         HEX_NUMBER = 16 | ||||
|     }; | ||||
| 
 | ||||
|     /** Source file */ | ||||
|     std::string source; | ||||
|     std::vector<Token> tokens; | ||||
|     std::vector<SourceError> errors; | ||||
|     /** Source file */ | ||||
|     ParseContext *parseContext; | ||||
|     unsigned fileId; | ||||
| 
 | ||||
| @ -41,32 +36,34 @@ public: | ||||
|     LexerResult tokenize(); | ||||
| 
 | ||||
| private: | ||||
|     /** Current parsing info */ | ||||
|     void skipWhitespace(); | ||||
| 
 | ||||
|     unsigned takeNumberInRadix(Radix radix); | ||||
| 
 | ||||
|     unsigned takeHexColor(); | ||||
| 
 | ||||
|     bool digitIsValid(char ch, Radix radix); | ||||
| 
 | ||||
|     Radix takeRadix(); | ||||
| 
 | ||||
|     PResult<TokenType> nextTokenType(); | ||||
| 
 | ||||
|     Position tokenBegin; | ||||
|     Position position; | ||||
|     char ch; | ||||
| 
 | ||||
|     /** Methods used to skip unused content */ | ||||
|     void skipWhitespace(); | ||||
|     void skipComment(); | ||||
| 
 | ||||
|     bool skipMultilineComment(); | ||||
|     void bump(unsigned count = 1); | ||||
| 
 | ||||
|     /** Metods used for number parsing */ | ||||
|     unsigned takeNumberInRadix(Radix radix); | ||||
|     bool digitIsValid(char ch, Radix radix); | ||||
|     Radix takeRadix(); | ||||
| 
 | ||||
|     unsigned takeHexColor(); | ||||
| 
 | ||||
|     PResult<TokenType> nextTokenType(); | ||||
| 
 | ||||
|     PResult<TokenType> takeString(); | ||||
| 
 | ||||
|     PResult<TokenType> takeRawString(); | ||||
| 
 | ||||
|     void bump(unsigned count = 1); | ||||
| 
 | ||||
|     char peek(); | ||||
| 
 | ||||
|     /** Checks if we reached end of file */ | ||||
|     bool eof(); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -42,20 +42,16 @@ private: | ||||
| 
 | ||||
|     Span &getPreviousSpan(); | ||||
| 
 | ||||
|     /** Skips current token */ | ||||
|     void bump(); | ||||
|     /** Checks if next token is of given type and if it is consumes it */ | ||||
| 
 | ||||
|     bool consume(TokenType tokenType); | ||||
|     /** Checks if next token is of given type */ | ||||
| 
 | ||||
|     bool check(TokenType tokenType); | ||||
|     /** Skips until next keyword on same level
 | ||||
|      * Used to continue parsing on error | ||||
|      * */ | ||||
| 
 | ||||
|     void skipUntilNextKeyword(); | ||||
|     /** Retuns current token */ | ||||
| 
 | ||||
|     Token ¤t(); | ||||
| 
 | ||||
|     /** Throws error of unexpected types */ | ||||
|     [[nodiscard]] PError unexpected(); | ||||
| 
 | ||||
|     template<typename T> | ||||
| @ -67,45 +63,71 @@ private: | ||||
| 
 | ||||
|     Spanner getSpanner(); | ||||
| 
 | ||||
|     /** Base types */ | ||||
|     // used to parse library and schema
 | ||||
|     PResult<StringNode> parseString(); | ||||
|     PResult<ColorNode> parseColor(); | ||||
| 
 | ||||
|     PResult<IdentifierNode> parseIdentifier(); | ||||
| 
 | ||||
|     PResult<NumberNode> parseNumber(); | ||||
|     PResult<NumberPairNode> parseNumberPair(); | ||||
| 
 | ||||
|     PResult<CountNode> parseCount(); | ||||
| 
 | ||||
|     PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType); | ||||
|     PResult<StringPropertyNode> parseStringProperty(); | ||||
| 
 | ||||
|     PResult<EnumerationNode> parseEnumeration(); | ||||
| 
 | ||||
|     PResult<ValueNode> parseConnectionWire(); | ||||
| 
 | ||||
|     PResult<ComponentNode> parseComponent(); | ||||
| 
 | ||||
|     PResult<AddressSpaceNode> parseAddress(); | ||||
| 
 | ||||
|     PResult<PinNode> parsePin(); | ||||
| 
 | ||||
|     PResult<DisplayNode> parseDisplay(); | ||||
| 
 | ||||
|     PResult<PinConnectionNode> parsePinConnection(); | ||||
| 
 | ||||
|     PResult<AttributeNode> parseAttribute(); | ||||
| 
 | ||||
|     PResult<PopupNode> parsePopup(); | ||||
| 
 | ||||
|     PResult<RuleNode> parseRule(); | ||||
| 
 | ||||
|     PResult<BusNode> parseBus(); | ||||
| 
 | ||||
|     PResult<WireNode> parseWire(); | ||||
| 
 | ||||
|     PResult<ConnectionNode> parseConnection(); | ||||
| 
 | ||||
|     PResult<DisplayItemNode> parseDisplayItem(); | ||||
| 
 | ||||
|     PResult<IfStatementNode> parseIfStatement(); | ||||
| 
 | ||||
|     PResult<ValueNode> parseValue(); | ||||
| 
 | ||||
|     /** Library types */ | ||||
|     PResult<ValueNode> parseConnectionWire(); | ||||
|     PResult<ComponentNode> parseComponent(); | ||||
|     // used to parse schema
 | ||||
|     PResult<CountNode> parsePosition(); | ||||
| 
 | ||||
|     PResult<InstanceNode> parseInstance(); | ||||
| 
 | ||||
|     PResult<InstanceAttributeNode> parseInstanceAttribute(); | ||||
| 
 | ||||
|     PResult<ConnectionInstanceNode> parseConnectionInstance(); | ||||
| 
 | ||||
|     PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType(); | ||||
|     PResult<AddressSpaceNode> parseAddress(); | ||||
|     PResult<PinNode> parsePin(); | ||||
|     PResult<DisplayNode> parseDisplay(); | ||||
|     PResult<AttributeNode> parseAttribute(); | ||||
|     PResult<PopupNode> parsePopup(); | ||||
|     PResult<RuleNode> parseRule(); | ||||
|     PResult<BusNode> parseBus(); | ||||
|     PResult<WireNode> parseWire(); | ||||
|     PResult<ConnectionNode> parseConnection(); | ||||
|     PResult<ConnectionComponentNode> parseConnectionComponent(); | ||||
|     PResult<DisplayItemNode> parseDisplayItem(); | ||||
|     PResult<IfStatementNode> parseIfStatement(); | ||||
| 
 | ||||
|     PResult<EnumNode<BusNode::BusType>> parseBusType(); | ||||
| 
 | ||||
|     /** Schema types */ | ||||
|     PResult<InstanceNode> parseInstance(); | ||||
|     PResult<InstanceAttributeNode> parseInstanceAttribute(); | ||||
|     PResult<ConnectionInstanceNode> parseConnectionInstance(); | ||||
|     PResult<ConnectionComponentInstanceNode> parseConnectionComponentInstance(); | ||||
|     PResult<EnumNode<PinConnectionNode::ConnectionType>> parseConnectionType(); | ||||
| 
 | ||||
| public: | ||||
|     explicit ComdelParser(std::vector<Token> tokens); | ||||
| 
 | ||||
|     std::optional<SchemaNode> parseSchema(); | ||||
| 
 | ||||
|     std::optional<LibraryNode> parseLibrary(); | ||||
| 
 | ||||
|     const std::vector<SourceError> &getErrors(); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -7,7 +7,6 @@ | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| /*** Represent source file */ | ||||
| class SourceFile { | ||||
|     std::string fileName; | ||||
|     std::string source; | ||||
| @ -23,7 +22,7 @@ public: | ||||
|     void addLineOffset(unsigned offset); | ||||
| }; | ||||
| 
 | ||||
| /*** Represent parsing context */ | ||||
| 
 | ||||
| class ParseContext { | ||||
|     std::string applicationDir; | ||||
|     std::vector<SourceFile> fileMap; | ||||
|  | ||||
| @ -101,7 +101,7 @@ enum class TokenType { | ||||
|     KW_SCHEMA, | ||||
|     KW_POSITION, | ||||
|     KW_SIZE, | ||||
|     KW_DISPLAY_NAME, | ||||
|     KW_UNKNOWN, | ||||
| 
 | ||||
|     // TYPES
 | ||||
|     INT_TYPE, | ||||
|  | ||||
| @ -106,7 +106,6 @@ TokenTables::TokenTables() { | ||||
|     add(TokenType::KW_SCHEMA, "@schema", TOKENIZABLE | KEYWORD_NAME); | ||||
|     add(TokenType::KW_POSITION, "@position", TOKENIZABLE | KEYWORD_NAME); | ||||
|     add(TokenType::KW_SIZE, "@size", TOKENIZABLE | KEYWORD_NAME); | ||||
|     add(TokenType::KW_DISPLAY_NAME, "@displayName", TOKENIZABLE | KEYWORD_NAME); | ||||
| 
 | ||||
|     // All types
 | ||||
|     add(TokenType::INT_TYPE, "int", TOKENIZABLE); | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,233 +0,0 @@ | ||||
| @source "arm_library.csl" | ||||
| 
 | ||||
| @schema { | ||||
| 	@instance bridge Bridge { | ||||
| 		@position (-263, -97) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance arm ARM7tdmi { | ||||
| 		@position (-473, -283) | ||||
| 		@attribute _memory memorija | ||||
| 	} | ||||
| 
 | ||||
| 	@instance memorija Memory64KiB { | ||||
| 		@position (-545, 37) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance decoder Decoder { | ||||
| 		@position (-541, -212) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance rtc RTC_IO { | ||||
| 		@position (-63, -190) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio GPIO { | ||||
| 		@position (32, 11) | ||||
| 		@attribute title "GPIO 1" | ||||
| 	} | ||||
| 
 | ||||
| 	@instance temperature Temperature { | ||||
| 		@position (144, -25) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance led LED { | ||||
| 		@position (159, 138) | ||||
| 		@attribute onColor "green" | ||||
| 	} | ||||
| 
 | ||||
| 	@instance led_000 LED { | ||||
| 		@position (182, 139) | ||||
| 		@attribute onColor "yellow" | ||||
| 	} | ||||
| 
 | ||||
| 	@instance led_001 LED { | ||||
| 		@position (202, 140) | ||||
| 		@attribute onColor "red" | ||||
| 	} | ||||
| 
 | ||||
| 	@instance interruptSelector interrupt_selector { | ||||
| 		@position (-235, -134) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance signal signal { | ||||
| 		@position (63, -44) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance interruptSelector_000 interrupt_selector { | ||||
| 		@position (-238, -160) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance lcd lcd8 { | ||||
| 		@position (181, -199) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_000 GPIO { | ||||
| 		@position (53, -222) | ||||
| 		@attribute title "GPIO 2" | ||||
| 	} | ||||
| 
 | ||||
| 	@instance push_button pushbutton { | ||||
| 		@position (260, -98) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance toggle_button togglebutton { | ||||
| 		@position (205, -70) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance dmac DMAC_simple { | ||||
| 		@position (-445, 12) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance ui_unit UI_UNIT { | ||||
| 		@position (-200, 24) | ||||
| 		@attribute type 0 | ||||
| 		@attribute name "Izlaz" | ||||
| 		@attribute width 8 | ||||
| 		@attribute duration 40 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance ui_unit_000 UI_UNIT { | ||||
| 		@position (-118, 63) | ||||
| 		@attribute type 1 | ||||
| 		@attribute name "Ulaz" | ||||
| 		@attribute width 8 | ||||
| 		@attribute duration 40 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance ahb AHB { | ||||
| 		@position (-514, -86) | ||||
| 		@size 249 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance apb APB { | ||||
| 		@position (-201, -87) | ||||
| 		@size 329 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_port gpio_port { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_port_000 gpio_port { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_sa gpio_sa { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_sa_000 gpio_sa { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_sa_001 gpio_sa { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_sa_002 gpio_sa { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_port_001 gpio_port { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_sa_003 gpio_sa { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance gpio_sa_004 gpio_sa { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance arm_dmac dmac_io { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance arm_dmac_000 dmac_io { | ||||
| 		@position (0, 0) | ||||
| 		@size -1 | ||||
| 	} | ||||
| 
 | ||||
| 	@connection (bridge.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (bridge.apbPin, apb) { | ||||
| 	} | ||||
| 	@connection (memorija.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (arm.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (decoder.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (rtc.apbPin, apb) { | ||||
| 	} | ||||
| 	@connection (gpio.apbPin, apb) { | ||||
| 		@attribute gpioSelect sel_gpio_1 | ||||
| 	} | ||||
| 	@connection (gpio.portA, gpio_port_000, temperature.gpioPin) { | ||||
| 	} | ||||
| 	@connection (gpio.portB, gpio_sa, led.gpioPin) { | ||||
| 		@attribute gpioPortB "XP0" | ||||
| 		@attribute ledGpioPin "Ulaz" | ||||
| 	} | ||||
| 	@connection (gpio.portB, gpio_sa_000, led_000.gpioPin) { | ||||
| 		@attribute gpioPortB "XP4" | ||||
| 		@attribute ledGpioPin "Ulaz" | ||||
| 	} | ||||
| 	@connection (gpio.portB, gpio_sa_001, led_001.gpioPin) { | ||||
| 		@attribute gpioPortB "XP6" | ||||
| 		@attribute ledGpioPin "Ulaz" | ||||
| 	} | ||||
| 	@connection (interruptSelector.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (interruptSelector.apbPin, apb) { | ||||
| 		@attribute interrupt rtc_int | ||||
| 	} | ||||
| 	@connection (signal.apbPin, apb) { | ||||
| 	} | ||||
| 	@connection (interruptSelector_000.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (interruptSelector_000.apbPin, apb) { | ||||
| 		@attribute interrupt dmac_int | ||||
| 	} | ||||
| 	@connection (gpio_000.apbPin, apb) { | ||||
| 		@attribute gpioSelect sel_gpio_2 | ||||
| 	} | ||||
| 	@connection (gpio_000.portA, gpio_port_001, lcd.gpioPin) { | ||||
| 	} | ||||
| 	@connection (gpio_000.portB, gpio_sa_003, push_button.gpioPin) { | ||||
| 		@attribute gpioPortB "XP0" | ||||
| 		@attribute buttonGpioPin "Izlaz" | ||||
| 	} | ||||
| 	@connection (gpio_000.portB, gpio_sa_004, toggle_button.gpioPin) { | ||||
| 		@attribute gpioPortB "XP1" | ||||
| 		@attribute buttonGpioPin "Izlaz" | ||||
| 	} | ||||
| 	@connection (dmac.apbPin, apb) { | ||||
| 	} | ||||
| 	@connection (dmac.ahbMasterPin, ahb) { | ||||
| 	} | ||||
| 	@connection (dmac.ahbSlavePin, ahb) { | ||||
| 	} | ||||
| 	@connection (ui_unit_000.dmacPin, arm_dmac, dmac.dev3) { | ||||
| 	} | ||||
| 	@connection (ui_unit.dmacPin, arm_dmac_000, dmac.dev2) { | ||||
| 	} | ||||
| 	@connection (ui_unit.apbPin, apb) { | ||||
| 		@attribute intSelect sel_ui_in | ||||
| 	} | ||||
| 	@connection (ui_unit_000.apbPin, apb) { | ||||
| 		@attribute intSelect sel_ui_out | ||||
| 	} | ||||
| } | ||||
| @ -1,248 +0,0 @@ | ||||
| 
 | ||||
| \\ Version 0.0.1 | ||||
| set load_performs_init; | ||||
| 
 | ||||
| #include ".\arm7tdmi.comdel" | ||||
| #include ".\bridge.comdel" | ||||
| #include ".\decoder.comdel" | ||||
| #include ".\dmac.comdel" | ||||
| #include ".\gpio.comdel" | ||||
| #include ".\interrupt_selector.comdel" | ||||
| #include ".\lcd8.comdel" | ||||
| #include ".\led.comdel" | ||||
| #include ".\memory.comdel" | ||||
| #include ".\pushbutton.comdel" | ||||
| #include ".\rtc.comdel" | ||||
| #include ".\signal.comdel" | ||||
| #include ".\temperature.comdel" | ||||
| #include ".\togglebutton.comdel" | ||||
| #include ".\ui_unit.comdel" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| component System | ||||
| { | ||||
|     clock 100MHz; | ||||
| 	//ahb | ||||
| 	wire<32> addr; | ||||
| 	wire<32> rdata; | ||||
| 	wire<32> wdata; | ||||
| 	wire<3> size; | ||||
| 	wire write; | ||||
| 	wired_or ready; | ||||
| 	wired_or irq; | ||||
| 	wired_or fiq; | ||||
| 	wired_and nmreq; | ||||
| 	wire --sel_mem; | ||||
| 	wire sel_bridge; | ||||
| 	wire sel_dmac; | ||||
| 	wire busreq; | ||||
| 	wire grant; | ||||
| 
 | ||||
| 
 | ||||
| 	//apb | ||||
| 	wire<32> apb__addr; | ||||
| 	wire<32> apb__rdata; | ||||
| 	wire<32> apb__wdata; | ||||
| 	wire<3> --size; | ||||
| 	wire enable; | ||||
| 	wire apb__write; | ||||
| 	wire sel_gpio_1; | ||||
| 	wire sel_gpio_2; | ||||
| 	wire sel_ui_in; | ||||
| 	wire sel_rtc; | ||||
| 	wire sel_ui_out; | ||||
| 	wire --rtc_int; | ||||
| 	wire --dmac_int; | ||||
| 	wire --impulse; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_port | ||||
| 	wire --xp0; | ||||
| 	wire --xp1; | ||||
| 	wire --xp2; | ||||
| 	wire --xp3; | ||||
| 	wire --xp4; | ||||
| 	wire --xp5; | ||||
| 	wire --xp6; | ||||
| 	wire --xp7; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_port_000 | ||||
| 	wire --gpio_port_000__xp0; | ||||
| 	wire --gpio_port_000__xp1; | ||||
| 	wire --gpio_port_000__xp2; | ||||
| 	wire --gpio_port_000__xp3; | ||||
| 	wire --gpio_port_000__xp4; | ||||
| 	wire --gpio_port_000__xp5; | ||||
| 	wire --gpio_port_000__xp6; | ||||
| 	wire --gpio_port_000__xp7; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_sa | ||||
| 	wire --xp; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_sa_000 | ||||
| 	wire --gpio_sa_000__xp; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_sa_001 | ||||
| 	wire --gpio_sa_001__xp; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_sa_002 | ||||
| 	wire --gpio_sa_002__xp; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_port_001 | ||||
| 	wire --gpio_port_001__xp0; | ||||
| 	wire --gpio_port_001__xp1; | ||||
| 	wire --gpio_port_001__xp2; | ||||
| 	wire --gpio_port_001__xp3; | ||||
| 	wire --gpio_port_001__xp4; | ||||
| 	wire --gpio_port_001__xp5; | ||||
| 	wire --gpio_port_001__xp6; | ||||
| 	wire --gpio_port_001__xp7; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_sa_003 | ||||
| 	wire --gpio_sa_003__xp; | ||||
| 
 | ||||
| 
 | ||||
| 	//gpio_sa_004 | ||||
| 	wire --gpio_sa_004__xp; | ||||
| 
 | ||||
| 
 | ||||
| 	//arm_dmac | ||||
| 	wire --dmareq; | ||||
| 	wire --dmaack; | ||||
| 
 | ||||
| 
 | ||||
| 	//arm_dmac_000 | ||||
| 	wire --arm_dmac_000__dmareq; | ||||
| 	wire --arm_dmac_000__dmaack; | ||||
| 
 | ||||
| 
 | ||||
| 	// components -------------------------------------------- | ||||
| 	subcomponent Memory64KiB memorija(addr, rdata, wdata, size, write, ready, --sel_mem); | ||||
| 	subcomponent Bridge bridge(addr, rdata, wdata, size, write, ready, sel_bridge, apb__addr, apb__rdata, apb__wdata, --size, enable, apb__write, sel_gpio_1, sel_gpio_2, sel_rtc, sel_ui_in, sel_ui_out, 1, 1, 1, 1, 1); | ||||
| 	subcomponent ARM7tdmi arm(addr, rdata, wdata, size, write, ready, irq, fiq, nmreq, busreq, grant, *, *) uses memorija; | ||||
| 	subcomponent Decoder decoder(addr, nmreq, --sel_mem, sel_bridge, sel_dmac, 1, 1); | ||||
| 	subcomponent RTC_IO rtc(apb__addr, apb__rdata, apb__wdata, --size, enable, apb__write, sel_rtc, --rtc_int, --impulse); | ||||
| 	subcomponent GPIO gpio<"GPIO 1">(apb__addr, apb__rdata, apb__wdata, enable, apb__write, sel_gpio_1, --gpio_port_000__xp0, --gpio_port_000__xp1, --gpio_port_000__xp2, --gpio_port_000__xp3, --gpio_port_000__xp4, --gpio_port_000__xp5, --gpio_port_000__xp6, --gpio_port_000__xp7, --xp, *, *, *, --gpio_sa_000__xp, *, --gpio_sa_001__xp, *); | ||||
| 	subcomponent Temperature temperature(--gpio_port_000__xp0, --gpio_port_000__xp1, --gpio_port_000__xp2, --gpio_port_000__xp3, --gpio_port_000__xp4, --gpio_port_000__xp5, --gpio_port_000__xp6, --gpio_port_000__xp7); | ||||
| 	subcomponent LED led<"green">(--xp); | ||||
| 	subcomponent LED led_000<"yellow">(--gpio_sa_000__xp); | ||||
| 	subcomponent LED led_001<"red">(--gpio_sa_001__xp); | ||||
| 	subcomponent interrupt_selector interruptSelector(rtc_int, irq, fiq); | ||||
| 	subcomponent signal signal(--impulse); | ||||
| 	subcomponent interrupt_selector interruptSelector_000(dmac_int, irq, fiq); | ||||
| 	subcomponent lcd8 lcd(--gpio_port_001__xp0, --gpio_port_001__xp1, --gpio_port_001__xp2, --gpio_port_001__xp3, --gpio_port_001__xp4, --gpio_port_001__xp5, --gpio_port_001__xp6, --gpio_port_001__xp7); | ||||
| 	subcomponent GPIO gpio_000<"GPIO 2">(apb__addr, apb__rdata, apb__wdata, enable, apb__write, sel_gpio_2, --gpio_port_001__xp0, --gpio_port_001__xp1, --gpio_port_001__xp2, --gpio_port_001__xp3, --gpio_port_001__xp4, --gpio_port_001__xp5, --gpio_port_001__xp6, --gpio_port_001__xp7, --gpio_sa_003__xp, --gpio_sa_004__xp, *, *, *, *, *, *); | ||||
| 	subcomponent pushbutton push_button(--gpio_sa_003__xp); | ||||
| 	subcomponent togglebutton toggle_button(--gpio_sa_004__xp); | ||||
| 	subcomponent DMAC_simple dmac(addr, rdata, wdata, size, write, ready, sel_dmac, addr, rdata, wdata, size, write, ready, nmreq, busreq, grant, --dmac_int, 0, *, 0, *, --arm_dmac_000__dmareq, --arm_dmac_000__dmaack, --dmareq, --dmaack); | ||||
| 	subcomponent UI_UNIT ui_unit<0, "Izlaz", 8, 40>(apb__addr, apb__rdata, apb__wdata, --size, enable, apb__write, sel_ui_in, --arm_dmac_000__dmareq, --arm_dmac_000__dmaack); | ||||
| 	subcomponent UI_UNIT ui_unit_000<1, "Ulaz", 8, 40>(apb__addr, apb__rdata, apb__wdata, --size, enable, apb__write, sel_ui_out, --dmareq, --dmaack); | ||||
| 
 | ||||
| 	display { | ||||
| 		component { x: -263; y: -97; ref: "bridge"; } | ||||
| 		component { x: -473; y: -283; ref: "arm"; } | ||||
| 		component { x: -545; y: 37; ref: "memorija"; } | ||||
| 		component { x: -541; y: -212; ref: "decoder"; } | ||||
| 		component { x: -63; y: -190; ref: "rtc"; } | ||||
| 		component { x: 32; y: 11; ref: "gpio"; } | ||||
| 		component { x: 144; y: -25; ref: "temperature"; } | ||||
| 		component { x: 159; y: 138; ref: "led"; } | ||||
| 		component { x: 182; y: 139; ref: "led_000"; } | ||||
| 		component { x: 202; y: 140; ref: "led_001"; } | ||||
| 		component { x: -235; y: -134; ref: "interruptSelector"; } | ||||
| 		component { x: 63; y: -44; ref: "signal"; } | ||||
| 		component { x: -238; y: -160; ref: "interruptSelector_000"; } | ||||
| 		component { x: 181; y: -199; ref: "lcd"; } | ||||
| 		component { x: 53; y: -222; ref: "gpio_000"; } | ||||
| 		component { x: 260; y: -98; ref: "push_button"; } | ||||
| 		component { x: 205; y: -70; ref: "toggle_button"; } | ||||
| 		component { x: -445; y: 12; ref: "dmac"; } | ||||
| 		component { x: -189; y: 25; ref: "ui_unit"; } | ||||
| 		component { x: -118; y: 63; ref: "ui_unit_000"; } | ||||
| 
 | ||||
| 		// ahb bus | ||||
| 
 | ||||
| 		rectangle { | ||||
| 			x: -514; y: -86; | ||||
| 			w: 249; h: 20; | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		// apb bus | ||||
| 
 | ||||
| 		rectangle { | ||||
| 			x: -201; y: -87; | ||||
| 			w: 329; h: 20; | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_port bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_port_000 bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_sa bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_sa_000 bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_sa_001 bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_sa_002 bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_port_001 bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_sa_003 bus | ||||
| 
 | ||||
| 
 | ||||
| 		// gpio_sa_004 bus | ||||
| 
 | ||||
| 
 | ||||
| 		// arm_dmac bus | ||||
| 
 | ||||
| 
 | ||||
| 		// arm_dmac_000 bus | ||||
| 
 | ||||
| 
 | ||||
| 		line {x1:-263; y1:-77; x2:-389; y2:-75;} | ||||
| 		line {x1:-203; y1:-77; x2:-36; y2:-76;} | ||||
| 		line {x1:-540; y1:37; x2:-389; y2:-75;} | ||||
| 		line {x1:-418; y1:-152; x2:-389; y2:-75;} | ||||
| 		line {x1:-521; y1:-182; x2:-389; y2:-75;} | ||||
| 		line {x1:-43; y1:-150; x2:-36; y2:-76;} | ||||
| 		line {x1:32; y1:56; x2:-36; y2:-76;} | ||||
| 		line {x1:112; y1:32; x2:164; y2:15;} | ||||
| 		line {x1:112; y1:91; x2:164; y2:138;} | ||||
| 		line {x1:112; y1:91; x2:187; y2:139;} | ||||
| 		line {x1:112; y1:91; x2:207; y2:140;} | ||||
| 		line {x1:-245; y1:-129; x2:-389; y2:-75;} | ||||
| 		line {x1:-215; y1:-129; x2:-36; y2:-76;} | ||||
| 		line {x1:68; y1:-44; x2:-36; y2:-76;} | ||||
| 		line {x1:-248; y1:-155; x2:-389; y2:-75;} | ||||
| 		line {x1:-218; y1:-155; x2:-36; y2:-76;} | ||||
| 		line {x1:53; y1:-177; x2:-36; y2:-76;} | ||||
| 		line {x1:133; y1:-201; x2:171; y2:-172;} | ||||
| 		line {x1:133; y1:-142; x2:277; y2:-108;} | ||||
| 		line {x1:133; y1:-142; x2:222; y2:-80;} | ||||
| 		line {x1:-340; y1:32; x2:-36; y2:-76;} | ||||
| 		line {x1:-370; y1:12; x2:-389; y2:-75;} | ||||
| 		line {x1:-410; y1:12; x2:-389; y2:-75;} | ||||
| 		line {x1:-118; y1:93; x2:-325; y2:92;} | ||||
| 		line {x1:-189; y1:55; x2:-325; y2:77;} | ||||
| 		line {x1:-159; y1:25; x2:-36; y2:-76;} | ||||
| 		line {x1:-88; y1:63; x2:-36; y2:-76;} | ||||
| 	} | ||||
| } | ||||
| @ -1,28 +0,0 @@ | ||||
| @source "arm_library.csl" | ||||
| 
 | ||||
| @schema { | ||||
| 	@instance arm ARM7tdmi { | ||||
| 		@position (1179, 326) | ||||
| 		@attribute _memory memorija | ||||
| 	} | ||||
| 
 | ||||
| 	@instance memorija Memory64KiB { | ||||
| 		@position (1148, 521) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance decoder Decoder { | ||||
| 		@position (1070, 381) | ||||
| 	} | ||||
| 
 | ||||
| 	@instance ahb AHB { | ||||
| 		@position (1027, 465) | ||||
| 		@size 249 | ||||
| 	} | ||||
| 
 | ||||
| 	@connection (memorija.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (arm.ahbPin, ahb) { | ||||
| 	} | ||||
| 	@connection (decoder.ahbPin, ahb) { | ||||
| 	} | ||||
| } | ||||
| @ -1,67 +0,0 @@ | ||||
| 
 | ||||
| // Version 0.0.1 | ||||
| set load_performs_init; | ||||
| 
 | ||||
| #include ".\arm7tdmi.comdel" | ||||
| #include ".\decoder.comdel" | ||||
| #include ".\memory.comdel" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| component System | ||||
| { | ||||
|     clock 100 MHz; | ||||
| 	//ahb | ||||
| 	wire<32> addr; | ||||
| 	wire<32> rdata; | ||||
| 	wire<32> wdata; | ||||
| 	wire<3> size; | ||||
| 	wire write; | ||||
| 	wired_or ready; | ||||
| 	wired_or irq; | ||||
| 	wired_or fiq; | ||||
| 	wired_and nmreq; | ||||
| 	wire --sel_mem; | ||||
| 	wire sel_bridge; | ||||
| 	wire sel_dmac; | ||||
| 	wire --ahb__sel_mem; | ||||
| 	wire ahb__sel_bridge; | ||||
| 	wire ahb__sel_dmac; | ||||
| 	wire busreq = 0; | ||||
| 	wire grant; | ||||
| 
 | ||||
| 
 | ||||
| 	// components -------------------------------------------- | ||||
| 	subcomponent Memory64KiB memorija(addr, rdata, wdata, size, write, ready, sel_mem); | ||||
| 	subcomponent ARM7tdmi arm(addr, rdata, wdata, size, write, ready, irq, fiq, nmreq, busreq, grant) uses memorija; | ||||
| 	subcomponent Decoder decoder(addr, nmreq, sel_mem, sel_bridge, sel_dmac, 1, 1); | ||||
| 
 | ||||
| 	display { | ||||
| 		component { x: 1179; y: 326; ref: "arm"; } | ||||
| 		component { x: 1148; y: 521; ref: "memorija"; } | ||||
| 		component { x: 1070; y: 381; ref: "decoder"; } | ||||
| 
 | ||||
| 		// ahb bus | ||||
| 
 | ||||
| 		rectangle { | ||||
| 			x: 1027; y: 465; | ||||
| 			width: 249; height: 20; | ||||
| 			fill_color: #999999; | ||||
| 			line_color: #999999; | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		path { | ||||
| 			x:0; y:0; | ||||
| 			points: ((1153, 521),(-1,-46)); | ||||
| 		} | ||||
| 		path { | ||||
| 			x:0; y:0; | ||||
| 			points: ((1234, 457),(-82,18)); | ||||
| 		} | ||||
| 		path { | ||||
| 			x:0; y:0; | ||||
| 			points: ((1090, 421),(62,54)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -1,6 +1,5 @@ | ||||
| // Version 0.0.1 | ||||
| #include "libraries\frisc\vjezba1\FRISC.cdl" | ||||
| #include "libraries\frisc\vjezba1\dma.cdl" | ||||
| #include "libraries\frisc\vjezba1\memory.cdl" | ||||
| 
 | ||||
| 
 | ||||
| @ -24,43 +23,31 @@ component System | ||||
| 	wire --BACK; | ||||
| 
 | ||||
| 
 | ||||
| 	//PIOSabirnica | ||||
| 	wire<8> PIO_DATA; | ||||
| 	wire READY; | ||||
| 	wire STROBE; | ||||
| 
 | ||||
| 
 | ||||
| 	//directRam | ||||
| 	wire INT; | ||||
| 
 | ||||
| 
 | ||||
| 	// components -------------------------------------------- | ||||
| 	subcomponent Memorija memorija<false, 1, 1024, 8, 0>(ADR, DATA, READ, WRITE, SIZE, WAIT, INT, *, *, *); | ||||
| 	subcomponent Memorija memorija<false, 1, 65536, 8, 0>(ADR, DATA, READ, WRITE, SIZE, WAIT, *, *, *, INT); | ||||
| 	subcomponent FRISC procesor(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, INT, *, *, *); | ||||
| 	subcomponent DMA dma<1024>(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, --BREQ, --BACK, 0, 0, *, *); | ||||
| 
 | ||||
| 	display { | ||||
| 		component { x: -104; y: -102; ref: "procesor"; } | ||||
| 		component { x: 39; y: 199; ref: "memorija"; } | ||||
| 		component { x: -352; y: 13; ref: "dma"; } | ||||
| 		component { x: -377; y: -302; ref: "procesor"; } | ||||
| 		component { x: -56; y: -80; ref: "memorija"; } | ||||
| 
 | ||||
| 		// glavnaSabirnica bus | ||||
| 
 | ||||
| 		rectangle { | ||||
| 			x: -106; y: 80; | ||||
| 			x: -377; y: -106; | ||||
| 			w: 100; h: 20; | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		// PIOSabirnica bus | ||||
| 
 | ||||
| 
 | ||||
| 		// directRam bus | ||||
| 
 | ||||
| 
 | ||||
| 		line {x1:-54; y1:14; x2:-55; y2:90;} | ||||
| 		line {x1:89; y1:183; x2:-55; y2:90;} | ||||
| 		line {x1:-236; y1:51; x2:-55; y2:90;} | ||||
| 		line {x1:23; y1:227; x2:12; y2:-52;} | ||||
| 		line {x1:-6; y1:-96; x2:-326; y2:-95;} | ||||
| 		line {x1:-327; y1:-186; x2:-326; y2:-95;} | ||||
| 		line {x1:-72; y1:-52; x2:-261; y2:-252;} | ||||
| 	} | ||||
| } | ||||
| @ -17,7 +17,6 @@ | ||||
| } | ||||
| 
 | ||||
| @component FRISC processor { | ||||
|     @displayName "Frisc procesor" | ||||
|     @instanceName procesor | ||||
|     @tooltip "Procesor FRISC, mora postojati jedan" | ||||
|     @count (1, 1) | ||||
| @ -50,18 +49,10 @@ | ||||
|         rect { | ||||
|             x: 0; y:0; w:100; h:100; | ||||
|         } | ||||
|         text { | ||||
|             x: 0; y: 0; w: 100; h: 100; | ||||
|             text: "FRISC"; | ||||
|         } | ||||
|         text { | ||||
|             x: 0; y: 16; w: 100; h: 100; | ||||
|             text: "{instanceName}"; | ||||
|         } | ||||
|     } | ||||
|     @pin glavniPin in { | ||||
|         @tooltip "pin za spajanje na glavnu sabirnicu" | ||||
|         @connection "COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu" | ||||
|         @connection required("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu") | ||||
|         @display { | ||||
|             pin { | ||||
|                 x: 42; y: 100; w: 16; h:16; | ||||
| @ -73,6 +64,7 @@ | ||||
| 
 | ||||
|     @pin memDirect inOut { | ||||
|             @tooltip "pin za izravno spajanje na RAM" | ||||
|             @connection optional("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu") | ||||
|             @display { | ||||
|                 pin { | ||||
|                     x: 100; y: 42; w: 16; h:16; | ||||
| @ -132,7 +124,6 @@ | ||||
|     } | ||||
|     @attribute size int default 8 | ||||
|     @attribute pocetnaAdresa int default 0 { | ||||
|         @displayName "Početna adresa" | ||||
|         @popup automatic { | ||||
|             @title "Početna adresa memorije" | ||||
|             @text "Zadajte početnu adresu memorije" | ||||
| @ -182,7 +173,7 @@ | ||||
| 
 | ||||
|     @pin glavniPin inOut { | ||||
|         @tooltip "pin za spajanje na glavnu sabirnicu" | ||||
|         @connection "COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu" | ||||
|         @connection required("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu") | ||||
|         @display { | ||||
|             /* | ||||
|             pin { | ||||
| @ -205,6 +196,7 @@ | ||||
| 
 | ||||
|     @pin memDirect inOut { | ||||
|             @tooltip "pin za spajanje na procesor" | ||||
|             @connection optional("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu") | ||||
|             @display { | ||||
|                 /* | ||||
|                 pin { | ||||
| @ -228,14 +220,12 @@ | ||||
| } | ||||
| 
 | ||||
| @component DMA { | ||||
|     @displayName "DMA kontroler" | ||||
|     @instanceName dma | ||||
|     @tooltip "DMA-kontroler" | ||||
|     @count (0,1000) | ||||
|     @source "dma.cdl" | ||||
| 
 | ||||
|     @attribute pocetnaAdresa int default 0 { | ||||
|         @displayName "Početna adresa" | ||||
|         @popup automatic { | ||||
|             @title "Početna adresa DMA-kontrolera" | ||||
|             @text "Zadajte početnu adresu DMA-kontrolera" | ||||
| @ -278,7 +268,7 @@ | ||||
| 
 | ||||
|     @pin glavniPin in { | ||||
|         @tooltip "pin za spajanje na glavnu sabirnicu" | ||||
|         @connection "COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu" | ||||
|         @connection required("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu") | ||||
|         @display { | ||||
|             /* | ||||
|             pin { | ||||
| @ -293,17 +283,16 @@ | ||||
|             */ | ||||
|             pin { | ||||
|                 x: 100; y: 30; w: 16; h: 16; | ||||
|                 orientation: "right"; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @pin dodatnaPoveznica in { | ||||
|         @tooltip "pin za spajanje na pomocnu sabirnicu" | ||||
|         @connection optional("COMDEL se ne može stvoriti. DMA nije spojen na nesto!") | ||||
|         @display { | ||||
|             pin { | ||||
|                 x: 100; y: 7; w: 16; h: 16; | ||||
|                 orientation: "right"; | ||||
|             } | ||||
|         } | ||||
|         @wires { 0, 0, null, null} | ||||
| @ -311,7 +300,6 @@ | ||||
| } | ||||
| 
 | ||||
| @bus glavnaSabirnica regular { | ||||
|     @displayName "Glavna sabirnica" | ||||
|     @instanceName glavnaSabirnica | ||||
|     @tooltip "sabirnica za spajanje FRISC a s memorijama i UI/jedinicama" | ||||
|     @count (1,1) | ||||
| @ -329,8 +317,6 @@ | ||||
|             h: 20; w: 100; | ||||
|             orientation: "horizontal"; | ||||
|             resizable: true; | ||||
|             lineColor: #bbbbbb; | ||||
|             fillColor: #bbbbbb; | ||||
|         } | ||||
|     } | ||||
|     @wires { | ||||
|  | ||||
							
								
								
									
										14
									
								
								examples/simplified FRISC model/schema2.csl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								examples/simplified FRISC model/schema2.csl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| @source "/home/bbr/Documents/Personal/FER/schema_editor/examples/simplified FRISC model/frisc_library.csl" | ||||
| 
 | ||||
| @schema { | ||||
| 	@instance procesor FRISC { | ||||
| 		@position (-177, -122) | ||||
| 		@attribute _memory memorija2 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance procesor FRISC { | ||||
| 		@position (49, -97) | ||||
| 		@attribute _memory null | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										29
									
								
								examples/simplified FRISC model/schema3.csl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/simplified FRISC model/schema3.csl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| @source "/home/bbr/Documents/Personal/FER/schema_editor/examples/simplified FRISC model/frisc_library.csl" | ||||
| 
 | ||||
| @schema { | ||||
| 	@instance procesor FRISC { | ||||
| 		@position (-464, -314) | ||||
| 		@attribute _memory null | ||||
| 	} | ||||
| 
 | ||||
| 	@instance dma DMA { | ||||
| 		@position (-269, 46) | ||||
| 		@attribute pocetnaAdresa 0 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance glavnaSabirnica glavnaSabirnica { | ||||
| 		@position (-579, -160) | ||||
| 		@size 100 | ||||
| 	} | ||||
| 
 | ||||
| 	@instance PIOSabirnica PIOSabirnica { | ||||
| 		@position (0, 0) | ||||
| 		@size 0 | ||||
| 	} | ||||
| 
 | ||||
| 	@connection (dma.glavniPin, glavnaSabirnica) { | ||||
| 		@attribute interupt INT2 | ||||
| 	} | ||||
| 	@connection (dma.glavniPin, PIOSabirnica, procesor.glavniPin) { | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										16
									
								
								examples/simplified FRISC model/schema4.csl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								examples/simplified FRISC model/schema4.csl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| @source "/home/bbr/Documents/Personal/FER/schema_editor/examples/simplified FRISC model/frisc_library.csl" | ||||
| 
 | ||||
| @schema { | ||||
| 	@instance procesor FRISC { | ||||
| 		@position (-543, -304) | ||||
| 		@attribute _memory null | ||||
| 	} | ||||
| 
 | ||||
| 	@instance glavnaSabirnica glavnaSabirnica { | ||||
| 		@position (-544, -91) | ||||
| 		@size 100 | ||||
| 	} | ||||
| 
 | ||||
| 	@connection (procesor.glavniPin, glavnaSabirnica) { | ||||
| 	} | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| @source "frisc_library.csl" | ||||
| @source "/home/bbr/Documents/Personal/FER/schema_editor/examples/simplified FRISC model/frisc_library.csl" | ||||
| 
 | ||||
| @schema { | ||||
| 	@instance procesor FRISC { | ||||
| @ -1,18 +1,19 @@ | ||||
| #include "mainwindow.h" | ||||
| #include "ui_mainwindow.h" | ||||
| #include "application.h" | ||||
| #include "comdel/display/dialog/error_dialog.h" | ||||
| #include "comdel/display/dialog/success_dialog.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| #include <QFileDialog> | ||||
| #include <QHBoxLayout> | ||||
| 
 | ||||
| #include <comdel/parser/parse_context.h> | ||||
| #include <comdel/domain/comdel_validator.h> | ||||
| #include <comdel/parser/parser_util.h> | ||||
| #include <comdel/domain/schema_creator.h> | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <QPlainTextEdit> | ||||
| #include <comdel/domain/comdel_validator.h> | ||||
| #include <fstream> | ||||
| #include <comdel/domain/comdel_generator.h> | ||||
| 
 | ||||
| MainWindow::MainWindow(QWidget *parent) | ||||
|     : QMainWindow(parent) | ||||
| @ -31,12 +32,10 @@ void MainWindow::setupUi() | ||||
|     ui->centralwidget->setLayout(layout); | ||||
| 
 | ||||
|     // setup toolbar
 | ||||
|     loadLibrary = ui->toolBar->addAction(QMESSAGE("msg_toolbar_load_library"), this, &MainWindow::onLoadLibrary); | ||||
|     loadSchema = ui->toolBar->addAction(QMESSAGE("msg_toolbar_load_schema"), this, &MainWindow::onLoadSchema); | ||||
|     saveSchema = ui->toolBar->addAction(QMESSAGE("msg_toolbar_save_schema"), this, &MainWindow::onStoreScheme); | ||||
|     generateComdel = ui->toolBar->addAction(QMESSAGE("msg_toolbar_generate_comdel"), this, &MainWindow::onGenerateComdel); | ||||
| 
 | ||||
|     updateTranslations(); | ||||
|     ui->toolBar->addAction("Učitaj bibiloteku", this, &MainWindow::onLoadLibrary); | ||||
|     ui->toolBar->addAction("Učitaj shemu", this, &MainWindow::onLoadSchema); | ||||
|     ui->toolBar->addAction("Spremi shemu", this, &MainWindow::onStoreScheme); | ||||
|     ui->toolBar->addAction("Generiraj comdel", this, &MainWindow::onGenerateComdel); | ||||
| 
 | ||||
|     connect(ui->actionSave_schema, &QAction::triggered, this, &MainWindow::onStoreScheme); | ||||
|     connect(ui->actionExport_schema, &QAction::triggered, this, &MainWindow::onGenerateComdel); | ||||
| @ -56,25 +55,25 @@ void MainWindow::setupUi() | ||||
|     layout->setContentsMargins(0, 0, 0, 0); | ||||
|     layout->addWidget(libraryDisplay); | ||||
|     layout->addWidget(schemaParent, 1); | ||||
| 
 | ||||
|     log = new QPlainTextEdit(); | ||||
|     log->setFont(QFont("Courier")); | ||||
|     log->setReadOnly(false); | ||||
|     schemaLayout->addWidget(log); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::onLoadLibrary() { | ||||
|     auto filename = QFileDialog::getOpenFileName(this, | ||||
|                                                  QMESSAGE("msg_files_load_library"), | ||||
|                                                  "", | ||||
|                                                  QMESSAGE("msg_files_load_library_format")); | ||||
|              tr("Otvori biblioteku"), "", tr("Comdel biblioteka (*.csl)")); | ||||
|     if(!filename.isEmpty()) { | ||||
|         std::ostringstream output; | ||||
|         log->clear(); | ||||
| 
 | ||||
|         auto librarySource = filename.toStdString(); | ||||
| 
 | ||||
|         auto instance = Application::instance(); | ||||
|         if(!instance->loadLibrary(librarySource, output)) { | ||||
|             auto dialog = new display::ErrorDialog(output); | ||||
|             dialog->exec(); | ||||
|         } else { | ||||
|             MessageSource::instance()->load(Application::instance()->getLibrary()->getMessages()); | ||||
|             updateTranslations(); | ||||
|             log->appendPlainText(QString::fromStdString(output.str())); | ||||
|         } | ||||
| 
 | ||||
|         libraryDisplay->refreshContent(); | ||||
| @ -84,11 +83,10 @@ void MainWindow::onLoadLibrary() { | ||||
| 
 | ||||
| void MainWindow::onLoadSchema() { | ||||
|     auto filename = QFileDialog::getOpenFileName(this, | ||||
|                                                  QMESSAGE("msg_files_load_schema"), | ||||
|                                                  "", | ||||
|                                                  QMESSAGE("msg_files_load_schema_format")); | ||||
|              tr("Otvori shemu"), "", tr("Comdel shema (*.csl)")); | ||||
|     if(!filename.isEmpty()) { | ||||
|         std::ostringstream output; | ||||
|         log->clear(); | ||||
| 
 | ||||
|         auto schemaSource = filename.toStdString(); | ||||
| 
 | ||||
| @ -96,11 +94,7 @@ void MainWindow::onLoadSchema() { | ||||
|         auto result = instance->loadSchema(schemaSource, output); | ||||
|         if(!result.first){ | ||||
|             formatErrors(result.second, output); | ||||
|             auto dialog = new display::ErrorDialog(output); | ||||
|             dialog->exec(); | ||||
|         } else { | ||||
|             MessageSource::instance()->load(Application::instance()->getLibrary()->getMessages()); | ||||
|             updateTranslations(); | ||||
|             log->appendPlainText(QString::fromStdString(output.str())); | ||||
|         } | ||||
| 
 | ||||
|         libraryDisplay->refreshContent(); | ||||
| @ -110,10 +104,10 @@ void MainWindow::onLoadSchema() { | ||||
| 
 | ||||
| void MainWindow::onStoreScheme() { | ||||
|     auto filename = QFileDialog::getSaveFileName(this, | ||||
|                                                  QMESSAGE("msg_files_store_schema"), | ||||
|                                                  "", | ||||
|                                                  QMESSAGE("msg_files_store_schema_format")); | ||||
|                                                  tr("Spremi shemu"), "", tr("Comdel shema (*.csl)")); | ||||
|     if(!filename.isEmpty()) { | ||||
|         log->clear(); | ||||
| 
 | ||||
|         std::ostringstream output; | ||||
| 
 | ||||
|         if(Application::instance()->generateSchema(output)) { | ||||
| @ -121,11 +115,9 @@ void MainWindow::onStoreScheme() { | ||||
|             out<<output.str(); | ||||
|             out.close(); | ||||
| 
 | ||||
|             auto dialog = new display::SuccessDialog(MESSAGE("msg_dialog_success_save_schema")); | ||||
|             dialog->exec(); | ||||
|             log->appendPlainText("Uspješno spremljena shema\n"); | ||||
|         } else { | ||||
|             auto dialog = new display::ErrorDialog(output); | ||||
|             dialog->exec(); | ||||
|             log->appendPlainText("Greška tijekom spremanja sheme\n"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -133,27 +125,26 @@ void MainWindow::onStoreScheme() { | ||||
| 
 | ||||
| void MainWindow::onGenerateComdel() { | ||||
|     auto filename = QFileDialog::getSaveFileName(this, | ||||
|                                                  QMESSAGE("msg_files_store_comdel"), | ||||
|                                                  "", | ||||
|                                                  QMESSAGE("msg_files_store_comdel_format")); | ||||
|                                                  tr("Spremi shemu"), "", tr("Comdel sustav (*.system)")); | ||||
|     if(!filename.isEmpty()) { | ||||
|         log->clear(); | ||||
| 
 | ||||
|         std::ostringstream output; | ||||
| 
 | ||||
|         auto validationErrors = Application::instance()->generateComdel(output); | ||||
| 
 | ||||
|         std::ostringstream errorOutput; | ||||
|         formatErrors(validationErrors, errorOutput); | ||||
|         std::ostringstream buff; | ||||
|         formatErrors(validationErrors, buff); | ||||
|         log->appendPlainText(QString::fromStdString(buff.str())); | ||||
| 
 | ||||
|         if(!Application::hasErrors(validationErrors)) { | ||||
|             std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary); | ||||
|             out<<output.str(); | ||||
|             out.close(); | ||||
| 
 | ||||
|             auto dialog = new display::SuccessDialog(MESSAGE("msg_dialog_success_comdel_generation")); | ||||
|             dialog->exec(); | ||||
|             log->appendPlainText("Uspješno generiranje comdel modela\n"); | ||||
|         } else { | ||||
|             auto dialog = new display::ErrorDialog(errorOutput); | ||||
|             dialog->exec(); | ||||
|             log->appendPlainText("Neuspješno generiranje comdel modela\n"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -161,17 +152,15 @@ void MainWindow::onGenerateComdel() { | ||||
| 
 | ||||
| void MainWindow::onValidateSchema(bool /*toggled*/) { | ||||
| 
 | ||||
|     log->clear(); | ||||
| 
 | ||||
|     auto errors = Application::instance()->validateSchema(); | ||||
| 
 | ||||
|     if(Application::hasErrors(errors)) { | ||||
|         std::ostringstream buff; | ||||
|         formatErrors(errors, buff); | ||||
|         auto dialog = new display::ErrorDialog(buff); | ||||
|         dialog->exec(); | ||||
|     } else { | ||||
|         auto dialog = new display::SuccessDialog(MESSAGE("msg_dialog_success_validation")); | ||||
|         dialog->exec(); | ||||
|     } | ||||
|     std::ostringstream buff; | ||||
|     formatErrors(errors, buff); | ||||
| 
 | ||||
|     log->appendPlainText(QString::fromStdString(buff.str())); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void MainWindow::formatErrors(std::vector<domain::ValidationError>& errors, std::ostream& output) { | ||||
| @ -195,10 +184,3 @@ MainWindow::~MainWindow() | ||||
| { | ||||
|     delete ui; | ||||
| } | ||||
| 
 | ||||
| void MainWindow::updateTranslations() { | ||||
|     loadLibrary->setText(QMESSAGE("msg_toolbar_load_library")); | ||||
|     loadSchema->setText(QMESSAGE("msg_toolbar_load_schema")); | ||||
|     saveSchema->setText(QMESSAGE("msg_toolbar_save_schema")); | ||||
|     generateComdel->setText(QMESSAGE("msg_toolbar_generate_comdel")); | ||||
| } | ||||
|  | ||||
| @ -40,14 +40,8 @@ private: | ||||
|     display::Library *libraryDisplay; | ||||
|     display::Schema *schemaDisplay; | ||||
|     Ui::MainWindow *ui; | ||||
| 
 | ||||
|     QAction* loadLibrary; | ||||
|     QAction* loadSchema; | ||||
|     QAction* saveSchema; | ||||
|     QAction* generateComdel; | ||||
|     QPlainTextEdit *log; | ||||
| 
 | ||||
|     static void formatErrors(std::vector<domain::ValidationError>& errors, std::ostream& output); | ||||
| 
 | ||||
|     void updateTranslations(); | ||||
| }; | ||||
| #endif // MAIN_WINDOW_H
 | ||||
|  | ||||
| @ -1,145 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 14.06.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| #include <utility> | ||||
| 
 | ||||
| // static instance of application
 | ||||
| static MessageSource *messageSource = nullptr; | ||||
| 
 | ||||
| MessageSource *MessageSource::instance() { | ||||
|     if (messageSource == nullptr) { | ||||
|         messageSource = new MessageSource(); | ||||
|     } | ||||
|     return messageSource; | ||||
| } | ||||
| 
 | ||||
| void MessageSource::loadDefaults() { | ||||
|     messages.clear(); | ||||
| 
 | ||||
|     // TOOLBAR
 | ||||
|     add("msg_toolbar_load_library", "Load library"); | ||||
|     add("msg_toolbar_load_schema", "Load schema"); | ||||
|     add("msg_toolbar_save_schema", "Save schema"); | ||||
|     add("msg_toolbar_generate_comdel", "Generate comdel"); | ||||
| 
 | ||||
|     // SIDEBAR
 | ||||
|     add("msg_sidebar_components", "Components:"); | ||||
|     add("msg_sidebar_busses", "Busses:"); | ||||
| 
 | ||||
|     // VALUES
 | ||||
|     add("msg_boolean_true", "True"); | ||||
|     add("msg_boolean_false", "False"); | ||||
| 
 | ||||
|     // SUCCESS MESSAGES
 | ||||
|     add("msg_dialog_success_title", "Success"); | ||||
|     add("msg_dialog_success_validation", "No validation errors found!"); | ||||
|     add("msg_dialog_success_comdel_generation", "Successfully generate COMDEL model!"); | ||||
|     add("msg_dialog_success_save_schema", "Successfully saved schema"); | ||||
| 
 | ||||
|     // DEFAULT ACTIONS
 | ||||
|     add("msg_dialog_actions_ok", "Ok"); | ||||
|     add("msg_dialog_actions_cancel", "Cancel"); | ||||
|     add("msg_dialog_actions_set", "Set"); | ||||
|     add("msg_dialog_actions_update", "Update"); | ||||
|     add("msg_dialog_actions_update_named", "Update {name}"); | ||||
|     add("msg_dialog_actions_remove_named", "Remove {name}"); | ||||
|     // PIN DIALOG
 | ||||
|     add("msg_pin_update", "Update"); | ||||
|     add("msg_pin_remove", "Remove"); | ||||
|     add("msg_sa_pin_update_title", "Update {wire1} - {wire2}"); | ||||
|     add("msg_sa_pin_remove_title", "Remove {wire1} - {wire2}"); | ||||
|     add("msg_pin_update_action", "Update connection"); | ||||
|     add("msg_pin_remove_action", "Remove connection"); | ||||
|     // ERROR DIALOG
 | ||||
|     add("msg_dialog_error_title", "Error"); | ||||
|     add("msg_dialog_error_close", "Close"); | ||||
|     // WARNING DIALOG
 | ||||
|     add("msg_dialog_warning_title", "Warning"); | ||||
|     // ATTRIBUTE DIALOG/ACTION
 | ||||
|     add("msg_dialog_attribute_update", "Update {attribute}"); | ||||
|     add("msg_dialog_attribute_set", "Set {attribute}"); | ||||
|     // NAME DIALOG
 | ||||
|     add("msg_dialog_name_update", "Update name"); | ||||
|     // MEMORY DIALOG/ACTION
 | ||||
|     add("msg_dialog_memory_update", "Update memory"); | ||||
|     add("msg_dialog_memory_set", "Set memory"); | ||||
|     add("msg_dialog_memory_default", "No memory selected"); | ||||
|     // CONNECTION
 | ||||
|     add("msg_dialog_sa_pin_set", "Set wire"); | ||||
|     // VALIDATORS
 | ||||
|     add("msg_validators_component_min_count", "Missing instances of component {componentName}. Required at least {min}, found {count}!"); | ||||
|     add("msg_validators_component_max_count", "Too many instances of component {componentname}. Expected at most {max}, found {count}!"); | ||||
|     add("msg_validators_bus_min_count", "Missing instances of bus {busName}. Required at least {min}, found {count}!"); | ||||
|     add("msg_validators_bus_max_count", "Too many instances of bus {busName}. Expected at most {max}, found {count}!"); | ||||
|     add("msg_validators_memory_not_found", "Cannot find memory instance {memoryReference}"); | ||||
|     add("msg_validators_duplicates_found", "Found multiple instances with name {instanceName}"); | ||||
| 
 | ||||
|     // LOADING/SAVING DIALOGS
 | ||||
|     add("msg_files_load_library", "Open library"); | ||||
|     add("msg_files_load_library_format", "COMDEL library (*.csl)"); | ||||
|     add("msg_files_load_schema", "Open schema"); | ||||
|     add("msg_files_load_schema_format", "COMDEL schema (*.csch)"); | ||||
|     add("msg_files_store_schema", "Store schema"); | ||||
|     add("msg_files_store_schema_format", "COMDEL schema (*.csch)"); | ||||
|     add("msg_files_store_comdel", "Store COMDEL system"); | ||||
|     add("msg_files_store_comdel_format", "COMDEL system (*.system)"); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void MessageSource::add(const std::string& key, std::string message) { | ||||
|     messages[key] = message; | ||||
| } | ||||
| 
 | ||||
| std::string MessageSource::get(const std::string& key, std::map<std::string, std::string> parametars) { | ||||
|     std::string message; | ||||
|     if(messages.count(key) == 1) { | ||||
|         // if key not found in translations use key as message
 | ||||
|         message = messages[key]; | ||||
|     } else { | ||||
|         message = key; | ||||
|     } | ||||
| 
 | ||||
|     message = populateMessage(message, parametars); | ||||
| 
 | ||||
|     return message; | ||||
| } | ||||
| 
 | ||||
| std::string MessageSource::get(const std::string &key) { | ||||
|     return get(key, {}); | ||||
| } | ||||
| 
 | ||||
| std::string MessageSource::populateMessage(std::string message, std::map<std::string, std::string> parametars) { | ||||
|     for (auto &[key, value]: parametars) { | ||||
|         message = replacePlaceholder(message, key, value); | ||||
|     } | ||||
|     return message; | ||||
| } | ||||
| 
 | ||||
| std::string MessageSource::replacePlaceholder(std::string message, const std::string key, std::string value) { | ||||
|     auto wholeKey = "{" + key + "}"; | ||||
| 
 | ||||
|     auto found = message.find(wholeKey); | ||||
|     while (found != std::string::npos) { | ||||
|         message.replace(found, wholeKey.length(), value); | ||||
|         found = message.find(key); | ||||
|     } | ||||
|     return message; | ||||
| } | ||||
| 
 | ||||
| void MessageSource::load(std::map<std::string, std::string> _messages) { | ||||
|     loadDefaults(); | ||||
|     for (auto &[key, value]: _messages) { | ||||
|         messages[key] = value; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::map<std::string, std::string> MessageSource::map(std::map<std::string, domain::Value> values) { | ||||
|     std::map<std::string, std::string> parametars; | ||||
|     for (auto &[key, value]: values) { | ||||
|         parametars[key] = value.string(); | ||||
|     } | ||||
|     return parametars; | ||||
| } | ||||
| @ -1,43 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 14.06.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef SCHEMEEDITOR_MESSAGE_SOURCE_H | ||||
| #define SCHEMEEDITOR_MESSAGE_SOURCE_H | ||||
| 
 | ||||
| 
 | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include "comdel/domain/value.h" | ||||
| 
 | ||||
| class MessageSource { | ||||
| private: | ||||
|     MessageSource() { | ||||
|         loadDefaults(); | ||||
|     } | ||||
| 
 | ||||
|     void add(const std::string& key, std::string message); | ||||
|     std::string populateMessage(std::string message, std::map<std::string, std::string> parametars); | ||||
|     std::string replacePlaceholder(std::string message, std::string key, std::string value); | ||||
| 
 | ||||
|     std::map<std::string, std::string> messages; | ||||
| 
 | ||||
| public: | ||||
|     static MessageSource *instance(); | ||||
|     static std::map<std::string, std::string> map(std::map<std::string, domain::Value> values); | ||||
| 
 | ||||
|     std::string get(const std::string& key); | ||||
|     std::string get(const std::string& key, std::map<std::string, std::string> parametars); | ||||
| 
 | ||||
|     void loadDefaults(); | ||||
|     void load(std::map<std::string, std::string> messages); | ||||
| }; | ||||
| 
 | ||||
| #define MESSAGE_PARAM(key, params) MessageSource::instance()->get(key, params) | ||||
| #define MESSAGE(key) MessageSource::instance()->get(key) | ||||
| #define MESSAGE_MAP(value) MessageSource::instance()->map(value) | ||||
| 
 | ||||
| #define QMESSAGE_PARAM(key, params) QString::fromStdString(MessageSource::instance()->get(key, params)) | ||||
| #define QMESSAGE(key) QString::fromStdString(MessageSource::instance()->get(key)) | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_MESSAGE_SOURCE_H
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user