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<std::string> get_names() { + tools_map& m = getSingletonMap(); + std::vector<std::string> 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 <QDialogButtonBox> +#include <QFormLayout> +#include <QLabel> +#include <QLineEdit> +#include <QPushButton> +#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 <QDialog> +#include <QMap> +#include <QLineEdit> +#include <QVBoxLayout> +#include <QFormLayout> +#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<QLineEdit*> paramNameEdits; + QList<QLineEdit*> 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 <QFileDialog> #include <QMessageBox> -#include <QDebug> +#include <QDebug> #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<std::string> generatorNames = KiterRegistry<generator_t>::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<std::string> transformationNames = KiterRegistry<transformation_t>::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<std::string> bufferSizingNames = KiterRegistry<buffer_sizing_t>::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<std::string> printerNames = KiterRegistry<printer_t>::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<transformation_t, void>( + [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<printer_t, void>( + [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<buffer_sizing_t, BufferSizingResult>( + [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<generator_t, models::Dataflow *>( + [](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 <typename ActionType, typename ResultType, typename ActionFunction, typename PostAction> +void MainWindow::handleAction(ActionFunction actionFunction, PostAction postAction) { + try { + QAction *actionSender = qobject_cast<QAction *>(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<ActionType>::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<ResultType, void>::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 <typename ActionType, typename ResultType, typename ActionFunction, typename PostAction> + void handleAction(ActionFunction actionFunction, PostAction postAction) ; }; #endif // MAINWINDOW_H