From 7f58b5957488a2a03c8bc228aec852e23ba0415e Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Fri, 16 Jun 2023 11:08:45 +0200 Subject: [PATCH 01/52] initial commit From 6c74c7e3c0cfdb222b204f0417e757024958b243 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Fri, 16 Jun 2023 22:40:05 +0200 Subject: [PATCH 02/52] Added isolateInNewView function --- plugins/gui/include/gui/gui_api/gui_api.h | 2 + .../gui/include/gui/main_window/main_window.h | 9 +-- plugins/gui/src/gui_api/gui_api.cpp | 67 +++++++++++++++++++ plugins/gui/src/main_window/main_window.cpp | 42 +++++++++--- 4 files changed, 108 insertions(+), 12 deletions(-) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 4b89f34c074..7e375ebc6e6 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -531,6 +531,8 @@ namespace hal */ void deselect(const std::vector& gates, const std::vector& nets, const std::vector& modules); + int isolateInNewView(const std::vector, const std::vector); + Q_SIGNALS: /** * Q_SIGNAL that is emitted whenever the view should be moved to a new selection. diff --git a/plugins/gui/include/gui/main_window/main_window.h b/plugins/gui/include/gui/main_window/main_window.h index d2d28d7c3ba..7402db9bd76 100644 --- a/plugins/gui/include/gui/main_window/main_window.h +++ b/plugins/gui/include/gui/main_window/main_window.h @@ -25,13 +25,12 @@ #pragma once -#include "hal_core/utilities/program_options.h" - -#include "gui/content_layout_area/content_layout_area.h" -#include "hal_core/utilities/program_options.h" #include "gui/action/action.h" +#include "gui/content_layout_area/content_layout_area.h" #include "gui/settings/main_settings_widget.h" #include "gui/splitter/splitter.h" +#include "hal_core/netlist/module.h" +#include "hal_core/utilities/program_options.h" #include #include @@ -566,6 +565,8 @@ namespace hal void handleImportProjectTriggered(); + int isolateInNewView(const std::vector, const std::vector); + private: /** * Overwritten Qt function to handle the close event. diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index ef6528e7dcb..102bf145535 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -1,6 +1,10 @@ #include "gui/gui_api/gui_api.h" #include "gui/gui_globals.h" +#include "gui/user_action/user_action_compound.h" +#include "gui/user_action/user_action_object.h" +#include "gui/user_action/action_create_object.h" +#include "gui/user_action/action_add_items_to_object.h" #include @@ -428,4 +432,67 @@ namespace hal { gSelectionRelay->clearAndUpdate(); } + + int GuiApi::isolateInNewView(std::vector modules, std::vector gates) + { + static QSet usedIds; + QString name; + //TODO: make sure that modules and gates are not empty + if(modules.empty() && gates.empty()) + return 0; + + //Check if view should be bound exclusively to module + if(modules.size() == 1 && gates.empty()){ + name = QString::fromStdString(modules[0]->get_name()) + QString(" (ID: %1)").arg(modules[0]->get_id()); + + //If the view already exists then return 0 + if(gGraphContextManager->contextWithNameExists(name)){ + return 0; + } + } + else + { + //Get the number which has to be appended to name + + u32 id = 1; + name = QString("Isolated View %1").arg(id); + + /* TODO free id "i" if context "i" is deleted and use this which is probably faster instead of the Placeholder code + while(usedIds.contains(id)){ + id++; + } + + usedIds.insert(id); + QString name = QString("Isolated View %1").arg(id); + */ + + //TODO: Placeholder code + while (gGraphContextManager->contextWithNameExists(name)) + { + id++; + name = QString("Isolated View %1").arg(id); + } + usedIds.insert(id); + } + + + // Get ids from modules and gates + QSet moduleIds; + QSet gateIds; + + for(Module* module : modules) + moduleIds.insert(module->get_id()); + for(Gate* gate : gates) + gateIds.insert(gate->get_id()); + + + UserActionCompound* act = new UserActionCompound; + act->setUseCreatedObject(); + act->addAction(new ActionCreateObject(UserActionObjectType::Context, name)); + act->addAction(new ActionAddItemsToObject(moduleIds, gateIds)); + act->exec(); + + //TODO: return actual context id + return 0; + } } diff --git a/plugins/gui/src/main_window/main_window.cpp b/plugins/gui/src/main_window/main_window.cpp index de4a1f202cd..6a9a5addd0d 100644 --- a/plugins/gui/src/main_window/main_window.cpp +++ b/plugins/gui/src/main_window/main_window.cpp @@ -3,8 +3,8 @@ #include "gui/action/action.h" #include "gui/content_manager/content_manager.h" #include "gui/docking_system/dock_bar.h" -#include "gui/export/export_registered_format.h" #include "gui/export/export_project_dialog.h" +#include "gui/export/export_registered_format.h" #include "gui/export/import_project_dialog.h" #include "gui/file_manager/file_manager.h" #include "gui/file_manager/project_dir_dialog.h" @@ -24,33 +24,34 @@ #include "gui/user_action/action_open_netlist_file.h" #include "gui/welcome_screen/welcome_screen.h" #include "hal_core/defines.h" +#include "hal_core/netlist/event_system/event_log.h" #include "hal_core/netlist/gate.h" #include "hal_core/netlist/gate_library/gate_library_manager.h" +#include "hal_core/netlist/grouping.h" #include "hal_core/netlist/net.h" #include "hal_core/netlist/netlist.h" #include "hal_core/netlist/netlist_factory.h" #include "hal_core/netlist/netlist_writer/netlist_writer_manager.h" #include "hal_core/netlist/persistent/netlist_serializer.h" -#include "hal_core/utilities/log.h" -#include "hal_core/netlist/event_system/event_log.h" #include "hal_core/netlist/project_manager.h" -#include "hal_core/utilities/project_directory.h" -#include "hal_core/plugin_system/plugin_manager.h" #include "hal_core/plugin_system/gui_extension_interface.h" +#include "hal_core/plugin_system/plugin_manager.h" +#include "hal_core/utilities/log.h" +#include "hal_core/utilities/project_directory.h" #include #include #include +#include #include #include #include #include #include -#include -#include #include +#include #include -#include +#include namespace hal { @@ -264,6 +265,11 @@ namespace hal mMenuHelp->addAction(mActionAbout); mMenuHelp->addSeparator(); mMenuHelp->addAction(mActionPlugins); + mMenuHelp->addAction("Test developed function", [this] () { + std::vector modules; + std::vector gates; + isolateInNewView(modules, gates); + }); mLeftToolBar->addAction(mActionNew); mLeftToolBar->addAction(mActionOpenProject); mLeftToolBar->addAction(mActionSave); @@ -1070,4 +1076,24 @@ namespace hal { SettingsManager::instance()->mainWindowSaveGeometry(pos(), size()); } + + int MainWindow::isolateInNewView(std::vector modules, std::vector gates) + { + + modules.push_back(gNetlist->get_module_by_id(4)); + /*modules.push_back(gNetlist->get_module_by_id(2)); + modules.push_back(gNetlist->get_module_by_id(1)); + + gates.push_back(gNetlist->get_gate_by_id(10)); + gates.push_back(gNetlist->get_gate_by_id(2)); + gates.push_back(gNetlist->get_gate_by_id(1));*/ + + + qInfo() << "Test action isolateInNewView was called"; + //Create a new view which contains the given Modules and Gates + + return GuiApi().isolateInNewView(modules, gates); + + + } } // namespace hal From aa2ad2f947e687f159b7b0c2dde052c40dec8778 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Sun, 18 Jun 2023 20:06:28 +0200 Subject: [PATCH 03/52] Added pybind for GuiApi().isolateNewView --- plugins/gui/src/main_window/main_window.cpp | 5 +++-- plugins/gui/src/python/python_gui_api_bindings.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/gui/src/main_window/main_window.cpp b/plugins/gui/src/main_window/main_window.cpp index 6a9a5addd0d..122492ad992 100644 --- a/plugins/gui/src/main_window/main_window.cpp +++ b/plugins/gui/src/main_window/main_window.cpp @@ -1080,13 +1080,14 @@ namespace hal int MainWindow::isolateInNewView(std::vector modules, std::vector gates) { + //Creating modules for testing purposes modules.push_back(gNetlist->get_module_by_id(4)); - /*modules.push_back(gNetlist->get_module_by_id(2)); + modules.push_back(gNetlist->get_module_by_id(2)); modules.push_back(gNetlist->get_module_by_id(1)); gates.push_back(gNetlist->get_gate_by_id(10)); gates.push_back(gNetlist->get_gate_by_id(2)); - gates.push_back(gNetlist->get_gate_by_id(1));*/ + gates.push_back(gNetlist->get_gate_by_id(1)); qInfo() << "Test action isolateInNewView was called"; diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index e65dd5fe924..7caae7cf590 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -466,6 +466,12 @@ PYBIND11_PLUGIN(hal_gui) Deselect all gates, nets and modules in the graph view of the GUI. )"); + py_gui_api.def("isolateNewView",py::overload_cast, const std::vector>(&GuiApi::isolateInNewView), py::arg("modules"), py::arg("gates"),R"( + Creates a new Isolated View from the given modules and gates. + :param list[hal_py.module] modules: The modules to be shown. + :param list[hal_py.Gate] gates: The gates to be shown. +)"); + #ifndef PYBIND11_MODULE return m.ptr(); #endif // PYBIND11_MODULE From a3b861614e264181e72519d73df45cc95ce789f8 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Sun, 18 Jun 2023 22:52:51 +0200 Subject: [PATCH 04/52] Added inner class View to GuiApi with static method isolateInNewView Added pybind for GuiApi::View::isolateInNewView --- plugins/gui/include/gui/gui_api/gui_api.h | 5 ++ plugins/gui/src/gui_api/gui_api.cpp | 67 +++++++++++++++++++ plugins/gui/src/main_window/main_window.cpp | 3 +- .../src/python/python_gui_api_bindings.cpp | 3 + 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 7e375ebc6e6..4a2d4058d66 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -533,6 +533,11 @@ namespace hal int isolateInNewView(const std::vector, const std::vector); + class View{ + public: + static int isolateInNewView(const std::vector, const std::vector); + }; + Q_SIGNALS: /** * Q_SIGNAL that is emitted whenever the view should be moved to a new selection. diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 102bf145535..646e39454ce 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -433,6 +433,9 @@ namespace hal gSelectionRelay->clearAndUpdate(); } + + //TODO check View class and pybindings + //function called from GuiApi class int GuiApi::isolateInNewView(std::vector modules, std::vector gates) { static QSet usedIds; @@ -476,6 +479,70 @@ namespace hal } + // Get ids from modules and gates + QSet moduleIds; + QSet gateIds; + + for(Module* module : modules) + moduleIds.insert(module->get_id()); + for(Gate* gate : gates) + gateIds.insert(gate->get_id()); + + + UserActionCompound* act = new UserActionCompound; + act->setUseCreatedObject(); + act->addAction(new ActionCreateObject(UserActionObjectType::Context, name)); + act->addAction(new ActionAddItemsToObject(moduleIds, gateIds)); + act->exec(); + + //TODO: return actual context id + return 0; + } + + //function called from inner class View of GuiApi class + int GuiApi::View::isolateInNewView(std::vector modules, std::vector gates) + { + static QSet usedIds; + QString name; + //TODO: make sure that modules and gates are not empty + if(modules.empty() && gates.empty()) + return 0; + + //Check if view should be bound exclusively to module + if(modules.size() == 1 && gates.empty()){ + name = QString::fromStdString(modules[0]->get_name()) + QString(" (ID: %1)").arg(modules[0]->get_id()); + + //If the view already exists then return 0 + if(gGraphContextManager->contextWithNameExists(name)){ + return 0; + } + } + else + { + //Get the number which has to be appended to name + + u32 id = 1; + name = QString("Isolated View %1").arg(id); + + /* TODO free id "i" if context "i" is deleted and use this which is probably faster instead of the Placeholder code + while(usedIds.contains(id)){ + id++; + } + + usedIds.insert(id); + QString name = QString("Isolated View %1").arg(id); + */ + + //TODO: Placeholder code + while (gGraphContextManager->contextWithNameExists(name)) + { + id++; + name = QString("Isolated View %1").arg(id); + } + usedIds.insert(id); + } + + // Get ids from modules and gates QSet moduleIds; QSet gateIds; diff --git a/plugins/gui/src/main_window/main_window.cpp b/plugins/gui/src/main_window/main_window.cpp index 122492ad992..5ed927e1233 100644 --- a/plugins/gui/src/main_window/main_window.cpp +++ b/plugins/gui/src/main_window/main_window.cpp @@ -1093,7 +1093,8 @@ namespace hal qInfo() << "Test action isolateInNewView was called"; //Create a new view which contains the given Modules and Gates - return GuiApi().isolateInNewView(modules, gates); + //return GuiApi().isolateInNewView(modules, gates); + return GuiApi::View::isolateInNewView(modules, gates); } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 7caae7cf590..34986690571 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -78,6 +78,9 @@ PYBIND11_PLUGIN(hal_gui) py::class_ py_gui_api(m, "GuiApi", R"(GUI API)"); + py::class_(py_gui_api, "View") + .def_static("isolateInNewView", &GuiApi::View::isolateInNewView, py::arg("modules"), py::arg("gates")); + py_gui_api.def("getSelectedGateIds", &GuiApi::getSelectedGateIds, R"( Get the gate ids of currently selected gates in the graph view of the GUI. From 9084e9b8bb65c4c286e55b007cbaf2619a6be67f Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 20 Jun 2023 13:53:49 +0200 Subject: [PATCH 05/52] 1.Interface GuiApiClasses::View expanded 2.Get ID of newly create view 3.Method to generate unique view name --- .../gui/graph_widget/graph_context_manager.h | 7 ++ plugins/gui/include/gui/gui_api/gui_api.h | 23 +++-- .../graph_widget/graph_context_manager.cpp | 11 +++ .../src/graph_widget/graph_graphics_view.cpp | 27 ++---- plugins/gui/src/gui_api/gui_api.cpp | 83 ++++++++++--------- plugins/gui/src/main_window/main_window.cpp | 2 +- .../src/python/python_gui_api_bindings.cpp | 4 +- .../tree_navigation/selection_tree_view.cpp | 9 +- 8 files changed, 91 insertions(+), 75 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/graph_context_manager.h b/plugins/gui/include/gui/graph_widget/graph_context_manager.h index 55634c4aedb..a0e84ba974a 100644 --- a/plugins/gui/include/gui/graph_widget/graph_context_manager.h +++ b/plugins/gui/include/gui/graph_widget/graph_context_manager.h @@ -115,6 +115,13 @@ namespace hal */ bool contextWithNameExists(const QString& name) const; + /** + * Generate next view with given prefix + * @param prefix + * @return the view name which does not exist so far + */ + QString nextViewName(const QString& prefix) const; + /** * Handler to be called after a module has been created. Used to apply the changes in the affected contexts.
* diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 4a2d4058d66..4f33b04aebf 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -37,6 +37,22 @@ namespace hal { + namespace GuiApiClasses { + + class View{ + public: + static int isolateInNew(const std::vector, const std::vector); + static bool addTo(int id, const std::vector, const std::vector); + static bool removeFrom(int id, const std::vector, const std::vector); + static bool setName(int id, const std::string& name); + static int getId(const std::string& name); + static std::string getName(int id); + static std::vector getModules(int id); + static std::vector getGates(int id); + }; + } + + /** * @ingroup gui * @brief Interface to interact with the gui itself. @@ -533,15 +549,10 @@ namespace hal int isolateInNewView(const std::vector, const std::vector); - class View{ - public: - static int isolateInNewView(const std::vector, const std::vector); - }; - Q_SIGNALS: /** * Q_SIGNAL that is emitted whenever the view should be moved to a new selection. */ void navigationRequested(); - }; + }; } diff --git a/plugins/gui/src/graph_widget/graph_context_manager.cpp b/plugins/gui/src/graph_widget/graph_context_manager.cpp index e050e5b9452..399759a76ce 100644 --- a/plugins/gui/src/graph_widget/graph_context_manager.cpp +++ b/plugins/gui/src/graph_widget/graph_context_manager.cpp @@ -127,6 +127,17 @@ namespace hal return nullptr; } + QString GraphContextManager::nextViewName(const QString& prefix) const + { + int cnt = 0; + + for (;;) + { + QString name = QString("%1 %2").arg(prefix).arg(++cnt); + if (!contextWithNameExists(name)) return name; + } + } + bool GraphContextManager::contextWithNameExists(const QString& name) const { for (GraphContext* ctx : mContextTableModel->list()) diff --git a/plugins/gui/src/graph_widget/graph_graphics_view.cpp b/plugins/gui/src/graph_widget/graph_graphics_view.cpp index 198ba9de57f..108d4b2799b 100644 --- a/plugins/gui/src/graph_widget/graph_graphics_view.cpp +++ b/plugins/gui/src/graph_widget/graph_graphics_view.cpp @@ -154,25 +154,14 @@ namespace hal return; } - u32 cnt = 0; - while (true) - { - ++cnt; - QString name = "Isolated View " + QString::number(cnt); - - if (!gGraphContextManager->contextWithNameExists(name)) - { - UserActionCompound* act = new UserActionCompound; - act->setUseCreatedObject(); - act->addAction(new ActionCreateObject(UserActionObjectType::Context, name)); - act->addAction(new ActionAddItemsToObject(selected_modules, selected_gates)); - act->exec(); - GraphContext* context = gGraphContextManager->getContextById(act->object().id()); - context->setDirty(false); - - return; - } - } + QString name = gGraphContextManager->nextViewName("Isolated View"); + UserActionCompound* act = new UserActionCompound; + act->setUseCreatedObject(); + act->addAction(new ActionCreateObject(UserActionObjectType::Context, name)); + act->addAction(new ActionAddItemsToObject(selected_modules, selected_gates)); + act->exec(); + GraphContext* context = gGraphContextManager->getContextById(act->object().id()); + context->setDirty(false); } void GraphGraphicsView::handleMoveAction(u32 moduleId) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 646e39454ce..2e0ec33db7e 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -438,7 +438,6 @@ namespace hal //function called from GuiApi class int GuiApi::isolateInNewView(std::vector modules, std::vector gates) { - static QSet usedIds; QString name; //TODO: make sure that modules and gates are not empty if(modules.empty() && gates.empty()) @@ -457,25 +456,9 @@ namespace hal { //Get the number which has to be appended to name - u32 id = 1; - name = QString("Isolated View %1").arg(id); + name = gGraphContextManager->nextViewName("Isolated View"); - /* TODO free id "i" if context "i" is deleted and use this which is probably faster instead of the Placeholder code - while(usedIds.contains(id)){ - id++; - } - - usedIds.insert(id); - QString name = QString("Isolated View %1").arg(id); - */ - - //TODO: Placeholder code - while (gGraphContextManager->contextWithNameExists(name)) - { - id++; - name = QString("Isolated View %1").arg(id); - } - usedIds.insert(id); + //TODO: Placeholder code } @@ -495,14 +478,15 @@ namespace hal act->addAction(new ActionAddItemsToObject(moduleIds, gateIds)); act->exec(); + u32 contextId = act->object().id(); + //TODO: return actual context id return 0; } - //function called from inner class View of GuiApi class - int GuiApi::View::isolateInNewView(std::vector modules, std::vector gates) + //function called from class View of GuiApiClasses class + int GuiApiClasses::View::isolateInNew(std::vector modules, std::vector gates) { - static QSet usedIds; QString name; //TODO: make sure that modules and gates are not empty if(modules.empty() && gates.empty()) @@ -521,25 +505,9 @@ namespace hal { //Get the number which has to be appended to name - u32 id = 1; - name = QString("Isolated View %1").arg(id); - - /* TODO free id "i" if context "i" is deleted and use this which is probably faster instead of the Placeholder code - while(usedIds.contains(id)){ - id++; - } - - usedIds.insert(id); - QString name = QString("Isolated View %1").arg(id); - */ + name = gGraphContextManager->nextViewName("Isolated View"); //TODO: Placeholder code - while (gGraphContextManager->contextWithNameExists(name)) - { - id++; - name = QString("Isolated View %1").arg(id); - } - usedIds.insert(id); } @@ -562,4 +530,41 @@ namespace hal //TODO: return actual context id return 0; } + + + bool GuiApiClasses::View::addTo(int id, const std::vector, const std::vector) + { + return false; // TODO : implement + } + + bool removeFrom(int id, const std::vector, const std::vector) + { + return false; // TODO : implement + } + + bool GuiApiClasses::View::setName(int id, const std::string& name) + { + return false; // TODO : implement + } + + int GuiApiClasses::View::getId(const std::string& name) + { + return 0; // TODO : implement + } + + std::string GuiApiClasses::View::getName(int id) + { + return std::string(); // TODO : implement + } + + std::vector GuiApiClasses::View::getModules(int id) + { + return std::vector(); // TODO : implement + } + + std::vector GuiApiClasses::View::getGates(int id) + { + return std::vector(); // TODO : implement + } + } diff --git a/plugins/gui/src/main_window/main_window.cpp b/plugins/gui/src/main_window/main_window.cpp index 5ed927e1233..3fc656859b2 100644 --- a/plugins/gui/src/main_window/main_window.cpp +++ b/plugins/gui/src/main_window/main_window.cpp @@ -1094,7 +1094,7 @@ namespace hal //Create a new view which contains the given Modules and Gates //return GuiApi().isolateInNewView(modules, gates); - return GuiApi::View::isolateInNewView(modules, gates); + return GuiApiClasses::View::isolateInNew(modules, gates); } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 34986690571..4a511004bd2 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -78,8 +78,8 @@ PYBIND11_PLUGIN(hal_gui) py::class_ py_gui_api(m, "GuiApi", R"(GUI API)"); - py::class_(py_gui_api, "View") - .def_static("isolateInNewView", &GuiApi::View::isolateInNewView, py::arg("modules"), py::arg("gates")); + py::class_(py_gui_api, "View") + .def_static("isolateInNewView", &GuiApiClasses::View::isolateInNew, py::arg("modules"), py::arg("gates")); py_gui_api.def("getSelectedGateIds", &GuiApi::getSelectedGateIds, R"( Get the gate ids of currently selected gates in the graph view of the GUI. diff --git a/plugins/gui/src/selection_details_widget/tree_navigation/selection_tree_view.cpp b/plugins/gui/src/selection_details_widget/tree_navigation/selection_tree_view.cpp index 247628ee4ad..2772c6be51b 100644 --- a/plugins/gui/src/selection_details_widget/tree_navigation/selection_tree_view.cpp +++ b/plugins/gui/src/selection_details_widget/tree_navigation/selection_tree_view.cpp @@ -148,14 +148,7 @@ namespace hal if (nd.type() == Node::Gate) { - u32 cnt = 0; - for (;;) - { - ++cnt; - name = "Isolated View " + QString::number(cnt); - if (!gGraphContextManager->contextWithNameExists(name)) - break; - } + name = gGraphContextManager->nextViewName("Isolated View"); gateId.insert(nd.id()); } else if (nd.type() == Node::Module) From 36652fdc2e31aa507d37225085f211d4be2fe6a2 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Thu, 22 Jun 2023 19:12:01 +0200 Subject: [PATCH 06/52] Changed implemented TODOS from View::isolateInNew Added implementation of View::setName and added corresponding pybind --- plugins/gui/src/gui_api/gui_api.cpp | 83 ++++++------------- .../src/python/python_gui_api_bindings.cpp | 10 +-- 2 files changed, 28 insertions(+), 65 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 2e0ec33db7e..6778e11fc6e 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -1,10 +1,13 @@ #include "gui/gui_api/gui_api.h" + #include "gui/gui_globals.h" #include "gui/user_action/user_action_compound.h" #include "gui/user_action/user_action_object.h" #include "gui/user_action/action_create_object.h" #include "gui/user_action/action_add_items_to_object.h" +#include "gui/graph_widget/graph_context_manager.h" +#include "gui/context_manager_widget/models/context_table_model.h" #include @@ -434,61 +437,10 @@ namespace hal } - //TODO check View class and pybindings - //function called from GuiApi class - int GuiApi::isolateInNewView(std::vector modules, std::vector gates) - { - QString name; - //TODO: make sure that modules and gates are not empty - if(modules.empty() && gates.empty()) - return 0; - - //Check if view should be bound exclusively to module - if(modules.size() == 1 && gates.empty()){ - name = QString::fromStdString(modules[0]->get_name()) + QString(" (ID: %1)").arg(modules[0]->get_id()); - - //If the view already exists then return 0 - if(gGraphContextManager->contextWithNameExists(name)){ - return 0; - } - } - else - { - //Get the number which has to be appended to name - - name = gGraphContextManager->nextViewName("Isolated View"); - - //TODO: Placeholder code - } - - - // Get ids from modules and gates - QSet moduleIds; - QSet gateIds; - - for(Module* module : modules) - moduleIds.insert(module->get_id()); - for(Gate* gate : gates) - gateIds.insert(gate->get_id()); - - - UserActionCompound* act = new UserActionCompound; - act->setUseCreatedObject(); - act->addAction(new ActionCreateObject(UserActionObjectType::Context, name)); - act->addAction(new ActionAddItemsToObject(moduleIds, gateIds)); - act->exec(); - - u32 contextId = act->object().id(); - - //TODO: return actual context id - return 0; - } - - //function called from class View of GuiApiClasses class int GuiApiClasses::View::isolateInNew(std::vector modules, std::vector gates) { QString name; - //TODO: make sure that modules and gates are not empty + //make sure that modules and gates are not empty if(modules.empty() && gates.empty()) return 0; @@ -496,18 +448,20 @@ namespace hal if(modules.size() == 1 && gates.empty()){ name = QString::fromStdString(modules[0]->get_name()) + QString(" (ID: %1)").arg(modules[0]->get_id()); - //If the view already exists then return 0 + //If the view already exists then return existing id if(gGraphContextManager->contextWithNameExists(name)){ + for(GraphContext* ctx : gGraphContextManager->getContexts()){ + if(ctx->name() == name){ + return ctx->id(); + } + } return 0; } } else { //Get the number which has to be appended to name - name = gGraphContextManager->nextViewName("Isolated View"); - - //TODO: Placeholder code } @@ -527,12 +481,12 @@ namespace hal act->addAction(new ActionAddItemsToObject(moduleIds, gateIds)); act->exec(); - //TODO: return actual context id - return 0; + + return act->object().id(); } - bool GuiApiClasses::View::addTo(int id, const std::vector, const std::vector) + bool GuiApiClasses::View::addTo(int id, const std::vector modules, const std::vector gates) { return false; // TODO : implement } @@ -544,6 +498,17 @@ namespace hal bool GuiApiClasses::View::setName(int id, const std::string& name) { + //check if name is occupied + if(gGraphContextManager->contextWithNameExists(QString::fromStdString(name))) + return false; + + //get context matching id and rename it + for(GraphContext* ctx : gGraphContextManager->getContexts()){ + if(ctx->id() == id){ + gGraphContextManager->renameGraphContextAction(ctx, QString::fromStdString(name)); + return true; + } + } return false; // TODO : implement } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 4a511004bd2..a8cf53c4e85 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -79,7 +79,9 @@ PYBIND11_PLUGIN(hal_gui) py::class_ py_gui_api(m, "GuiApi", R"(GUI API)"); py::class_(py_gui_api, "View") - .def_static("isolateInNewView", &GuiApiClasses::View::isolateInNew, py::arg("modules"), py::arg("gates")); + .def_static("isolateInNew", &GuiApiClasses::View::isolateInNew, py::arg("modules"), py::arg("gates")) + .def_static("setName", &GuiApiClasses::View::setName, py::arg("id"), py::arg("name")) + .def_static("addTo", &GuiApiClasses::View::addTo, py::arg("id"), py::arg("modules"), py::arg("gates")); py_gui_api.def("getSelectedGateIds", &GuiApi::getSelectedGateIds, R"( Get the gate ids of currently selected gates in the graph view of the GUI. @@ -469,11 +471,7 @@ PYBIND11_PLUGIN(hal_gui) Deselect all gates, nets and modules in the graph view of the GUI. )"); - py_gui_api.def("isolateNewView",py::overload_cast, const std::vector>(&GuiApi::isolateInNewView), py::arg("modules"), py::arg("gates"),R"( - Creates a new Isolated View from the given modules and gates. - :param list[hal_py.module] modules: The modules to be shown. - :param list[hal_py.Gate] gates: The gates to be shown. -)"); + #ifndef PYBIND11_MODULE return m.ptr(); From c57fefdd1d1ccce77f3a2c31ed62d8573756df9b Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Sat, 24 Jun 2023 12:21:18 +0200 Subject: [PATCH 07/52] Added implementation of View methods and added corresponding pybinds --- plugins/gui/src/gui_api/gui_api.cpp | 80 +++++++++++++++++-- .../src/python/python_gui_api_bindings.cpp | 65 ++++++++++++++- 2 files changed, 134 insertions(+), 11 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 6778e11fc6e..78b440ec70d 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -488,12 +488,46 @@ namespace hal bool GuiApiClasses::View::addTo(int id, const std::vector modules, const std::vector gates) { - return false; // TODO : implement + //TODO check why ctx->remove does clear the whole view and only apply after a restart + // Get ids from modules and gates + QSet moduleIds; + QSet gateIds; + + for(Module* module : modules) + moduleIds.insert(module->get_id()); + for(Gate* gate : gates) + gateIds.insert(gate->get_id()); + + GraphContext* ctx = gGraphContextManager->getContextById(id); + if(ctx != nullptr){ + //ctx->beginChange(); + ctx->add(moduleIds, gateIds); + //ctx->endChange(); + return true; + } + return false; } - bool removeFrom(int id, const std::vector, const std::vector) + bool GuiApiClasses::View::removeFrom(int id, const std::vector modules, const std::vector gates) { - return false; // TODO : implement + //TODO check why ctx->remove does clear the whole view and only apply after a restart + // Get ids from modules and gates + QSet moduleIds; + QSet gateIds; + + for(Module* module : modules) + moduleIds.insert(module->get_id()); + for(Gate* gate : gates) + gateIds.insert(gate->get_id()); + + GraphContext* ctx = gGraphContextManager->getContextById(id); + if(ctx != nullptr){ + //ctx->beginChange(); + ctx->remove(moduleIds, gateIds); + //ctx->endChange(); + return true; + } + return false; } bool GuiApiClasses::View::setName(int id, const std::string& name) @@ -502,6 +536,10 @@ namespace hal if(gGraphContextManager->contextWithNameExists(QString::fromStdString(name))) return false; + //check if view is exclusively bound to module + if(gGraphContextManager->getContextById(id)->isShowingModuleExclusively()) + return false; + //get context matching id and rename it for(GraphContext* ctx : gGraphContextManager->getContexts()){ if(ctx->id() == id){ @@ -509,27 +547,53 @@ namespace hal return true; } } - return false; // TODO : implement + return false; } int GuiApiClasses::View::getId(const std::string& name) { - return 0; // TODO : implement + //find View related to the name + for(GraphContext* ctx : gGraphContextManager->getContexts()){ + if(ctx->name() == QString::fromStdString(name)){ + return ctx->id(); + } + } + return 0; } std::string GuiApiClasses::View::getName(int id) { - return std::string(); // TODO : implement + GraphContext* ctx = gGraphContextManager->getContextById(id); + if(ctx != nullptr){ + return ctx->name().toStdString(); + } + return std::string(); // } std::vector GuiApiClasses::View::getModules(int id) { - return std::vector(); // TODO : implement + GraphContext* ctx = gGraphContextManager->getContextById(id); + if(ctx != nullptr){ + std::vector modules; + for(u32 id : ctx->modules()){ + modules.push_back(gNetlist->get_module_by_id(id)); + } + return modules; + } + return std::vector(); } std::vector GuiApiClasses::View::getGates(int id) { - return std::vector(); // TODO : implement + GraphContext* ctx = gGraphContextManager->getContextById(id); + if(ctx != nullptr){ + std::vector gates; + for(u32 id : ctx->gates()){ + gates.push_back(gNetlist->get_gate_by_id(id)); + } + return gates; + } + return std::vector(); } } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index a8cf53c4e85..dedf40c7a59 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -79,9 +79,68 @@ PYBIND11_PLUGIN(hal_gui) py::class_ py_gui_api(m, "GuiApi", R"(GUI API)"); py::class_(py_gui_api, "View") - .def_static("isolateInNew", &GuiApiClasses::View::isolateInNew, py::arg("modules"), py::arg("gates")) - .def_static("setName", &GuiApiClasses::View::setName, py::arg("id"), py::arg("name")) - .def_static("addTo", &GuiApiClasses::View::addTo, py::arg("id"), py::arg("modules"), py::arg("gates")); + .def_static("isolateInNew", &GuiApiClasses::View::isolateInNew, py::arg("modules"), py::arg("gates"),R"( + Isolates given modules and gates into a new view + + :param list[hal_py.module] modules: List of modules to be added. + :param list[hal_py.Gate] gates: List of gates to be added. + :returns: ID of created view or the existing one if view is exclusively bound to a module. + :rtype: int +)") + .def_static("renameView", &GuiApiClasses::View::setName, py::arg("id"), py::arg("name"),R"( + Renames the view specified by the given ID. + + :param int id: ID of the view. + :param string name: New unique name. + :returns: True on success otherwise False. + :rtype: bool +)") + .def_static("addTo", &GuiApiClasses::View::addTo, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( + Adds the given modules and gates to the view specified by the ID. + + :param list[hal.py.module] modules: Modules to be added. + :param list[hal.py.Gate] gates: Gates to be added. + :returns: True on success, otherwise False. + :rtype: bool +)") + .def_static("removeFrom", &GuiApiClasses::View::removeFrom, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( + Removes the given modules and gates from the view specified by the ID. + + :param list[hal.py.module] modules: Modules to be removed. + :param list[hal.py.Gate] gates: Gates to be removed. + :returns: True on success, otherwise False. + :rtype: bool +)") + .def_static("getId", &GuiApiClasses::View::getId, py::arg("name"),R"( + Returns the ID of the view with the given name if existing. + + :param string name: Name of the view + :returns: ID of the specified view or 0 if none is found + :rtype: int +)") + .def_static("getName", &GuiApiClasses::View::getName, py::arg("id"), R"( + Returns the name of the view with the given ID if existing. + + :param int id: ID of the view. + :returns: Name of the view specified by the ID or empty string if none is found. + :rtype: string +)") + .def_static("getModules", &GuiApiClasses::View::getModules, py::arg("id"), R"( + Returns all modules attached to the view + + :param int id: ID of the view. + :returns: List of the attached modules + :rtype: list[hal.py.module] +)") + .def_static("getGates", &GuiApiClasses::View::getGates, py::arg("id"),R"( + Returns all gates attached to the view + + :param int id: ID of the view. + :returns: List of the attached gates + :rtype: list[hal.py.Gate] +)"); + + py_gui_api.def("getSelectedGateIds", &GuiApi::getSelectedGateIds, R"( Get the gate ids of currently selected gates in the graph view of the GUI. From e617f8c8b4ea97a1d1594cba7ebe66ad332bb4a1 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Wed, 28 Jun 2023 10:45:05 +0200 Subject: [PATCH 08/52] added deleteView Python binding and minor changes --- plugins/gui/include/gui/gui_api/gui_api.h | 1 + plugins/gui/src/gui_api/gui_api.cpp | 30 +++++++++++++++++-- .../src/python/python_gui_api_bindings.cpp | 10 ++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 4f33b04aebf..11e0a92c86f 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -42,6 +42,7 @@ namespace hal class View{ public: static int isolateInNew(const std::vector, const std::vector); + static bool deleteView(int id); static bool addTo(int id, const std::vector, const std::vector); static bool removeFrom(int id, const std::vector, const std::vector); static bool setName(int id, const std::string& name); diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 78b440ec70d..abdb9a3c81f 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -5,6 +5,7 @@ #include "gui/user_action/user_action_compound.h" #include "gui/user_action/user_action_object.h" #include "gui/user_action/action_create_object.h" +#include "gui/user_action/action_delete_object.h" #include "gui/user_action/action_add_items_to_object.h" #include "gui/graph_widget/graph_context_manager.h" #include "gui/context_manager_widget/models/context_table_model.h" @@ -444,10 +445,12 @@ namespace hal if(modules.empty() && gates.empty()) return 0; + bool isModuleExclusive = false; + //Check if view should be bound exclusively to module if(modules.size() == 1 && gates.empty()){ name = QString::fromStdString(modules[0]->get_name()) + QString(" (ID: %1)").arg(modules[0]->get_id()); - + isModuleExclusive = true; //If the view already exists then return existing id if(gGraphContextManager->contextWithNameExists(name)){ for(GraphContext* ctx : gGraphContextManager->getContexts()){ @@ -481,14 +484,37 @@ namespace hal act->addAction(new ActionAddItemsToObject(moduleIds, gateIds)); act->exec(); + if (isModuleExclusive){ + GraphContext* context = gGraphContextManager->getContextById(act->object().id()); + context->setDirty(false); + context->setExclusiveModuleId(modules[0]->get_id()); + } + return act->object().id(); } + bool GuiApiClasses::View::deleteView(int id) + { + if(gGraphContextManager->getContextById(id)->empty()) + { + return false; + } + ActionDeleteObject* del = new ActionDeleteObject(); + del->setObject(UserActionObject(id, UserActionObjectType::Context)); + + UserActionCompound* act = new UserActionCompound; + act->setUseCreatedObject(); + act->addAction(del); + act->addAction(new ActionDeleteObject); + act->exec(); + return true; + } + bool GuiApiClasses::View::addTo(int id, const std::vector modules, const std::vector gates) { - //TODO check why ctx->remove does clear the whole view and only apply after a restart + //TODO check why ctx->add does clear the whole view and only apply after a restart // Get ids from modules and gates QSet moduleIds; QSet gateIds; diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index dedf40c7a59..8fff0672672 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -87,7 +87,7 @@ PYBIND11_PLUGIN(hal_gui) :returns: ID of created view or the existing one if view is exclusively bound to a module. :rtype: int )") - .def_static("renameView", &GuiApiClasses::View::setName, py::arg("id"), py::arg("name"),R"( + .def_static("rename", &GuiApiClasses::View::setName, py::arg("id"), py::arg("name"),R"( Renames the view specified by the given ID. :param int id: ID of the view. @@ -103,6 +103,14 @@ PYBIND11_PLUGIN(hal_gui) :returns: True on success, otherwise False. :rtype: bool )") + .def_static("deleteView", &GuiApiClasses::View::deleteView, py::arg("id"),R"( + Adds the given modules and gates to the view specified by the ID. + + :param list[hal.py.module] modules: Modules to be added. + :param list[hal.py.Gate] gates: Gates to be added. + :returns: True on success, otherwise False. + :rtype: bool + )") .def_static("removeFrom", &GuiApiClasses::View::removeFrom, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( Removes the given modules and gates from the view specified by the ID. From d13ea98bf9a6dbf96942de84ecf001ffe8957127 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Sun, 2 Jul 2023 18:43:51 +0200 Subject: [PATCH 09/52] Added View.getIds() and corresponding pybind --- plugins/gui/include/gui/gui_api/gui_api.h | 1 + plugins/gui/src/gui_api/gui_api.cpp | 44 +++++++++++++++++++ .../src/python/python_gui_api_bindings.cpp | 28 +++++++----- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 11e0a92c86f..8315484ea10 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -50,6 +50,7 @@ namespace hal static std::string getName(int id); static std::vector getModules(int id); static std::vector getGates(int id); + static std::vector getIds(const std::vector modules, const std::vector gates); }; } diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index abdb9a3c81f..ec4d6e64ac2 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -622,4 +622,48 @@ namespace hal return std::vector(); } + std::vector GuiApiClasses::View::getIds(const std::vector modules, const std::vector gates){ + + std::vector ids; + + QSet moduleIds; + QSet gateIds; + + + //Get ids of given modules and gates + for(Module* module : modules) + moduleIds.insert(module->get_id()); + for(Gate* gate : gates) + gateIds.insert(gate->get_id()); + + + //iterate over each context and look if its showing modules + for(GraphContext* ctx : gGraphContextManager->getContexts()){ + bool isCandidate = true; + + //Check if modules are in ctx + for(u32 moduleId : moduleIds){ + if(ctx->modules().contains(moduleId)) + continue; + isCandidate = false; + break; + } + //Only check modules if ctx still a valid candidate + if(isCandidate){ + for(u32 gateId : gateIds){ + if(ctx->gates().contains(gateId)) + continue; + isCandidate = false; + break; + } + } + + //add it to ids if its a candidate + if(isCandidate) + ids.push_back(ctx->id()); + + } + + return ids; + } } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 8fff0672672..3c0666a1c44 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -104,12 +104,12 @@ PYBIND11_PLUGIN(hal_gui) :rtype: bool )") .def_static("deleteView", &GuiApiClasses::View::deleteView, py::arg("id"),R"( - Adds the given modules and gates to the view specified by the ID. + Adds the given modules and gates to the view specified by the ID. - :param list[hal.py.module] modules: Modules to be added. - :param list[hal.py.Gate] gates: Gates to be added. - :returns: True on success, otherwise False. - :rtype: bool + :param list[hal.py.module] modules: Modules to be added. + :param list[hal.py.Gate] gates: Gates to be added. + :returns: True on success, otherwise False. + :rtype: bool )") .def_static("removeFrom", &GuiApiClasses::View::removeFrom, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( Removes the given modules and gates from the view specified by the ID. @@ -122,8 +122,8 @@ PYBIND11_PLUGIN(hal_gui) .def_static("getId", &GuiApiClasses::View::getId, py::arg("name"),R"( Returns the ID of the view with the given name if existing. - :param string name: Name of the view - :returns: ID of the specified view or 0 if none is found + :param string name: Name of the view. + :returns: ID of the specified view or 0 if none is found. :rtype: int )") .def_static("getName", &GuiApiClasses::View::getName, py::arg("id"), R"( @@ -134,18 +134,26 @@ PYBIND11_PLUGIN(hal_gui) :rtype: string )") .def_static("getModules", &GuiApiClasses::View::getModules, py::arg("id"), R"( - Returns all modules attached to the view + Returns all modules attached to the view. :param int id: ID of the view. - :returns: List of the attached modules + :returns: List of the attached modules. :rtype: list[hal.py.module] )") .def_static("getGates", &GuiApiClasses::View::getGates, py::arg("id"),R"( Returns all gates attached to the view :param int id: ID of the view. - :returns: List of the attached gates + :returns: List of the attached gates. :rtype: list[hal.py.Gate] +)") + .def_static("getIds", &GuiApiClasses::View::getIds, py::arg("modules"), py::arg("gates"),R"( + Returns the ID for from each View containing at least the given modules and gates. + + :param list[hal.py.module] modules: Required modules. + :param list[hal.py.Gate] gates: Required gates. + :returns: List of ID of views which contains modules and gates. + :rtype: list[int] )"); From bb6ae79e7abdacfa53a94b0dedbc9ff166cdb6f6 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Mon, 3 Jul 2023 00:45:15 +0200 Subject: [PATCH 10/52] added "foldModule" and "unfoldModule" --- plugins/gui/include/gui/gui_api/gui_api.h | 2 ++ plugins/gui/src/gui_api/gui_api.cpp | 23 +++++++++++++++++++ .../src/python/python_gui_api_bindings.cpp | 16 +++++++++++++ 3 files changed, 41 insertions(+) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 8315484ea10..313cfc9b941 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -51,6 +51,8 @@ namespace hal static std::vector getModules(int id); static std::vector getGates(int id); static std::vector getIds(const std::vector modules, const std::vector gates); + static bool foldModule(int view_id, Module* module); + static bool unfoldModule(int view_id, Module* module); }; } diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index ec4d6e64ac2..9c389f09dc7 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -7,6 +7,8 @@ #include "gui/user_action/action_create_object.h" #include "gui/user_action/action_delete_object.h" #include "gui/user_action/action_add_items_to_object.h" +#include "gui/user_action/action_fold_module.h" +#include "gui/user_action/action_unfold_module.h" #include "gui/graph_widget/graph_context_manager.h" #include "gui/context_manager_widget/models/context_table_model.h" @@ -666,4 +668,25 @@ namespace hal return ids; } + bool GuiApiClasses::View::unfoldModule(int view_id, Module *module) + { + GraphContext* context = gGraphContextManager->getContextById(view_id); + if(!context->modules().contains(module->get_id())) return false; + + ActionUnfoldModule *act = new ActionUnfoldModule(module->get_id()); + act->exec(); + return true; + } + + bool GuiApiClasses::View::foldModule(int view_id, Module *module) + { + GraphContext* context = gGraphContextManager->getContextById(view_id); + if(!context->modules().contains(module->get_id())) return false; + if(module->get_parent_module() != nullptr){ + ActionFoldModule *act = new ActionFoldModule(module->get_parent_module()->get_id()); + act->exec(); + return true; + } + return false; + } } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 3c0666a1c44..ad2d1f7ca74 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -154,6 +154,22 @@ PYBIND11_PLUGIN(hal_gui) :param list[hal.py.Gate] gates: Required gates. :returns: List of ID of views which contains modules and gates. :rtype: list[int] +)") + .def_static("unfoldModule", &GuiApiClasses::View::unfoldModule, py::arg("view_id"), py::arg("module"), R"( + Unfold a specific module. Remove the module from view, add submodules and gates + + :param int view_id: ID of the view. + :param Module* module: module to unfold + :returns: True on success, otherwise False. + :rtype: bool +)") + .def_static("foldModule", &GuiApiClasses::View::foldModule, py::arg("view_id"), py::arg("module"), R"( + Fold a specific module. Remove the submodules and gates from view, add parent module + + :param int view_id: ID of the view. + :param Module* module: module to fold + :returns: True on success, otherwise False. + :rtype: bool )"); From 6c3bd22b2463a58545eb8fe06e3d64cdaee7baee Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 3 Jul 2023 12:07:43 +0200 Subject: [PATCH 11/52] Bugfix: Python implied UserActions must be executed in GUI thread --- .../gui/user_action/user_action_manager.h | 10 ++++ .../gui/src/graph_widget/graphics_scene.cpp | 1 + plugins/gui/src/gui_api/gui_api.cpp | 55 ++++++++----------- .../src/user_action/user_action_manager.cpp | 18 +++++- 4 files changed, 51 insertions(+), 33 deletions(-) diff --git a/plugins/gui/include/gui/user_action/user_action_manager.h b/plugins/gui/include/gui/user_action/user_action_manager.h index b7da620f918..7812eb019c7 100644 --- a/plugins/gui/include/gui/user_action/user_action_manager.h +++ b/plugins/gui/include/gui/user_action/user_action_manager.h @@ -32,6 +32,7 @@ #include #include #include +#include #include "hal_core/defines.h" namespace hal @@ -138,6 +139,8 @@ namespace hal */ void crashDump(int sig); + void executeActionBlockThread(UserAction* act); + private: UserActionManager(QObject *parent = nullptr); void testUndo(); @@ -151,6 +154,8 @@ namespace hal static UserActionManager* inst; QPlainTextEdit* mDumpAction; SettingsItemCheckbox* mSettingDumpAction; + UserAction* mThreadedAction; + QMutex mMutex; public Q_SLOTS: /** @@ -160,6 +165,9 @@ namespace hal */ void handleSettingDumpActionChanged(bool wantDump); + private Q_SLOTS: + void handleTriggerExecute(); + Q_SIGNALS: /** * Q_SIGNAL that is emitted when undoLastAction() is called. The parameter is set to true @@ -168,5 +176,7 @@ namespace hal * @param yesWeCan - True if last action could be undone. */ void canUndoLastAction(bool yesWeCan); + + void triggerExecute(); }; } diff --git a/plugins/gui/src/graph_widget/graphics_scene.cpp b/plugins/gui/src/graph_widget/graphics_scene.cpp index 0303ae441a2..78d40b965d3 100644 --- a/plugins/gui/src/graph_widget/graphics_scene.cpp +++ b/plugins/gui/src/graph_widget/graphics_scene.cpp @@ -708,6 +708,7 @@ namespace hal void GraphicsScene::debugDrawLayouterGrid(QPainter* painter, const int x_from, const int x_to, const int y_from, const int y_to) { + if (mDebugXLines.isEmpty() || mDebugYLines.isEmpty()) return; painter->setPen(QPen(Qt::magenta)); for (qreal x : mDebugXLines) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index ec4d6e64ac2..45850e098c9 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -4,9 +4,12 @@ #include "gui/gui_globals.h" #include "gui/user_action/user_action_compound.h" #include "gui/user_action/user_action_object.h" +#include "gui/user_action/user_action_manager.h" #include "gui/user_action/action_create_object.h" #include "gui/user_action/action_delete_object.h" #include "gui/user_action/action_add_items_to_object.h" +#include "gui/user_action/action_remove_items_from_object.h" +#include "gui/user_action/action_rename_object.h" #include "gui/graph_widget/graph_context_manager.h" #include "gui/context_manager_widget/models/context_table_model.h" @@ -482,7 +485,7 @@ namespace hal act->setUseCreatedObject(); act->addAction(new ActionCreateObject(UserActionObjectType::Context, name)); act->addAction(new ActionAddItemsToObject(moduleIds, gateIds)); - act->exec(); + UserActionManager::instance()->executeActionBlockThread(act); if (isModuleExclusive){ GraphContext* context = gGraphContextManager->getContextById(act->object().id()); @@ -500,14 +503,9 @@ namespace hal { return false; } - ActionDeleteObject* del = new ActionDeleteObject(); - del->setObject(UserActionObject(id, UserActionObjectType::Context)); - - UserActionCompound* act = new UserActionCompound; - act->setUseCreatedObject(); - act->addAction(del); - act->addAction(new ActionDeleteObject); - act->exec(); + ActionDeleteObject* act = new ActionDeleteObject(); + act->setObject(UserActionObject(id, UserActionObjectType::Context)); + UserActionManager::instance()->executeActionBlockThread(act); return true; } @@ -524,14 +522,11 @@ namespace hal for(Gate* gate : gates) gateIds.insert(gate->get_id()); - GraphContext* ctx = gGraphContextManager->getContextById(id); - if(ctx != nullptr){ - //ctx->beginChange(); - ctx->add(moduleIds, gateIds); - //ctx->endChange(); - return true; - } - return false; + if (!gGraphContextManager->getContextById(id)) return false; // context does not exist + ActionAddItemsToObject* act = new ActionAddItemsToObject(moduleIds,gateIds); + act->setObject(UserActionObject(id,UserActionObjectType::Context)); + UserActionManager::instance()->executeActionBlockThread(act); + return true; } bool GuiApiClasses::View::removeFrom(int id, const std::vector modules, const std::vector gates) @@ -541,23 +536,22 @@ namespace hal QSet moduleIds; QSet gateIds; + if (!gGraphContextManager->getContextById(id)) return false; // context does not exist for(Module* module : modules) moduleIds.insert(module->get_id()); for(Gate* gate : gates) gateIds.insert(gate->get_id()); - GraphContext* ctx = gGraphContextManager->getContextById(id); - if(ctx != nullptr){ - //ctx->beginChange(); - ctx->remove(moduleIds, gateIds); - //ctx->endChange(); - return true; - } - return false; + ActionRemoveItemsFromObject* act = new ActionRemoveItemsFromObject(moduleIds,gateIds); + act->setObject(UserActionObject(id,UserActionObjectType::Context)); + UserActionManager::instance()->executeActionBlockThread(act); + return true; } bool GuiApiClasses::View::setName(int id, const std::string& name) { + if (!gGraphContextManager->getContextById(id)) return false; // context does not exist + //check if name is occupied if(gGraphContextManager->contextWithNameExists(QString::fromStdString(name))) return false; @@ -567,13 +561,10 @@ namespace hal return false; //get context matching id and rename it - for(GraphContext* ctx : gGraphContextManager->getContexts()){ - if(ctx->id() == id){ - gGraphContextManager->renameGraphContextAction(ctx, QString::fromStdString(name)); - return true; - } - } - return false; + ActionRenameObject* act = new ActionRenameObject(QString::fromStdString(name)); + act->setObject(UserActionObject(id,UserActionObjectType::Context)); + UserActionManager::instance()->executeActionBlockThread(act); + return true; } int GuiApiClasses::View::getId(const std::string& name) diff --git a/plugins/gui/src/user_action/user_action_manager.cpp b/plugins/gui/src/user_action/user_action_manager.cpp index 654632b745e..8c5f90bb91a 100644 --- a/plugins/gui/src/user_action/user_action_manager.cpp +++ b/plugins/gui/src/user_action/user_action_manager.cpp @@ -21,7 +21,8 @@ namespace hal UserActionManager::UserActionManager(QObject *parent) : QObject(parent), mStartRecording(-1), mRecordHashAttribute(true), - mDumpAction(nullptr) + mDumpAction(nullptr), + mThreadedAction(nullptr) { mElapsedTime.start(); mSettingDumpAction = new SettingsItemCheckbox( @@ -32,6 +33,21 @@ namespace hal "Specifies whether hal opens an extra window to list all executed instances of UserAction" ); connect(mSettingDumpAction,&SettingsItemCheckbox::boolChanged,this,&UserActionManager::handleSettingDumpActionChanged); + connect(this,&UserActionManager::triggerExecute,this,&UserActionManager::handleTriggerExecute,Qt::BlockingQueuedConnection); + } + + void UserActionManager::executeActionBlockThread(UserAction *act) + { + if (!act) return; + mMutex.lock(); + mThreadedAction = act; + Q_EMIT triggerExecute(); + mMutex.unlock(); + } + + void UserActionManager::handleTriggerExecute() + { + mThreadedAction->exec(); } void UserActionManager::handleSettingDumpActionChanged(bool wantDump) From 48b57cdc18c4ae2692f23270dde0b9eef3460d86 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Wed, 5 Jul 2023 09:53:21 +0200 Subject: [PATCH 12/52] foldModule() fix --- plugins/gui/src/gui_api/gui_api.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 54d3f255270..26b12d4e1d2 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -674,6 +674,18 @@ namespace hal GraphContext* context = gGraphContextManager->getContextById(view_id); if(!context->modules().contains(module->get_id())) return false; if(module->get_parent_module() == nullptr) return false; + + //get gates and submodules that belong to the current module + std::vector submodules = module->get_parent_module()->get_submodules(); + std::vector gates = module->get_parent_module()->get_gates(); + + //check if the view contains gates and submodules of the current module, return false if not + for(Gate* gate : gates) + if(!context->gates().contains(gate->get_id())) return false; + for(Module* submodule : submodules) + if(!context->modules().contains(submodule->get_id())) return false; + + ActionFoldModule *act = new ActionFoldModule(module->get_parent_module()->get_id()); UserActionManager::instance()->executeActionBlockThread(act); return true; From 731b600bb5c8aff717f6fa2b13bc640c9c08277a Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Sun, 9 Jul 2023 14:07:26 +0200 Subject: [PATCH 13/52] added validity check for isolateInNew still contains TODO's --- plugins/gui/include/gui/gui_api/gui_api.h | 13 +++- plugins/gui/src/gui_api/gui_api.cpp | 78 ++++++++++++++++++++++- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 313cfc9b941..0cdcc84e571 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -30,10 +30,10 @@ #include "hal_core/netlist/module.h" -#include -#include - #include +#include +#include +#include namespace hal { @@ -53,6 +53,13 @@ namespace hal static std::vector getIds(const std::vector modules, const std::vector gates); static bool foldModule(int view_id, Module* module); static bool unfoldModule(int view_id, Module* module); + + struct ModuleGateIdPair { + QSet moduleIds; + QSet gateIds; + }; + + static ModuleGateIdPair getValidObjects(int viewId, const std::vector, const std::vector); }; } diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 26b12d4e1d2..b6cc43c5db5 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -471,17 +471,19 @@ namespace hal //Get the number which has to be appended to name name = gGraphContextManager->nextViewName("Isolated View"); } + GuiApiClasses::View::ModuleGateIdPair pair = GuiApiClasses::View::getValidObjects(NULL, modules, gates); // Get ids from modules and gates - QSet moduleIds; - QSet gateIds; + QSet moduleIds = pair.moduleIds; + QSet gateIds = pair.gateIds; + /* for(Module* module : modules) moduleIds.insert(module->get_id()); for(Gate* gate : gates) gateIds.insert(gate->get_id()); - + */ UserActionCompound* act = new UserActionCompound; act->setUseCreatedObject(); @@ -690,4 +692,74 @@ namespace hal UserActionManager::instance()->executeActionBlockThread(act); return true; } + + GuiApiClasses::View::ModuleGateIdPair GuiApiClasses::View::getValidObjects(int viewId, const std::vector mods, const std::vector gats) + { + if(viewId != NULL){ + //TODO check content of view before processing further + } + + //copy to prevent inplace operations + std::vector modules = mods; + std::vector gates = gats; + + //TODO validate gates and modules + //here we dont have any view so we dont have to check there + + //1) sort them by priority in DESCENDING order + std::sort(modules.begin(), modules.end(), [](const Module* a, const Module* b) -> bool + { + //sorting in DESCENDING order to check from lowest to highest priority + return a->get_submodule_depth() > b->get_submodule_depth(); + } + ); + + //2) create set which stores module Ids + QSet modIds; + QSet gatIds; + + Module* topModule = gNetlist->get_top_module(); + + for(Module* mod : modules){ + modIds.insert(mod->get_id()); + } + + + //3) remove id if parent is in set + bool onlyAddParent = false; + for(Module* mod : modules){ + //get top module + if(mod == gNetlist->get_top_module()){ + // only add the top module because it has highest priority + QSet temp; + temp.insert(topModule->get_id()); + modIds = temp; + break; + } + + //check if parent is in current set and if so remove current mod + Module* iterator = mod->get_parent_module(); + while(iterator != topModule){ + if(modIds.contains(iterator->get_id())) + { + // parent is already in the set so remove mod and stop traversing parent tree + modIds.remove(mod->get_id()); + break; + } + iterator = iterator->get_parent_module(); + } + } + + + + //TODO check gates if valid to place + + + GuiApiClasses::View::ModuleGateIdPair pair; + pair.moduleIds = modIds; + pair.gateIds = gatIds; + + return pair; + ///End + } } From 0b050dfef407c01e5fb489a3e738b2ac19c654b0 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Sun, 9 Jul 2023 14:46:51 +0200 Subject: [PATCH 14/52] foldModule fix --- plugins/gui/src/gui_api/gui_api.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 26b12d4e1d2..896ad7636ed 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -672,22 +672,25 @@ namespace hal bool GuiApiClasses::View::foldModule(int view_id, Module *module) { GraphContext* context = gGraphContextManager->getContextById(view_id); - if(!context->modules().contains(module->get_id())) return false; - if(module->get_parent_module() == nullptr) return false; //get gates and submodules that belong to the current module - std::vector submodules = module->get_parent_module()->get_submodules(); - std::vector gates = module->get_parent_module()->get_gates(); + std::vector submodules = module->get_submodules(); + std::vector gates = module->get_gates(); + bool isValidToFold = false; //check if the view contains gates and submodules of the current module, return false if not for(Gate* gate : gates) - if(!context->gates().contains(gate->get_id())) return false; + if(context->gates().contains(gate->get_id())) {isValidToFold = true; break;} for(Module* submodule : submodules) - if(!context->modules().contains(submodule->get_id())) return false; + if(context->modules().contains(submodule->get_id())) {isValidToFold = true; break;} - ActionFoldModule *act = new ActionFoldModule(module->get_parent_module()->get_id()); - UserActionManager::instance()->executeActionBlockThread(act); - return true; + if (isValidToFold) + { + ActionFoldModule *act = new ActionFoldModule(module->get_id()); + UserActionManager::instance()->executeActionBlockThread(act); + return true; + } + return false; } } From 0c498269772815959ea4bf8e16a8491279ca6e3e Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Mon, 10 Jul 2023 17:41:55 +0200 Subject: [PATCH 15/52] implemented gate check in getValidObjects() and decreased unnecessary loops --- plugins/gui/src/gui_api/gui_api.cpp | 143 +++++++++++++++++++++------- 1 file changed, 108 insertions(+), 35 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index b6cc43c5db5..8ddfacd5f72 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -478,12 +478,6 @@ namespace hal QSet moduleIds = pair.moduleIds; QSet gateIds = pair.gateIds; - /* - for(Module* module : modules) - moduleIds.insert(module->get_id()); - for(Gate* gate : gates) - gateIds.insert(gate->get_id()); - */ UserActionCompound* act = new UserActionCompound; act->setUseCreatedObject(); @@ -516,17 +510,21 @@ namespace hal bool GuiApiClasses::View::addTo(int id, const std::vector modules, const std::vector gates) { - //TODO check why ctx->add does clear the whole view and only apply after a restart + + if (!gGraphContextManager->getContextById(id)) return false; // context does not exist + + + if (gGraphContextManager->getContextById(id)->isShowingModuleExclusively() && gGraphContextManager->getContextById(id)->getExclusiveModuleId() == gNetlist->get_top_module()->get_id()) + return false; //context shows topmodule so we can not add anything to it + + + GuiApiClasses::View::ModuleGateIdPair pair = GuiApiClasses::View::getValidObjects(id, modules, gates); + // Get ids from modules and gates - QSet moduleIds; - QSet gateIds; + QSet moduleIds = pair.moduleIds; + QSet gateIds = pair.gateIds; - for(Module* module : modules) - moduleIds.insert(module->get_id()); - for(Gate* gate : gates) - gateIds.insert(gate->get_id()); - if (!gGraphContextManager->getContextById(id)) return false; // context does not exist ActionAddItemsToObject* act = new ActionAddItemsToObject(moduleIds,gateIds); act->setObject(UserActionObject(id,UserActionObjectType::Context)); UserActionManager::instance()->executeActionBlockThread(act); @@ -535,12 +533,12 @@ namespace hal bool GuiApiClasses::View::removeFrom(int id, const std::vector modules, const std::vector gates) { - //TODO check why ctx->remove does clear the whole view and only apply after a restart - // Get ids from modules and gates + + if (!gGraphContextManager->getContextById(id)) return false; // context does not exist + QSet moduleIds; QSet gateIds; - if (!gGraphContextManager->getContextById(id)) return false; // context does not exist for(Module* module : modules) moduleIds.insert(module->get_id()); for(Gate* gate : gates) @@ -695,16 +693,71 @@ namespace hal GuiApiClasses::View::ModuleGateIdPair GuiApiClasses::View::getValidObjects(int viewId, const std::vector mods, const std::vector gats) { - if(viewId != NULL){ - //TODO check content of view before processing further - } + Module* topModule = gNetlist->get_top_module(); //copy to prevent inplace operations std::vector modules = mods; - std::vector gates = gats; + std::vector gates = gats; + + QSet Parents; + + QSet modIds; + QSet gatIds; + + //0) if its not a new view we have to check all parents which have to be placed + if (viewId != NULL) + { + Parents.insert(topModule->get_id()); - //TODO validate gates and modules - //here we dont have any view so we dont have to check there + //check if view is valid + std::vector validMods; + + //Add parents from module to parents + for (Module* mod : GuiApiClasses::View::getModules(viewId)) + { + validMods.push_back(mod); + if (mod != topModule) + { + Module* itr = mod->get_parent_module(); + while (itr != topModule) + { + if (Parents.contains(itr->get_id())) + break; + Parents.insert(itr->get_id()); + itr = itr->get_parent_module(); + } + } + } + //Add parents from gate to parents + for (Gate* gate : GuiApiClasses::View::getGates(viewId)) + { + Module* itr = gate->get_module(); + while (itr != topModule) + { + if (Parents.contains(itr->get_id())) + break; + Parents.insert(itr->get_id()); + itr = itr->get_parent_module(); + } + } + + //Delete every parent from the list if submodule is in the view + for (Module* mod : modules) + { + if (Parents.contains(mod->get_id())) + continue; + validMods.push_back(mod); + modIds.insert(mod->get_id()); + } + modules = validMods; + } + // no existing view so insert module ids here + else{ + for (Module* mod : modules) + { + modIds.insert(mod->get_id()); + } + } //1) sort them by priority in DESCENDING order std::sort(modules.begin(), modules.end(), [](const Module* a, const Module* b) -> bool @@ -714,22 +767,16 @@ namespace hal } ); - //2) create set which stores module Ids - QSet modIds; - QSet gatIds; + //2) create set which stores module Ids of modules already in view and which has to be added to the view - Module* topModule = gNetlist->get_top_module(); - for(Module* mod : modules){ - modIds.insert(mod->get_id()); - } + //TODO store parents maybe in the same set if it wont cause problems (it did in some cases) //3) remove id if parent is in set - bool onlyAddParent = false; for(Module* mod : modules){ - //get top module - if(mod == gNetlist->get_top_module()){ + //check if top module + if(mod == topModule){ // only add the top module because it has highest priority QSet temp; temp.insert(topModule->get_id()); @@ -751,15 +798,41 @@ namespace hal } + //4) remove all gates which has its ancestor in modIds + + //check ancestors until topmodule or found in modIds + //TODO maybe create allowed parents if there is a link from gate upto topmodule so we can break loop if we encounter one of these + for(Gate* gate : gates){ + Module* itr = gate->get_module(); + bool shouldInsert = true; + while(itr != topModule) + { + if (modIds.contains(itr->get_id())){ + gatIds.remove(gate->get_id()); + shouldInsert = false; + break; + } + itr = itr->get_parent_module(); + } + if(shouldInsert) + gatIds.insert(gate->get_id()); + } + //remove child gates - //TODO check gates if valid to place + //remove duplicates + for(Module* mod : GuiApiClasses::View::getModules(viewId)){ + modIds.remove(mod->get_id()); + } + + //create struct to return module and gate ID pairs + //TODO maybe use QHash with "module" / "gate" value with (void*) ptr of module / gate as key GuiApiClasses::View::ModuleGateIdPair pair; pair.moduleIds = modIds; pair.gateIds = gatIds; return pair; - ///End + } } From 91f4a09831845890a37ac3c62bf0402f83cd1641 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Mon, 10 Jul 2023 20:36:09 +0200 Subject: [PATCH 16/52] minor changes to comments --- plugins/gui/src/gui_api/gui_api.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 8ddfacd5f72..a1a64858443 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -767,13 +767,12 @@ namespace hal } ); - //2) create set which stores module Ids of modules already in view and which has to be added to the view //TODO store parents maybe in the same set if it wont cause problems (it did in some cases) - //3) remove id if parent is in set + //2) remove id if parent is in set for(Module* mod : modules){ //check if top module if(mod == topModule){ @@ -798,7 +797,7 @@ namespace hal } - //4) remove all gates which has its ancestor in modIds + //3) remove all gates which has its ancestor in modIds //check ancestors until topmodule or found in modIds //TODO maybe create allowed parents if there is a link from gate upto topmodule so we can break loop if we encounter one of these From 43f0267b80013374c8dbe25692447a4825d2bdba Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Mon, 10 Jul 2023 23:24:42 +0200 Subject: [PATCH 17/52] fixed issue where gates got added even if not valid --- plugins/gui/src/gui_api/gui_api.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index a1a64858443..2b4fa2ef42d 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -749,16 +749,20 @@ namespace hal validMods.push_back(mod); modIds.insert(mod->get_id()); } + qInfo() << "Starting -2"; + for(Module* modId : validMods){ + qInfo() << QString::fromStdString(modId->get_name()); + } modules = validMods; + } - // no existing view so insert module ids here - else{ - for (Module* mod : modules) - { - modIds.insert(mod->get_id()); - } + //get ids of modules + for (Module* mod : modules) + { + modIds.insert(mod->get_id()); } + //1) sort them by priority in DESCENDING order std::sort(modules.begin(), modules.end(), [](const Module* a, const Module* b) -> bool { @@ -767,9 +771,10 @@ namespace hal } ); - - - + qInfo() << "Starting 0"; + for(u32 modId : modIds){ + qInfo() << QString::fromStdString(gNetlist->get_module_by_id(modId)->get_name()); + } //TODO store parents maybe in the same set if it wont cause problems (it did in some cases) //2) remove id if parent is in set @@ -801,6 +806,11 @@ namespace hal //check ancestors until topmodule or found in modIds //TODO maybe create allowed parents if there is a link from gate upto topmodule so we can break loop if we encounter one of these + + qInfo() << "Starting 1"; + for(u32 modId : modIds){ + qInfo() << QString::fromStdString(gNetlist->get_module_by_id(modId)->get_name()); + } for(Gate* gate : gates){ Module* itr = gate->get_module(); bool shouldInsert = true; From c20f19c75c57f9e6d44f62b3a11d69fb97402d35 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Tue, 11 Jul 2023 18:24:47 +0200 Subject: [PATCH 18/52] removed NULL check --- plugins/gui/src/gui_api/gui_api.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 2b4fa2ef42d..4230aaeb1cd 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -471,7 +471,7 @@ namespace hal //Get the number which has to be appended to name name = gGraphContextManager->nextViewName("Isolated View"); } - GuiApiClasses::View::ModuleGateIdPair pair = GuiApiClasses::View::getValidObjects(NULL, modules, gates); + GuiApiClasses::View::ModuleGateIdPair pair = GuiApiClasses::View::getValidObjects(0, modules, gates); // Get ids from modules and gates @@ -705,7 +705,7 @@ namespace hal QSet gatIds; //0) if its not a new view we have to check all parents which have to be placed - if (viewId != NULL) + if (viewId) { Parents.insert(topModule->get_id()); @@ -749,10 +749,6 @@ namespace hal validMods.push_back(mod); modIds.insert(mod->get_id()); } - qInfo() << "Starting -2"; - for(Module* modId : validMods){ - qInfo() << QString::fromStdString(modId->get_name()); - } modules = validMods; } @@ -771,10 +767,7 @@ namespace hal } ); - qInfo() << "Starting 0"; - for(u32 modId : modIds){ - qInfo() << QString::fromStdString(gNetlist->get_module_by_id(modId)->get_name()); - } + //TODO store parents maybe in the same set if it wont cause problems (it did in some cases) //2) remove id if parent is in set @@ -807,10 +800,6 @@ namespace hal //check ancestors until topmodule or found in modIds //TODO maybe create allowed parents if there is a link from gate upto topmodule so we can break loop if we encounter one of these - qInfo() << "Starting 1"; - for(u32 modId : modIds){ - qInfo() << QString::fromStdString(gNetlist->get_module_by_id(modId)->get_name()); - } for(Gate* gate : gates){ Module* itr = gate->get_module(); bool shouldInsert = true; From 62c395a77ace8355eb5b7a4bedbdf8f691057ac0 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Tue, 11 Jul 2023 18:46:04 +0200 Subject: [PATCH 19/52] removed unnecessary insert --- plugins/gui/src/gui_api/gui_api.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 4230aaeb1cd..b2851c75434 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -747,7 +747,6 @@ namespace hal if (Parents.contains(mod->get_id())) continue; validMods.push_back(mod); - modIds.insert(mod->get_id()); } modules = validMods; From 8ceac6331516f9d48c84f57b92f1db140c3f3a1c Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Wed, 12 Jul 2023 18:36:33 +0200 Subject: [PATCH 20/52] added topmodule check to prevent illegal placed gates --- plugins/gui/src/gui_api/gui_api.cpp | 37 +++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index b2851c75434..bce45968dfc 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -704,15 +704,14 @@ namespace hal QSet modIds; QSet gatIds; - //0) if its not a new view we have to check all parents which have to be placed + //0) if its not a new view we have to check and remove all parents which have to be placed if (viewId) { + //put topmodule into parents because we dont iterate over it here Parents.insert(topModule->get_id()); - - //check if view is valid std::vector validMods; - //Add parents from module to parents + //Add parents from the view modules to Parents for (Module* mod : GuiApiClasses::View::getModules(viewId)) { validMods.push_back(mod); @@ -797,24 +796,26 @@ namespace hal //3) remove all gates which has its ancestor in modIds //check ancestors until topmodule or found in modIds - //TODO maybe create allowed parents if there is a link from gate upto topmodule so we can break loop if we encounter one of these - - for(Gate* gate : gates){ - Module* itr = gate->get_module(); - bool shouldInsert = true; - while(itr != topModule) + if(!modIds.contains(topModule->get_id())) + { + for (Gate* gate : gates) { - if (modIds.contains(itr->get_id())){ - gatIds.remove(gate->get_id()); - shouldInsert = false; - break; + Module* itr = gate->get_module(); + bool shouldInsert = true; + while (itr != topModule) + { + if (modIds.contains(itr->get_id())) + { + gatIds.remove(gate->get_id()); + shouldInsert = false; + break; + } + itr = itr->get_parent_module(); } - itr = itr->get_parent_module(); + if (shouldInsert) + gatIds.insert(gate->get_id()); } - if(shouldInsert) - gatIds.insert(gate->get_id()); } - //remove child gates From 94b7c486bb8bdd634d67cb259a20bca52ea8ec36 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Wed, 12 Jul 2023 19:12:39 +0200 Subject: [PATCH 21/52] adjusted iterator to go up to nullptr instead of topmodule --- plugins/gui/src/gui_api/gui_api.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index bce45968dfc..f6aca4eee0e 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -704,34 +704,33 @@ namespace hal QSet modIds; QSet gatIds; + //0) if its not a new view we have to check and remove all parents which have to be placed if (viewId) { //put topmodule into parents because we dont iterate over it here - Parents.insert(topModule->get_id()); + //Parents.insert(topModule->get_id()); std::vector validMods; //Add parents from the view modules to Parents for (Module* mod : GuiApiClasses::View::getModules(viewId)) { validMods.push_back(mod); - if (mod != topModule) + Module* itr = mod->get_parent_module(); + while (itr != nullptr) { - Module* itr = mod->get_parent_module(); - while (itr != topModule) - { - if (Parents.contains(itr->get_id())) - break; - Parents.insert(itr->get_id()); - itr = itr->get_parent_module(); - } + if (Parents.contains(itr->get_id())) + break; + Parents.insert(itr->get_id()); + itr = itr->get_parent_module(); } + } //Add parents from gate to parents for (Gate* gate : GuiApiClasses::View::getGates(viewId)) { Module* itr = gate->get_module(); - while (itr != topModule) + while (itr != nullptr) { if (Parents.contains(itr->get_id())) break; @@ -781,7 +780,7 @@ namespace hal //check if parent is in current set and if so remove current mod Module* iterator = mod->get_parent_module(); - while(iterator != topModule){ + while(iterator != nullptr){ if(modIds.contains(iterator->get_id())) { // parent is already in the set so remove mod and stop traversing parent tree @@ -802,7 +801,7 @@ namespace hal { Module* itr = gate->get_module(); bool shouldInsert = true; - while (itr != topModule) + while (itr != nullptr) { if (modIds.contains(itr->get_id())) { From ab953842c2c95989594129177a409dd4f4fbb1ed Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 13 Jul 2023 10:13:20 +0200 Subject: [PATCH 22/52] Minor fix: test whether module already in view only if viewId given --- plugins/gui/src/gui_api/gui_api.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index f6aca4eee0e..55c7e58c424 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -819,8 +819,11 @@ namespace hal //remove duplicates - for(Module* mod : GuiApiClasses::View::getModules(viewId)){ - modIds.remove(mod->get_id()); + if (viewId) + { + for(Module* mod : GuiApiClasses::View::getModules(viewId)){ + modIds.remove(mod->get_id()); + } } //create struct to return module and gate ID pairs From caff8e5b11e273f8af488ca3cc737f46a4d024b1 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Thu, 13 Jul 2023 14:55:14 +0200 Subject: [PATCH 23/52] removed already existing gates from output or valid objects --- plugins/gui/src/gui_api/gui_api.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 55c7e58c424..8e3f2f77285 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -699,6 +699,10 @@ namespace hal std::vector modules = mods; std::vector gates = gats; + //set to store already existing mods and gates + QSet existingModules; + QSet existingGates; + QSet Parents; QSet modIds; @@ -715,6 +719,7 @@ namespace hal //Add parents from the view modules to Parents for (Module* mod : GuiApiClasses::View::getModules(viewId)) { + existingModules.insert(mod->get_id()); validMods.push_back(mod); Module* itr = mod->get_parent_module(); while (itr != nullptr) @@ -729,6 +734,7 @@ namespace hal //Add parents from gate to parents for (Gate* gate : GuiApiClasses::View::getGates(viewId)) { + existingGates.insert(gate->get_id()); Module* itr = gate->get_module(); while (itr != nullptr) { @@ -821,11 +827,11 @@ namespace hal //remove duplicates if (viewId) { - for(Module* mod : GuiApiClasses::View::getModules(viewId)){ - modIds.remove(mod->get_id()); - } + modIds -= existingModules; + gatIds -= existingGates; } + //create struct to return module and gate ID pairs //TODO maybe use QHash with "module" / "gate" value with (void*) ptr of module / gate as key GuiApiClasses::View::ModuleGateIdPair pair; From fc77bfef73d2199f67ad0ca4ea00cf0d6a40831c Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Sat, 15 Jul 2023 23:41:37 +0200 Subject: [PATCH 24/52] fixed crash where nullptr was in module or gate vector --- plugins/gui/src/gui_api/gui_api.cpp | 60 ++++++++++++------- .../src/python/python_gui_api_bindings.cpp | 4 +- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 8e3f2f77285..0a926ab74c3 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -446,14 +446,16 @@ namespace hal int GuiApiClasses::View::isolateInNew(std::vector modules, std::vector gates) { QString name; + + bool isModuleExclusive = false; + + //make sure that modules and gates are not empty if(modules.empty() && gates.empty()) return 0; - bool isModuleExclusive = false; - //Check if view should be bound exclusively to module - if(modules.size() == 1 && gates.empty()){ + if(modules.size() == 1 && gates.empty() && modules[0]){ name = QString::fromStdString(modules[0]->get_name()) + QString(" (ID: %1)").arg(modules[0]->get_id()); isModuleExclusive = true; //If the view already exists then return existing id @@ -478,6 +480,8 @@ namespace hal QSet moduleIds = pair.moduleIds; QSet gateIds = pair.gateIds; + if(moduleIds.isEmpty() && gateIds.isEmpty()) + return 0; UserActionCompound* act = new UserActionCompound; act->setUseCreatedObject(); @@ -497,7 +501,7 @@ namespace hal bool GuiApiClasses::View::deleteView(int id) { - if(gGraphContextManager->getContextById(id)->empty()) + if(gGraphContextManager->getContextById(id) == nullptr) { return false; } @@ -623,12 +627,18 @@ namespace hal QSet gateIds; + //Get ids of given modules and gates for(Module* module : modules) - moduleIds.insert(module->get_id()); + { + if(module) + moduleIds.insert(module->get_id()); + } for(Gate* gate : gates) - gateIds.insert(gate->get_id()); - + { + if(gate) + gateIds.insert(gate->get_id()); + } //iterate over each context and look if its showing modules for(GraphContext* ctx : gGraphContextManager->getContexts()){ @@ -661,6 +671,8 @@ namespace hal } bool GuiApiClasses::View::unfoldModule(int view_id, Module *module) { + if(!module) + return false; GraphContext* context = gGraphContextManager->getContextById(view_id); if(!context->modules().contains(module->get_id())) return false; @@ -671,6 +683,8 @@ namespace hal bool GuiApiClasses::View::foldModule(int view_id, Module *module) { + if(!module) + return false; GraphContext* context = gGraphContextManager->getContextById(view_id); if(!context->modules().contains(module->get_id())) return false; if(module->get_parent_module() == nullptr) return false; @@ -699,6 +713,10 @@ namespace hal std::vector modules = mods; std::vector gates = gats; + //remove nullptr from list + modules.erase(std::remove_if(modules.begin(), modules.end(), [](const auto& element) { return element == nullptr; }), modules.end()); + gates.erase(std::remove_if(gates.begin(), gates.end(), [](const auto& element) { return element == nullptr; }), gates.end()); + //set to store already existing mods and gates QSet existingModules; QSet existingGates; @@ -772,7 +790,6 @@ namespace hal - //TODO store parents maybe in the same set if it wont cause problems (it did in some cases) //2) remove id if parent is in set for(Module* mod : modules){ //check if top module @@ -801,25 +818,23 @@ namespace hal //3) remove all gates which has its ancestor in modIds //check ancestors until topmodule or found in modIds - if(!modIds.contains(topModule->get_id())) + + for (Gate* gate : gates) { - for (Gate* gate : gates) + Module* itr = gate->get_module(); + bool shouldInsert = true; + while (itr != nullptr) { - Module* itr = gate->get_module(); - bool shouldInsert = true; - while (itr != nullptr) + if (modIds.contains(itr->get_id())) { - if (modIds.contains(itr->get_id())) - { - gatIds.remove(gate->get_id()); - shouldInsert = false; - break; - } - itr = itr->get_parent_module(); + gatIds.remove(gate->get_id()); + shouldInsert = false; + break; } - if (shouldInsert) - gatIds.insert(gate->get_id()); + itr = itr->get_parent_module(); } + if (shouldInsert) + gatIds.insert(gate->get_id()); } @@ -833,7 +848,6 @@ namespace hal //create struct to return module and gate ID pairs - //TODO maybe use QHash with "module" / "gate" value with (void*) ptr of module / gate as key GuiApiClasses::View::ModuleGateIdPair pair; pair.moduleIds = modIds; pair.gateIds = gatIds; diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index ad2d1f7ca74..583ab07b541 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -103,7 +103,7 @@ PYBIND11_PLUGIN(hal_gui) :returns: True on success, otherwise False. :rtype: bool )") - .def_static("deleteView", &GuiApiClasses::View::deleteView, py::arg("id"),R"( + .def_static("deleteView", &GuiApiClasses::View::deleteView, py::arg("id"),R"( Adds the given modules and gates to the view specified by the ID. :param list[hal.py.module] modules: Modules to be added. @@ -163,7 +163,7 @@ PYBIND11_PLUGIN(hal_gui) :returns: True on success, otherwise False. :rtype: bool )") - .def_static("foldModule", &GuiApiClasses::View::foldModule, py::arg("view_id"), py::arg("module"), R"( + .def_static("foldModule", &GuiApiClasses::View::foldModule, py::arg("view_id"), py::arg("module"), R"( Fold a specific module. Remove the submodules and gates from view, add parent module :param int view_id: ID of the view. From 029abaf98c8506847c5b72c6281ca3955cd54e21 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Sun, 16 Jul 2023 10:46:38 +0200 Subject: [PATCH 25/52] added validity check --- plugins/gui/src/gui_api/gui_api.cpp | 42 +++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index ec425db3fac..0d12eafe84a 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -445,6 +445,10 @@ namespace hal int GuiApiClasses::View::isolateInNew(std::vector modules, std::vector gates) { + //check if the inputs are valid + for(Module* mod : modules) + if(mod == nullptr) return 0; + QString name; //make sure that modules and gates are not empty if(modules.empty() && gates.empty()) @@ -497,7 +501,7 @@ namespace hal bool GuiApiClasses::View::deleteView(int id) { - if(gGraphContextManager->getContextById(id)->empty()) + if(gGraphContextManager->getContextById(id) == nullptr) { return false; } @@ -510,6 +514,12 @@ namespace hal bool GuiApiClasses::View::addTo(int id, const std::vector modules, const std::vector gates) { + //check if the inputs are valid + for(Module* mod : modules) + if(mod == nullptr) return false; + for(Gate* gt : gates) + if(gt == nullptr) return false; + if (!gGraphContextManager->getContextById(id)) return false; // context does not exist @@ -533,6 +543,11 @@ namespace hal bool GuiApiClasses::View::removeFrom(int id, const std::vector modules, const std::vector gates) { + //check if the inputs are valid + for(Module* mod : modules) + if(mod == nullptr) return false; + for(Gate* gt : gates) + if(gt == nullptr) return false; if (!gGraphContextManager->getContextById(id)) return false; // context does not exist @@ -552,6 +567,8 @@ namespace hal bool GuiApiClasses::View::setName(int id, const std::string& name) { + + if (!gGraphContextManager->getContextById(id)) return false; // context does not exist //check if name is occupied @@ -615,7 +632,13 @@ namespace hal return std::vector(); } - std::vector GuiApiClasses::View::getIds(const std::vector modules, const std::vector gates){ + std::vector GuiApiClasses::View::getIds(const std::vector modules, const std::vector gates) + { + //check if the inputs are valid + for(Module* mod : modules) + if(mod == nullptr) return {}; + for(Gate* gt : gates) + if(gt == nullptr) return {}; std::vector ids; @@ -661,7 +684,13 @@ namespace hal } bool GuiApiClasses::View::unfoldModule(int view_id, Module *module) { + GraphContext* context = gGraphContextManager->getContextById(view_id); + + //check if the inputs are valid + if(module == nullptr || context == nullptr) return false; + + if(!context->modules().contains(module->get_id())) return false; ActionUnfoldModule *act = new ActionUnfoldModule(module->get_id()); @@ -673,6 +702,9 @@ namespace hal { GraphContext* context = gGraphContextManager->getContextById(view_id); + //check if the inputs are valid + if(module == nullptr || context == nullptr) return false; + //get gates and submodules that belong to the current module std::vector submodules = module->get_submodules(); std::vector gates = module->get_gates(); @@ -698,6 +730,7 @@ namespace hal { Module* topModule = gNetlist->get_top_module(); + //copy to prevent inplace operations std::vector modules = mods; std::vector gates = gats; @@ -757,6 +790,11 @@ namespace hal } modules = validMods; + + for (Module* mod : modules) + { + qInfo() << mod->get_id(); + } } //get ids of modules for (Module* mod : modules) From 9dcf584f61521a29bac81f53ef3df3dd1511f080 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Sun, 16 Jul 2023 10:52:00 +0200 Subject: [PATCH 26/52] added validity check --- plugins/gui/src/gui_api/gui_api.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 758d1ddcd48..233e5787dba 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -694,12 +694,8 @@ namespace hal } bool GuiApiClasses::View::unfoldModule(int view_id, Module *module) { -<<<<<<< HEAD - -======= if(!module) return false; ->>>>>>> fc77bfef73d2199f67ad0ca4ea00cf0d6a40831c GraphContext* context = gGraphContextManager->getContextById(view_id); //check if the inputs are valid From 97d20f78b78578eda49fb116f6081110df76452d Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 17 Jul 2023 17:17:13 +0200 Subject: [PATCH 27/52] Added class Python-visible class GridPlacement --- plugins/gui/include/gui/gui_def.h | 31 ++++++++++++++- .../src/python/python_gui_api_bindings.cpp | 38 +++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/plugins/gui/include/gui/gui_def.h b/plugins/gui/include/gui/gui_def.h index 2ea85eab0c8..56ce00b5bd2 100644 --- a/plugins/gui/include/gui/gui_def.h +++ b/plugins/gui/include/gui/gui_def.h @@ -135,6 +135,26 @@ namespace hal uint qHash(const Node &n); + class GridPlacement : public QHash + { + public: + GridPlacement() {;} + void setGatePosition(u32 gateId, std::pairp) { + operator[](hal::Node(gateId,hal::Node::Gate)) = QPoint(p.first,p.second); }; + void setModulePosition(u32 moduleId, std::pairp){ + operator[](hal::Node(moduleId,hal::Node::Module)) = QPoint(p.first,p.second);}; + std::pair* gatePosition(u32 gateId) const + { + auto it = constFind(hal::Node(gateId,hal::Node::Gate)); + return (it == constEnd() ? nullptr : new std::pair(it->x(),it->y())); + } + std::pair* modulePosition(u32 moduleId) const + { + auto it = constFind(hal::Node(moduleId,hal::Node::Module)); + return (it == constEnd() ? nullptr : new std::pair(it->x(),it->y())); + } + }; + /** * @brief The PlacementHint class object provides hints for the layouter how new box objects * are placed on a view. In standard mode placement is done using the most compact squere-like @@ -151,13 +171,20 @@ namespace hal enum PlacementModeType {Standard = 0, PreferLeft = 1, PreferRight = 2, GridPosition = 3}; /** - * @brief PlacementHint constructor + * @brief PlacementHint standard constructor * @param mod placement mode must be either Standard or PreferLeft or PreferRight * @param orign node to start from when PreferLeft or PreferRight are set */ PlacementHint(PlacementModeType mod = Standard, const Node& orign=Node()) : mMode(mod), mPreferredOrigin(orign) {;} + /** + * @brief PlacementHint constructor for grid placement + * @param gridPlc Hash node to position + */ + PlacementHint(const GridPlacement& gridPlc) + : mMode(GridPosition), mPreferredOrigin(Node()), mGridPos(gridPlc) {;} + /** * @brief mode getter for placement mode type * @return either Standard or PreferLeft or PreferRight @@ -216,7 +243,7 @@ namespace hal private: PlacementModeType mMode; Node mPreferredOrigin; - QHash mGridPos; + GridPlacement mGridPos; }; /** diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 583ab07b541..940b4f73a72 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -78,6 +78,44 @@ PYBIND11_PLUGIN(hal_gui) py::class_ py_gui_api(m, "GuiApi", R"(GUI API)"); + py::class_(py_gui_api,"GridPlacement",R"( + Helper class to determine placement of nodes on gui grid. + )") + + .def(py::init<>(), R"( + Constructor for empty placement hash. + )") + + .def("setGatePosition", &GridPlacement::setGatePosition, R"( + Set position for gate identified by ID. + + :param int gateId: Gate ID. + :param tuple(int,int) pos: New position. + )") + + .def("setModulePosition", &GridPlacement::setModulePosition, R"( + Set position for module identified by ID. + + :param int moduleId: Module ID. + :param tuple(int,int) pos: New position. + )") + + .def("gatePosition", &GridPlacement::gatePosition, R"( + Query position for gate identified by ID. + + :param int gateId: Gate ID. + :returns: Position of gate or None if gate not found in hash. + :rtype: tuple(int,int) or None + )") + + .def("modulePosition", &GridPlacement::modulePosition, R"( + Query position for module identified by ID. + + :param int moduleId: Module ID. + :returns: Position of module or None if module not found in hash. + :rtype: tuple(int,int) or None + )"); + py::class_(py_gui_api, "View") .def_static("isolateInNew", &GuiApiClasses::View::isolateInNew, py::arg("modules"), py::arg("gates"),R"( Isolates given modules and gates into a new view From 43ee24dd0941f6e63192c2bd2d38333bbcd58f2f Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Mon, 17 Jul 2023 19:12:12 +0200 Subject: [PATCH 28/52] Added log warnings for cases where the input was invalid --- plugins/gui/src/gui_api/gui_api.cpp | 108 +++++++++++++++++++++------- 1 file changed, 83 insertions(+), 25 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 233e5787dba..d46c7c220c6 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -14,6 +14,7 @@ #include "gui/user_action/action_unfold_module.h" #include "gui/graph_widget/graph_context_manager.h" #include "gui/context_manager_widget/models/context_table_model.h" +#include "hal_core/utilities/log.h" #include @@ -447,7 +448,22 @@ namespace hal { //check if the inputs are valid for(Module* mod : modules) - if(mod == nullptr) return 0; + { + if (mod == nullptr) + { + log_warning("gui","Null values not allowed in module argument"); + return 0; + } + } + + for(Gate* gate : gates) + { + if (gate == nullptr) + { + log_warning("gui","Null values not allowed in gate argument"); + return 0; + } + } QString name; @@ -480,7 +496,7 @@ namespace hal GuiApiClasses::View::ModuleGateIdPair pair = GuiApiClasses::View::getValidObjects(0, modules, gates); - // Get ids from modules and gates + // Unpack return values and check if not empty QSet moduleIds = pair.moduleIds; QSet gateIds = pair.gateIds; @@ -505,10 +521,12 @@ namespace hal bool GuiApiClasses::View::deleteView(int id) { + // check if id is valid if(gGraphContextManager->getContextById(id) == nullptr) { return false; } + ActionDeleteObject* act = new ActionDeleteObject(); act->setObject(UserActionObject(id, UserActionObjectType::Context)); UserActionManager::instance()->executeActionBlockThread(act); @@ -520,10 +538,22 @@ namespace hal { //check if the inputs are valid for(Module* mod : modules) - if(mod == nullptr) return false; - for(Gate* gt : gates) - if(gt == nullptr) return false; + { + if (mod == nullptr) + { + log_warning("gui","Null values not allowed in module argument"); + return 0; + } + } + for(Gate* gate : gates) + { + if (gate == nullptr) + { + log_warning("gui","Null values not allowed in gate argument"); + return 0; + } + } if (!gGraphContextManager->getContextById(id)) return false; // context does not exist @@ -549,9 +579,22 @@ namespace hal { //check if the inputs are valid for(Module* mod : modules) - if(mod == nullptr) return false; - for(Gate* gt : gates) - if(gt == nullptr) return false; + { + if (mod == nullptr) + { + log_warning("gui","Null values not allowed in module argument"); + return 0; + } + } + + for(Gate* gate : gates) + { + if (gate == nullptr) + { + log_warning("gui","Null values not allowed in gate argument"); + return 0; + } + } if (!gGraphContextManager->getContextById(id)) return false; // context does not exist @@ -592,6 +635,10 @@ namespace hal int GuiApiClasses::View::getId(const std::string& name) { + //check if there exists a context with the given name before we iterate over each of them + if(!gGraphContextManager->contextWithNameExists(QString::fromStdString(name))) + return 0; + //find View related to the name for(GraphContext* ctx : gGraphContextManager->getContexts()){ if(ctx->name() == QString::fromStdString(name)){ @@ -607,7 +654,7 @@ namespace hal if(ctx != nullptr){ return ctx->name().toStdString(); } - return std::string(); // + return {}; // } std::vector GuiApiClasses::View::getModules(int id) @@ -620,7 +667,7 @@ namespace hal } return modules; } - return std::vector(); + return {}; } std::vector GuiApiClasses::View::getGates(int id) @@ -633,16 +680,29 @@ namespace hal } return gates; } - return std::vector(); + return {}; } std::vector GuiApiClasses::View::getIds(const std::vector modules, const std::vector gates) { //check if the inputs are valid for(Module* mod : modules) - if(mod == nullptr) return {}; - for(Gate* gt : gates) - if(gt == nullptr) return {}; + { + if (mod == nullptr) + { + log_warning("gui","Null values not allowed in module argument"); + return {}; + } + } + + for(Gate* gate : gates) + { + if (gate == nullptr) + { + log_warning("gui","Null values not allowed in gate argument"); + return {}; + } + } std::vector ids; @@ -695,11 +755,14 @@ namespace hal bool GuiApiClasses::View::unfoldModule(int view_id, Module *module) { if(!module) + { + log_warning("gui","module must not be null"); return false; + } GraphContext* context = gGraphContextManager->getContextById(view_id); //check if the inputs are valid - if(module == nullptr || context == nullptr) return false; + if(context == nullptr) return false; if(!context->modules().contains(module->get_id())) return false; @@ -712,11 +775,15 @@ namespace hal bool GuiApiClasses::View::foldModule(int view_id, Module *module) { if(!module) + { + log_warning("gui","module must not be null"); return false; + } GraphContext* context = gGraphContextManager->getContextById(view_id); //check if the inputs are valid - if(module == nullptr || context == nullptr) return false; + if(context == nullptr) return false; + //get gates and submodules that belong to the current module std::vector submodules = module->get_submodules(); @@ -748,10 +815,6 @@ namespace hal std::vector modules = mods; std::vector gates = gats; - //remove nullptr from list - modules.erase(std::remove_if(modules.begin(), modules.end(), [](const auto& element) { return element == nullptr; }), modules.end()); - gates.erase(std::remove_if(gates.begin(), gates.end(), [](const auto& element) { return element == nullptr; }), gates.end()); - //set to store already existing mods and gates QSet existingModules; QSet existingGates; @@ -807,11 +870,6 @@ namespace hal } modules = validMods; - - for (Module* mod : modules) - { - qInfo() << mod->get_id(); - } } //get ids of modules for (Module* mod : modules) From bdc8011bcb1b6f7204c47b407162e4f15c8d831f Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Mon, 17 Jul 2023 19:43:17 +0200 Subject: [PATCH 29/52] added getGridPlacement --- plugins/gui/include/gui/gui_api/gui_api.h | 2 ++ plugins/gui/src/gui_api/gui_api.cpp | 11 +++++++++++ plugins/gui/src/python/python_gui_api_bindings.cpp | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index 0cdcc84e571..e31e6fe92f5 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -28,6 +28,7 @@ #include "hal_core/netlist/gate.h" #include "hal_core/netlist/net.h" #include "hal_core/netlist/module.h" +#include "gui/include/gui/gui_def.h" #include @@ -60,6 +61,7 @@ namespace hal }; static ModuleGateIdPair getValidObjects(int viewId, const std::vector, const std::vector); + static GridPlacement* getGridPlacement(int viewId); }; } diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 233e5787dba..8614c6007cf 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -895,4 +895,15 @@ namespace hal return pair; } + + GridPlacement* GuiApiClasses::View::getGridPlacement(int viewId) + { + GraphContext* context = gGraphContextManager->getContextById(viewId); + if (context == nullptr) return new GridPlacement(); + GridPlacement* retval = new GridPlacement(); + QMap contextNodeMap = context->getLayouter()->nodeToPositionMap(); + for (auto it = contextNodeMap.begin(); it != contextNodeMap.end(); it++) + retval->insert(it.key(), it.value()); + return retval; + } } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 940b4f73a72..528fa0fb848 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -208,6 +208,12 @@ PYBIND11_PLUGIN(hal_gui) :param Module* module: module to fold :returns: True on success, otherwise False. :rtype: bool +)") + .def_static("getGridPlacement", &GuiApiClasses::View::getGridPlacement, py::arg("view_id"), R"( + Get positions of all nodes in the view + + :param int view_id: ID of the view. + :rtype: GridPlacement )"); From 0dcdda4cf5523051f10d759601f32521d2c31e39 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Tue, 18 Jul 2023 23:37:27 +0200 Subject: [PATCH 30/52] added setGridPlacement --- plugins/gui/include/gui/gui_api/gui_api.h | 1 + plugins/gui/src/gui_api/gui_api.cpp | 30 +++++++++++++++++++ .../src/python/python_gui_api_bindings.cpp | 9 ++++++ 3 files changed, 40 insertions(+) diff --git a/plugins/gui/include/gui/gui_api/gui_api.h b/plugins/gui/include/gui/gui_api/gui_api.h index e31e6fe92f5..c01f4acdc7a 100644 --- a/plugins/gui/include/gui/gui_api/gui_api.h +++ b/plugins/gui/include/gui/gui_api/gui_api.h @@ -62,6 +62,7 @@ namespace hal static ModuleGateIdPair getValidObjects(int viewId, const std::vector, const std::vector); static GridPlacement* getGridPlacement(int viewId); + static bool setGridPlacement(int viewId, GridPlacement* gp); }; } diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index a804caf93f2..4da8fcb43f0 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -12,6 +12,7 @@ #include "gui/user_action/action_rename_object.h" #include "gui/user_action/action_fold_module.h" #include "gui/user_action/action_unfold_module.h" +#include "gui/user_action/action_move_node.h" #include "gui/graph_widget/graph_context_manager.h" #include "gui/context_manager_widget/models/context_table_model.h" #include "hal_core/utilities/log.h" @@ -964,4 +965,33 @@ namespace hal retval->insert(it.key(), it.value()); return retval; } + + bool GuiApiClasses::View::setGridPlacement(int viewId, GridPlacement *gp) + { + /*UserActionCompound* actComp = new UserActionCompound; + actComp->setUseCreatedObject();*/ + + for(Node nd : gp->keys()) + { + ActionMoveNode* act = new ActionMoveNode(viewId, gp->value(nd)); + if(nd.isGate()) act->setObject(UserActionObject(nd.Gate, UserActionObjectType::Gate)); + else if(nd.isModule()) act->setObject(UserActionObject(nd.Module, UserActionObjectType::Module)); + else return false; + + UserActionManager::instance()->executeActionBlockThread(act); + + } + + /* for(auto i = gp->begin(); i != gp->end(); i++) + { + ActionMoveNode* act = new ActionMoveNode(viewId, i.value()); + qInfo() << i.key().type(); + if(i.key().isGate()) act->setObject(UserActionObject(i.key().Gate, UserActionObjectType::Gate)); + else if(i.key().isModule()) act->setObject(UserActionObject(i.key().Module, UserActionObjectType::Module)); + else return false; + actComp->addAction(act); + }*/ + return true; + + } } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 528fa0fb848..67368218d68 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -214,6 +214,15 @@ PYBIND11_PLUGIN(hal_gui) :param int view_id: ID of the view. :rtype: GridPlacement +)") + + + .def_static("setGridPlacement", &GuiApiClasses::View::setGridPlacement, py::arg("view_id"), py::arg("grid placement"), R"( + Set grid placement to the view + + :param int view_id: ID of the view. + :param GridPlacement* gp: grid placement. + :rtype: bool )"); From e13d9797518ac20866c3f24d6f665b4f5172ec4d Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Mon, 14 Aug 2023 17:32:20 +0200 Subject: [PATCH 31/52] ActionMoveNode modified --- .../gui/user_action/action_move_node.h | 17 +++-- .../src/graph_widget/graph_graphics_view.cpp | 2 +- plugins/gui/src/gui_api/gui_api.cpp | 6 +- .../gui/src/user_action/action_move_node.cpp | 69 ++++++++++++++++--- 4 files changed, 76 insertions(+), 18 deletions(-) diff --git a/plugins/gui/include/gui/user_action/action_move_node.h b/plugins/gui/include/gui/user_action/action_move_node.h index ecb91776b77..9a57ec234a7 100644 --- a/plugins/gui/include/gui/user_action/action_move_node.h +++ b/plugins/gui/include/gui/user_action/action_move_node.h @@ -44,19 +44,26 @@ namespace hal QPoint mFrom, mTo; int mContextId; + GridPlacement* mGridPlacement; static QPoint parseFromString(const QString& s); public: + /** + * empty constructor + * @param ctxId + */ + + /*ActionMoveNode(u32 ctxId) + :mContextId(ctxId) {;}*/ /** * Action constructor. * * The action object is the graphics context - * + * @param ctxID - context * @param from - The initial position of the node to move * @param to - The destination of the node */ - ActionMoveNode(const QPoint& from = QPoint(), const QPoint& to = QPoint()) - : mFrom(from), mTo(to), mContextId(-1) {;} + ActionMoveNode(u32 ctxID=0, const QPoint& from = QPoint(), const QPoint& to = QPoint()); /** * Action constructor. @@ -67,8 +74,8 @@ namespace hal * @param - The initial position of the node to move * @param to - The destination of the node */ - ActionMoveNode(u32 ctxId, const QPoint& to) - : mTo(to), mContextId(ctxId) {;} + /*ActionMoveNode(u32 ctxId, const QPoint& to) + :mContextId(ctxId), mTo(to) {;}*/ bool exec() override; QString tagname() const override; diff --git a/plugins/gui/src/graph_widget/graph_graphics_view.cpp b/plugins/gui/src/graph_widget/graph_graphics_view.cpp index 108d4b2799b..8bda3550836 100644 --- a/plugins/gui/src/graph_widget/graph_graphics_view.cpp +++ b/plugins/gui/src/graph_widget/graph_graphics_view.cpp @@ -589,7 +589,7 @@ namespace hal } else { - ActionMoveNode* act = new ActionMoveNode(sourceLayouterPos,targetLayouterPos); + ActionMoveNode* act = new ActionMoveNode(context->id(),sourceLayouterPos,targetLayouterPos); act->setObject(UserActionObject(context->id(),UserActionObjectType::Context)); act->exec(); } diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 4da8fcb43f0..bbb21d113cd 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -970,10 +970,11 @@ namespace hal { /*UserActionCompound* actComp = new UserActionCompound; actComp->setUseCreatedObject();*/ - + GridPlacement* oldGp = GuiApiClasses::View::getGridPlacement(viewId); + qInfo() << oldGp->values(); for(Node nd : gp->keys()) { - ActionMoveNode* act = new ActionMoveNode(viewId, gp->value(nd)); + ActionMoveNode* act = new ActionMoveNode(viewId, oldGp->value(nd), gp->value(nd)); if(nd.isGate()) act->setObject(UserActionObject(nd.Gate, UserActionObjectType::Gate)); else if(nd.isModule()) act->setObject(UserActionObject(nd.Module, UserActionObjectType::Module)); else return false; @@ -981,6 +982,7 @@ namespace hal UserActionManager::instance()->executeActionBlockThread(act); } + qInfo() << gp->values(); /* for(auto i = gp->begin(); i != gp->end(); i++) { diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index 673cf2b8189..d3cc531e406 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -15,6 +15,40 @@ namespace hal return new ActionMoveNode; } + ActionMoveNode::ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to) + { + mContextId = ctxID; + GraphContext* ctx = mContextId >= 0 + ? gGraphContextManager->getContextById(mContextId) + : gGraphContextManager->getContextById(mObject.id()); + + mGridPlacement = GuiApiClasses::View::getGridPlacement(ctxID); + mFrom = from; + mTo = to; + + /*GraphContext* context = gGraphContextManager->getContextById(mContextId); + Node nd = context->getLayouter()->positionToNodeMap().find(from).value();*/ + qInfo() << "mFrom: " << mFrom.isNull(); + qInfo() << "mTo: " << mTo.isNull(); + if(!mFrom.isNull() && !mTo.isNull()) + { + + UserActionObject undoObject(mObject); + if (mContextId != 0) + { + undoObject = UserActionObject(ctx->id(),UserActionObjectType::Context); + } + GridPlacement oldGp = *mGridPlacement; + Node ndToMove = mGridPlacement->key(mFrom); // get the node we want to move + mGridPlacement->insert(ndToMove, mTo); // set the position of the node to the new one + ActionMoveNode* undo = new ActionMoveNode(mContextId); + undo->mGridPlacement = &oldGp; + undo->setObject(undoObject); + mUndoAction = undo; + } + + } + QString ActionMoveNode::tagname() const { return ActionMoveNodeFactory::sFactory->tagname(); @@ -52,11 +86,28 @@ namespace hal bool ActionMoveNode::exec() { - GraphContext* ctx = mContextId >= 0 - ? gGraphContextManager->getContextById(mContextId) - : gGraphContextManager->getContextById(mObject.id()); - UserActionObject undoObject(mObject); - if (!ctx) return false; + qInfo() << "1"; + GraphContext* ctx = gGraphContextManager->getContextById(mContextId); + if(ctx == nullptr) return false; + + + ctx->clear(); + QSet modIds; + QSet gateIds; + + qInfo() << "2"; + QList nodes = mGridPlacement->keys(); + + qInfo() << "3"; + for (Node node : nodes) + { + if(node.isModule()) modIds.insert(node.id()); + else gateIds.insert(node.id()); + } + + ctx->add(modIds, gateIds); + + /*if (!ctx) return false; if (mContextId >= 0) { Node nd(mObject.id(),UserActionObjectType::toNodeType(mObject.type())); @@ -64,12 +115,10 @@ namespace hal if (!box) return false; mFrom.setX(box->x()); mFrom.setY(box->y()); - undoObject = UserActionObject(ctx->id(),UserActionObjectType::Context); + } - ActionMoveNode* undo = new ActionMoveNode(mTo,mFrom); - undo->setObject(undoObject); - mUndoAction = undo; - ctx->moveNodeAction(mFrom,mTo); + ctx->moveNodeAction(mFrom,mTo);*/ + return UserAction::exec(); } } From 071895efc687ad35f9ff650a9f9e0e8145927b15 Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 15 Aug 2023 08:19:51 +0200 Subject: [PATCH 32/52] Fix ActionMoveNode --- .../gui/user_action/action_move_node.h | 30 +++-- .../src/graph_widget/graph_graphics_view.cpp | 1 - .../gui/src/user_action/action_move_node.cpp | 118 +++++++++++++----- 3 files changed, 104 insertions(+), 45 deletions(-) diff --git a/plugins/gui/include/gui/user_action/action_move_node.h b/plugins/gui/include/gui/user_action/action_move_node.h index 9a57ec234a7..69499356276 100644 --- a/plugins/gui/include/gui/user_action/action_move_node.h +++ b/plugins/gui/include/gui/user_action/action_move_node.h @@ -41,12 +41,14 @@ namespace hal */ class ActionMoveNode : public UserAction { + u32 mContextId; QPoint mFrom, mTo; - int mContextId; - GridPlacement* mGridPlacement; + GridPlacement mGridPlacement; static QPoint parseFromString(const QString& s); + + bool checkContextId(); public: /** * empty constructor @@ -58,24 +60,32 @@ namespace hal /** * Action constructor. * - * The action object is the graphics context + * The action object will be set by 'from' node * @param ctxID - context * @param from - The initial position of the node to move * @param to - The destination of the node */ - ActionMoveNode(u32 ctxID=0, const QPoint& from = QPoint(), const QPoint& to = QPoint()); + ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to); /** * Action constructor. * - * Will move the node object (gate or module) in view identified by context - * A call to setObject is required to identify the node object - * - * @param - The initial position of the node to move + * The action object is the node to be moved + * @param ctxID - context * @param to - The destination of the node */ - /*ActionMoveNode(u32 ctxId, const QPoint& to) - :mContextId(ctxId), mTo(to) {;}*/ + ActionMoveNode(u32 ctxID, const QPoint& to); + + /** + * Action constructor. + * + * Will move the nodes according to GridPlacement position info, + * no action object should be given + * + * @param ctxID - context + * @param gridPlc - The grid placement instance to copy (if any) + */ + ActionMoveNode(u32 ctxId=0, const GridPlacement* gridPlc=nullptr); bool exec() override; QString tagname() const override; diff --git a/plugins/gui/src/graph_widget/graph_graphics_view.cpp b/plugins/gui/src/graph_widget/graph_graphics_view.cpp index 8bda3550836..0da4263517a 100644 --- a/plugins/gui/src/graph_widget/graph_graphics_view.cpp +++ b/plugins/gui/src/graph_widget/graph_graphics_view.cpp @@ -590,7 +590,6 @@ namespace hal else { ActionMoveNode* act = new ActionMoveNode(context->id(),sourceLayouterPos,targetLayouterPos); - act->setObject(UserActionObject(context->id(),UserActionObjectType::Context)); act->exec(); } context->setDirty(true); diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index d3cc531e406..6881787bd04 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -2,6 +2,8 @@ #include #include "gui/graph_widget/contexts/graph_context.h" #include "gui/gui_globals.h" +#include "gui/implementations/qpoint_extension.h" +#include "hal_core/utilities/log.h" namespace hal { @@ -15,38 +17,61 @@ namespace hal return new ActionMoveNode; } - ActionMoveNode::ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to) + bool ActionMoveNode::checkContextId() { - mContextId = ctxID; - GraphContext* ctx = mContextId >= 0 - ? gGraphContextManager->getContextById(mContextId) - : gGraphContextManager->getContextById(mObject.id()); - - mGridPlacement = GuiApiClasses::View::getGridPlacement(ctxID); - mFrom = from; - mTo = to; - - /*GraphContext* context = gGraphContextManager->getContextById(mContextId); - Node nd = context->getLayouter()->positionToNodeMap().find(from).value();*/ - qInfo() << "mFrom: " << mFrom.isNull(); - qInfo() << "mTo: " << mTo.isNull(); - if(!mFrom.isNull() && !mTo.isNull()) + if (!mContextId) { - - UserActionObject undoObject(mObject); - if (mContextId != 0) - { - undoObject = UserActionObject(ctx->id(),UserActionObjectType::Context); - } - GridPlacement oldGp = *mGridPlacement; - Node ndToMove = mGridPlacement->key(mFrom); // get the node we want to move - mGridPlacement->insert(ndToMove, mTo); // set the position of the node to the new one - ActionMoveNode* undo = new ActionMoveNode(mContextId); - undo->mGridPlacement = &oldGp; - undo->setObject(undoObject); - mUndoAction = undo; + log_warning("gui", "ActionMoveNode invoked without context ID."); + return false; } + GraphContext* ctx = gGraphContextManager->getContextById(mContextId); + if (!ctx) + { + log_warning("gui", "ActionMoveNode invoked with illegal context ID {}.", mContextId); + mContextId = 0; + return false; + } + return true; + } + + ActionMoveNode::ActionMoveNode(u32 ctxId, const GridPlacement* gridPlc) + : mContextId(ctxId) + { + if (!checkContextId()) return; + if (gridPlc) + mGridPlacement = *gridPlc; + } + ActionMoveNode::ActionMoveNode(u32 ctxID, const QPoint& to) + : mContextId(ctxID), mTo(to) + { + if (!checkContextId()) return; + } + + ActionMoveNode::ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to) + : mContextId(ctxID), mTo(to) + { + if (!checkContextId()) return; + GraphContext* ctx = gGraphContextManager->getContextById(mContextId); + auto it = ctx->getLayouter()->positionToNodeMap().find(from); + if (it == ctx->getLayouter()->positionToNodeMap().constEnd()) + { + mContextId = 0; // node not found, exit + return; + } + Node ndToMove = it.value(); // get the node we want to move + switch (ndToMove.type()) + { + case Node::Module: + mObject = UserActionObject(ndToMove.id(),UserActionObjectType::Module); + break; + case Node::Gate: + mObject = UserActionObject(ndToMove.id(),UserActionObjectType::Gate); + break; + default: + mContextId = 0; // node type None, exit + return; + } } QString ActionMoveNode::tagname() const @@ -86,26 +111,51 @@ namespace hal bool ActionMoveNode::exec() { + if (!mContextId) return false; + qInfo() << "1"; GraphContext* ctx = gGraphContextManager->getContextById(mContextId); - if(ctx == nullptr) return false; + if (!ctx) return false; + + // current placement for undo + ActionMoveNode* undo = new ActionMoveNode(mContextId, GuiApiClasses::View::getGridPlacement(mContextId)); + mUndoAction = undo; + + // test whether there is a user object + Node ndToMove; + switch (mObject.type()) { + case UserActionObjectType::Gate: + ndToMove = Node(mObject.id(),Node::Gate); + break; + case UserActionObjectType::Module: + ndToMove = Node(mObject.id(),Node::Module); + break; + default: + break; + } + qInfo() << "2"; + + if (ndToMove.type() != Node::None) + { + mGridPlacement = undo->mGridPlacement; + mGridPlacement[ndToMove] = mTo; // set the position of the node to the new one + } ctx->clear(); + QSet modIds; QSet gateIds; - qInfo() << "2"; - QList nodes = mGridPlacement->keys(); - qInfo() << "3"; - for (Node node : nodes) + for (Node node : mGridPlacement.keys()) { if(node.isModule()) modIds.insert(node.id()); else gateIds.insert(node.id()); } - ctx->add(modIds, gateIds); + ctx->add(modIds, gateIds, PlacementHint(mGridPlacement)); + ctx->scheduleSceneUpdate(); /*if (!ctx) return false; if (mContextId >= 0) From 9837094de1c4d471d8b74229d451ac462efe3f90 Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 16 Aug 2023 17:26:38 +0200 Subject: [PATCH 33/52] ActionMoveNode does not need attribute mFrom any more, removed --- .../gui/include/gui/user_action/action_move_node.h | 5 +++-- plugins/gui/src/user_action/action_move_node.cpp | 12 ++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/plugins/gui/include/gui/user_action/action_move_node.h b/plugins/gui/include/gui/user_action/action_move_node.h index 69499356276..a7b8c291259 100644 --- a/plugins/gui/include/gui/user_action/action_move_node.h +++ b/plugins/gui/include/gui/user_action/action_move_node.h @@ -42,7 +42,8 @@ namespace hal class ActionMoveNode : public UserAction { u32 mContextId; - QPoint mFrom, mTo; + QPoint mTo; + bool mSwap; GridPlacement mGridPlacement; @@ -65,7 +66,7 @@ namespace hal * @param from - The initial position of the node to move * @param to - The destination of the node */ - ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to); + ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to, bool swap = false); /** * Action constructor. diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index 6881787bd04..83f98142bd1 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -35,7 +35,7 @@ namespace hal } ActionMoveNode::ActionMoveNode(u32 ctxId, const GridPlacement* gridPlc) - : mContextId(ctxId) + : mContextId(ctxId), mSwap(false) { if (!checkContextId()) return; if (gridPlc) @@ -43,13 +43,13 @@ namespace hal } ActionMoveNode::ActionMoveNode(u32 ctxID, const QPoint& to) - : mContextId(ctxID), mTo(to) + : mContextId(ctxID), mTo(to), mSwap(false) { if (!checkContextId()) return; } - ActionMoveNode::ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to) - : mContextId(ctxID), mTo(to) + ActionMoveNode::ActionMoveNode(u32 ctxID, const QPoint& from, const QPoint& to, bool swap) + : mContextId(ctxID), mTo(to), mSwap(swap) { if (!checkContextId()) return; GraphContext* ctx = gGraphContextManager->getContextById(mContextId); @@ -81,13 +81,11 @@ namespace hal void ActionMoveNode::addToHash(QCryptographicHash& cryptoHash) const { - cryptoHash.addData((char*)(&mFrom), sizeof(QPoint)); cryptoHash.addData((char*)(&mTo) , sizeof(QPoint)); } void ActionMoveNode::writeToXml(QXmlStreamWriter& xmlOut) const { - xmlOut.writeTextElement("from", QString("%1,%2").arg(mFrom.x()).arg(mFrom.y())); xmlOut.writeTextElement("to", QString("%1,%2").arg(mTo.x()).arg(mTo.y())); } @@ -95,8 +93,6 @@ namespace hal { while (xmlIn.readNextStartElement()) { - if (xmlIn.name() == "from") - mFrom = parseFromString(xmlIn.readElementText()); if (xmlIn.name() == "to") mTo = parseFromString(xmlIn.readElementText()); } From 4f9310e8d5ee674c86cdd0423d548c4f904a2f7f Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 17 Aug 2023 21:02:30 +0200 Subject: [PATCH 34/52] Incomplete GateLibraryManager widget removed from main window --- plugins/gui/include/gui/main_window/main_window.h | 2 +- plugins/gui/src/main_window/main_window.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/gui/include/gui/main_window/main_window.h b/plugins/gui/include/gui/main_window/main_window.h index d2d28d7c3ba..105cd3df536 100644 --- a/plugins/gui/include/gui/main_window/main_window.h +++ b/plugins/gui/include/gui/main_window/main_window.h @@ -614,7 +614,7 @@ namespace hal Action* mActionImportNetlist; Action* mActionSave; Action* mActionSaveAs; - Action* mActionGateLibraryManager; +// Action* mActionGateLibraryManager; Action* mActionAbout; Action* mActionStartRecording; Action* mActionStopRecording; diff --git a/plugins/gui/src/main_window/main_window.cpp b/plugins/gui/src/main_window/main_window.cpp index ad51767aaea..f08028593de 100644 --- a/plugins/gui/src/main_window/main_window.cpp +++ b/plugins/gui/src/main_window/main_window.cpp @@ -141,7 +141,7 @@ namespace hal mActionSaveAs = new Action(this); mActionExportProject = new Action(this); mActionImportProject = new Action(this); - mActionGateLibraryManager = new Action(this); +// mActionGateLibraryManager = new Action(this); mActionAbout = new Action(this); mActionStartRecording = new Action(this); @@ -187,7 +187,7 @@ namespace hal mActionSaveAs->setIcon(gui_utility::getStyledSvgIcon(mSaveAsIconStyle, mSaveAsIconPath)); mActionClose->setIcon(gui_utility::getStyledSvgIcon(mCloseIconStyle, mCloseIconPath)); mActionQuit->setIcon(gui_utility::getStyledSvgIcon(mQuitIconStyle, mQuitIconPath)); - mActionGateLibraryManager->setIcon(gui_utility::getStyledSvgIcon(mSaveAsIconStyle, mSaveAsIconPath)); +// mActionGateLibraryManager->setIcon(gui_utility::getStyledSvgIcon(mSaveAsIconStyle, mSaveAsIconPath)); mActionUndo->setIcon(gui_utility::getStyledSvgIcon(mUndoIconStyle, mUndoIconPath)); mActionSettings->setIcon(gui_utility::getStyledSvgIcon(mSettingsIconStyle, mSettingsIconPath)); mActionPlugins->setIcon(gui_utility::getStyledSvgIcon(mPluginsIconStyle, mPluginsIconPath)); @@ -206,7 +206,7 @@ namespace hal mMenuFile->addAction(mActionClose); mMenuFile->addAction(mActionSave); mMenuFile->addAction(mActionSaveAs); - mMenuFile->addAction(mActionGateLibraryManager); +// mMenuFile->addAction(mActionGateLibraryManager); QMenu* menuImport = new QMenu("Import …", this); menuImport->addAction(mActionImportNetlist); @@ -288,7 +288,7 @@ namespace hal mActionImportNetlist->setText("Import Netlist"); mActionImportProject->setText("Import Project"); mActionExportProject->setText("Export Project"); - mActionGateLibraryManager->setText("Gate Library Manager"); +// mActionGateLibraryManager->setText("Gate Library Manager"); mActionUndo->setText("Undo"); mActionAbout->setText("About"); mActionSettings->setText("Settings"); @@ -341,7 +341,7 @@ namespace hal connect(mActionSaveAs, &Action::triggered, this, &MainWindow::handleSaveAsTriggered); connect(mActionExportProject, &Action::triggered, this, &MainWindow::handleExportProjectTriggered); connect(mActionImportProject, &Action::triggered, this, &MainWindow::handleImportProjectTriggered); - connect(mActionGateLibraryManager, &Action::triggered, this, &MainWindow::handleActionGatelibraryManager); +// connect(mActionGateLibraryManager, &Action::triggered, this, &MainWindow::handleActionGatelibraryManager); connect(mActionClose, &Action::triggered, this, &MainWindow::handleActionCloseFile); connect(mActionQuit, &Action::triggered, this, &MainWindow::onActionQuitTriggered); @@ -788,7 +788,7 @@ namespace hal } gPythonContext->updateNetlist(); - mActionGateLibraryManager->setVisible(false); +// mActionGateLibraryManager->setVisible(false); } void MainWindow::handleActionExport() @@ -1056,7 +1056,7 @@ namespace hal gNetlistRelay->reset(); - mActionGateLibraryManager->setVisible(true); +// mActionGateLibraryManager->setVisible(true); return true; } From 2704bf05341fe564cd41ad52ecbeb373d65cf7bc Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 18 Aug 2023 11:53:07 +0200 Subject: [PATCH 35/52] unnecessary header files removed --- plugins/gui/src/file_manager/new_project_dialog.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/gui/src/file_manager/new_project_dialog.cpp b/plugins/gui/src/file_manager/new_project_dialog.cpp index 3a375928d68..4ea28bc4f81 100644 --- a/plugins/gui/src/file_manager/new_project_dialog.cpp +++ b/plugins/gui/src/file_manager/new_project_dialog.cpp @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include #include #include From adef5e9bd732773a763f3390a56a2e01c733f42c Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 18 Aug 2023 15:37:53 +0200 Subject: [PATCH 36/52] work in progress --- .../netlist/persistent/netlist_serializer.h | 13 ++++- plugins/gui/src/file_manager/file_manager.cpp | 53 +++++++++++++------ .../gate_library/gate_library_manager.cpp | 4 +- .../gate_library_parser_manager.cpp | 8 +++ src/netlist/netlist_factory.cpp | 10 ++++ src/netlist/persistent/netlist_serializer.cpp | 5 +- 6 files changed, 74 insertions(+), 19 deletions(-) diff --git a/include/hal_core/netlist/persistent/netlist_serializer.h b/include/hal_core/netlist/persistent/netlist_serializer.h index 9f1edf5aebd..9994fb28a2a 100644 --- a/include/hal_core/netlist/persistent/netlist_serializer.h +++ b/include/hal_core/netlist/persistent/netlist_serializer.h @@ -43,6 +43,17 @@ namespace hal namespace netlist_serializer { + enum ErrorCode { NoError, + ProjectNotAccessible, + NetlistNotAccessible, + NetlistJsonParseError, + GatelibNotProvieded, + GatelibFileNotFound, + GatelibParserError, + HglPluginNotLoaded, + LibPluginNotLoaded, + OtherPluginNotLoaded, + } last_error; /** * Serializes a netlist into a `.hal` file. @@ -63,4 +74,4 @@ namespace hal */ NETLIST_API std::unique_ptr deserialize_from_file(const std::filesystem::path& hal_file, GateLibrary* gate_lib = nullptr); } // namespace netlist_serializer -} // namespace hal \ No newline at end of file +} // namespace hal diff --git a/plugins/gui/src/file_manager/file_manager.cpp b/plugins/gui/src/file_manager/file_manager.cpp index bcc3ab9774e..35a120d118c 100644 --- a/plugins/gui/src/file_manager/file_manager.cpp +++ b/plugins/gui/src/file_manager/file_manager.cpp @@ -521,23 +521,44 @@ namespace hal QFileInfo nlInfo(filename); if (nlInfo.suffix()=="hal") { - // event_controls::enable_all(false); won't get events until callbacks are registered - auto netlist = netlist_factory::load_netlist(filename.toStdString()); - // event_controls::enable_all(true); - if (netlist) - { - gNetlistOwner = std::move(netlist); - gNetlist = gNetlistOwner.get(); - gNetlistRelay->registerNetlistCallbacks(); - fileSuccessfullyLoaded(logical_file_name); - return true; - } - else + QHash errorCount; + for (;;) // try loading hal file until exit by return { - std::string error_message("Failed to create netlist from .hal file"); - log_error("gui", "{}", error_message); - displayErrorMessage(QString::fromStdString(error_message)); - return false; + // event_controls::enable_all(false); won't get events until callbacks are registered + auto netlist = netlist_factory::load_netlist(filename.toStdString()); + // event_controls::enable_all(true); + if (netlist) + { + gNetlistOwner = std::move(netlist); + gNetlist = gNetlistOwner.get(); + gNetlistRelay->registerNetlistCallbacks(); + fileSuccessfullyLoaded(logical_file_name); + return true; + } + else + { + bool tryAgain = false; + if (++errorCount[netlist_serializer::last_error] < 3) + { + switch (netlist_serializer::last_error) + { + case netlist_serializer::HglPluginNotLoaded: + gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,".hgl"); + tryAgain = true; + case netlist_serializer::LibPluginNotLoaded: + gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,".hgl"); + tryAgain = true; + default: + break; + } + } + if (tryAgain) continue; + + std::string error_message("Failed to create netlist from .hal file"); + log_error("gui", "{}", error_message); + displayErrorMessage(QString::fromStdString(error_message)); + return false; + } } } else diff --git a/src/netlist/gate_library/gate_library_manager.cpp b/src/netlist/gate_library/gate_library_manager.cpp index 344b8ebc447..7427f5dbc5c 100644 --- a/src/netlist/gate_library/gate_library_manager.cpp +++ b/src/netlist/gate_library/gate_library_manager.cpp @@ -3,6 +3,7 @@ #include "hal_core/netlist/gate_library/gate_library.h" #include "hal_core/netlist/gate_library/gate_library_parser/gate_library_parser_manager.h" #include "hal_core/netlist/gate_library/gate_library_writer/gate_library_writer_manager.h" +#include "hal_core/netlist/persistent/netlist_serializer.h" #include "hal_core/utilities/log.h" #include "hal_core/utilities/utils.h" @@ -77,6 +78,7 @@ namespace hal if (!std::filesystem::exists(file_path)) { log_error("gate_library_manager", "gate library file '{}' does not exist.", file_path.string()); + netlist_serializer::last_error = netlist_serializer::GatelibFileNotFound; return nullptr; } @@ -228,4 +230,4 @@ namespace hal return res; } } // namespace gate_library_manager -} // namespace hal \ No newline at end of file +} // namespace hal diff --git a/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp b/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp index e0733518b5f..4453cad0a0e 100644 --- a/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp +++ b/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp @@ -2,6 +2,7 @@ #include "hal_core/netlist/gate_library/gate_library.h" #include "hal_core/netlist/gate_library/gate_library_parser/gate_library_parser.h" +#include "hal_core/netlist/persistent/netlist_serializer.h" #include "hal_core/plugin_system/plugin_manager.h" #include "hal_core/utilities/log.h" #include "hal_core/utilities/utils.h" @@ -79,6 +80,12 @@ namespace hal auto factory = get_parser_factory_for_file(file_path); if (!factory) { + if (file_path.extension().string() == ".hgl") + netlist_serializer::last_error = netlist_serializer::HglPluginNotLoaded; + else if (file_path.extension().string() == ".lib") + netlist_serializer::last_error = netlist_serializer::LibPluginNotLoaded; + else + netlist_serializer::last_error = netlist_serializer::OtherPluginNotLoaded; return nullptr; } @@ -89,6 +96,7 @@ namespace hal if (auto res = parser->parse(file_path); res.is_error()) { log_error("gate_library_parser", "error encountered while parsing gate library from file '{}':\n{}", file_path.string(), res.get_error().get()); + netlist_serializer::last_error = netlist_serializer::GatelibParserError; return nullptr; } else diff --git a/src/netlist/netlist_factory.cpp b/src/netlist/netlist_factory.cpp index a929d0fa6b7..23a42c2b896 100644 --- a/src/netlist/netlist_factory.cpp +++ b/src/netlist/netlist_factory.cpp @@ -18,9 +18,11 @@ namespace hal { std::unique_ptr create_netlist(const GateLibrary* gate_library) { + netlist_serializer::last_error = netlist_serializer::NoError; if (gate_library == nullptr) { log_critical("netlist", "nullptr given as gate library."); + netlist_serializer::last_error = netlist_serializer::GatelibNotProvieded; return nullptr; } @@ -29,9 +31,11 @@ namespace hal std::unique_ptr load_netlist(const std::filesystem::path& netlist_file, const std::filesystem::path& gate_library_file) { + netlist_serializer::last_error = netlist_serializer::NoError; if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "could not access file '{}'.", netlist_file.string()); + netlist_serializer::last_error = netlist_serializer::NetlistNotAccessible; return nullptr; } @@ -64,9 +68,11 @@ namespace hal std::unique_ptr load_hal_project(const std::filesystem::path& project_dir) { + netlist_serializer::last_error = netlist_serializer::NoError; if (!std::filesystem::is_directory(project_dir)) { log_critical("netlist", "could not access hal project '{}'.", project_dir.string()); + netlist_serializer::last_error = netlist_serializer::ProjectNotAccessible; return nullptr; } @@ -74,6 +80,7 @@ namespace hal if (!pm->open_project(project_dir.string())) { log_critical("netlist", "could not open hal project '{}'.", project_dir.string()); + netlist_serializer::last_error = netlist_serializer::ProjectNotAccessible; return nullptr; } @@ -83,6 +90,7 @@ namespace hal std::unique_ptr load_netlist(const ProjectDirectory& pdir, const ProgramArguments& args) { + netlist_serializer::last_error = netlist_serializer::NoError; std::filesystem::path netlist_file = args.is_option_set("--import-netlist") ? std::filesystem::path(args.get_parameter("--import-netlist")) : pdir.get_default_filename(); @@ -90,6 +98,7 @@ namespace hal if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "cannot access file '{}'.", netlist_file.string()); + netlist_serializer::last_error = netlist_serializer::NetlistNotAccessible; return nullptr; } @@ -105,6 +114,7 @@ namespace hal std::vector> load_netlists(const std::filesystem::path& netlist_file) { + netlist_serializer::last_error = netlist_serializer::NoError; if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "could not access file '{}'.", netlist_file.string()); diff --git a/src/netlist/persistent/netlist_serializer.cpp b/src/netlist/persistent/netlist_serializer.cpp index 52d3b12f77c..911897a5db7 100644 --- a/src/netlist/persistent/netlist_serializer.cpp +++ b/src/netlist/persistent/netlist_serializer.cpp @@ -980,6 +980,7 @@ namespace hal std::unique_ptr deserialize_from_file(const std::filesystem::path& hal_file, GateLibrary* gatelib) { + last_error = netlist_serializer::NoError; auto begin_time = std::chrono::high_resolution_clock::now(); // event_controls::enable_all(false); @@ -988,6 +989,7 @@ namespace hal if (pFile == NULL) { log_error("netlist_persistent", "unable to open '{}'.", hal_file.string()); + last_error = NetlistNotAccessible; return nullptr; } @@ -1000,6 +1002,7 @@ namespace hal if (document.HasParseError()) { log_error("netlist_persistent", "invalid json string for deserialization"); + last_error = NetlistJsonParseError; return nullptr; } @@ -1033,4 +1036,4 @@ namespace hal } // namespace netlist_serializer } // namespace hal -#undef DURATION \ No newline at end of file +#undef DURATION From 8f195eb818b18bba0509281b9a2a68e7f65b6176 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Fri, 18 Aug 2023 21:41:06 +0200 Subject: [PATCH 37/52] Changed setGridPlacement to work with new ActionMoveNode implementation --- plugins/gui/src/gui_api/gui_api.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index bbb21d113cd..325a4af41e7 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -972,16 +972,8 @@ namespace hal actComp->setUseCreatedObject();*/ GridPlacement* oldGp = GuiApiClasses::View::getGridPlacement(viewId); qInfo() << oldGp->values(); - for(Node nd : gp->keys()) - { - ActionMoveNode* act = new ActionMoveNode(viewId, oldGp->value(nd), gp->value(nd)); - if(nd.isGate()) act->setObject(UserActionObject(nd.Gate, UserActionObjectType::Gate)); - else if(nd.isModule()) act->setObject(UserActionObject(nd.Module, UserActionObjectType::Module)); - else return false; - - UserActionManager::instance()->executeActionBlockThread(act); - - } + ActionMoveNode* act = new ActionMoveNode(viewId, gp); + act->exec(); qInfo() << gp->values(); /* for(auto i = gp->begin(); i != gp->end(); i++) From 09246e30381b9a2617386434f9dceec1fc3b7d4e Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Mon, 21 Aug 2023 10:21:58 +0300 Subject: [PATCH 38/52] implemented swap for nodes --- plugins/gui/include/gui/gui_def.h | 37 +++++++++++++++++-- .../gui/src/user_action/action_move_node.cpp | 27 ++++++++++---- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/plugins/gui/include/gui/gui_def.h b/plugins/gui/include/gui/gui_def.h index 56ce00b5bd2..9c0825e2ce7 100644 --- a/plugins/gui/include/gui/gui_def.h +++ b/plugins/gui/include/gui/gui_def.h @@ -26,6 +26,8 @@ #pragma once #include "hal_core/defines.h" +#include "hal_core/utilities/log.h" +#include #include #include #include @@ -139,10 +141,37 @@ namespace hal { public: GridPlacement() {;} - void setGatePosition(u32 gateId, std::pairp) { - operator[](hal::Node(gateId,hal::Node::Gate)) = QPoint(p.first,p.second); }; - void setModulePosition(u32 moduleId, std::pairp){ - operator[](hal::Node(moduleId,hal::Node::Module)) = QPoint(p.first,p.second);}; + void setGatePosition(u32 gateId, std::pairp, bool swap = false) { + QPoint pos = QPoint(gatePosition(gateId)->first, gatePosition(gateId)->second); //position of current gate to move + hal::Node nd = key(QPoint(p.first, p.second)); //find the node in the destination + + if(!nd.isNull() && !swap) //if the destination placement is not available + log_warning("gui", "Target position is already occupied"); + else if (!nd.isNull() && swap) + { + operator[](hal::Node(gateId,hal::Node::Gate)) = QPoint(p.first,p.second);//set the position of the first node to the destination + if(nd.isGate()) + operator[](hal::Node(nd.id(), hal::Node::Gate)) = pos;//set the position of the destination node to the position of the first node + else operator[](hal::Node(nd.id(), hal::Node::Module)) = pos; + } + else + operator[](hal::Node(gateId,hal::Node::Gate)) = QPoint(p.first,p.second); + } + void setModulePosition(u32 moduleId, std::pairp, bool swap = false){ + QPoint pos = QPoint(modulePosition(moduleId)->first, modulePosition(moduleId)->second); + hal::Node nd = key(QPoint(p.first, p.second)); + + if(!nd.isNull() && !swap) + log_warning("gui", "Target position is already occupied"); + else if (!nd.isNull() && swap) + { + operator[](hal::Node(moduleId,hal::Node::Module)) = QPoint(p.first,p.second); + if(nd.isGate()) + operator[](hal::Node(nd.id(), hal::Node::Gate)) = pos; + else operator[](hal::Node(nd.id(), hal::Node::Module)) = pos; + } + else + operator[](hal::Node(moduleId,hal::Node::Module)) = QPoint(p.first,p.second);}; std::pair* gatePosition(u32 gateId) const { auto it = constFind(hal::Node(gateId,hal::Node::Gate)); diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index 83f98142bd1..7ac3f4e3d49 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -60,6 +60,12 @@ namespace hal return; } Node ndToMove = it.value(); // get the node we want to move + + if(mSwap) + { + + } + switch (ndToMove.type()) { case Node::Module: @@ -108,8 +114,6 @@ namespace hal bool ActionMoveNode::exec() { if (!mContextId) return false; - - qInfo() << "1"; GraphContext* ctx = gGraphContextManager->getContextById(mContextId); if (!ctx) return false; @@ -129,13 +133,23 @@ namespace hal default: break; } - - qInfo() << "2"; - if (ndToMove.type() != Node::None) { mGridPlacement = undo->mGridPlacement; - mGridPlacement[ndToMove] = mTo; // set the position of the node to the new one + auto it = ctx->getLayouter()->positionToNodeMap().find(mTo);//node and its coordinate at the destination position + if (it != ctx->getLayouter()->positionToNodeMap().constEnd() && mSwap) + { + QPoint temp = mGridPlacement[ndToMove];//current position of the node to move + mGridPlacement[ndToMove] = mTo; // set the position of the first node to the new one + mGridPlacement[it.value()] = temp; //set the position of the second node to the position of the first node + } + else if (it.key() == ctx->getLayouter()->positionToNodeMap().find(mGridPlacement[ndToMove]).key() && !mSwap) //check if the destination position is occupied and if we want to swap nodes + { + log_warning("gui", "The destination position is already occupied", mContextId); + return false; + } + else + mGridPlacement[ndToMove] = mTo; } ctx->clear(); @@ -143,7 +157,6 @@ namespace hal QSet modIds; QSet gateIds; - qInfo() << "3"; for (Node node : mGridPlacement.keys()) { if(node.isModule()) modIds.insert(node.id()); From 5f6a49cdd356edb2ac14a4ba492c4546ce63feef Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Mon, 21 Aug 2023 11:06:53 +0300 Subject: [PATCH 39/52] implemented swap for nodes --- .../gui/src/user_action/action_move_node.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index 7ac3f4e3d49..8d01420e582 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -136,20 +136,17 @@ namespace hal if (ndToMove.type() != Node::None) { mGridPlacement = undo->mGridPlacement; - auto it = ctx->getLayouter()->positionToNodeMap().find(mTo);//node and its coordinate at the destination position - if (it != ctx->getLayouter()->positionToNodeMap().constEnd() && mSwap) + auto it = ctx->getLayouter()->positionToNodeMap().find(mTo); + if (it != ctx->getLayouter()->positionToNodeMap().constEnd() && mSwap) //if the position is not available and swap is set { - QPoint temp = mGridPlacement[ndToMove];//current position of the node to move - mGridPlacement[ndToMove] = mTo; // set the position of the first node to the new one - mGridPlacement[it.value()] = temp; //set the position of the second node to the position of the first node + QPoint temp = mGridPlacement[ndToMove]; + mGridPlacement[ndToMove] = mTo; + mGridPlacement[it.value()] = temp; } - else if (it.key() == ctx->getLayouter()->positionToNodeMap().find(mGridPlacement[ndToMove]).key() && !mSwap) //check if the destination position is occupied and if we want to swap nodes + else if(it == ctx->getLayouter()->positionToNodeMap().constEnd()) //if the position is available { - log_warning("gui", "The destination position is already occupied", mContextId); - return false; - } - else mGridPlacement[ndToMove] = mTo; + } } ctx->clear(); From eb5d2f7f2ada1b6177e1df712cb1751312499587 Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Mon, 21 Aug 2023 15:47:07 +0300 Subject: [PATCH 40/52] small changes to ActionMoveNode --- plugins/gui/src/user_action/action_move_node.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index 8d01420e582..12616fff6c2 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -137,16 +137,8 @@ namespace hal { mGridPlacement = undo->mGridPlacement; auto it = ctx->getLayouter()->positionToNodeMap().find(mTo); - if (it != ctx->getLayouter()->positionToNodeMap().constEnd() && mSwap) //if the position is not available and swap is set - { - QPoint temp = mGridPlacement[ndToMove]; + if (it != ctx->getLayouter()->positionToNodeMap().constEnd()) mGridPlacement[ndToMove] = mTo; - mGridPlacement[it.value()] = temp; - } - else if(it == ctx->getLayouter()->positionToNodeMap().constEnd()) //if the position is available - { - mGridPlacement[ndToMove] = mTo; - } } ctx->clear(); From 227a5a78dadc3da20c6477cc02fc5b0e28c94134 Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 23 Aug 2023 14:36:55 +0200 Subject: [PATCH 41/52] feature/recover_parser_error --- include/hal_core/netlist/persistent/netlist_serializer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/hal_core/netlist/persistent/netlist_serializer.h b/include/hal_core/netlist/persistent/netlist_serializer.h index 9994fb28a2a..2f34160cabe 100644 --- a/include/hal_core/netlist/persistent/netlist_serializer.h +++ b/include/hal_core/netlist/persistent/netlist_serializer.h @@ -53,7 +53,9 @@ namespace hal HglPluginNotLoaded, LibPluginNotLoaded, OtherPluginNotLoaded, - } last_error; + }; + + static ErrorCode last_error; /** * Serializes a netlist into a `.hal` file. From 7f645c9635e5f23b93e04447d4eb26bbd296d799 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Wed, 23 Aug 2023 20:12:50 +0200 Subject: [PATCH 42/52] cleanup --- plugins/gui/src/gui_api/gui_api.cpp | 15 +-------------- plugins/gui/src/user_action/action_move_node.cpp | 12 ------------ 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 325a4af41e7..79d4abb01b2 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -968,23 +968,10 @@ namespace hal bool GuiApiClasses::View::setGridPlacement(int viewId, GridPlacement *gp) { - /*UserActionCompound* actComp = new UserActionCompound; - actComp->setUseCreatedObject();*/ - GridPlacement* oldGp = GuiApiClasses::View::getGridPlacement(viewId); - qInfo() << oldGp->values(); + ActionMoveNode* act = new ActionMoveNode(viewId, gp); act->exec(); - qInfo() << gp->values(); - /* for(auto i = gp->begin(); i != gp->end(); i++) - { - ActionMoveNode* act = new ActionMoveNode(viewId, i.value()); - qInfo() << i.key().type(); - if(i.key().isGate()) act->setObject(UserActionObject(i.key().Gate, UserActionObjectType::Gate)); - else if(i.key().isModule()) act->setObject(UserActionObject(i.key().Module, UserActionObjectType::Module)); - else return false; - actComp->addAction(act); - }*/ return true; } diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index 12616fff6c2..ea927a4b123 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -155,18 +155,6 @@ namespace hal ctx->add(modIds, gateIds, PlacementHint(mGridPlacement)); ctx->scheduleSceneUpdate(); - /*if (!ctx) return false; - if (mContextId >= 0) - { - Node nd(mObject.id(),UserActionObjectType::toNodeType(mObject.type())); - NodeBox* box = ctx->getLayouter()->boxes().boxForNode(nd); - if (!box) return false; - mFrom.setX(box->x()); - mFrom.setY(box->y()); - - } - ctx->moveNodeAction(mFrom,mTo);*/ - return UserAction::exec(); } } From eaef6898bc45850e366ecda0c9ea43e4e64ddaf1 Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 24 Aug 2023 21:32:30 +0200 Subject: [PATCH 43/52] change appearance and behavior of import project dialog, make sure existing hal projects don't get overwritten --- CHANGELOG.md | 1 + .../gui/export/import_project_dialog.h | 9 +- .../gui/file_manager/import_netlist_dialog.h | 1 - .../gui/src/export/import_project_dialog.cpp | 150 ++++++++++++++---- .../file_manager/import_netlist_dialog.cpp | 20 +-- plugins/gui/src/main_window/main_window.cpp | 2 +- 6 files changed, 133 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ead9b901ed3..f52c0631c1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. * added `GateType::delete_pin_group` and `GateType::assign_pin_to_group` to enable more operations on pin groups of gate pins * changed supported input file formats for import from hard coded list to list provided by loadable parser plugins * changed behavior of import netlist dialog, suggest only non-existing directory names and loop until an acceptable name was entered + * changed appearance and behavior of import project dialog, make sure existing hal projects don't get overwritten * bugfixes * fixed colors in Python Console when switching between color schemes * fixed pybind of `Module::get_gates` diff --git a/plugins/gui/include/gui/export/import_project_dialog.h b/plugins/gui/include/gui/export/import_project_dialog.h index f676a0696a5..3e2419c2a9d 100644 --- a/plugins/gui/include/gui/export/import_project_dialog.h +++ b/plugins/gui/include/gui/export/import_project_dialog.h @@ -61,14 +61,19 @@ namespace hal ImportStatus mStatus; FileSelectWidget* mZippedFile; FileSelectWidget* mTargetDirectory; + QLineEdit* mExtractProjectEdit; QDialogButtonBox* mButtonBox; - QString mExtractedProjectDir; + QString mTargetProjectName; + QString mExtractedProjectAbsolutePath; + static void deleteFilesList(QStringList files); + static void deleteFilesRecursion(QString dir); private Q_SLOTS: void handleSelectionStatusChanged(); public: ImportProjectDialog(QWidget* parent = nullptr); bool importProject(); ImportStatus status() const { return mStatus; } - QString extractedProjectDir() const { return mExtractedProjectDir; } + QString extractedProjectAbsolutePath() const { return mExtractedProjectAbsolutePath; } + static QString suggestedProjectDir(const QString& filename); }; } diff --git a/plugins/gui/include/gui/file_manager/import_netlist_dialog.h b/plugins/gui/include/gui/file_manager/import_netlist_dialog.h index b3042cfd29c..750f5f1ba49 100644 --- a/plugins/gui/include/gui/file_manager/import_netlist_dialog.h +++ b/plugins/gui/include/gui/file_manager/import_netlist_dialog.h @@ -54,7 +54,6 @@ namespace hal { private Q_SLOTS: void handleGateLibraryPathChanged(const QString& txt); void handleFileDialogTriggered(); - void setSuggestedProjectDir(const QString& filename); public: ImportNetlistDialog(const QString& filename, QWidget* parent = nullptr); QString projectDirectory() const; diff --git a/plugins/gui/src/export/import_project_dialog.cpp b/plugins/gui/src/export/import_project_dialog.cpp index 2c9566cd085..e9b1ace4cb9 100644 --- a/plugins/gui/src/export/import_project_dialog.cpp +++ b/plugins/gui/src/export/import_project_dialog.cpp @@ -2,10 +2,13 @@ #include "gui/file_manager/file_manager.h" #include "gui/gui_utils/graphics.h" #include "hal_core/utilities/log.h" +#include #include #include #include #include +#include +#include #include namespace hal { @@ -68,6 +71,12 @@ namespace hal { layout->addStretch(); + layout->addWidget(new QLabel("Decompressed HAL project name:")); + mExtractProjectEdit = new QLineEdit(this); + layout->addWidget(mExtractProjectEdit); + + layout->addStretch(); + mButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel,this); connect(mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); @@ -77,7 +86,26 @@ namespace hal { void ImportProjectDialog::handleSelectionStatusChanged() { - mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(mZippedFile->valid() && mTargetDirectory->valid()); + bool valid = mTargetDirectory->valid() && mZippedFile->valid(); + if (valid) + { + QRegularExpression reProj("(.*)/\\.project.json$"); + QStringList zipFlist = JlCompress::getFileList(mZippedFile->selection()); + int inx = zipFlist.indexOf(reProj); + if (inx < 0) + { + QMessageBox::warning(this,"Invalid ZIP-file", "The zipped file " + mZippedFile->selection() + " does not seem to be a hal project.\n"); + valid = false; + } + else + { + QRegularExpressionMatch match = reProj.match(zipFlist.at(inx)); + mTargetProjectName = match.captured(1); + QString suggestedDir = suggestedProjectDir(QDir(mTargetDirectory->selection()).absoluteFilePath(mTargetProjectName)); + mExtractProjectEdit->setText(QFileInfo(suggestedDir).fileName()); + } + } + mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); } bool ImportProjectDialog::importProject() @@ -85,15 +113,32 @@ namespace hal { mStatus = NoFileSelected; if (mZippedFile->selection().isEmpty()) return false; + mExtractedProjectAbsolutePath = QDir(mTargetDirectory->selection()).absoluteFilePath(mExtractProjectEdit->text()); + if (QFileInfo(mExtractedProjectAbsolutePath).exists()) + { + QMessageBox::warning(this, "Cannot Create Project", "Direcotry " + mExtractedProjectAbsolutePath + " already exists"); + return false; + } + QStringList extracted; + QString tempdir; + if (mExtractProjectEdit->text() != mTargetProjectName) + { + tempdir = QDir(mTargetDirectory->selection()).absoluteFilePath("hal_temp_" + QUuid::createUuid().toString(QUuid::WithoutBraces)); + QDir().mkpath(tempdir); + extracted = JlCompress::extractDir(mZippedFile->selection(),tempdir); + } + else + { + extracted = JlCompress::extractDir(mZippedFile->selection(),mTargetDirectory->selection()); + } mStatus = ErrorDecompress; - QStringList extracted = JlCompress::extractDir(mZippedFile->selection(),mTargetDirectory->selection()); if (extracted.isEmpty()) return false; - mExtractedProjectDir = extracted.at(0); - while (mExtractedProjectDir.back().unicode() == '/' || mExtractedProjectDir.back().unicode() == '\\') - mExtractedProjectDir.chop(1); + QString extractedDir = extracted.at(0); + while (extractedDir.back().unicode() == '/' || extractedDir.back().unicode() == '\\') + extractedDir.chop(1); - switch (FileManager::directoryStatus(mExtractedProjectDir)) + switch (FileManager::directoryStatus(extractedDir)) { case FileManager::ProjectDirectory: mStatus = Ok; @@ -127,38 +172,87 @@ namespace hal { mStatus = NotAHalProject; break; case FileManager::UnknownDirectoryEntry: - log_warning("gui", "Failed to decompress archiv '{}', result is neither a file nor a directory.", mZippedFile->selection().toStdString()); + log_warning("gui", "Failed to decompress archive '{}', result is neither a file nor a directory.", mZippedFile->selection().toStdString()); mStatus = NotAHalProject; break; } - if (mStatus != Ok) + if (!tempdir.isEmpty()) { - // Not a hal project, delete extracted - auto it = extracted.begin(); - while (it != extracted.end()) - if (QFileInfo(*it).isDir()) - ++it; - else - { - QFile::remove(*it); - it = extracted.erase(it); - } - - // Delete directories in revers order - if (!extracted.isEmpty()) + if (!QFile::rename(extractedDir,mExtractedProjectAbsolutePath)) { - for (;;) - { - --it; - QFile::remove(*it); - if (it == extracted.begin()) - break; - } + log_warning("gui", "Failed to move decompressed archive to new location '{}'.", mExtractedProjectAbsolutePath.toStdString()); + mStatus = ErrorDecompress; } + else + { + // delete everything left in tempdir after moving project to project dir + deleteFilesRecursion(tempdir); + } + } + + if (mStatus != Ok) + { + // Not a hal project, delete all extracted + deleteFilesList(extracted); return false; } return true; } + + void ImportProjectDialog::deleteFilesRecursion(QString dir) + { + for (QFileInfo finfo : QDir(dir).entryInfoList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot)) + { + if (finfo.isDir()) + deleteFilesRecursion(finfo.absoluteFilePath()); + else + QFile::remove(finfo.absoluteFilePath()); + } + QDir().rmdir(dir); + } + + void ImportProjectDialog::deleteFilesList(QStringList files) + { + // Delete files, keep directories (might be not empty) + auto it = files.begin(); + while (it != files.end()) + if (QFileInfo(*it).isDir()) + ++it; + else + { + QFile::remove(*it); + it = files.erase(it); + } + + // Delete directories in revers order + if (!files.isEmpty()) + { + for (;;) + { + --it; + QFile::remove(*it); + if (it == files.begin()) + break; + } + } + } + + QString ImportProjectDialog::suggestedProjectDir(const QString& filename) + { + QString retval = filename; + retval.remove(QRegularExpression("\\.\\w*$")); + + QString basedir = retval; + int count = 2; + + for (;;) // loop until non existing directory found + { + if (!QFileInfo(retval).exists()) + return retval; + retval = QString("%1_%2").arg(basedir).arg(count++); + } + return retval; + } } diff --git a/plugins/gui/src/file_manager/import_netlist_dialog.cpp b/plugins/gui/src/file_manager/import_netlist_dialog.cpp index b0c788ed1ca..7a3c5412b37 100644 --- a/plugins/gui/src/file_manager/import_netlist_dialog.cpp +++ b/plugins/gui/src/file_manager/import_netlist_dialog.cpp @@ -1,6 +1,7 @@ #include "gui/file_manager/import_netlist_dialog.h" #include "gui/gui_utils/graphics.h" +#include "gui/export/import_project_dialog.h" #include "hal_core/netlist/gate_library/gate_library.h" #include "hal_core/netlist/gate_library/gate_library_manager.h" @@ -17,7 +18,6 @@ #include #include #include -#include #include namespace hal @@ -53,7 +53,7 @@ namespace hal layout->setRowStretch(irow - 1, 20); layout->addWidget(new QLabel("Location of project directory:", this), irow++, 0, Qt::AlignLeft); - setSuggestedProjectDir(filename); + mProjectdir = ImportProjectDialog::suggestedProjectDir(filename); QFrame* frameProjectdir = new QFrame(this); QHBoxLayout* layProjectdir = new QHBoxLayout(frameProjectdir); @@ -119,22 +119,6 @@ namespace hal handleGateLibraryPathChanged(mComboGatelib->currentText()); } - void ImportNetlistDialog::setSuggestedProjectDir(const QString& filename) - { - mProjectdir = filename; - mProjectdir.remove(QRegularExpression("\\.\\w*$")); - - QString basedir = mProjectdir; - int count = 2; - - for (;;) // loop until non existing directory found - { - if (!QFileInfo(mProjectdir).exists()) - return; - mProjectdir = QString("%1_%2").arg(basedir).arg(count++); - } - } - QString ImportNetlistDialog::projectDirectory() const { return mEditProjectdir->text(); diff --git a/plugins/gui/src/main_window/main_window.cpp b/plugins/gui/src/main_window/main_window.cpp index f08028593de..ad4dd832ea4 100644 --- a/plugins/gui/src/main_window/main_window.cpp +++ b/plugins/gui/src/main_window/main_window.cpp @@ -817,7 +817,7 @@ namespace hal if (ipd.importProject()) { ActionOpenNetlistFile* act = new ActionOpenNetlistFile(ActionOpenNetlistFile::OpenProject, - ipd.extractedProjectDir()); + ipd.extractedProjectAbsolutePath()); act->exec(); } else From 4ab5453d0fc76929bd0b5466124f320ea48ca846 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Fri, 25 Aug 2023 12:41:05 +0200 Subject: [PATCH 44/52] Added py::args to GridPlacement pybinds --- plugins/gui/src/python/python_gui_api_bindings.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 67368218d68..418a1355a35 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -86,21 +86,21 @@ PYBIND11_PLUGIN(hal_gui) Constructor for empty placement hash. )") - .def("setGatePosition", &GridPlacement::setGatePosition, R"( + .def("setGatePosition", &GridPlacement::setGatePosition, py::arg("gateId"), py::arg("point"), py::arg("swap") = false, R"( Set position for gate identified by ID. :param int gateId: Gate ID. :param tuple(int,int) pos: New position. )") - .def("setModulePosition", &GridPlacement::setModulePosition, R"( + .def("setModulePosition", &GridPlacement::setModulePosition, py::arg("moduleId"), py::arg("point"), py::arg("swap") = false, R"( Set position for module identified by ID. :param int moduleId: Module ID. :param tuple(int,int) pos: New position. )") - .def("gatePosition", &GridPlacement::gatePosition, R"( + .def("gatePosition", &GridPlacement::gatePosition, py::arg("gateId"), R"( Query position for gate identified by ID. :param int gateId: Gate ID. @@ -108,7 +108,7 @@ PYBIND11_PLUGIN(hal_gui) :rtype: tuple(int,int) or None )") - .def("modulePosition", &GridPlacement::modulePosition, R"( + .def("modulePosition", &GridPlacement::modulePosition, py::arg("moduleId"), R"( Query position for module identified by ID. :param int moduleId: Module ID. From 2cf1c7591328cc4a7b56cb0b9eee027a343d5c3f Mon Sep 17 00:00:00 2001 From: tarapn79 Date: Sat, 26 Aug 2023 17:42:38 +0300 Subject: [PATCH 45/52] Fixed Sphinx-documentation --- plugins/gui/src/gui_api/gui_api.cpp | 40 ------------------- .../src/python/python_gui_api_bindings.cpp | 19 +++++---- 2 files changed, 11 insertions(+), 48 deletions(-) diff --git a/plugins/gui/src/gui_api/gui_api.cpp b/plugins/gui/src/gui_api/gui_api.cpp index 79d4abb01b2..07734133b79 100644 --- a/plugins/gui/src/gui_api/gui_api.cpp +++ b/plugins/gui/src/gui_api/gui_api.cpp @@ -465,12 +465,10 @@ namespace hal return 0; } } - QString name; bool isModuleExclusive = false; - //make sure that modules and gates are not empty if(modules.empty() && gates.empty()) return 0; @@ -496,7 +494,6 @@ namespace hal } GuiApiClasses::View::ModuleGateIdPair pair = GuiApiClasses::View::getValidObjects(0, modules, gates); - // Unpack return values and check if not empty QSet moduleIds = pair.moduleIds; QSet gateIds = pair.gateIds; @@ -515,8 +512,6 @@ namespace hal context->setDirty(false); context->setExclusiveModuleId(modules[0]->get_id()); } - - return act->object().id(); } @@ -562,14 +557,12 @@ namespace hal if (gGraphContextManager->getContextById(id)->isShowingModuleExclusively() && gGraphContextManager->getContextById(id)->getExclusiveModuleId() == gNetlist->get_top_module()->get_id()) return false; //context shows topmodule so we can not add anything to it - GuiApiClasses::View::ModuleGateIdPair pair = GuiApiClasses::View::getValidObjects(id, modules, gates); // Get ids from modules and gates QSet moduleIds = pair.moduleIds; QSet gateIds = pair.gateIds; - ActionAddItemsToObject* act = new ActionAddItemsToObject(moduleIds,gateIds); act->setObject(UserActionObject(id,UserActionObjectType::Context)); UserActionManager::instance()->executeActionBlockThread(act); @@ -615,8 +608,6 @@ namespace hal bool GuiApiClasses::View::setName(int id, const std::string& name) { - - if (!gGraphContextManager->getContextById(id)) return false; // context does not exist //check if name is occupied @@ -710,8 +701,6 @@ namespace hal QSet moduleIds; QSet gateIds; - - //Get ids of given modules and gates for(Module* module : modules) { @@ -750,7 +739,6 @@ namespace hal ids.push_back(ctx->id()); } - return ids; } bool GuiApiClasses::View::unfoldModule(int view_id, Module *module) @@ -765,7 +753,6 @@ namespace hal //check if the inputs are valid if(context == nullptr) return false; - if(!context->modules().contains(module->get_id())) return false; ActionUnfoldModule *act = new ActionUnfoldModule(module->get_id()); @@ -785,7 +772,6 @@ namespace hal //check if the inputs are valid if(context == nullptr) return false; - //get gates and submodules that belong to the current module std::vector submodules = module->get_submodules(); std::vector gates = module->get_gates(); @@ -796,8 +782,6 @@ namespace hal if(context->gates().contains(gate->get_id())) {isValidToFold = true; break;} for(Module* submodule : submodules) if(context->modules().contains(submodule->get_id())) {isValidToFold = true; break;} - - if (isValidToFold) { ActionFoldModule *act = new ActionFoldModule(module->get_id()); @@ -810,8 +794,6 @@ namespace hal GuiApiClasses::View::ModuleGateIdPair GuiApiClasses::View::getValidObjects(int viewId, const std::vector mods, const std::vector gats) { Module* topModule = gNetlist->get_top_module(); - - //copy to prevent inplace operations std::vector modules = mods; std::vector gates = gats; @@ -821,18 +803,14 @@ namespace hal QSet existingGates; QSet Parents; - QSet modIds; QSet gatIds; - - //0) if its not a new view we have to check and remove all parents which have to be placed if (viewId) { //put topmodule into parents because we dont iterate over it here //Parents.insert(topModule->get_id()); std::vector validMods; - //Add parents from the view modules to Parents for (Module* mod : GuiApiClasses::View::getModules(viewId)) { @@ -861,7 +839,6 @@ namespace hal itr = itr->get_parent_module(); } } - //Delete every parent from the list if submodule is in the view for (Module* mod : modules) { @@ -870,15 +847,12 @@ namespace hal validMods.push_back(mod); } modules = validMods; - } //get ids of modules for (Module* mod : modules) { modIds.insert(mod->get_id()); } - - //1) sort them by priority in DESCENDING order std::sort(modules.begin(), modules.end(), [](const Module* a, const Module* b) -> bool { @@ -886,9 +860,6 @@ namespace hal return a->get_submodule_depth() > b->get_submodule_depth(); } ); - - - //2) remove id if parent is in set for(Module* mod : modules){ //check if top module @@ -899,7 +870,6 @@ namespace hal modIds = temp; break; } - //check if parent is in current set and if so remove current mod Module* iterator = mod->get_parent_module(); while(iterator != nullptr){ @@ -912,12 +882,8 @@ namespace hal iterator = iterator->get_parent_module(); } } - - //3) remove all gates which has its ancestor in modIds - //check ancestors until topmodule or found in modIds - for (Gate* gate : gates) { Module* itr = gate->get_module(); @@ -936,16 +902,12 @@ namespace hal gatIds.insert(gate->get_id()); } - - //remove duplicates if (viewId) { modIds -= existingModules; gatIds -= existingGates; } - - //create struct to return module and gate ID pairs GuiApiClasses::View::ModuleGateIdPair pair; pair.moduleIds = modIds; @@ -968,11 +930,9 @@ namespace hal bool GuiApiClasses::View::setGridPlacement(int viewId, GridPlacement *gp) { - ActionMoveNode* act = new ActionMoveNode(viewId, gp); act->exec(); return true; - } } diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 418a1355a35..291fa78e93b 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -91,6 +91,7 @@ PYBIND11_PLUGIN(hal_gui) :param int gateId: Gate ID. :param tuple(int,int) pos: New position. + :param bool swap: set the swap of positions of the nodes )") .def("setModulePosition", &GridPlacement::setModulePosition, py::arg("moduleId"), py::arg("point"), py::arg("swap") = false, R"( @@ -98,6 +99,7 @@ PYBIND11_PLUGIN(hal_gui) :param int moduleId: Module ID. :param tuple(int,int) pos: New position. + :param bool swap: set the swap of positions of the nodes )") .def("gatePosition", &GridPlacement::gatePosition, py::arg("gateId"), R"( @@ -136,22 +138,23 @@ PYBIND11_PLUGIN(hal_gui) .def_static("addTo", &GuiApiClasses::View::addTo, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( Adds the given modules and gates to the view specified by the ID. + :param int id: ID of the view. :param list[hal.py.module] modules: Modules to be added. :param list[hal.py.Gate] gates: Gates to be added. :returns: True on success, otherwise False. :rtype: bool )") .def_static("deleteView", &GuiApiClasses::View::deleteView, py::arg("id"),R"( - Adds the given modules and gates to the view specified by the ID. + Deletes the view specified by the ID. - :param list[hal.py.module] modules: Modules to be added. - :param list[hal.py.Gate] gates: Gates to be added. + :param int id: ID of the view. :returns: True on success, otherwise False. :rtype: bool )") .def_static("removeFrom", &GuiApiClasses::View::removeFrom, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( Removes the given modules and gates from the view specified by the ID. + :param int id: ID of the view. :param list[hal.py.module] modules: Modules to be removed. :param list[hal.py.Gate] gates: Gates to be removed. :returns: True on success, otherwise False. @@ -186,7 +189,7 @@ PYBIND11_PLUGIN(hal_gui) :rtype: list[hal.py.Gate] )") .def_static("getIds", &GuiApiClasses::View::getIds, py::arg("modules"), py::arg("gates"),R"( - Returns the ID for from each View containing at least the given modules and gates. + Returns the ID of each View containing at least the given modules and gates. :param list[hal.py.module] modules: Required modules. :param list[hal.py.Gate] gates: Required gates. @@ -194,7 +197,7 @@ PYBIND11_PLUGIN(hal_gui) :rtype: list[int] )") .def_static("unfoldModule", &GuiApiClasses::View::unfoldModule, py::arg("view_id"), py::arg("module"), R"( - Unfold a specific module. Remove the module from view, add submodules and gates + Unfold a specific module. Hides the module, shows submodules and gates :param int view_id: ID of the view. :param Module* module: module to unfold @@ -202,7 +205,7 @@ PYBIND11_PLUGIN(hal_gui) :rtype: bool )") .def_static("foldModule", &GuiApiClasses::View::foldModule, py::arg("view_id"), py::arg("module"), R"( - Fold a specific module. Remove the submodules and gates from view, add parent module + Fold a specific module. Hides the submodules and gates, shows the specific module :param int view_id: ID of the view. :param Module* module: module to fold @@ -210,7 +213,7 @@ PYBIND11_PLUGIN(hal_gui) :rtype: bool )") .def_static("getGridPlacement", &GuiApiClasses::View::getGridPlacement, py::arg("view_id"), R"( - Get positions of all nodes in the view + Get positions of all nodes in the view specified by id :param int view_id: ID of the view. :rtype: GridPlacement @@ -218,7 +221,7 @@ PYBIND11_PLUGIN(hal_gui) .def_static("setGridPlacement", &GuiApiClasses::View::setGridPlacement, py::arg("view_id"), py::arg("grid placement"), R"( - Set grid placement to the view + Set grid placement to the view specified by id :param int view_id: ID of the view. :param GridPlacement* gp: grid placement. From 31e0caca6f628f94aca2ff071f44bf4a1ca96ea6 Mon Sep 17 00:00:00 2001 From: HerrKermet Date: Sun, 27 Aug 2023 13:34:01 +0200 Subject: [PATCH 46/52] made pybind documentation for GuiApiClasses::View more consistent --- .../src/python/python_gui_api_bindings.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/plugins/gui/src/python/python_gui_api_bindings.cpp b/plugins/gui/src/python/python_gui_api_bindings.cpp index 291fa78e93b..7086ec44334 100644 --- a/plugins/gui/src/python/python_gui_api_bindings.cpp +++ b/plugins/gui/src/python/python_gui_api_bindings.cpp @@ -130,7 +130,7 @@ PYBIND11_PLUGIN(hal_gui) .def_static("rename", &GuiApiClasses::View::setName, py::arg("id"), py::arg("name"),R"( Renames the view specified by the given ID. - :param int id: ID of the view. + :param int viewId: ID of the view. :param string name: New unique name. :returns: True on success otherwise False. :rtype: bool @@ -138,7 +138,7 @@ PYBIND11_PLUGIN(hal_gui) .def_static("addTo", &GuiApiClasses::View::addTo, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( Adds the given modules and gates to the view specified by the ID. - :param int id: ID of the view. + :param int viewId: ID of the view. :param list[hal.py.module] modules: Modules to be added. :param list[hal.py.Gate] gates: Gates to be added. :returns: True on success, otherwise False. @@ -147,14 +147,14 @@ PYBIND11_PLUGIN(hal_gui) .def_static("deleteView", &GuiApiClasses::View::deleteView, py::arg("id"),R"( Deletes the view specified by the ID. - :param int id: ID of the view. + :param int viewId: ID of the view. :returns: True on success, otherwise False. :rtype: bool )") .def_static("removeFrom", &GuiApiClasses::View::removeFrom, py::arg("id"), py::arg("modules"), py::arg("gates"),R"( Removes the given modules and gates from the view specified by the ID. - :param int id: ID of the view. + :param int viewId: ID of the view. :param list[hal.py.module] modules: Modules to be removed. :param list[hal.py.Gate] gates: Gates to be removed. :returns: True on success, otherwise False. @@ -170,21 +170,21 @@ PYBIND11_PLUGIN(hal_gui) .def_static("getName", &GuiApiClasses::View::getName, py::arg("id"), R"( Returns the name of the view with the given ID if existing. - :param int id: ID of the view. + :param int viewId: ID of the view. :returns: Name of the view specified by the ID or empty string if none is found. :rtype: string )") .def_static("getModules", &GuiApiClasses::View::getModules, py::arg("id"), R"( Returns all modules attached to the view. - :param int id: ID of the view. + :param int viewId: ID of the view. :returns: List of the attached modules. :rtype: list[hal.py.module] )") .def_static("getGates", &GuiApiClasses::View::getGates, py::arg("id"),R"( Returns all gates attached to the view - :param int id: ID of the view. + :param int viewId: ID of the view. :returns: List of the attached gates. :rtype: list[hal.py.Gate] )") @@ -199,7 +199,7 @@ PYBIND11_PLUGIN(hal_gui) .def_static("unfoldModule", &GuiApiClasses::View::unfoldModule, py::arg("view_id"), py::arg("module"), R"( Unfold a specific module. Hides the module, shows submodules and gates - :param int view_id: ID of the view. + :param int viewId: ID of the view. :param Module* module: module to unfold :returns: True on success, otherwise False. :rtype: bool @@ -207,7 +207,7 @@ PYBIND11_PLUGIN(hal_gui) .def_static("foldModule", &GuiApiClasses::View::foldModule, py::arg("view_id"), py::arg("module"), R"( Fold a specific module. Hides the submodules and gates, shows the specific module - :param int view_id: ID of the view. + :param int viewId: ID of the view. :param Module* module: module to fold :returns: True on success, otherwise False. :rtype: bool @@ -215,7 +215,8 @@ PYBIND11_PLUGIN(hal_gui) .def_static("getGridPlacement", &GuiApiClasses::View::getGridPlacement, py::arg("view_id"), R"( Get positions of all nodes in the view specified by id - :param int view_id: ID of the view. + :param int viewId: ID of the view. + :returns: GridPlacement of the specified view. :rtype: GridPlacement )") @@ -223,7 +224,7 @@ PYBIND11_PLUGIN(hal_gui) .def_static("setGridPlacement", &GuiApiClasses::View::setGridPlacement, py::arg("view_id"), py::arg("grid placement"), R"( Set grid placement to the view specified by id - :param int view_id: ID of the view. + :param int viewId ID of the view. :param GridPlacement* gp: grid placement. :rtype: bool )"); From fb8e5246e0104d003f19e0f8bad5a4fd2cbbb284 Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 28 Aug 2023 22:16:08 +0200 Subject: [PATCH 47/52] New gatelib picker for import --- .../netlist/persistent/netlist_serializer.h | 37 ++-- .../gui/file_manager/import_netlist_dialog.h | 9 +- .../gatelibrary_selection.h | 83 ++++++++ plugins/gui/src/file_manager/file_manager.cpp | 12 +- .../file_manager/import_netlist_dialog.cpp | 70 ++----- .../gatelibrary_selection.cpp | 190 ++++++++++++++++++ .../gate_library/gate_library_manager.cpp | 2 +- .../gate_library_parser_manager.cpp | 8 +- src/netlist/netlist_factory.cpp | 20 +- src/netlist/persistent/netlist_serializer.cpp | 14 +- 10 files changed, 350 insertions(+), 95 deletions(-) create mode 100644 plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h create mode 100644 plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp diff --git a/include/hal_core/netlist/persistent/netlist_serializer.h b/include/hal_core/netlist/persistent/netlist_serializer.h index 2f34160cabe..0fb5d5f3442 100644 --- a/include/hal_core/netlist/persistent/netlist_serializer.h +++ b/include/hal_core/netlist/persistent/netlist_serializer.h @@ -43,19 +43,30 @@ namespace hal namespace netlist_serializer { - enum ErrorCode { NoError, - ProjectNotAccessible, - NetlistNotAccessible, - NetlistJsonParseError, - GatelibNotProvieded, - GatelibFileNotFound, - GatelibParserError, - HglPluginNotLoaded, - LibPluginNotLoaded, - OtherPluginNotLoaded, - }; - - static ErrorCode last_error; + class Error + { + public: + enum ErrorCode { NoError, + ProjectNotAccessible, + NetlistNotAccessible, + NetlistJsonParseError, + GatelibNotProvieded, + GatelibFileNotFound, + GatelibParserError, + HglPluginNotLoaded, + LibPluginNotLoaded, + OtherPluginNotLoaded, + }; + private: + static Error* inst; + ErrorCode mCode; + Error() : mCode(NoError) {;} + public: + ErrorCode code() const { return mCode; } + void setError(ErrorCode ec) { mCode = ec; } + void reset() { mCode = NoError; } + static Error* instance(); + }; /** * Serializes a netlist into a `.hal` file. diff --git a/plugins/gui/include/gui/file_manager/import_netlist_dialog.h b/plugins/gui/include/gui/file_manager/import_netlist_dialog.h index b3042cfd29c..48d59908778 100644 --- a/plugins/gui/include/gui/file_manager/import_netlist_dialog.h +++ b/plugins/gui/include/gui/file_manager/import_netlist_dialog.h @@ -30,12 +30,13 @@ #include #include -class QComboBox; class QCheckBox; class QLineEdit; namespace hal { + class GateLibrarySelection; + class ImportNetlistDialog : public QDialog { Q_OBJECT @@ -43,16 +44,14 @@ namespace hal { Q_PROPERTY(QString saveIconStyle READ saveIconStyle WRITE setSaveIconStyle) QString mProjectdir; QLineEdit* mEditProjectdir; - QComboBox* mComboGatelib; + GateLibrarySelection* mGatelibSelection; QCheckBox* mCheckMoveNetlist; QCheckBox* mCheckCopyGatelib; - QStringList mGateLibraryPath; - QMap mGateLibraryMap; QString mSaveIconPath; QString mSaveIconStyle; private Q_SLOTS: - void handleGateLibraryPathChanged(const QString& txt); + void handleGatelibSelected(bool singleFile); void handleFileDialogTriggered(); void setSuggestedProjectDir(const QString& filename); public: diff --git a/plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h b/plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h new file mode 100644 index 00000000000..6f6a18cbabb --- /dev/null +++ b/plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h @@ -0,0 +1,83 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +class QComboBox; +class QPushButton; +class QCheckBox; + +namespace hal { + class GateLibrarySelectionEntry + { + QString mName; + QString mPath; + int mCount; + public: + GateLibrarySelectionEntry(const QString& name_, const QString& path_, int cnt) + : mName(name_), mPath(path_), mCount(cnt) {;} + QVariant data(int column, bool fullPath) const; + QString name() const {return mName; } + QString path() const {return mPath; } + }; + + class GateLibrarySelectionTable : public QAbstractTableModel + { + Q_OBJECT + QList mEntries; + bool mShowFullPath; + public: + GateLibrarySelectionTable(bool addAutoDetect, QObject* parent = nullptr); + int columnCount(const QModelIndex& index = QModelIndex()) const override; + int rowCount(const QModelIndex& index = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + void handleShowFullPath(bool checked); + int addGateLibrary(const QString& path); + QString gateLibraryPath(int inx) const; + int getIndexByPath(const QString& path); + }; + + class GateLibrarySelection : public QFrame + { + Q_OBJECT + QComboBox* mComboGatelib; + QPushButton* mInvokeFileDialog; + QCheckBox* mCheckFullPath; + Q_SIGNALS: + void gatelibSelected(bool singleFile); + private Q_SLOTS: + void handleInvokeFileDialog(); + void handleShowFullPath(bool checked); + public: + GateLibrarySelection(const QString& defaultGl, QWidget* parent = nullptr); + QString gateLibraryPath() const; + void setIcon(const QString& path, const QString& style); + void setCurrent(const QString& glPath); + }; +} diff --git a/plugins/gui/src/file_manager/file_manager.cpp b/plugins/gui/src/file_manager/file_manager.cpp index 35a120d118c..33b7641bf40 100644 --- a/plugins/gui/src/file_manager/file_manager.cpp +++ b/plugins/gui/src/file_manager/file_manager.cpp @@ -525,7 +525,7 @@ namespace hal for (;;) // try loading hal file until exit by return { // event_controls::enable_all(false); won't get events until callbacks are registered - auto netlist = netlist_factory::load_netlist(filename.toStdString()); + auto netlist = netlist_factory::load_netlist(filename.toStdString(),gatelibraryPath.toStdString()); // event_controls::enable_all(true); if (netlist) { @@ -538,14 +538,16 @@ namespace hal else { bool tryAgain = false; - if (++errorCount[netlist_serializer::last_error] < 3) + + netlist_serializer::Error::ErrorCode errCode = netlist_serializer::Error::instance()->code(); + if (++errorCount[errCode] < 3) { - switch (netlist_serializer::last_error) + switch (errCode) { - case netlist_serializer::HglPluginNotLoaded: + case netlist_serializer::Error::HglPluginNotLoaded: gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,".hgl"); tryAgain = true; - case netlist_serializer::LibPluginNotLoaded: + case netlist_serializer::Error::LibPluginNotLoaded: gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,".hgl"); tryAgain = true; default: diff --git a/plugins/gui/src/file_manager/import_netlist_dialog.cpp b/plugins/gui/src/file_manager/import_netlist_dialog.cpp index b0c788ed1ca..d7becde23af 100644 --- a/plugins/gui/src/file_manager/import_netlist_dialog.cpp +++ b/plugins/gui/src/file_manager/import_netlist_dialog.cpp @@ -1,16 +1,13 @@ #include "gui/file_manager/import_netlist_dialog.h" #include "gui/gui_utils/graphics.h" -#include "hal_core/netlist/gate_library/gate_library.h" -#include "hal_core/netlist/gate_library/gate_library_manager.h" +#include "gui/gatelibrary_management/gatelibrary_selection.h" #include -#include #include #include #include #include -#include #include #include #include @@ -19,6 +16,7 @@ #include #include #include +#include namespace hal { @@ -27,8 +25,7 @@ namespace hal QStyle* s = style(); s->unpolish(this); s->polish(this); - QString suggestedGateLibraryPath; - QString suggestedGateLibraryName; + QString gatelibFromHal; if (filename.endsWith(".hal")) { QFile halFile(filename); @@ -40,7 +37,7 @@ namespace hal { const QJsonObject& nlObj = halObj["netlist"].toObject(); if (nlObj.contains("gate_library") && nlObj["gate_library"].isString()) - suggestedGateLibraryPath = nlObj["gate_library"].toString(); + gatelibFromHal = nlObj["gate_library"].toString(); } } } @@ -66,42 +63,10 @@ namespace hal layout->addWidget(frameProjectdir, irow++, 0); layout->addItem(new QSpacerItem(30, 30), irow++, 0); - QLabel* labGatelib = new QLabel("Gate library:", this); - layout->addWidget(labGatelib, irow++, 0, Qt::AlignLeft); - mComboGatelib = new QComboBox(this); - if (filename.endsWith(".hal")) - { - mComboGatelib->setDisabled(true); - labGatelib->setDisabled(true); - } - else - { - mComboGatelib->addItem("(Auto detect)"); - for (const std::filesystem::path& path : gate_library_manager::get_all_path()) - { - int n = mGateLibraryPath.size(); - QString qName = QString::fromStdString(path.filename()); - mGateLibraryMap.insert(qName, n); - QString qPath = QString::fromStdString(path.string()); - mGateLibraryPath.append(qPath); - if (qPath == suggestedGateLibraryPath) - suggestedGateLibraryName = qName; - } - if (suggestedGateLibraryName.isEmpty() && !suggestedGateLibraryPath.isEmpty()) - { - // suggested gate library not found in default path - QFileInfo info(suggestedGateLibraryPath); - suggestedGateLibraryName = info.fileName(); - int n = mGateLibraryPath.size(); - mGateLibraryMap.insert(suggestedGateLibraryName, n); - mGateLibraryPath.append(suggestedGateLibraryPath); - } - mComboGatelib->addItems(mGateLibraryMap.keys()); - if (!suggestedGateLibraryName.isEmpty()) - mComboGatelib->setCurrentText(suggestedGateLibraryName); - } - mComboGatelib->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - layout->addWidget(mComboGatelib, irow++, 0); + mGatelibSelection = new GateLibrarySelection(gatelibFromHal, this); + mGatelibSelection->setIcon(mSaveIconPath, mSaveIconStyle); + layout->addWidget(mGatelibSelection, irow++, 0); + //mGatelibSelection->setDisabled(filename.endsWith(".hal")); layout->addItem(new QSpacerItem(30, 30), irow++, 0); layout->setRowStretch(irow - 1, 20); @@ -115,8 +80,6 @@ namespace hal connect(dbb, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(dbb, &QDialogButtonBox::rejected, this, &QDialog::reject); layout->addWidget(dbb, irow++, 0, Qt::AlignRight); - connect(mComboGatelib, &QComboBox::currentTextChanged, this, &ImportNetlistDialog::handleGateLibraryPathChanged); - handleGateLibraryPathChanged(mComboGatelib->currentText()); } void ImportNetlistDialog::setSuggestedProjectDir(const QString& filename) @@ -148,24 +111,22 @@ namespace hal mEditProjectdir->setText(dir); } - void ImportNetlistDialog::handleGateLibraryPathChanged(const QString& txt) + void ImportNetlistDialog::handleGatelibSelected(bool singleFile) { - if (mGateLibraryMap.value(txt, -1) < 0) + if (singleFile) + { + mCheckCopyGatelib->setEnabled(true); + } + else { mCheckCopyGatelib->setCheckState(Qt::Unchecked); mCheckCopyGatelib->setDisabled(true); } - else - mCheckCopyGatelib->setEnabled(true); } QString ImportNetlistDialog::gateLibraryPath() const { - QString seltxt = mComboGatelib->currentText(); - int inx = mGateLibraryMap.value(seltxt, -1); - if (inx < 0) - return QString(); - return mGateLibraryPath.at(inx); + return mGatelibSelection->gateLibraryPath(); } bool ImportNetlistDialog::isMoveNetlistChecked() const @@ -177,4 +138,5 @@ namespace hal { return mCheckCopyGatelib->isChecked(); } + } // namespace hal diff --git a/plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp b/plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp new file mode 100644 index 00000000000..b117e8ccd49 --- /dev/null +++ b/plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp @@ -0,0 +1,190 @@ +#include "gui/gatelibrary_management/gatelibrary_selection.h" +#include "gui/gui_utils/graphics.h" +#include "hal_core/netlist/gate_library/gate_library.h" +#include "hal_core/netlist/gate_library/gate_library_manager.h" +#include "hal_core/utilities/log.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace hal { + GateLibrarySelection::GateLibrarySelection(const QString &defaultGl, QWidget* parent) + : QFrame(parent) + { + QVBoxLayout* vlayout = new QVBoxLayout(this); + QLabel* labGatelib = new QLabel("Gate library:", this); + vlayout->addWidget(labGatelib); + + + QHBoxLayout* hlayout = new QHBoxLayout; + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + setFrameStyle(QFrame::Sunken | QFrame::Panel); + + mComboGatelib = new QComboBox(this); + GateLibrarySelectionTable* glTable = new GateLibrarySelectionTable(true,this); + mComboGatelib->setModel(glTable); + + mComboGatelib->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + hlayout->addWidget(mComboGatelib); + + int inx = glTable->getIndexByPath(defaultGl); + if (inx >= 0) mComboGatelib->setCurrentIndex(inx); + + mInvokeFileDialog = new QPushButton(this); + connect(mInvokeFileDialog, &QPushButton::clicked, this, &GateLibrarySelection::handleInvokeFileDialog); + hlayout->addWidget(mInvokeFileDialog); + + vlayout->addLayout(hlayout); + mCheckFullPath = new QCheckBox("Show full path"); + mCheckFullPath->setChecked(false); + connect(mCheckFullPath,&QCheckBox::toggled,this,&GateLibrarySelection::handleShowFullPath); + vlayout->addWidget(mCheckFullPath); + } + + void GateLibrarySelection::setIcon(const QString &path, const QString &style) + { + mInvokeFileDialog->setIcon(gui_utility::getStyledSvgIcon(style, path)); + } + + void GateLibrarySelection::handleInvokeFileDialog() + { + QString glFilename = QFileDialog::getOpenFileName(this, "Select Gate Library", QDir::currentPath(), "HGL Files (*.hgl);;Lib Files (*.lib)"); + if (glFilename.isEmpty()) return; + int inx = static_cast(mComboGatelib->model())->addGateLibrary(glFilename); + mComboGatelib->setCurrentIndex(inx); + } + + QString GateLibrarySelection::gateLibraryPath() const + { + const GateLibrarySelectionTable* glst = static_cast(mComboGatelib->model()); + return glst->gateLibraryPath(mComboGatelib->currentIndex()); + } + + void GateLibrarySelection::handleShowFullPath(bool checked) + { + int inx = mComboGatelib->currentIndex(); + static_cast(mComboGatelib->model())->handleShowFullPath(checked); + mComboGatelib->setCurrentIndex(inx); + } + + //----------------------------------------------- + + QVariant GateLibrarySelectionEntry::data(int column, bool fullPath) const + { + if (fullPath) + { + if (mCount<0) + return mName; + return mPath; + } + + switch(column) + { + case 0: + if (!mCount) return mName; + return QString("%1 (%2)").arg(mName).arg(mCount+1); + case 1: return mPath; + } + return QVariant(); + } + + GateLibrarySelectionTable::GateLibrarySelectionTable(bool addAutoDetect, QObject *parent) + : QAbstractTableModel(parent), mShowFullPath(false) + { + if (addAutoDetect) + mEntries.append(GateLibrarySelectionEntry("(Auto detect)", "", -1)); + QMap nameMap; + for (const std::filesystem::path& path : gate_library_manager::get_all_path()) + { + QString name = QString::fromStdString(path.filename()); + mEntries.append(GateLibrarySelectionEntry(name, QString::fromStdString(path.string()), nameMap[name]++)); + } + } + + int GateLibrarySelectionTable::columnCount(const QModelIndex& index) const + { + Q_UNUSED(index); + return 2; + } + + int GateLibrarySelectionTable::rowCount(const QModelIndex& index) const + { + Q_UNUSED(index); + return mEntries.size(); + } + + QVariant GateLibrarySelectionTable::data(const QModelIndex& index, int role) const + { + if (role != Qt::DisplayRole) return QVariant(); + if (index.row() >= mEntries.size()) return QVariant(); + return (mEntries.at(index.row()).data(index.column(),mShowFullPath)); + } + + int GateLibrarySelectionTable::addGateLibrary(const QString &path) + { + int inx = 0; + QMap nameMap; + + for (const GateLibrarySelectionEntry& glse : mEntries) + { + if (glse.path() == path) return inx; // path already in table + nameMap[glse.name()]++; + inx++; + } + + QString name = QFileInfo(path).fileName(); + beginResetModel(); + mEntries.append(GateLibrarySelectionEntry(name,path,nameMap[name]++)); + return inx; + } + + int GateLibrarySelectionTable::getIndexByPath(const QString& path) + { + // try exact path + int inx = 0; + for (const GateLibrarySelectionEntry& glse : mEntries) + { + if (glse.path() == path) return inx; + ++inx; + } + + // existing gatelib path not in list : add it + if (QFileInfo(path).exists()) + return addGateLibrary(path); + + // try name + QString name = QFileInfo(path).fileName(); + inx = 0; + for (const GateLibrarySelectionEntry& glse : mEntries) + { + if (glse.name() == name) + { + log_info("gui", "Requested gate library '{}' not found, suggest '{}' instead.", path.toStdString(), glse.path().toStdString()); + return inx; + } + ++inx; + } + + return -1; + } + + + QString GateLibrarySelectionTable::gateLibraryPath(int inx) const + { + if (inx < 0 || inx >= mEntries.size()) return QString(); + return mEntries.at(inx).path(); + } + + void GateLibrarySelectionTable::handleShowFullPath(bool checked) + { + beginResetModel(); + mShowFullPath = checked; + endResetModel(); + } +} diff --git a/src/netlist/gate_library/gate_library_manager.cpp b/src/netlist/gate_library/gate_library_manager.cpp index 7427f5dbc5c..3ea14100234 100644 --- a/src/netlist/gate_library/gate_library_manager.cpp +++ b/src/netlist/gate_library/gate_library_manager.cpp @@ -78,7 +78,7 @@ namespace hal if (!std::filesystem::exists(file_path)) { log_error("gate_library_manager", "gate library file '{}' does not exist.", file_path.string()); - netlist_serializer::last_error = netlist_serializer::GatelibFileNotFound; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::GatelibFileNotFound); return nullptr; } diff --git a/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp b/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp index 4453cad0a0e..b0002902256 100644 --- a/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp +++ b/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp @@ -81,11 +81,11 @@ namespace hal if (!factory) { if (file_path.extension().string() == ".hgl") - netlist_serializer::last_error = netlist_serializer::HglPluginNotLoaded; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::HglPluginNotLoaded); else if (file_path.extension().string() == ".lib") - netlist_serializer::last_error = netlist_serializer::LibPluginNotLoaded; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::LibPluginNotLoaded); else - netlist_serializer::last_error = netlist_serializer::OtherPluginNotLoaded; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::OtherPluginNotLoaded); return nullptr; } @@ -96,7 +96,7 @@ namespace hal if (auto res = parser->parse(file_path); res.is_error()) { log_error("gate_library_parser", "error encountered while parsing gate library from file '{}':\n{}", file_path.string(), res.get_error().get()); - netlist_serializer::last_error = netlist_serializer::GatelibParserError; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::GatelibParserError); return nullptr; } else diff --git a/src/netlist/netlist_factory.cpp b/src/netlist/netlist_factory.cpp index 23a42c2b896..b99df02cc28 100644 --- a/src/netlist/netlist_factory.cpp +++ b/src/netlist/netlist_factory.cpp @@ -18,11 +18,11 @@ namespace hal { std::unique_ptr create_netlist(const GateLibrary* gate_library) { - netlist_serializer::last_error = netlist_serializer::NoError; + netlist_serializer::Error::instance()->reset(); if (gate_library == nullptr) { log_critical("netlist", "nullptr given as gate library."); - netlist_serializer::last_error = netlist_serializer::GatelibNotProvieded; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::GatelibNotProvieded); return nullptr; } @@ -31,11 +31,11 @@ namespace hal std::unique_ptr load_netlist(const std::filesystem::path& netlist_file, const std::filesystem::path& gate_library_file) { - netlist_serializer::last_error = netlist_serializer::NoError; + netlist_serializer::Error::instance()->reset(); if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "could not access file '{}'.", netlist_file.string()); - netlist_serializer::last_error = netlist_serializer::NetlistNotAccessible; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::NetlistNotAccessible); return nullptr; } @@ -68,11 +68,11 @@ namespace hal std::unique_ptr load_hal_project(const std::filesystem::path& project_dir) { - netlist_serializer::last_error = netlist_serializer::NoError; + netlist_serializer::Error::instance()->reset(); if (!std::filesystem::is_directory(project_dir)) { log_critical("netlist", "could not access hal project '{}'.", project_dir.string()); - netlist_serializer::last_error = netlist_serializer::ProjectNotAccessible; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::ProjectNotAccessible); return nullptr; } @@ -80,7 +80,7 @@ namespace hal if (!pm->open_project(project_dir.string())) { log_critical("netlist", "could not open hal project '{}'.", project_dir.string()); - netlist_serializer::last_error = netlist_serializer::ProjectNotAccessible; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::ProjectNotAccessible); return nullptr; } @@ -90,7 +90,7 @@ namespace hal std::unique_ptr load_netlist(const ProjectDirectory& pdir, const ProgramArguments& args) { - netlist_serializer::last_error = netlist_serializer::NoError; + netlist_serializer::Error::instance()->reset(); std::filesystem::path netlist_file = args.is_option_set("--import-netlist") ? std::filesystem::path(args.get_parameter("--import-netlist")) : pdir.get_default_filename(); @@ -98,7 +98,7 @@ namespace hal if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "cannot access file '{}'.", netlist_file.string()); - netlist_serializer::last_error = netlist_serializer::NetlistNotAccessible; + netlist_serializer::Error::instance()->setError(netlist_serializer::Error::NetlistNotAccessible); return nullptr; } @@ -114,7 +114,7 @@ namespace hal std::vector> load_netlists(const std::filesystem::path& netlist_file) { - netlist_serializer::last_error = netlist_serializer::NoError; + netlist_serializer::Error::instance()->reset(); if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "could not access file '{}'.", netlist_file.string()); diff --git a/src/netlist/persistent/netlist_serializer.cpp b/src/netlist/persistent/netlist_serializer.cpp index 911897a5db7..16b9b2e3d09 100644 --- a/src/netlist/persistent/netlist_serializer.cpp +++ b/src/netlist/persistent/netlist_serializer.cpp @@ -31,6 +31,14 @@ namespace hal { namespace netlist_serializer { + Error* Error::inst = nullptr; + + Error* Error::instance() + { + if (!inst) inst = new Error; + return inst; + } + // serializing functions namespace { @@ -980,7 +988,7 @@ namespace hal std::unique_ptr deserialize_from_file(const std::filesystem::path& hal_file, GateLibrary* gatelib) { - last_error = netlist_serializer::NoError; + Error::instance()->reset(); auto begin_time = std::chrono::high_resolution_clock::now(); // event_controls::enable_all(false); @@ -989,7 +997,7 @@ namespace hal if (pFile == NULL) { log_error("netlist_persistent", "unable to open '{}'.", hal_file.string()); - last_error = NetlistNotAccessible; + Error::instance()->setError(Error::NetlistNotAccessible); return nullptr; } @@ -1002,7 +1010,7 @@ namespace hal if (document.HasParseError()) { log_error("netlist_persistent", "invalid json string for deserialization"); - last_error = NetlistJsonParseError; + Error::instance()->setError(Error::NetlistJsonParseError); return nullptr; } From 03e91995740585b1655f774e8339eab6ca8d342a Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 31 Aug 2023 10:33:49 +0200 Subject: [PATCH 48/52] Revert core changes (1) --- src/netlist/gate_library/gate_library_manager.cpp | 4 +--- .../gate_library_parser_manager.cpp | 8 -------- src/netlist/netlist_factory.cpp | 10 ---------- src/netlist/persistent/netlist_serializer.cpp | 13 +------------ 4 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/netlist/gate_library/gate_library_manager.cpp b/src/netlist/gate_library/gate_library_manager.cpp index 3ea14100234..344b8ebc447 100644 --- a/src/netlist/gate_library/gate_library_manager.cpp +++ b/src/netlist/gate_library/gate_library_manager.cpp @@ -3,7 +3,6 @@ #include "hal_core/netlist/gate_library/gate_library.h" #include "hal_core/netlist/gate_library/gate_library_parser/gate_library_parser_manager.h" #include "hal_core/netlist/gate_library/gate_library_writer/gate_library_writer_manager.h" -#include "hal_core/netlist/persistent/netlist_serializer.h" #include "hal_core/utilities/log.h" #include "hal_core/utilities/utils.h" @@ -78,7 +77,6 @@ namespace hal if (!std::filesystem::exists(file_path)) { log_error("gate_library_manager", "gate library file '{}' does not exist.", file_path.string()); - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::GatelibFileNotFound); return nullptr; } @@ -230,4 +228,4 @@ namespace hal return res; } } // namespace gate_library_manager -} // namespace hal +} // namespace hal \ No newline at end of file diff --git a/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp b/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp index b0002902256..e0733518b5f 100644 --- a/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp +++ b/src/netlist/gate_library/gate_library_parser/gate_library_parser_manager.cpp @@ -2,7 +2,6 @@ #include "hal_core/netlist/gate_library/gate_library.h" #include "hal_core/netlist/gate_library/gate_library_parser/gate_library_parser.h" -#include "hal_core/netlist/persistent/netlist_serializer.h" #include "hal_core/plugin_system/plugin_manager.h" #include "hal_core/utilities/log.h" #include "hal_core/utilities/utils.h" @@ -80,12 +79,6 @@ namespace hal auto factory = get_parser_factory_for_file(file_path); if (!factory) { - if (file_path.extension().string() == ".hgl") - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::HglPluginNotLoaded); - else if (file_path.extension().string() == ".lib") - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::LibPluginNotLoaded); - else - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::OtherPluginNotLoaded); return nullptr; } @@ -96,7 +89,6 @@ namespace hal if (auto res = parser->parse(file_path); res.is_error()) { log_error("gate_library_parser", "error encountered while parsing gate library from file '{}':\n{}", file_path.string(), res.get_error().get()); - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::GatelibParserError); return nullptr; } else diff --git a/src/netlist/netlist_factory.cpp b/src/netlist/netlist_factory.cpp index b99df02cc28..a929d0fa6b7 100644 --- a/src/netlist/netlist_factory.cpp +++ b/src/netlist/netlist_factory.cpp @@ -18,11 +18,9 @@ namespace hal { std::unique_ptr create_netlist(const GateLibrary* gate_library) { - netlist_serializer::Error::instance()->reset(); if (gate_library == nullptr) { log_critical("netlist", "nullptr given as gate library."); - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::GatelibNotProvieded); return nullptr; } @@ -31,11 +29,9 @@ namespace hal std::unique_ptr load_netlist(const std::filesystem::path& netlist_file, const std::filesystem::path& gate_library_file) { - netlist_serializer::Error::instance()->reset(); if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "could not access file '{}'.", netlist_file.string()); - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::NetlistNotAccessible); return nullptr; } @@ -68,11 +64,9 @@ namespace hal std::unique_ptr load_hal_project(const std::filesystem::path& project_dir) { - netlist_serializer::Error::instance()->reset(); if (!std::filesystem::is_directory(project_dir)) { log_critical("netlist", "could not access hal project '{}'.", project_dir.string()); - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::ProjectNotAccessible); return nullptr; } @@ -80,7 +74,6 @@ namespace hal if (!pm->open_project(project_dir.string())) { log_critical("netlist", "could not open hal project '{}'.", project_dir.string()); - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::ProjectNotAccessible); return nullptr; } @@ -90,7 +83,6 @@ namespace hal std::unique_ptr load_netlist(const ProjectDirectory& pdir, const ProgramArguments& args) { - netlist_serializer::Error::instance()->reset(); std::filesystem::path netlist_file = args.is_option_set("--import-netlist") ? std::filesystem::path(args.get_parameter("--import-netlist")) : pdir.get_default_filename(); @@ -98,7 +90,6 @@ namespace hal if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "cannot access file '{}'.", netlist_file.string()); - netlist_serializer::Error::instance()->setError(netlist_serializer::Error::NetlistNotAccessible); return nullptr; } @@ -114,7 +105,6 @@ namespace hal std::vector> load_netlists(const std::filesystem::path& netlist_file) { - netlist_serializer::Error::instance()->reset(); if (access(netlist_file.c_str(), F_OK | R_OK) == -1) { log_critical("netlist", "could not access file '{}'.", netlist_file.string()); diff --git a/src/netlist/persistent/netlist_serializer.cpp b/src/netlist/persistent/netlist_serializer.cpp index 16b9b2e3d09..52d3b12f77c 100644 --- a/src/netlist/persistent/netlist_serializer.cpp +++ b/src/netlist/persistent/netlist_serializer.cpp @@ -31,14 +31,6 @@ namespace hal { namespace netlist_serializer { - Error* Error::inst = nullptr; - - Error* Error::instance() - { - if (!inst) inst = new Error; - return inst; - } - // serializing functions namespace { @@ -988,7 +980,6 @@ namespace hal std::unique_ptr deserialize_from_file(const std::filesystem::path& hal_file, GateLibrary* gatelib) { - Error::instance()->reset(); auto begin_time = std::chrono::high_resolution_clock::now(); // event_controls::enable_all(false); @@ -997,7 +988,6 @@ namespace hal if (pFile == NULL) { log_error("netlist_persistent", "unable to open '{}'.", hal_file.string()); - Error::instance()->setError(Error::NetlistNotAccessible); return nullptr; } @@ -1010,7 +1000,6 @@ namespace hal if (document.HasParseError()) { log_error("netlist_persistent", "invalid json string for deserialization"); - Error::instance()->setError(Error::NetlistJsonParseError); return nullptr; } @@ -1044,4 +1033,4 @@ namespace hal } // namespace netlist_serializer } // namespace hal -#undef DURATION +#undef DURATION \ No newline at end of file From 8390680a94411e81a1baaabc6f6142469a2e30a4 Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 31 Aug 2023 20:37:19 +0200 Subject: [PATCH 49/52] Warning message if gate library referenced by HAL file not found --- CHANGELOG.md | 1 + .../netlist/persistent/netlist_serializer.h | 26 +----------- .../gatelibrary_selection.h | 14 ++++++- plugins/gui/resources/stylesheet/dark.qss | 16 ++++++++ plugins/gui/resources/stylesheet/light.qss | 16 ++++++++ plugins/gui/src/file_manager/file_manager.cpp | 22 ++-------- .../file_manager/import_netlist_dialog.cpp | 1 - .../gatelibrary_selection.cpp | 41 ++++++++++++++++--- 8 files changed, 85 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f52c0631c1c..68eb10d7e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. * added `Show content` button to `Groupings` widget to show content of grouping as a list * added flag which python editor tab is active when serializing project * added `GateType::delete_pin_group` and `GateType::assign_pin_to_group` to enable more operations on pin groups of gate pins + * added extended gate library picker when importing a netlist * changed supported input file formats for import from hard coded list to list provided by loadable parser plugins * changed behavior of import netlist dialog, suggest only non-existing directory names and loop until an acceptable name was entered * changed appearance and behavior of import project dialog, make sure existing hal projects don't get overwritten diff --git a/include/hal_core/netlist/persistent/netlist_serializer.h b/include/hal_core/netlist/persistent/netlist_serializer.h index 0fb5d5f3442..9f1edf5aebd 100644 --- a/include/hal_core/netlist/persistent/netlist_serializer.h +++ b/include/hal_core/netlist/persistent/netlist_serializer.h @@ -43,30 +43,6 @@ namespace hal namespace netlist_serializer { - class Error - { - public: - enum ErrorCode { NoError, - ProjectNotAccessible, - NetlistNotAccessible, - NetlistJsonParseError, - GatelibNotProvieded, - GatelibFileNotFound, - GatelibParserError, - HglPluginNotLoaded, - LibPluginNotLoaded, - OtherPluginNotLoaded, - }; - private: - static Error* inst; - ErrorCode mCode; - Error() : mCode(NoError) {;} - public: - ErrorCode code() const { return mCode; } - void setError(ErrorCode ec) { mCode = ec; } - void reset() { mCode = NoError; } - static Error* instance(); - }; /** * Serializes a netlist into a `.hal` file. @@ -87,4 +63,4 @@ namespace hal */ NETLIST_API std::unique_ptr deserialize_from_file(const std::filesystem::path& hal_file, GateLibrary* gate_lib = nullptr); } // namespace netlist_serializer -} // namespace hal +} // namespace hal \ No newline at end of file diff --git a/plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h b/plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h index 6f6a18cbabb..a16c2d0f422 100644 --- a/plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h +++ b/plugins/gui/include/gui/gatelibrary_management/gatelibrary_selection.h @@ -26,6 +26,7 @@ #pragma once #include +#include #include #include @@ -52,6 +53,7 @@ namespace hal { Q_OBJECT QList mEntries; bool mShowFullPath; + bool mWarnSubstitute; public: GateLibrarySelectionTable(bool addAutoDetect, QObject* parent = nullptr); int columnCount(const QModelIndex& index = QModelIndex()) const override; @@ -61,23 +63,33 @@ namespace hal { int addGateLibrary(const QString& path); QString gateLibraryPath(int inx) const; int getIndexByPath(const QString& path); + bool isWarnSubstitute() const { return mWarnSubstitute; } }; class GateLibrarySelection : public QFrame { Q_OBJECT + Q_PROPERTY(QString saveIconPath READ saveIconPath WRITE setSaveIconPath) + Q_PROPERTY(QString saveIconStyle READ saveIconStyle WRITE setSaveIconStyle) QComboBox* mComboGatelib; QPushButton* mInvokeFileDialog; + QLabel* mWarningMsg; QCheckBox* mCheckFullPath; + QString mSaveIconPath; + QString mSaveIconStyle; Q_SIGNALS: void gatelibSelected(bool singleFile); private Q_SLOTS: + void handleGatelibIndexChanged(int inx); void handleInvokeFileDialog(); void handleShowFullPath(bool checked); public: GateLibrarySelection(const QString& defaultGl, QWidget* parent = nullptr); QString gateLibraryPath() const; - void setIcon(const QString& path, const QString& style); void setCurrent(const QString& glPath); + QString saveIconPath() const { return mSaveIconPath; } + QString saveIconStyle() const { return mSaveIconStyle; } + void setSaveIconPath(const QString& path) { mSaveIconPath = path; } + void setSaveIconStyle(const QString& sty) { mSaveIconStyle = sty; } }; } diff --git a/plugins/gui/resources/stylesheet/dark.qss b/plugins/gui/resources/stylesheet/dark.qss index a6e56ff8697..4cbe8ff2d47 100755 --- a/plugins/gui/resources/stylesheet/dark.qss +++ b/plugins/gui/resources/stylesheet/dark.qss @@ -884,6 +884,22 @@ hal--OpenFileWidget #icon-label margin-top : 220px; } +hal--GateLibrarySelection +{ + qproperty-saveIconStyle: "all->#3192C5"; + qproperty-saveIconPath: ":/icons/folder-down"; +} + +hal--GateLibrarySelection QLabel +{ + background: #171e22; +} + +hal--GateLibrarySelection QLabel#warningMsg +{ + color: yellow; +} + hal--ImportNetlistDialog { qproperty-saveIconStyle: "all->#3192C5"; diff --git a/plugins/gui/resources/stylesheet/light.qss b/plugins/gui/resources/stylesheet/light.qss index 1114a058322..ce3511af89b 100755 --- a/plugins/gui/resources/stylesheet/light.qss +++ b/plugins/gui/resources/stylesheet/light.qss @@ -911,6 +911,22 @@ hal--OpenFileWidget #icon-label margin-top : 220px; } +hal--GateLibrarySelection +{ + qproperty-saveIconStyle: "all->#3192C5"; + qproperty-saveIconPath: ":/icons/folder-down"; +} + +hal--GateLibrarySelection QLabel +{ + background: white; +} + +hal--GateLibrarySelection QLabel#warningMsg +{ + color: darkred; +} + hal--ImportNetlistDialog { qproperty-saveIconStyle: "all->#3192C5"; diff --git a/plugins/gui/src/file_manager/file_manager.cpp b/plugins/gui/src/file_manager/file_manager.cpp index 33b7641bf40..ec3ccffee68 100644 --- a/plugins/gui/src/file_manager/file_manager.cpp +++ b/plugins/gui/src/file_manager/file_manager.cpp @@ -494,6 +494,9 @@ namespace hal { QString logical_file_name = filename; + QString glSuffix = QFileInfo(gatelibraryPath).suffix(); + gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,"."+glSuffix); + if (gNetlist) { // ADD ERROR MESSAGE @@ -537,25 +540,6 @@ namespace hal } else { - bool tryAgain = false; - - netlist_serializer::Error::ErrorCode errCode = netlist_serializer::Error::instance()->code(); - if (++errorCount[errCode] < 3) - { - switch (errCode) - { - case netlist_serializer::Error::HglPluginNotLoaded: - gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,".hgl"); - tryAgain = true; - case netlist_serializer::Error::LibPluginNotLoaded: - gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,".hgl"); - tryAgain = true; - default: - break; - } - } - if (tryAgain) continue; - std::string error_message("Failed to create netlist from .hal file"); log_error("gui", "{}", error_message); displayErrorMessage(QString::fromStdString(error_message)); diff --git a/plugins/gui/src/file_manager/import_netlist_dialog.cpp b/plugins/gui/src/file_manager/import_netlist_dialog.cpp index 3a94cd95f78..921d02cdd50 100644 --- a/plugins/gui/src/file_manager/import_netlist_dialog.cpp +++ b/plugins/gui/src/file_manager/import_netlist_dialog.cpp @@ -64,7 +64,6 @@ namespace hal layout->addItem(new QSpacerItem(30, 30), irow++, 0); mGatelibSelection = new GateLibrarySelection(gatelibFromHal, this); - mGatelibSelection->setIcon(mSaveIconPath, mSaveIconStyle); layout->addWidget(mGatelibSelection, irow++, 0); //mGatelibSelection->setDisabled(filename.endsWith(".hal")); diff --git a/plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp b/plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp index fc38a0f22de..bb2d3f20a9f 100644 --- a/plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp +++ b/plugins/gui/src/gatelibrary_management/gatelibrary_selection.cpp @@ -17,6 +17,10 @@ namespace hal { GateLibrarySelection::GateLibrarySelection(const QString &defaultGl, QWidget* parent) : QFrame(parent) { + QStyle* s = style(); + s->unpolish(this); + s->polish(this); + QVBoxLayout* vlayout = new QVBoxLayout(this); QLabel* labGatelib = new QLabel("Gate library:", this); vlayout->addWidget(labGatelib); @@ -31,25 +35,48 @@ namespace hal { mComboGatelib->setModel(glTable); mComboGatelib->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + hlayout->addWidget(mComboGatelib); - int inx = glTable->getIndexByPath(defaultGl); - if (inx >= 0) mComboGatelib->setCurrentIndex(inx); + mWarningMsg = new QLabel(this); + mWarningMsg->setObjectName("warningMsg"); + if (!defaultGl.isEmpty()) + { + int inx = glTable->getIndexByPath(defaultGl); + if (inx < 0) + { + mWarningMsg->setText("Gate library '" + defaultGl + "' not found,\nplease select gate library from list."); + } + else + { + mComboGatelib->setCurrentIndex(inx); + if (glTable->isWarnSubstitute()) + mWarningMsg->setText("Gate library '" + defaultGl + "' not found,\na substitute has been suggested."); + } + } + - mInvokeFileDialog = new QPushButton(this); + mInvokeFileDialog = new QPushButton(gui_utility::getStyledSvgIcon(mSaveIconStyle, mSaveIconPath),"",this); connect(mInvokeFileDialog, &QPushButton::clicked, this, &GateLibrarySelection::handleInvokeFileDialog); hlayout->addWidget(mInvokeFileDialog); vlayout->addLayout(hlayout); + vlayout->addWidget(mWarningMsg); + if (mWarningMsg->text().isEmpty()) + mWarningMsg->hide(); + mCheckFullPath = new QCheckBox("Show full path"); mCheckFullPath->setChecked(false); connect(mCheckFullPath,&QCheckBox::toggled,this,&GateLibrarySelection::handleShowFullPath); vlayout->addWidget(mCheckFullPath); + connect(mComboGatelib,QOverload::of(&QComboBox::currentIndexChanged),this,&GateLibrarySelection::handleGatelibIndexChanged); } - void GateLibrarySelection::setIcon(const QString &path, const QString &style) + void GateLibrarySelection::handleGatelibIndexChanged(int inx) { - mInvokeFileDialog->setIcon(gui_utility::getStyledSvgIcon(style, path)); + Q_UNUSED(inx); + mWarningMsg->clear(); + mWarningMsg->hide(); } void GateLibrarySelection::handleInvokeFileDialog() @@ -95,7 +122,7 @@ namespace hal { } GateLibrarySelectionTable::GateLibrarySelectionTable(bool addAutoDetect, QObject *parent) - : QAbstractTableModel(parent), mShowFullPath(false) + : QAbstractTableModel(parent), mShowFullPath(false), mWarnSubstitute(false) { if (addAutoDetect) mEntries.append(GateLibrarySelectionEntry("(Auto detect)", "", -1)); @@ -168,11 +195,13 @@ namespace hal { if (glse.name() == name) { log_info("gui", "Requested gate library '{}' not found, suggest '{}' instead.", path.toStdString(), glse.path().toStdString()); + mWarnSubstitute = true; return inx; } ++inx; } + log_info("gui", "Requested gate library '{}' not found.", path.toStdString()); return -1; } From b50b43da81f04e42c37b4878df3bb9adfd95b38e Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 1 Sep 2023 11:12:07 +0200 Subject: [PATCH 50/52] Test function for new GUI API removed --- .../gui/include/gui/main_window/main_window.h | 2 -- plugins/gui/src/main_window/main_window.cpp | 26 ------------------- 2 files changed, 28 deletions(-) diff --git a/plugins/gui/include/gui/main_window/main_window.h b/plugins/gui/include/gui/main_window/main_window.h index 5ee0f0754b3..667af66a91a 100644 --- a/plugins/gui/include/gui/main_window/main_window.h +++ b/plugins/gui/include/gui/main_window/main_window.h @@ -565,8 +565,6 @@ namespace hal void handleImportProjectTriggered(); - int isolateInNewView(const std::vector, const std::vector); - private: /** * Overwritten Qt function to handle the close event. diff --git a/plugins/gui/src/main_window/main_window.cpp b/plugins/gui/src/main_window/main_window.cpp index 621c68105d9..715882ade95 100644 --- a/plugins/gui/src/main_window/main_window.cpp +++ b/plugins/gui/src/main_window/main_window.cpp @@ -265,11 +265,6 @@ namespace hal mMenuHelp->addAction(mActionAbout); mMenuHelp->addSeparator(); mMenuHelp->addAction(mActionPlugins); - mMenuHelp->addAction("Test developed function", [this] () { - std::vector modules; - std::vector gates; - isolateInNewView(modules, gates); - }); mLeftToolBar->addAction(mActionNew); mLeftToolBar->addAction(mActionOpenProject); mLeftToolBar->addAction(mActionSave); @@ -1082,25 +1077,4 @@ namespace hal SettingsManager::instance()->mainWindowSaveGeometry(pos(), size()); } - int MainWindow::isolateInNewView(std::vector modules, std::vector gates) - { - - //Creating modules for testing purposes - modules.push_back(gNetlist->get_module_by_id(4)); - modules.push_back(gNetlist->get_module_by_id(2)); - modules.push_back(gNetlist->get_module_by_id(1)); - - gates.push_back(gNetlist->get_gate_by_id(10)); - gates.push_back(gNetlist->get_gate_by_id(2)); - gates.push_back(gNetlist->get_gate_by_id(1)); - - - qInfo() << "Test action isolateInNewView was called"; - //Create a new view which contains the given Modules and Gates - - //return GuiApi().isolateInNewView(modules, gates); - return GuiApiClasses::View::isolateInNew(modules, gates); - - - } } // namespace hal From 77614ece692a521883b488c6f6fbc566fbad21da Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 12 Sep 2023 10:16:31 +0200 Subject: [PATCH 51/52] added GUI PluginParameter types 'Module' and 'Gated' for parameters that can be requested from plugin --- CHANGELOG.md | 1 + .../hal_core/plugin_system/plugin_parameter.h | 2 +- .../gui/main_window/plugin_parameter_dialog.h | 24 ++++ .../main_window/plugin_parameter_dialog.cpp | 117 ++++++++++++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68eb10d7e54..dd0aefd1bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] * miscellaneous + * added GUI PluginParameter types 'Module' and 'Gated' for parameters that can be requested from plugin * added `Show content` button to `Groupings` widget to show content of grouping as a list * added flag which python editor tab is active when serializing project * added `GateType::delete_pin_group` and `GateType::assign_pin_to_group` to enable more operations on pin groups of gate pins diff --git a/include/hal_core/plugin_system/plugin_parameter.h b/include/hal_core/plugin_system/plugin_parameter.h index eb79bd9b304..21f1a3f29e7 100644 --- a/include/hal_core/plugin_system/plugin_parameter.h +++ b/include/hal_core/plugin_system/plugin_parameter.h @@ -32,7 +32,7 @@ namespace hal class PluginParameter { public: - enum ParameterType { Absent, Boolean, Color, Dictionary, ExistingDir, Float, Integer, NewFile, PushButton, String, TabName }; + enum ParameterType { Absent, Boolean, Color, Dictionary, ExistingDir, Float, Gate, Integer, Module, NewFile, PushButton, String, TabName }; private: ParameterType m_type; std::string m_tagname; diff --git a/plugins/gui/include/gui/main_window/plugin_parameter_dialog.h b/plugins/gui/include/gui/main_window/plugin_parameter_dialog.h index 110335790b1..d4374690646 100644 --- a/plugins/gui/include/gui/main_window/plugin_parameter_dialog.h +++ b/plugins/gui/include/gui/main_window/plugin_parameter_dialog.h @@ -30,11 +30,14 @@ #include "hal_core/plugin_system/gui_extension_interface.h" #include #include +#include class QFormLayout; class QDialogButtonBox; class QPushButton; class QLineEdit; +class QSpinBox; +class QLabel; namespace hal { @@ -55,6 +58,27 @@ namespace hal { QString getFilename() const; }; + class PluginParameterNodeDialog : public QWidget + { + Q_OBJECT + + PluginParameter mParameter; + QPushButton* mButton; + QSpinBox* mNodeId; + QLabel* mNodeName; + std::set mValidIds; + private Q_SLOTS: + void handleActivateModuleDialog(); + void handleActivateGateDialog(); + private: + void setModule(int id); + void setGate(int id); + bool isValidId(int id) const; + public: + PluginParameterNodeDialog(const PluginParameter& par, QWidget* parent = nullptr); + int getNodeId() const; + }; + class PluginParameterDialog : public QDialog { Q_OBJECT diff --git a/plugins/gui/src/main_window/plugin_parameter_dialog.cpp b/plugins/gui/src/main_window/plugin_parameter_dialog.cpp index 08d30b7e00e..f9bc2cdc7f4 100644 --- a/plugins/gui/src/main_window/plugin_parameter_dialog.cpp +++ b/plugins/gui/src/main_window/plugin_parameter_dialog.cpp @@ -1,6 +1,8 @@ #include "gui/main_window/plugin_parameter_dialog.h" #include "hal_core/plugin_system/plugin_interface_base.h" #include "hal_core/plugin_system/gui_extension_interface.h" +#include "gui/module_dialog/module_dialog.h" +#include "gui/module_dialog/gate_dialog.h" #include "gui/main_window/color_selection.h" #include "gui/main_window/key_value_table.h" #include "gui/gui_utils/graphics.h" @@ -140,6 +142,12 @@ namespace hal { case PluginParameter::NewFile: mWidgetMap[parTagname] = new PluginParameterFileDialog(par,this); break; + case PluginParameter::Module: + mWidgetMap[parTagname] = new PluginParameterNodeDialog(par,this); + break; + case PluginParameter::Gate: + mWidgetMap[parTagname] = new PluginParameterNodeDialog(par,this); + break; default: break; } @@ -242,6 +250,13 @@ namespace hal { par.set_value(fileDlg->getFilename().toStdString()); break; } + case PluginParameter::Gate: + case PluginParameter::Module: + { + const PluginParameterNodeDialog* nodeDlg = static_cast(w); + par.set_value(QString::number(nodeDlg->getNodeId()).toStdString()); + break; + } default: continue; break; @@ -309,4 +324,106 @@ namespace hal { { return mEditor->text(); } + + PluginParameterNodeDialog::PluginParameterNodeDialog(const PluginParameter& par, QWidget* parent) + : QWidget(parent), mParameter(par) + { + QGridLayout* layout = new QGridLayout(this); + mNodeId = new QSpinBox(this); + mNodeId->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred); + layout->addWidget(mNodeId,0,0); + mNodeName = new QLabel(this); + mNodeName->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred); + mNodeName->setMinimumWidth(280); + layout->addWidget(mNodeName,0,1); + + mButton = new QPushButton("",this); + + u32 defaultId = QString::fromStdString(mParameter.get_value()).toUInt(); + mNodeId->setValue(defaultId); + + QString iconPath; + switch (mParameter.get_type()) { + case PluginParameter::Module: + iconPath = ":/icons/ne_module"; + setModule(defaultId); + connect(mButton,&QPushButton::clicked,this,&PluginParameterNodeDialog::handleActivateModuleDialog); + connect(mNodeId,static_cast(&QSpinBox::valueChanged),this,&PluginParameterNodeDialog::setModule); + mValidIds = gNetlist->get_used_module_ids(); + break; + case PluginParameter::Gate: + iconPath = ":/icons/ne_gate"; + setGate(defaultId); + connect(mButton,&QPushButton::clicked,this,&PluginParameterNodeDialog::handleActivateGateDialog); + connect(mNodeId,static_cast(&QSpinBox::valueChanged),this,&PluginParameterNodeDialog::setGate); + mValidIds = gNetlist->get_used_gate_ids(); + break; + default: + Q_ASSERT(1==0); // widget must not be created if parameter type not module or gate + break; + } + + u32 maxValue = 0; + for (u32 id : mValidIds) + if (id > maxValue) + maxValue = id; + mNodeId->setMaximum(maxValue); + if (defaultId > maxValue) + mNodeId->setValue(0); + mButton->setIcon(gui_utility::getStyledSvgIcon("all->#F0F0F1",iconPath)); + mButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred); + layout->addWidget(mButton,0,2); + } + + void PluginParameterNodeDialog::setGate(int id) + { + if (!id || !isValidId(id)) + { + mNodeName->setText("(no gate selected)"); + return; + } + Gate* g = gNetlist->get_gate_by_id(id); + if (g) mNodeName->setText(QString::fromStdString(g->get_name())); + } + + void PluginParameterNodeDialog::setModule(int id) + { + if (!id || !isValidId(id)) + { + mNodeName->setText("(no module selected)"); + return; + } + Module* m = gNetlist->get_module_by_id(id); + if (m) mNodeName->setText(QString::fromStdString(m->get_name())); + } + + bool PluginParameterNodeDialog::isValidId(int id) const + { + return (mValidIds.find(id)!=mValidIds.end()); + } + + void PluginParameterNodeDialog::handleActivateModuleDialog() + { + ModuleDialog md({}, "Select module", nullptr, this); + if (md.exec() == QDialog::Accepted) + { + setModule(md.selectedId()); + mNodeId->setValue(md.selectedId()); + } + } + + void PluginParameterNodeDialog::handleActivateGateDialog() + { + GateDialog gd({}, "Select gate", nullptr, this); + if (gd.exec() == QDialog::Accepted) + { + setGate(gd.selectedId()); + mNodeId->setValue(gd.selectedId()); + } + } + + int PluginParameterNodeDialog::getNodeId() const + { + return mNodeId->value(); + } } From 81b8107c786862308ac74e19b0fb5fc1ac8a3a5f Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 15 Sep 2023 13:14:28 +0200 Subject: [PATCH 52/52] added GUI PluginParameter type 'ComboBox' for parameters that can be requested from plugin --- CHANGELOG.md | 1 + include/hal_core/plugin_system/plugin_parameter.h | 2 +- .../src/main_window/plugin_parameter_dialog.cpp | 15 +++++++++++++++ .../gui_extension_demo/python/python_bindings.cpp | 3 +++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd0aefd1bb4..435e774d4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] * miscellaneous + * added GUI PluginParameter type 'ComboBox' for parameters that can be requested from plugin * added GUI PluginParameter types 'Module' and 'Gated' for parameters that can be requested from plugin * added `Show content` button to `Groupings` widget to show content of grouping as a list * added flag which python editor tab is active when serializing project diff --git a/include/hal_core/plugin_system/plugin_parameter.h b/include/hal_core/plugin_system/plugin_parameter.h index 21f1a3f29e7..60d54da14cd 100644 --- a/include/hal_core/plugin_system/plugin_parameter.h +++ b/include/hal_core/plugin_system/plugin_parameter.h @@ -32,7 +32,7 @@ namespace hal class PluginParameter { public: - enum ParameterType { Absent, Boolean, Color, Dictionary, ExistingDir, Float, Gate, Integer, Module, NewFile, PushButton, String, TabName }; + enum ParameterType { Absent, Boolean, Color, ComboBox, Dictionary, ExistingDir, Float, Gate, Integer, Module, NewFile, PushButton, String, TabName }; private: ParameterType m_type; std::string m_tagname; diff --git a/plugins/gui/src/main_window/plugin_parameter_dialog.cpp b/plugins/gui/src/main_window/plugin_parameter_dialog.cpp index f9bc2cdc7f4..b5c9c05544d 100644 --- a/plugins/gui/src/main_window/plugin_parameter_dialog.cpp +++ b/plugins/gui/src/main_window/plugin_parameter_dialog.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace hal { PluginParameterDialog::PluginParameterDialog(const QString &pname, GuiExtensionInterface *geif, QWidget* parent) @@ -148,6 +149,14 @@ namespace hal { case PluginParameter::Gate: mWidgetMap[parTagname] = new PluginParameterNodeDialog(par,this); break; + case PluginParameter::ComboBox: + { + QComboBox* cbox = new QComboBox(this); + cbox->insertItems(0,QString::fromStdString(par.get_value()).split(';')); + if (!par.get_value().empty()) cbox->setCurrentIndex(0); + mWidgetMap[parTagname] = cbox; + break; + } default: break; } @@ -257,6 +266,12 @@ namespace hal { par.set_value(QString::number(nodeDlg->getNodeId()).toStdString()); break; } + case PluginParameter::ComboBox: + { + const QComboBox* cbox = static_cast(w); + par.set_value(cbox->currentText().toStdString()); + break; + } default: continue; break; diff --git a/plugins/gui_extension_demo/python/python_bindings.cpp b/plugins/gui_extension_demo/python/python_bindings.cpp index ee96e1e7d3d..41ab6935f64 100644 --- a/plugins/gui_extension_demo/python/python_bindings.cpp +++ b/plugins/gui_extension_demo/python/python_bindings.cpp @@ -51,10 +51,13 @@ namespace hal .value("Absent", PluginParameter::Absent, R"(Indicate not used.)") .value("Boolean", PluginParameter::Boolean, R"('true' or 'false'.)") .value("Color", PluginParameter::Color, R"(Color value like '#ffe080'.)") + .value("ComboBox", PluginParameter::ComboBox, R"(Combo box to select string from semicolon separated input list.)") .value("Dictionary", PluginParameter::Dictionary, R"(Key value pairs (string).)") .value("ExistingDir", PluginParameter::ExistingDir, R"(Existing directory.)") .value("Float", PluginParameter::Float, R"(Floating point number.)") + .value("Gate", PluginParameter::Gate, R"(Gate ID.)") .value("Integer", PluginParameter::Integer, R"(Integer number.)") + .value("Module", PluginParameter::Gate, R"(Module ID.)") .value("NewFile", PluginParameter::NewFile, R"(New file name.)") .value("PushButton", PluginParameter::PushButton, R"(Push Button.)") .value("String", PluginParameter::String, R"(String value.)")