schema_editor/mainwindow.cpp

271 lines
8.2 KiB
C++
Raw Normal View History

2022-03-29 19:31:45 +00:00
#include "mainwindow.h"
#include "ui_mainwindow.h"
2022-04-07 22:21:23 +00:00
#include <QFileDialog>
#include <QHBoxLayout>
#include <comdel/parser/parsecontext.h>
#include <comdel/parser/parserutil.h>
2022-04-09 18:03:43 +00:00
#include <comdel/domain/schemacreator.h>
2022-04-07 22:21:23 +00:00
#include <iostream>
2022-04-09 19:11:17 +00:00
#include <QPlainTextEdit>
#include <sstream>
2022-04-10 12:23:18 +00:00
#include <comdel/domain/comdelvalidator.h>
2022-04-24 20:21:45 +00:00
#include <fstream>
2022-04-07 22:21:23 +00:00
2022-03-29 19:31:45 +00:00
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
2022-04-07 22:21:23 +00:00
setupUi();
// define allowed methods
2022-04-10 12:23:18 +00:00
signatures = domain::getSupportedFunctions();
2022-04-07 22:21:23 +00:00
}
void MainWindow::setupUi()
{
2022-04-12 21:37:05 +00:00
setWindowTitle("COMDEL schema editor");
2022-04-07 22:21:23 +00:00
auto layout = new QHBoxLayout();
ui->centralwidget->setLayout(layout);
// setup toolbar
ui->toolBar->addAction("Load library", this, &MainWindow::onLoadLibrary);
ui->toolBar->addAction("Load schema", this, &MainWindow::onLoadSchema);
2022-04-24 20:21:45 +00:00
ui->toolBar->addAction("Save schema", this, &MainWindow::onStoreScheme);
2022-04-07 22:21:23 +00:00
2022-04-10 12:23:18 +00:00
connect(ui->actionValidate, &QAction::triggered, this, &MainWindow::onValidateSchema);
2022-04-07 22:21:23 +00:00
// setup central content
libraryDisplay = new display::Library();
2022-04-09 19:11:17 +00:00
auto schemaParent = new QWidget();
auto schemaLayout = new QVBoxLayout();
schemaParent->setLayout(schemaLayout);
2022-04-07 22:21:23 +00:00
schemaDisplay = new display::Schema();
2022-04-09 19:11:17 +00:00
schemaLayout->setMargin(0);
schemaLayout->addWidget(schemaDisplay, 1);
2022-04-07 22:21:23 +00:00
layout->setMargin(0);
layout->addWidget(libraryDisplay);
2022-04-09 19:11:17 +00:00
layout->addWidget(schemaParent, 1);
2022-04-07 22:21:23 +00:00
2022-04-09 19:11:17 +00:00
log = new QPlainTextEdit();
log->setFont(QFont("Courier"));
2022-04-12 21:37:05 +00:00
log->setReadOnly(false);
2022-04-09 19:11:17 +00:00
schemaLayout->addWidget(log);
2022-04-07 22:21:23 +00:00
}
2022-04-12 21:37:05 +00:00
void MainWindow::onLoadLibrary() {
auto filename = QFileDialog::getOpenFileName(this,
tr("Open library"), "/home", tr("Comdel library (*.csl)"));
2022-04-07 22:21:23 +00:00
2022-04-09 19:11:17 +00:00
std::ostringstream buffer;
2022-04-12 21:37:05 +00:00
log->clear();
2022-04-07 22:21:23 +00:00
if(!filename.isEmpty()) {
2022-04-24 20:21:45 +00:00
librarySource = filename.toStdString();
2022-04-07 22:21:23 +00:00
clear();
ParseContext parseContext;
2022-04-12 21:37:05 +00:00
auto libraryNode = loadLibraryFromFile(&parseContext, filename.toStdString().c_str(), buffer);
if(libraryNode) {
2022-04-09 18:03:43 +00:00
domain::SchemaCreator generator(signatures);
2022-04-12 21:37:05 +00:00
library = generator.loadLibrary(*libraryNode);
2022-04-07 22:21:23 +00:00
2022-04-09 19:11:17 +00:00
for (auto& error : generator.getErrors()) {
2022-04-24 20:21:45 +00:00
parseContext.formatError(error, buffer, "ERROR: ");
2022-04-09 19:11:17 +00:00
}
if(generator.getErrors().empty()) {
libraryDisplay->setLibrary(library);
2022-04-12 21:37:05 +00:00
// on library load we create a new schema
2022-04-18 09:41:02 +00:00
schema = new domain::Schema();
2022-04-09 19:11:17 +00:00
schemaDisplay->setSchema(schema);
2022-04-07 22:21:23 +00:00
}
2022-04-12 21:37:05 +00:00
} else {
2022-04-24 20:21:45 +00:00
buffer<<"Bad request"<<std::endl;
2022-04-07 22:21:23 +00:00
}
}
2022-04-09 19:11:17 +00:00
log->appendPlainText(QString::fromStdString(buffer.str()));
2022-04-07 22:21:23 +00:00
}
void MainWindow::onLoadSchema() {
auto filename = QFileDialog::getOpenFileName(this,
tr("Open schema"), "/home", tr("Comdel schema (*.csl)"));
2022-04-12 21:37:05 +00:00
std::ostringstream buffer;
log->clear();
2022-04-07 22:21:23 +00:00
if(!filename.isEmpty()) {
clear();
ParseContext parseContext;
2022-04-12 21:37:05 +00:00
auto schemaNode = loadSchemaFromFile(&parseContext, filename.toStdString().c_str(), buffer);
2022-04-07 22:21:23 +00:00
if(schemaNode) {
2022-04-09 18:03:43 +00:00
domain::SchemaCreator generator(signatures);
2022-04-07 22:21:23 +00:00
library = generator.loadLibrary(*schemaNode->library);
2022-04-24 20:21:45 +00:00
librarySource = schemaNode->source->value;
2022-04-07 22:21:23 +00:00
for (auto& error : generator.getErrors()) {
2022-04-24 20:21:45 +00:00
parseContext.formatError(error, buffer, "ERROR: ");
2022-04-07 22:21:23 +00:00
}
if(library) {
schema = generator.loadSchema(*schemaNode, *library);
for (auto& error : generator.getErrors()) {
2022-04-24 20:21:45 +00:00
parseContext.formatError(error, buffer, "ERROR: ");
2022-04-07 22:21:23 +00:00
}
}
2022-04-12 21:37:05 +00:00
if(generator.getErrors().empty()) {
libraryDisplay->setLibrary(library);
schemaDisplay->setSchema(schema);
}
2022-04-07 22:21:23 +00:00
}
}
2022-04-12 21:37:05 +00:00
log->appendPlainText(QString::fromStdString(buffer.str()));
2022-04-10 12:23:18 +00:00
}
2022-04-24 20:21:45 +00:00
void MainWindow::onStoreScheme() {
if(schema == nullptr) {
return;
}
auto filename = QFileDialog::getSaveFileName(this,
tr("Save schema"), "/home", tr("Comdel schema (*.csl)"));
std::ostringstream buffer;
buffer << "@source " << this->librarySource << std::endl << std::endl;
buffer << "@schema {" << std::endl;
for(auto &instance: schema->instances) {
auto componentInstance = dynamic_cast<domain::ComponentInstance*>(instance);
if(componentInstance != NULL) {
buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl;
buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl;
for(auto &attribute: instance->attributes) {
buffer << "\t\t" << "@attribute " << attribute->name << " " << attribute->value.stringify() << std::endl;
}
buffer << "\t}" << std::endl << std::endl;
}
auto busInstance = dynamic_cast<domain::BusInstance*>(instance);
if(busInstance != NULL) {
buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl;
buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl;
buffer << "\t\t" << "@size " << busInstance->size << std::endl;
buffer << "\t}" << std::endl << std::endl;
}
}
for(auto &wire: schema->wires) {
buffer << "\t" << "@wire " << wire->name << " {" << std::endl;
buffer << "\t\t" << "@position (" << wire->position.first << ", " << wire->position.second << ")" << std::endl;
buffer << "\t\t" << "@display {}" << std::endl;
buffer << "\t" << "}" << std::endl;
}
for(auto &conn: schema->connections) {
auto busConn = dynamic_cast<domain::BusConnectionInstance*>(conn);
if(busConn) {
buffer << "\t" << "@connection (" << busConn->instance->name << "." << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl;
buffer << "\t\t"<< "@wire " << busConn->wire->name << std::endl;
buffer << "\t" << "}" << std::endl;
}
}
buffer << "}" << std::endl;
auto value = buffer.str();
std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary);
out<<buffer.str();
out.close();
}
2022-04-10 12:23:18 +00:00
void MainWindow::onValidateSchema(bool /*toggled*/) {
2022-04-18 09:41:02 +00:00
if(schema == nullptr) {
2022-04-12 21:37:05 +00:00
return;
}
2022-04-10 12:23:18 +00:00
this->validationErrors.clear();
std::map<std::string, domain::FunctionCallback> callbacks;
auto functions = domain::getSupportedFunctions();
for(auto &func: functions) {
callbacks[func.name] = func.callback;
}
domain::ComdelValidator validator{callbacks};
domain::ValidationContext context;
context.instance = nullptr;
context.attribute = nullptr;
context.addressSpaces = {};
for(auto &lib: library->getAddressSpaces()) {
context.addressSpaces.insert(std::make_pair(lib.getName(), lib));
}
auto errors = validator.validateSchema(*schema, context);
errors.erase(std::remove_if(
errors.begin(), errors.end(), [](const domain::ValidationError& error) { return error.type == domain::Action::WARNING;}),
errors.end());
std::ostringstream buff;
for(auto err: errors) {
if(err.instance != NULL) {
buff << err.instance->name;
}
if(err.attribute != NULL) {
buff << "::" << err.attribute->name;
}
if(err.type == domain::Action::ERROR) {
buff << " [ERROR] ";
} else {
buff << " [WARNING] ";
}
buff << err.message << std::endl;
}
2022-04-07 22:21:23 +00:00
2022-04-10 12:23:18 +00:00
log->appendPlainText(QString::fromStdString(buff.str()));
validationErrors = errors;
2022-04-07 22:21:23 +00:00
}
2022-04-10 12:23:18 +00:00
2022-04-07 22:21:23 +00:00
void MainWindow::clear() {
2022-04-10 12:23:18 +00:00
validationErrors.clear();
2022-04-18 09:41:02 +00:00
schema = nullptr;
2022-04-07 22:21:23 +00:00
library = std::nullopt;
libraryDisplay->setLibrary(library);
schemaDisplay->setSchema(schema);
2022-03-29 19:31:45 +00:00
}
MainWindow::~MainWindow()
{
delete ui;
2022-04-24 20:21:45 +00:00
}