From 3172d7e4cf5c4e964aea1df10bd1d163e311522a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borna=20Rajkovi=C4=87?= Date: Thu, 2 Jun 2022 01:37:14 +0200 Subject: [PATCH] Added component/bus deletion and rename --- application.cpp | 247 +++++++++++++++++--- application.h | 12 +- comdel/display/component_display.cpp | 29 ++- comdel/display/library_display.cpp | 6 +- comdel/display/library_display.h | 2 +- comdel/display/name_dialog.cpp | 41 +--- comdel/display/name_dialog.h | 8 +- comdel/display/schema_display.cpp | 9 +- comdel/display/schema_display.h | 4 +- comdel/domain/comdel_validator.cpp | 31 +++ comdel/domain/comdel_validator.h | 2 + examples/simplified FRISC model/schema2.csl | 38 +-- examples/simplified FRISC model/schema3.csl | 32 +-- mainwindow.cpp | 22 +- 14 files changed, 323 insertions(+), 160 deletions(-) diff --git a/application.cpp b/application.cpp index a18824f..94e963b 100644 --- a/application.cpp +++ b/application.cpp @@ -18,7 +18,7 @@ domain::Schema *Application::getSchema() { } void Application::clear() { - if(schema != nullptr) { + if (schema != nullptr) { delete schema; schema = nullptr; } @@ -26,76 +26,97 @@ void Application::clear() { libraryPath = ""; } -bool Application::loadLibrary(std::string& filename, std::ostream &errorOutput) { +bool Application::loadLibrary(std::string &filename, std::ostream &errorOutput) { clear(); ParseContext parseContext; auto libraryNode = load_library_from_file(&parseContext, filename.c_str(), errorOutput); - if(libraryNode) { + if (libraryNode) { domain::SchemaCreator generator(validators); library = generator.loadLibrary(*libraryNode); - for (auto& error : generator.getErrors()) { + for (auto &error: generator.getErrors()) { parseContext.formatError(error, errorOutput, "ERROR: "); } - if(library.has_value()) { - errorOutput<<"Failed creating library model"<> Application::loadSchema(std::string &filename, std::ostream &errorOutput) { clear(); + std::vector errors; + ParseContext parseContext; auto schemaNode = load_schema_from_file(&parseContext, filename.c_str(), errorOutput); - if(schemaNode) { + if (schemaNode) { domain::SchemaCreator generator(validators); library = generator.loadLibrary(*schemaNode->library); libraryPath = schemaNode->source->asString(); - for (auto& error : generator.getErrors()) { + for (auto &error: generator.getErrors()) { parseContext.formatError(error, errorOutput, "ERROR: "); } - if(library) { + if (library) { schema = generator.loadSchema(*schemaNode, *library); - for (auto& error : generator.getErrors()) { + for (auto &error: generator.getErrors()) { parseContext.formatError(error, errorOutput, "ERROR: "); } - if(schema == nullptr) { + if (schema == nullptr) { clear(); - return false; + return {false, errors}; } } else { clear(); - return false; + return {false, errors}; } } else { - errorOutput<<"Failed parsing library"< Application::validateSchema() { - if(schema == nullptr) { + if (schema == nullptr) { return std::vector{domain::ValidationError(domain::Action::ERROR, "No schema loaded")}; } @@ -114,17 +135,20 @@ std::vector Application::validateSchema() { context.attribute = nullptr; context.addressSpaces = {}; - for(auto &lib: library->getAddressSpaces()) { + for (auto &lib: library->getAddressSpaces()) { context.addressSpaces.insert(std::make_pair(lib.getName(), lib)); } auto errors = validator.validateSchema(*schema, context); - auto countValidation = validator.validateInstanceCount(*schema, *library, context); - errors.insert(errors.end(), countValidation.begin(), countValidation.end()); + auto memoryReferenceValidation = validator.validateMemoryReferences(*schema, *library, context); + errors.insert(errors.end(), memoryReferenceValidation.begin(), memoryReferenceValidation.end()); auto nameValidation = validator.validateInstanceNames(*schema, *library, context); errors.insert(errors.end(), nameValidation.begin(), nameValidation.end()); + auto countValidation = validator.validateInstanceCount(*schema, *library, context); + errors.insert(errors.end(), countValidation.begin(), countValidation.end()); + auto pinValidation = validator.validatePinConnections(*schema, *library, context); errors.insert(errors.end(), pinValidation.begin(), pinValidation.end()); return errors; @@ -133,7 +157,7 @@ std::vector Application::validateSchema() { std::vector Application::generateComdel(std::ostringstream &output) { auto errors = validateSchema(); - if(Application::hasErrors(errors)) { + if (Application::hasErrors(errors)) { // as long as all validation errors are warning we continue with build domain::generate_comdel(schema, library.value(), output); } @@ -141,8 +165,8 @@ std::vector Application::generateComdel(std::ostringstr } bool Application::hasErrors(std::vector errors) { - for(auto& err: errors) { - if(err.type == domain::Action::ERROR) { + for (auto &err: errors) { + if (err.type == domain::Action::ERROR) { return true; } } @@ -153,26 +177,29 @@ bool Application::hasErrors(std::vector errors) { static Application *application = nullptr; Application *Application::instance() { - if(application == nullptr) { + if (application == nullptr) { application = new Application(); } return application; } -std::shared_ptr Application::addComponent(domain::Component component, std::vector attributes, int x, int y) { +std::shared_ptr +Application::addComponent(domain::Component component, std::vector attributes, int x, + int y) { std::set names; - for(const auto& c: schema->componentInstances) { + for (const auto &c: schema->componentInstances) { names.insert(c->name); } std::string name = generateName(names, component.getInstanceName()); - schema->componentInstances.push_back(std::make_shared(name, attributes, std::make_pair(x, y), component)); + schema->componentInstances.push_back( + std::make_shared(name, attributes, std::make_pair(x, y), component)); return schema->componentInstances.back(); } std::shared_ptr Application::addBus(domain::Bus bus, int x, int y) { std::set names; - for(const auto& b: schema->busInstances) { + for (const auto &b: schema->busInstances) { names.insert(b->name); } std::string name = generateName(names, bus.getInstanceName()); @@ -182,18 +209,162 @@ std::shared_ptr Application::addBus(domain::Bus bus, int x, } -std::string Application::generateName(std::set& names, std::string instanceName) { - if(names.find(instanceName) == names.end()) { +std::string Application::generateName(std::set &names, std::string instanceName) { + if (names.find(instanceName) == names.end()) { return instanceName; } char buffer[4]; - for(int i=0; i<1000; i++) { + for (int i = 0; i < 1000; i++) { sprintf(buffer, "%03d", i); auto name = instanceName + "_" + buffer; - if(names.find(name) == names.end()) { + if (names.find(name) == names.end()) { return name; } } // return default value as this should never happen return instanceName; -} \ No newline at end of file +} + +bool Application::removeComponent(std::string componentName) { + auto component = findComponentByName(componentName); + if (component == nullptr) { + return false; + } + + std::set automaticBusses; + + schema->connections.erase( + std::remove_if( + schema->connections.begin(), + schema->connections.end(), + [component, &automaticBusses](const std::shared_ptr &conn) { + auto busConnection = dynamic_cast(conn.get()); + if (busConnection) { + if (busConnection->instance == component) { + return true; + } + } + auto directConnection = dynamic_cast(conn.get()); + if (directConnection) { + if (directConnection->instance == component || directConnection->secondInstance == component) { + automaticBusses.insert(directConnection->bus); + return true; + } + } + return false; + }), + schema->connections.end() + ); + + schema->busInstances.erase( + std::remove_if( + schema->busInstances.begin(), + schema->busInstances.end(), + [&automaticBusses](const std::shared_ptr &bus) { + return automaticBusses.count(bus.get()); + }), + schema->busInstances.end() + ); + + if(component->component.getType() == domain::Component::MEMORY) { + for(auto& comp: schema->componentInstances) { + if(comp->component.getType() == domain::Component::PROCESSOR) { + for(auto& attribute: comp->attributes) { + if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == component->name) { + attribute.value = domain::Value::fromMemoryReference(std::nullopt); + } + } + } + } + } + + for(auto iter = schema->componentInstances.begin(); iter != schema->componentInstances.end(); ++iter) { + if(iter->get() == component) { + schema->componentInstances.erase(iter); + break; + } + } + + return true; +} + +bool Application::removeBus(std::string busName) { + auto bus = findBusByName(busName); + if (bus == nullptr) { + return false; + } + + schema->connections.erase( + std::remove_if( + schema->connections.begin(), + schema->connections.end(), + [bus](const std::shared_ptr &conn) { + auto busConnection = dynamic_cast(conn.get()); + if (busConnection) { + if (busConnection->bus == bus) { + return true; + } + } + return false; + }), + schema->connections.end() + ); + + for(auto iter = schema->busInstances.begin(); iter != schema->busInstances.end(); ++iter) { + if(iter->get() == bus) { + schema->busInstances.erase(iter); + break; + } + } + + return true; +} + +domain::ComponentInstance *Application::findComponentByName(std::string componentName) { + for (auto &comp: schema->componentInstances) { + if (comp->name == componentName) { + return comp.get(); + } + } + return nullptr; +} + +domain::BusInstance *Application::findBusByName(std::string busName) { + for (auto &bus: schema->busInstances) { + if (bus->name == busName) { + return bus.get(); + } + } + return nullptr; +} + +void Application::renameComponent(std::string currentName, std::string newName) { + if(currentName == newName) { + return; + } + auto component = findComponentByName(currentName); + if(component) { + component->name = newName; + if(component->component.getType() == domain::Component::MEMORY) { + for(auto& comp: schema->componentInstances) { + if(comp.get()->component.getType() == domain::Component::PROCESSOR) { + for(auto& attribute: comp.get()->attributes) { + if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == currentName) { + attribute.value = domain::Value::fromMemoryReference(newName); + } + } + } + } + } + } +} + +void Application::renameBus(std::string currentName, std::string newName) { + if(currentName == newName) { + return; + } + auto bus = findBusByName(currentName); + if(bus) { + bus->name = newName; + } +} diff --git a/application.h b/application.h index f5443e9..1d0432e 100644 --- a/application.h +++ b/application.h @@ -21,6 +21,9 @@ private: std::string generateName(std::set& names, std::string instanceName); + domain::ComponentInstance *findComponentByName(std::string componentName); + domain::BusInstance *findBusByName(std::string busName); + public: std::optional getLibrary(); domain::Schema* getSchema(); @@ -28,7 +31,7 @@ public: void clear(); bool loadLibrary(std::string& filename, std::ostream& errorOutput); - bool loadSchema(std::string& filename, std::ostream& errorOutput); + std::pair> loadSchema(std::string& filename, std::ostream& errorOutput); static Application* instance(); @@ -37,11 +40,18 @@ public: std::vector generateComdel(std::ostringstream &output); std::shared_ptr addComponent(domain::Component component, std::vector attributes, int x, int y); + bool removeComponent(std::string component); + std::shared_ptr addBus(domain::Bus bus, int x, int y); + bool removeBus(std::string bus); static bool hasErrors(std::vector empty); ~Application() = default; + + void renameComponent(std::string currentName, std::string newName); + + void renameBus(std::string currentName, std::string newName); }; diff --git a/comdel/display/component_display.cpp b/comdel/display/component_display.cpp index bb7839b..cb1c102 100644 --- a/comdel/display/component_display.cpp +++ b/comdel/display/component_display.cpp @@ -18,9 +18,13 @@ namespace display { for(const auto &component: Application::instance()->getSchema()->componentInstances) { names.insert(component->name); } - - auto dialog = new NameDialog(this->instance.get(), names); + auto dialog = new NameDialog(this->instance->name, names); dialog->exec(); + + auto currentName = this->instance->name; + auto newName = dialog->getName(); + + Application::instance()->renameComponent(currentName, newName); }); menu.addSeparator(); for (int i = 0; i < this->instance->attributes.size(); i++) { @@ -40,6 +44,13 @@ namespace display { }); action->setEnabled(enabled); } + menu.addSeparator(); + menu.addAction(QString::fromStdString("Ukloni " + this->instance->name), [this]() { + Application::instance()->removeComponent(this->instance->name); + auto view = dynamic_cast(this->scene()->views()[0]); + view->refreshContent(); + }); + menu.exec(event->screenPos()); } @@ -103,9 +114,19 @@ namespace display { for(const auto &component: Application::instance()->getSchema()->busInstances) { names.insert(component->name); } - - auto dialog = new NameDialog(this->busInstance.get(), names); + auto dialog = new NameDialog(this->busInstance->name, names); dialog->exec(); + + auto currentName = this->busInstance->name; + auto newName = dialog->getName(); + + Application::instance()->renameBus(currentName, newName); + }); + menu.addSeparator(); + menu.addAction(QString::fromStdString("Ukloni " + this->busInstance->name), [this]() { + Application::instance()->removeBus(this->busInstance->name); + auto view = dynamic_cast(this->scene()->views()[0]); + view->refreshContent(); }); menu.exec(event->screenPos()); } diff --git a/comdel/display/library_display.cpp b/comdel/display/library_display.cpp index 07060e0..8af2765 100644 --- a/comdel/display/library_display.cpp +++ b/comdel/display/library_display.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace display { @@ -19,11 +20,10 @@ namespace display { layout->addSpacing(8); layout->addWidget(new QLabel("Buses:")); layout->addWidget(busList, 1); - - setLibrary(library); } - void Library::setLibrary(std::optional library) { + void Library::refreshContent() { + library = Application::instance()->getLibrary(); componentList->clear(); busList->clear(); diff --git a/comdel/display/library_display.h b/comdel/display/library_display.h index 41b6bc3..5033935 100644 --- a/comdel/display/library_display.h +++ b/comdel/display/library_display.h @@ -13,7 +13,7 @@ namespace display { public: Library(); - void setLibrary(std::optional library); + void refreshContent(); private: std::optional library; diff --git a/comdel/display/name_dialog.cpp b/comdel/display/name_dialog.cpp index ea13936..87c3ed7 100644 --- a/comdel/display/name_dialog.cpp +++ b/comdel/display/name_dialog.cpp @@ -5,38 +5,21 @@ #include #include "name_dialog.h" -display::NameDialog::NameDialog(domain::ComponentInstance *instance, std::set& names) : componentInstance(instance), usedNames(names) { - usedNames.erase(instance->name); +display::NameDialog::NameDialog(std::string currentName, std::set &names): currentName(currentName) { + usedNames.erase(currentName); auto *layout = new QVBoxLayout(this); layout->addWidget(new QLabel("Izmjeni ime", this)); edit = new QLineEdit(this); - edit->insert(instance->name.c_str()); + edit->insert(currentName.c_str()); connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate); layout->addWidget(edit); - this->setWindowTitle("Izmjeni ime"); + setWindowTitle("Izmjeni ime"); button = new QPushButton("Ažuriraj", this); connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange); layout->addWidget(button); - this->setLayout(layout); -} - -display::NameDialog::NameDialog(domain::BusInstance *instance, std::set& names): busInstance(instance), usedNames(names) { - usedNames.erase(instance->name); - - auto *layout = new QVBoxLayout(this); - layout->addWidget(new QLabel("Izmjeni ime", this)); - - edit = new QLineEdit(this); - edit->insert(instance->name.c_str()); - connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate); - layout->addWidget(edit); - this->setWindowTitle("Izmjeni ime"); - button = new QPushButton("Ažuriraj", this); - connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange); - layout->addWidget(button); - this->setLayout(layout); + setLayout(layout); } void display::NameDialog::onNameUpdate(const QString &text) { @@ -48,12 +31,10 @@ void display::NameDialog::onNameUpdate(const QString &text) { } void display::NameDialog::onNameChange() { - - - if (componentInstance != nullptr) { - componentInstance->name = this->edit->text().toStdString(); - } else if (busInstance != nullptr) { - busInstance->name = this->edit->text().toStdString(); - } - this->close(); + currentName = edit->text().toStdString(); + close(); +} + +std::string display::NameDialog::getName() { + return currentName; } diff --git a/comdel/display/name_dialog.h b/comdel/display/name_dialog.h index d4a8a50..8449c79 100644 --- a/comdel/display/name_dialog.h +++ b/comdel/display/name_dialog.h @@ -17,15 +17,13 @@ namespace display { std::set usedNames; QLineEdit *edit = nullptr; - domain::ComponentInstance *componentInstance = nullptr; - domain::BusInstance *busInstance = nullptr; + std::string currentName; QPushButton *button; public: + NameDialog(std::string currentName, std::set& names); - NameDialog(domain::ComponentInstance *instance, std::set& names); - - NameDialog(domain::BusInstance *instance, std::set& names); + std::string getName(); public slots: void onNameUpdate(const QString& text); diff --git a/comdel/display/schema_display.cpp b/comdel/display/schema_display.cpp index 8a5fc71..8f86c67 100644 --- a/comdel/display/schema_display.cpp +++ b/comdel/display/schema_display.cpp @@ -19,14 +19,15 @@ namespace display { } - void Schema::setSchema(domain::Schema *_schema, std::optional _library) { + void Schema::refreshContent() { + schema = Application::instance()->getSchema(); + library = Application::instance()->getLibrary(); + components.clear(); buses.clear(); - scene.clear(); busConnections.clear(); - this->schema = _schema; - this->library = _library; + if (schema != nullptr) { for (auto &instance: schema->componentInstances) { auto group = new display::ComponentGroup(instance); diff --git a/comdel/display/schema_display.h b/comdel/display/schema_display.h index 9d05e72..053d954 100644 --- a/comdel/display/schema_display.h +++ b/comdel/display/schema_display.h @@ -46,14 +46,14 @@ namespace display { std::vector busConnections; std::vector directConnections; - void setSchema(domain::Schema *schema, std::optional library); - void updateConnections(); void removeConnectable(QPointF f); void showConnectable(Pin *pin); + void refreshContent(); + protected: void dragEnterEvent(QDragEnterEvent *event) override; diff --git a/comdel/domain/comdel_validator.cpp b/comdel/domain/comdel_validator.cpp index be35322..187fe09 100644 --- a/comdel/domain/comdel_validator.cpp +++ b/comdel/domain/comdel_validator.cpp @@ -153,6 +153,37 @@ namespace domain { return nullopt; } + + std::vector + ComdelValidator::validateMemoryReferences(Schema &schema, Library &library, ValidationContext context) { + std::set memoryInstances; + for(auto& component: schema.componentInstances) { + if(component->component.getType() == Component::MEMORY) { + memoryInstances.insert(component->name); + } + } + + std::vector errors; + for(auto& component: schema.componentInstances) { + if(component->component.getType() == Component::PROCESSOR) { + for(auto& attribute: component->attributes) { + if(attribute.value.isType(Value::MEMORY_REFERENCE)) { + auto memoryReference = attribute.value.asMemoryReference(); + if(memoryReference != nullopt) { + if(memoryInstances.count(*memoryReference) == 0) { + context.attributes["memoryReference"] = domain::Value::fromString(memoryReference.value()); + auto message = populateMessage("There isn't a memory instance '{memoryReference}'", context); + errors.emplace_back(component.get(), nullptr, Action::ERROR, message); + } + } + } + } + } + } + + return errors; + } + std::vector ComdelValidator::validateInstanceNames(Schema &schema, Library &library, ValidationContext context) { std::set names; diff --git a/comdel/domain/comdel_validator.h b/comdel/domain/comdel_validator.h index 30f5b6f..2b9cdb3 100644 --- a/comdel/domain/comdel_validator.h +++ b/comdel/domain/comdel_validator.h @@ -35,6 +35,8 @@ namespace domain { std::optional validateRule(Rule rule, ValidationContext context); + std::vector validateMemoryReferences(Schema &schema, Library &library, ValidationContext context); + std::vector validateInstanceNames(Schema &schema, Library &library, ValidationContext context); std::vector validateInstanceCount(Schema &schema, Library &library, ValidationContext context); diff --git a/examples/simplified FRISC model/schema2.csl b/examples/simplified FRISC model/schema2.csl index 79f0e84..896cc01 100644 --- a/examples/simplified FRISC model/schema2.csl +++ b/examples/simplified FRISC model/schema2.csl @@ -1,42 +1,14 @@ -@source "frisc_library.csl" +@source "/home/bbr/Documents/Personal/FER/schema_editor/examples/simplified FRISC model/frisc_library.csl" @schema { - @instance procesor_002 FRISC { - @position (0, 0) - @attribute _memory null - } - - @instance mem Memorija { - @position (0, 250) - @attribute sinkroniziran false - @attribute brzina 1 - @attribute kapacitet 1024 - @attribute size 8 - @attribute pocetnaAdresa 1024 - } - - @instance procesor_001 FRISC { - @position (-89, 74) - @attribute _memory null - } - - @instance procesor_000 FRISC { - @position (-175, 195) - @attribute _memory null + @instance procesor FRISC { + @position (-177, -122) + @attribute _memory memorija2 } @instance procesor FRISC { - @position (-195, 63) + @position (49, -97) @attribute _memory null } - @instance bus glavnaSabirnica { - @position (0, 200) - @size 100 - } - - @connection (procesor_002.glavniPin, bus) { - } - @connection (mem.glavniPin, bus) { - } } diff --git a/examples/simplified FRISC model/schema3.csl b/examples/simplified FRISC model/schema3.csl index 984a346..28ba8ba 100644 --- a/examples/simplified FRISC model/schema3.csl +++ b/examples/simplified FRISC model/schema3.csl @@ -2,33 +2,13 @@ @schema { @instance procesor FRISC { - @position (-76, -97) - @attribute _memory memorija + @position (-112, -89) + @attribute _memory memorija2 } - @instance memorija Memorija { - @position (52, 119) - @attribute sinkroniziran false - @attribute brzina 1 - @attribute kapacitet 65536 - @attribute size 8 - @attribute pocetnaAdresa 0 - } + @instance procesor FRISC { + @position (112, -89) + @attribute _memory null + } - @instance glavnaSabirnica glavnaSabirnica { - @position (-78, 88) - @size 100 - } - - @instance directRam directRam { - @position (0, 0) - @size 0 - } - - @connection (memorija.glavniPin, glavnaSabirnica) { - } - @connection (procesor.glavniPin, glavnaSabirnica) { - } - @connection (memorija.memDirect, directRam, procesor.memDirect) { - } } diff --git a/mainwindow.cpp b/mainwindow.cpp index 8ca3948..14e1f3b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -65,7 +65,7 @@ void MainWindow::onLoadLibrary() { tr("Open library"), "/home", tr("Comdel library (*.csl)")); if(!filename.isEmpty()) { std::ostringstream output; - clear(); + log->clear(); auto librarySource = filename.toStdString(); @@ -74,8 +74,8 @@ void MainWindow::onLoadLibrary() { log->appendPlainText(QString::fromStdString(output.str())); } - libraryDisplay->setLibrary(instance->getLibrary()); - schemaDisplay->setSchema(instance->getSchema(), instance->getLibrary()); + libraryDisplay->refreshContent(); + schemaDisplay->refreshContent(); } } @@ -84,17 +84,19 @@ void MainWindow::onLoadSchema() { tr("Open schema"), "/home", tr("Comdel schema (*.csl)")); if(!filename.isEmpty()) { std::ostringstream output; - clear(); + log->clear(); auto schemaSource = filename.toStdString(); auto instance = Application::instance(); - if(!instance->loadSchema(schemaSource, output)) { + auto result = instance->loadSchema(schemaSource, output); + if(!result.first){ + formatErrors(result.second, output); log->appendPlainText(QString::fromStdString(output.str())); } - libraryDisplay->setLibrary(instance->getLibrary()); - schemaDisplay->setSchema(instance->getSchema(), instance->getLibrary()); + libraryDisplay->refreshContent(); + schemaDisplay->refreshContent(); } } @@ -176,12 +178,6 @@ void MainWindow::formatErrors(std::vector& errors, std: } } -void MainWindow::clear() { - log->clear(); - this->schemaDisplay->setSchema(nullptr, std::nullopt); - this->libraryDisplay->setLibrary(std::nullopt); -} - MainWindow::~MainWindow() { delete ui;