diff --git a/agui2/CMakeLists.txt b/agui2/CMakeLists.txt index af5a685d87ec17040039418dc881053cbe5a1b54..d8c4e1c345bd688999c7d2815526735def428206 100644 --- a/agui2/CMakeLists.txt +++ b/agui2/CMakeLists.txt @@ -44,6 +44,8 @@ add_executable(${PROJECT_NAME} src/Algorithm/Registry.hpp src/Converter.cpp src/Converter.hpp + src/Graphics/AlgorithmList.cpp + src/Graphics/AlgorithmList.hpp src/Graphics/Connection/Connection.cpp src/Graphics/Connection/Connection.hpp src/Graphics/Connection/ConnectionBox.cpp @@ -62,6 +64,8 @@ add_executable(${PROJECT_NAME} src/Graphics/GraphicsBox.hpp src/Graphics/GraphicsScene.cpp src/Graphics/GraphicsScene.hpp + src/Graphics/GraphicsView.cpp + src/Graphics/GraphicsView.hpp src/Graphics/InputGraphicsBox.cpp src/Graphics/InputGraphicsBox.hpp src/GraphvizIntegrator.cpp diff --git a/agui2/src/Graphics/AlgorithmList.cpp b/agui2/src/Graphics/AlgorithmList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d23db99eafa929fc587397a303a152e69aa5b264 --- /dev/null +++ b/agui2/src/Graphics/AlgorithmList.cpp @@ -0,0 +1,31 @@ +#include <Graphics/AlgorithmList.hpp> + +#include <QDrag> +#include <QtGui/QDragMoveEvent> +#include <QtGui/QStandardItemModel> +#include <QMimeData> + +void AlgorithmList::startDrag(Qt::DropActions supportedActions) { + auto* item = dynamic_cast<QStandardItemModel*>(this->model())->itemFromIndex(this->currentIndex()); + if (!item) + return; + + auto algorithm = item->data(); + if (algorithm.isNull()) + return; + + auto algorithmName = algorithm.toString(); + if (algorithmName.isEmpty()) + return; + + auto* mimeData = new QMimeData; + mimeData->setData("application/x-algorithm", algorithmName.toUtf8()); + auto* drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->exec(Qt::MoveAction); +} + +AlgorithmList::AlgorithmList(QWidget* parent) + : QTreeView(parent) { + this->setDragEnabled(true); +} diff --git a/agui2/src/Graphics/AlgorithmList.hpp b/agui2/src/Graphics/AlgorithmList.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e58990b130ce8c7170a7b853ed539d6cf29bd448 --- /dev/null +++ b/agui2/src/Graphics/AlgorithmList.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <QtWidgets/QTreeView> + +class AlgorithmList : public QTreeView { +public: + explicit AlgorithmList(QWidget* parent); + +protected: + void startDrag(Qt::DropActions supportedActions) override; + +}; + + diff --git a/agui2/src/Graphics/GraphicsView.cpp b/agui2/src/Graphics/GraphicsView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cec2d0f45c4cc9fa3765e4c250e963fac32edf9b --- /dev/null +++ b/agui2/src/Graphics/GraphicsView.cpp @@ -0,0 +1,39 @@ +#include <Graphics/GraphicsView.hpp> + +#include <QDragEnterEvent> +#include <QMimeData> +#include <QtWidgets/QGraphicsScene> +#include <QtWidgets/QWidget> + +#include <Algorithm/Registry.hpp> +#include <Graphics/GraphicsBox.hpp> +#include <Models/AlgorithmModelBox.hpp> + +GraphicsView::GraphicsView(QWidget* parent) + : QGraphicsView(parent) +{ + this->setAcceptDrops(true); +} + +void GraphicsView::dragEnterEvent(QDragEnterEvent* event) { + if (event->mimeData()->hasFormat("application/x-algorithm")) + event->acceptProposedAction(); +} + +void GraphicsView::dropEvent(QDropEvent* event) { + auto name = event->mimeData()->data("application/x-algorithm").toStdString(); + if (auto* algo = Registry::getAlgorithm(name)) { + + this->scene()->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(algo), this->mapToScene(event->pos()))); + event->acceptProposedAction(); + } + else { + event->ignore(); + } +} + +void GraphicsView::dragMoveEvent(QDragMoveEvent* event) { + if (event->mimeData()->hasFormat("application/x-algorithm")) + event->acceptProposedAction(); +} + diff --git a/agui2/src/Graphics/GraphicsView.hpp b/agui2/src/Graphics/GraphicsView.hpp new file mode 100644 index 0000000000000000000000000000000000000000..789262e179e0f497d1686d34195ef9a009ed98a6 --- /dev/null +++ b/agui2/src/Graphics/GraphicsView.hpp @@ -0,0 +1,14 @@ +#pragma once +#include <QtWidgets/QGraphicsView> + +class GraphicsView : public QGraphicsView { +public: + GraphicsView(QWidget* parent); + +protected: + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dropEvent(QDropEvent* event) override; +}; + + diff --git a/agui2/src/MainWindow.cpp b/agui2/src/MainWindow.cpp index 0a8e4b27c0d8f1c74dc5ea0dbcd42e38e54e15e8..d7322539639f484764a1a660a222bbe4d9fc13eb 100644 --- a/agui2/src/MainWindow.cpp +++ b/agui2/src/MainWindow.cpp @@ -17,16 +17,32 @@ #include <Models/InputModelBox.hpp> #include <ui_MainWindow.h> #include <Models/AlgorithmModelBox.hpp> +#include <Models/OutputModelBox.hpp> MainWindow::MainWindow() : ui(new Ui::MainWindow) , scene(new GraphicsScene(this)) + , algorithmModel(std::make_unique<QStandardItemModel>()) { ui->setupUi(this); ui->graphicsView->setScene(this->scene.get()); Registry::initialize(); + for (const auto& group: Registry::getGroups()) { + auto* groupItem = new QStandardItem(QString::fromStdString(group.first)); + this->algorithmModel->appendRow(groupItem); + + for (const auto* algo: group.second) { + auto* item = new QStandardItem(QString::fromStdString(std::string{" "} + algo->getPrettyName())); + item->setData(QString::fromStdString(algo->getName())); + groupItem->appendRow(item); + } + } + + this->ui->algorithmList->setModel(this->algorithmModel.get()); + this->ui->algorithmList->expandAll(); + this->scene->addItem(new InputGraphicsBox(std::make_unique<InputModelBox>(), {0, 200})); outputBox = new GraphicsBox(std::make_unique<OutputModelBox>(), {400, 200});; this->scene->addItem(outputBox); @@ -56,154 +72,6 @@ void MainWindow::on_RunBtn_clicked() } } -void MainWindow::on_DeterminizeBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::determinize::Determinize")), {200, 50})); -} - -void MainWindow::on_TotalBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::Total")), {300, 50})); -} - -void MainWindow::on_CompactBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::Compaction")), {200, -50})); -} - -void MainWindow::on_SingleInitialBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::SingleInitialState")), {200, 30})); -} - -void MainWindow::on_EpsilonRemoveBtn_clicked() -{ - QMenu menu; - QAction * a; - a = menu.addAction("&Incoming"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_EpsilonRemoveIncoming())); - a = menu.addAction("&Outgoing"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_EpsilonRemoveOutgoing())); - QPoint point = ui->EpsilonRemoveBtn->mapToGlobal(ui->EpsilonRemoveBtn->rect().topRight()); - menu.exec(point); -} - -void MainWindow::on_MinimizeBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::Minimize")), {200, 100})); -} - -void MainWindow::on_NormilizeBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::Normalize")), {200, 100})); -} - -void MainWindow::on_EpsilonRemoveIncoming() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::EpsilonRemoverIncoming")), {200, 30})); -} - -void MainWindow::on_EpsilonRemoveOutgoing() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::EpsilonRemoverOutgoing")), {200, 30})); -} - -void MainWindow::on_RenameBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::Rename")), {200, 30})); -} - -void MainWindow::on_TrimBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::Trim")), {200, 30})); -} - -void MainWindow::on_RemoveUselessBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::UselessStatesRemover")), {200, 30})); -} - -void MainWindow::on_RemoveUnreachableBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::simplify::UnreachableStatesRemover")), {200, 30})); -} - -void MainWindow::on_ReverseBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::Reverse")), {200, 30})); -} - -void MainWindow::on_IterateBtn_clicked() -{ - QMenu menu; - QAction * a; - a = menu.addAction("&Without epsilon transitions"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_Iterate())); - a = menu.addAction("&Epsilon transitions"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_IterateEpsilon())); - QPoint point = ui->IterateBtn->mapToGlobal(ui->IterateBtn->rect().topRight()); - menu.exec(point); -} - -void MainWindow::on_Iterate() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::AutomatonIteration")), {200, 30})); -} - -void MainWindow::on_IterateEpsilon() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::AutomatonIterationEpsilonTransition")), {200, 30})); -} - -void MainWindow::on_ConcatenateBtn_clicked() -{ - QMenu menu; - QAction * a; - a = menu.addAction("&Without epsilon transitions"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_Concatenate())); - a = menu.addAction("&Epsilon transitions"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_ConcatenateEpsilon())); - QPoint point = ui->ConcatenateBtn->mapToGlobal(ui->ConcatenateBtn->rect().topRight()); - menu.exec(point); -} - -void MainWindow::on_Concatenate() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::AutomataConcatenation")), {200, 100})); -} - -void MainWindow::on_ConcatenateEpsilon() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::AutomataConcatenationEpsilonTransition")), {200, 100})); -} - -void MainWindow::on_UnionBtn_clicked() -{ - QMenu menu; - QAction * a; - a = menu.addAction("&Without epsilon transitions"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_Union())); - a = menu.addAction("&Epsilon transitions"); - QObject::connect(a,SIGNAL(triggered()), this, SLOT(on_UnionEpsilon())); - QPoint point = ui->UnionBtn->mapToGlobal(ui->UnionBtn->rect().topRight()); - menu.exec(point); -} - -void MainWindow::on_Union() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::AutomataUnionCartesianProduct")), {200, 100})); -} - -void MainWindow::on_UnionEpsilon() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::AutomataUnionEpsilonTransition")), {200, 100})); -} - -void MainWindow::on_IntersectBtn_clicked() -{ - this->scene->addItem(new GraphicsBox(std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::transform::AutomataIntersectionCartesianProduct")), {200, 100})); -} - void MainWindow::on_AddInputBtn_clicked() { qreal y = qrand() % 4 * 100; diff --git a/agui2/src/MainWindow.hpp b/agui2/src/MainWindow.hpp index c6daacfa5a26014cf6ab2c3cd133d772a8a15f10..870184e2ac306cae851d816850c1c4732ad81510 100644 --- a/agui2/src/MainWindow.hpp +++ b/agui2/src/MainWindow.hpp @@ -8,6 +8,8 @@ #include <Graphics/GraphicsScene.hpp> #include <ui_MainWindow.h> +#include <QtCore/QStringListModel> +#include <QtGui/QStandardItemModel> class GraphicsBox; @@ -24,35 +26,11 @@ private: private slots: void on_AddInputBtn_clicked(); void on_RunBtn_clicked(); - void on_DeterminizeBtn_clicked(); - void on_TotalBtn_clicked(); - void on_CompactBtn_clicked(); - void on_SingleInitialBtn_clicked(); - void on_EpsilonRemoveBtn_clicked(); - void on_ConcatenateBtn_clicked(); - void on_MinimizeBtn_clicked(); - void on_NormilizeBtn_clicked(); - void on_RenameBtn_clicked(); - void on_TrimBtn_clicked(); - void on_RemoveUselessBtn_clicked(); - void on_RemoveUnreachableBtn_clicked(); - void on_ReverseBtn_clicked(); - void on_IterateBtn_clicked(); - void on_UnionBtn_clicked(); - void on_IntersectBtn_clicked(); - - void on_EpsilonRemoveIncoming(); - void on_EpsilonRemoveOutgoing(); - void on_Iterate(); - void on_IterateEpsilon(); - void on_Concatenate(); - void on_ConcatenateEpsilon(); - void on_Union(); - void on_UnionEpsilon(); private: std::unique_ptr<Ui::MainWindow> ui; std::unique_ptr<GraphicsScene> scene; + std::unique_ptr<QStandardItemModel> algorithmModel; GraphicsBox* outputBox; }; diff --git a/agui2/src/MainWindow.ui b/agui2/src/MainWindow.ui index 135b95f790234a8824443efcdb03248a77e24c73..0ab81953b8a212818a17bee858d9ac38956f9f2b 100644 --- a/agui2/src/MainWindow.ui +++ b/agui2/src/MainWindow.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>987</width> - <height>615</height> + <height>752</height> </rect> </property> <property name="sizePolicy"> @@ -36,7 +36,7 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0"> <property name="spacing"> <number>0</number> </property> @@ -51,157 +51,28 @@ </widget> </item> <item> - <widget class="QGroupBox" name="groupBox"> + <widget class="AlgorithmList" name="algorithmList"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <sizepolicy hsizetype="Fixed" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="title"> - <string>Simplify</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QPushButton" name="EpsilonRemoveBtn"> - <property name="text"> - <string>Remove Epsilon</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="MinimizeBtn"> - <property name="text"> - <string>Minimize</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="RenameBtn"> - <property name="text"> - <string>Rename</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="NormilizeBtn"> - <property name="text"> - <string>Normalize</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="SingleInitialBtn"> - <property name="text"> - <string>Single Initial State</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="TotalBtn"> - <property name="text"> - <string>Total</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="TrimBtn"> - <property name="text"> - <string>Trim</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="RemoveUselessBtn"> - <property name="text"> - <string>Remove Useless</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="RemoveUnreachableBtn"> - <property name="text"> - <string>Remove Unreachable</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Transform</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QPushButton" name="ReverseBtn"> - <property name="text"> - <string>Reverse</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="CompactBtn"> - <property name="text"> - <string>Compact</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="IterateBtn"> - <property name="text"> - <string>Iterate</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="UnionBtn"> - <property name="text"> - <string>Union</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="ConcatenateBtn"> - <property name="text"> - <string>Concatenate</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="IntersectBtn"> - <property name="text"> - <string>Intersect</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QPushButton" name="DeterminizeBtn"> - <property name="text"> - <string>Determinize</string> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> </widget> </item> </layout> </item> <item> - <widget class="QGraphicsView" name="graphicsView"> + <widget class="GraphicsView" name="graphicsView"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> @@ -233,7 +104,7 @@ <x>0</x> <y>0</y> <width>987</width> - <height>19</height> + <height>18</height> </rect> </property> </widget> @@ -245,6 +116,18 @@ </action> </widget> <layoutdefault spacing="6" margin="11"/> + <customwidgets> + <customwidget> + <class>GraphicsView</class> + <extends>QGraphicsView</extends> + <header>Graphics/GraphicsView.hpp</header> + </customwidget> + <customwidget> + <class>AlgorithmList</class> + <extends>QTreeView</extends> + <header>Graphics/AlgorithmList.hpp</header> + </customwidget> + </customwidgets> <resources/> <connections/> </ui>