From d3dcdbf33ab016a63b32e9dbc77236c2e91ff083 Mon Sep 17 00:00:00 2001 From: Bruno Date: Tue, 3 Dec 2024 23:46:43 +0100 Subject: [PATCH] Add actions in the GUI --- src/libkiter/commons/KiterRegistry.h | 12 ++ src/qiter/CMakeLists.txt | 2 + src/qiter/ParameterInputDialog.cpp | 73 ++++++++++ src/qiter/ParameterInputDialog.h | 36 +++++ src/qiter/graphwidget.h | 3 + src/qiter/mainwindow.cpp | 191 ++++++++++++++++++++++++++- src/qiter/mainwindow.h | 9 +- 7 files changed, 322 insertions(+), 4 deletions(-) create mode 100644 src/qiter/ParameterInputDialog.cpp create mode 100644 src/qiter/ParameterInputDialog.h diff --git a/src/libkiter/commons/KiterRegistry.h b/src/libkiter/commons/KiterRegistry.h index e6c3369f..4872a9e9 100644 --- a/src/libkiter/commons/KiterRegistry.h +++ b/src/libkiter/commons/KiterRegistry.h @@ -92,6 +92,18 @@ class KiterRegistry { return true; } + static const std::vector get_names() { + tools_map& m = getSingletonMap(); + std::vector keys; + keys.reserve(m.size()); // Reserve memory to improve performance + std::transform(m.begin(), m.end(), std::back_inserter(keys), + [](const auto& pair) { + return pair.first; + }); + return keys; + + } + static const T* get(const std::string& name) { tools_map& map = getSingletonMap(); if (map.find(name) == map.end()) return nullptr; diff --git a/src/qiter/CMakeLists.txt b/src/qiter/CMakeLists.txt index f5d05dc7..00a30d35 100644 --- a/src/qiter/CMakeLists.txt +++ b/src/qiter/CMakeLists.txt @@ -13,6 +13,8 @@ set(SOURCE_FILES graphwidget.cpp qtNode.cpp qtEdge.cpp + ParameterInputDialog.h + ParameterInputDialog.cpp ) add_executable(qiter ${SOURCE_FILES}) diff --git a/src/qiter/ParameterInputDialog.cpp b/src/qiter/ParameterInputDialog.cpp new file mode 100644 index 00000000..02b43842 --- /dev/null +++ b/src/qiter/ParameterInputDialog.cpp @@ -0,0 +1,73 @@ +// +// Created by toky on 3/12/24. +// + +#include "ParameterInputDialog.h" +#include +#include +#include +#include +#include +#include "commons/KiterRegistry.h" +#include "generators/generators.h" + +ParameterInputDialog::ParameterInputDialog(const QString &generatorName, QWidget *parent) + : QDialog(parent), generatorName(generatorName) +{ + setWindowTitle(tr("Parameters for %1").arg(generatorName)); + layout = new QVBoxLayout(this); + + QLabel *infoLabel = new QLabel(tr("Enter parameters (name and value):"), this); + layout->addWidget(infoLabel); + + formLayout = new QFormLayout; + + // Add an initial parameter row + QLineEdit *paramNameEdit = new QLineEdit(this); + QLineEdit *paramValueEdit = new QLineEdit(this); + paramNameEdits.append(paramNameEdit); + paramValueEdits.append(paramValueEdit); + formLayout->addRow(paramNameEdit, paramValueEdit); + + layout->addLayout(formLayout); + + // Add "Add Parameter" button + QPushButton *addParamButton = new QPushButton(tr("Add Parameter"), this); + connect(addParamButton, &QPushButton::clicked, this, &ParameterInputDialog::onAddParameterClicked); + layout->addWidget(addParamButton); + + // Add OK and Cancel buttons + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + connect(buttonBox, &QDialogButtonBox::accepted, this, &ParameterInputDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &ParameterInputDialog::reject); + + layout->addWidget(buttonBox); +} + +void ParameterInputDialog::onAddParameterClicked() +{ + QLineEdit *paramNameEdit = new QLineEdit(this); + QLineEdit *paramValueEdit = new QLineEdit(this); + paramNameEdits.append(paramNameEdit); + paramValueEdits.append(paramValueEdit); + formLayout->addRow(paramNameEdit, paramValueEdit); +} + +void ParameterInputDialog::accept() +{ + // Collect parameters + for (int i = 0; i < paramNameEdits.size(); ++i) { + QString paramName = paramNameEdits[i]->text(); + QString paramValue = paramValueEdits[i]->text(); + if (!paramName.isEmpty()) { + parameters[paramName.toStdString()] = paramValue.toStdString(); + } + } + + QDialog::accept(); +} + +parameters_list_t ParameterInputDialog::getParameters() const +{ + return parameters; +} diff --git a/src/qiter/ParameterInputDialog.h b/src/qiter/ParameterInputDialog.h new file mode 100644 index 00000000..d25ee679 --- /dev/null +++ b/src/qiter/ParameterInputDialog.h @@ -0,0 +1,36 @@ +// +// Created by toky on 3/12/24. +// + +#ifndef KITER_PARAMETERINPUTDIALOG_H +#define KITER_PARAMETERINPUTDIALOG_H + +#include +#include +#include +#include +#include +#include "printers/printers.h" // For parameters_list_t + +class ParameterInputDialog : public QDialog +{ +Q_OBJECT + +public: + explicit ParameterInputDialog(const QString &generatorName, QWidget *parent = nullptr); + parameters_list_t getParameters() const; + +private slots: + void accept() override; + void onAddParameterClicked(); + +private: + QString generatorName; + parameters_list_t parameters; + QList paramNameEdits; + QList paramValueEdits; + QVBoxLayout *layout; + QFormLayout *formLayout; +}; + +#endif //KITER_PARAMETERINPUTDIALOG_H diff --git a/src/qiter/graphwidget.h b/src/qiter/graphwidget.h index 4d5633dd..2bde810d 100644 --- a/src/qiter/graphwidget.h +++ b/src/qiter/graphwidget.h @@ -16,6 +16,9 @@ Q_OBJECT public: GraphWidget(QWidget *parent = nullptr); void setDataflow(models::Dataflow *dataflow); + inline models::Dataflow * getDataflow() { + return this->dataflow; + } void drawGraph(); void startLayout(); diff --git a/src/qiter/mainwindow.cpp b/src/qiter/mainwindow.cpp index 45e3c940..3b23596e 100644 --- a/src/qiter/mainwindow.cpp +++ b/src/qiter/mainwindow.cpp @@ -2,9 +2,11 @@ #include "ui_mainwindow.h" #include #include -#include +#include #include "printers/printers.h" - +#include "commons/KiterRegistry.h" +#include "generators/generators.h" +#include "ParameterInputDialog.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -19,6 +21,62 @@ MainWindow::MainWindow(QWidget *parent) } connect(ui->actionLoad, &QAction::triggered, this, &MainWindow::loadGraph); + + // Create Generate menu dynamically + QMenu *generateMenu = new QMenu(tr("&Generate"), this); + ui->menubar->addMenu(generateMenu); + + // Get the list of generators from KiterRegistry + std::vector generatorNames = KiterRegistry::get_names(); + + for (const std::string &generatorName : generatorNames) { + QAction *action = new QAction(QString::fromStdString(generatorName), this); + action->setData(QString::fromStdString(generatorName)); + generateMenu->addAction(action); + connect(action, &QAction::triggered, this, &MainWindow::onGenerateActionTriggered); + } + + // Create Transformations menu dynamically + QMenu *transformationsMenu = new QMenu(tr("&Transformations"), this); + ui->menubar->addMenu(transformationsMenu); + + // Get the list of transformations from KiterRegistry + std::vector transformationNames = KiterRegistry::get_names(); + + for (const std::string &transformationName : transformationNames) { + QAction *action = new QAction(QString::fromStdString(transformationName), this); + action->setData(QString::fromStdString(transformationName)); + transformationsMenu->addAction(action); + connect(action, &QAction::triggered, this, &MainWindow::onTransformationActionTriggered); + } + + // Create Buffer Sizing menu dynamically + QMenu *bufferSizingMenu = new QMenu(tr("&Buffer Sizing"), this); + ui->menubar->addMenu(bufferSizingMenu); + + // Get the list of buffer sizings from KiterRegistry + std::vector bufferSizingNames = KiterRegistry::get_names(); + + for (const std::string &bufferSizingName : bufferSizingNames) { + QAction *action = new QAction(QString::fromStdString(bufferSizingName), this); + action->setData(QString::fromStdString(bufferSizingName)); + bufferSizingMenu->addAction(action); + connect(action, &QAction::triggered, this, &MainWindow::onBufferSizingActionTriggered); + } + + // Create Printers menu dynamically + QMenu *printersMenu = new QMenu(tr("&Printers"), this); + ui->menubar->addMenu(printersMenu); + + // Get the list of printers from KiterRegistry + std::vector printerNames = KiterRegistry::get_names(); + + for (const std::string &printerName : printerNames) { + QAction *action = new QAction(QString::fromStdString(printerName), this); + action->setData(QString::fromStdString(printerName)); + printersMenu->addAction(action); + connect(action, &QAction::triggered, this, &MainWindow::onPrinterActionTriggered); + } } MainWindow::~MainWindow() @@ -26,6 +84,7 @@ MainWindow::~MainWindow() delete ui; } + void MainWindow::loadGraph() { qInfo() << "Attempting to open file dialog for XML file selection..."; @@ -35,7 +94,7 @@ void MainWindow::loadGraph() if (fileName.isEmpty()) { qInfo() << "No file selected or dialog canceled."; - return; + return; } qInfo() << "Selected file:" << fileName; @@ -53,3 +112,129 @@ void MainWindow::loadGraph() graphWidget->setDataflow(dataflow); } +void MainWindow::onTransformationActionTriggered() +{ + handleAction( + [this](const transformation_t *actionInstance, const parameters_list_t ¶meters) { + // Ensure dataflow is loaded + models::Dataflow *dataflow = graphWidget->getDataflow(); + if (!dataflow) { + QMessageBox::warning(this, tr("No Dataflow"), tr("Please load or generate a dataflow graph first.")); + throw std::runtime_error("No dataflow loaded"); + } + // Perform the action + actionInstance->fun(dataflow, parameters); + }, + [this]() { + // Post-action processing + graphWidget->update(); // Update the graph display + }); +} + + +void MainWindow::onPrinterActionTriggered() +{ + handleAction( + [this](const printer_t *actionInstance, const parameters_list_t ¶meters) { + models::Dataflow *dataflow = graphWidget->getDataflow(); + if (!dataflow) { + QMessageBox::warning(this, tr("No Dataflow"), tr("Please load or generate a dataflow graph first.")); + throw std::runtime_error("No dataflow loaded"); + } + actionInstance->fun(dataflow, parameters); + }, + []() { + // Post-action processing + qInfo() << "Printer executed successfully."; + }); +} + + +void MainWindow::onBufferSizingActionTriggered() +{ + handleAction( + [this](const buffer_sizing_t *actionInstance, const parameters_list_t ¶meters) -> BufferSizingResult { + models::Dataflow *dataflow = graphWidget->getDataflow(); + if (!dataflow) { + QMessageBox::warning(this, tr("No Dataflow"), tr("Please load or generate a dataflow graph first.")); + throw std::runtime_error("No dataflow loaded"); + } + return actionInstance->fun(dataflow, parameters); + }, + [this](const BufferSizingResult &res) { + // Post-action processing + qInfo() << "Total buffer size:" << res.total_size(); + QMessageBox::information(this, tr("Buffer Sizing Result"), + tr("Total buffer size: %1").arg(res.total_size())); + }); +} + + + +void MainWindow::onGenerateActionTriggered() +{ + handleAction( + [](const generator_t *actionInstance, const parameters_list_t ¶meters) -> models::Dataflow * { + return actionInstance->fun(parameters); + }, + [this](models::Dataflow *newDataflow) { + if (!newDataflow) { + QMessageBox::critical(this, tr("Error"), tr("Failed to generate the graph.")); + qWarning() << "Failed to generate the graph."; + return; + } + qInfo() << "Dataflow generated successfully, updating graph widget..."; + graphWidget->setDataflow(newDataflow); + }); +} + +template +void MainWindow::handleAction(ActionFunction actionFunction, PostAction postAction) { + try { + QAction *actionSender = qobject_cast(sender()); + if (!actionSender) { + qWarning() << "Sender is not a QAction!"; + return; + } + QString actionName = actionSender->data().toString(); + qInfo() << "Action selected:" << actionName; + + // Show a dialog to input parameters + ParameterInputDialog dialog(actionName, this); + if (dialog.exec() != QDialog::Accepted) { + qInfo() << "Action dialog canceled."; + return; + } + + parameters_list_t parameters = dialog.getParameters(); + + const ActionType *actionInstance = KiterRegistry::get(actionName.toStdString()); + if (!actionInstance) { + QMessageBox::critical(this, tr("Error"), tr("Action not found.")); + qWarning() << "Action not found:" << actionName; + return; + } + + qInfo() << "Performing action..."; + + // Run the action on the main thread + if constexpr (std::is_same::value) { + // If ResultType is void, call the function without assigning to a variable + actionFunction(actionInstance, parameters); + qInfo() << "Action completed."; + // Process the result using the provided post-action function + postAction(); + } else { + // If ResultType is not void, assign the result to a variable + ResultType result = actionFunction(actionInstance, parameters); + qInfo() << "Action completed."; + // Process the result using the provided post-action function + postAction(result); + } + + + } catch (const std::exception &e) { + QMessageBox::critical(this, tr("Error"), e.what()); + qWarning() << "Exception occurred:" << e.what(); + } +} diff --git a/src/qiter/mainwindow.h b/src/qiter/mainwindow.h index 493bc33b..a5e73c87 100644 --- a/src/qiter/mainwindow.h +++ b/src/qiter/mainwindow.h @@ -18,9 +18,16 @@ Q_OBJECT private slots: void loadGraph(); + void onGenerateActionTriggered(); + void onTransformationActionTriggered(); + void onBufferSizingActionTriggered(); + void onPrinterActionTriggered(); private: Ui::MainWindow *ui; - GraphWidget *graphWidget; + GraphWidget *graphWidget; + + template + void handleAction(ActionFunction actionFunction, PostAction postAction) ; }; #endif // MAINWINDOW_H