diff --git a/src/Gui/WorkbenchManipulatorPython.cpp b/src/Gui/WorkbenchManipulatorPython.cpp
index dc5c61895e..b85b49c99a 100644
--- a/src/Gui/WorkbenchManipulatorPython.cpp
+++ b/src/Gui/WorkbenchManipulatorPython.cpp
@@ -24,6 +24,8 @@
#include "PreCompiled.h"
#include "WorkbenchManipulatorPython.h"
+#include "MenuManager.h"
+#include "ToolBarManager.h"
#include
using namespace Gui;
@@ -57,15 +59,30 @@ WorkbenchManipulatorPython::~WorkbenchManipulatorPython()
object = Py::None();
}
-void WorkbenchManipulatorPython::modifyMenuBar([[maybe_unused]] MenuItem* menuBar)
+/*!
+ * \brief WorkbenchManipulatorPython::modifyMenuBar
+ * \param menuBar
+ * The Python manipulator can be implemented as
+ * \code
+ * class Manipulator:
+ * def modifyMenuBar(self):
+ * return [{"remove" : "Std_Quit"},
+ * {"append" : "Std_About", "menuItem" : "Std_DlgMacroRecord"},
+ * {"insert" : "Std_About", "menuItem" : "Std_DlgParameter"}
+ * {"insert" : "Std_Windows", "menuItem" : "Std_DlgParameter", "after" : ""}]
+ *
+ * manip = Manipulator()
+ * Gui.addWorkbenchManipulator(manip)
+ * \endcode
+ * This manipulator removes the Std_Quit command, appends the Std_About command
+ * to the Macro menu, inserts it to the Tools menu before the Std_DlgParameter
+ * and adds the Std_Windows after the Std_DlgParameter command.
+ */
+void WorkbenchManipulatorPython::modifyMenuBar(MenuItem* menuBar)
{
Base::PyGILStateLocker lock;
try {
- if (object.hasAttr(std::string("modifyMenuBar"))) {
- Py::Callable method(object.getAttr(std::string("modifyMenuBar")));
- Py::Tuple args(1);
- method.apply(args);
- }
+ tryModifyMenuBar(menuBar);
}
catch (Py::Exception&) {
Base::PyException exc; // extract the Python error text
@@ -73,17 +90,99 @@ void WorkbenchManipulatorPython::modifyMenuBar([[maybe_unused]] MenuItem* menuBa
}
}
-void WorkbenchManipulatorPython::modifyContextMenu([[maybe_unused]] const char* recipient,
- [[maybe_unused]] MenuItem* menuBar)
+void WorkbenchManipulatorPython::tryModifyMenuBar(MenuItem* menuBar)
+{
+ if (object.hasAttr(std::string("modifyMenuBar"))) {
+ Py::Callable method(object.getAttr(std::string("modifyMenuBar")));
+ Py::Tuple args;
+ Py::Object result = method.apply(args);
+ if (result.isDict()) {
+ tryModifyMenuBar(Py::Dict(result), menuBar);
+ }
+ else if (result.isSequence()) {
+ Py::Sequence list(result);
+ for (const auto& it : list) {
+ if (it.isDict()) {
+ tryModifyMenuBar(Py::Dict(it), menuBar);
+ }
+ }
+ }
+ }
+}
+
+// NOLINTNEXTLINE
+void WorkbenchManipulatorPython::tryModifyMenuBar(const Py::Dict& dict, MenuItem* menuBar)
+{
+ std::string insert("insert");
+ std::string append("append");
+ std::string remove("remove");
+
+ // insert a new command
+ if (dict.hasKey(insert)) {
+ std::string command = static_cast(Py::String(dict.getItem(insert)));
+ std::string itemName = static_cast(Py::String(dict.getItem("menuItem")));
+ bool after = dict.hasKey(std::string("after"));
+
+ if (auto par = menuBar->findParentOf(itemName)) {
+ if (MenuItem* item = par->findItem(itemName)) {
+ if (after) {
+ item = par->afterItem(item);
+ }
+
+ if (item) {
+ auto add = new MenuItem(); // NOLINT
+ add->setCommand(command);
+ par->insertItem(item, add);
+ }
+ }
+ }
+ }
+ // append a command
+ else if (dict.hasKey(append)) {
+ std::string command = static_cast(Py::String(dict.getItem(append)));
+ std::string itemName = static_cast(Py::String(dict.getItem("menuItem")));
+
+ if (auto par = menuBar->findParentOf(itemName)) {
+ auto add = new MenuItem(); // NOLINT
+ add->setCommand(command);
+ par->appendItem(add);
+ }
+ }
+ // remove a command
+ else if (dict.hasKey(remove)) {
+ std::string command = static_cast(Py::String(dict.getItem(remove)));
+ if (auto par = menuBar->findParentOf(command)) {
+ if (MenuItem* item = par->findItem(command)) {
+ par->removeItem(item);
+ delete item; // NOLINT
+ }
+ }
+
+ }
+}
+
+/*!
+ * \brief WorkbenchManipulatorPython::modifyContextMenu
+ * \param menuBar
+ * The Python manipulator can be implemented as
+ * \code
+ * class Manipulator:
+ * def modifyContextMenu(self, recipient):
+ * if recipient == "View":
+ * return [{"remove" : "Standard views"},
+ * {"insert" : "Std_Windows", "menuItem" : "View_Measure_Toggle_All"}]
+ *
+ * manip = Manipulator()
+ * Gui.addWorkbenchManipulator(manip)
+ * \endcode
+ * This manipulator removes the "Standard views sub-menu and
+ * adds the Std_Windows before the View_Measure_Toggle_All command.
+ */
+void WorkbenchManipulatorPython::modifyContextMenu(const char* recipient, MenuItem* menuBar)
{
Base::PyGILStateLocker lock;
try {
- if (object.hasAttr(std::string("modifyContextMenu"))) {
- Py::Callable method(object.getAttr(std::string("modifyContextMenu")));
- Py::Tuple args(2);
- args.setItem(0, Py::String(recipient));
- method.apply(args);
- }
+ tryModifyContextMenu(recipient, menuBar);
}
catch (Py::Exception&) {
Base::PyException exc; // extract the Python error text
@@ -91,15 +190,37 @@ void WorkbenchManipulatorPython::modifyContextMenu([[maybe_unused]] const char*
}
}
-void WorkbenchManipulatorPython::modifyToolBars([[maybe_unused]] ToolBarItem* toolBar)
+void WorkbenchManipulatorPython::tryModifyContextMenu(const char* recipient, MenuItem* menuBar)
+{
+ if (object.hasAttr(std::string("modifyContextMenu"))) {
+ Py::Callable method(object.getAttr(std::string("modifyContextMenu")));
+ Py::Tuple args(1);
+ args.setItem(0, Py::String(recipient));
+ Py::Object result = method.apply(args);
+ if (result.isDict()) {
+ tryModifyContextMenu(Py::Dict(result), menuBar);
+ }
+ else if (result.isSequence()) {
+ Py::Sequence list(result);
+ for (const auto& it : list) {
+ if (it.isDict()) {
+ tryModifyContextMenu(Py::Dict(it), menuBar);
+ }
+ }
+ }
+ }
+}
+
+void WorkbenchManipulatorPython::tryModifyContextMenu(const Py::Dict& dict, MenuItem* menuBar)
+{
+ tryModifyMenuBar(dict, menuBar);
+}
+
+void WorkbenchManipulatorPython::modifyToolBars(ToolBarItem* toolBar)
{
Base::PyGILStateLocker lock;
try {
- if (object.hasAttr(std::string("modifyToolBars"))) {
- Py::Callable method(object.getAttr(std::string("modifyToolBars")));
- Py::Tuple args(1);
- method.apply(args);
- }
+ tryModifyToolBar(toolBar);
}
catch (Py::Exception&) {
Base::PyException exc; // extract the Python error text
@@ -107,18 +228,130 @@ void WorkbenchManipulatorPython::modifyToolBars([[maybe_unused]] ToolBarItem* to
}
}
-void WorkbenchManipulatorPython::modifyDockWindows([[maybe_unused]] DockWindowItems* dockWindow)
+/*!
+ * \brief WorkbenchManipulatorPython::tryModifyToolBar
+ * \param toolBar
+ * The Python manipulator can be implemented as
+ * \code
+ * class Manipulator:
+ * def modifyToolBars(self):
+ return [{"remove" : "Macro"},
+ {"append" : "Std_Quit", "toolBar" : "File"},
+ * {"insert" : "Std_Cut", "toolItem" : "Std_New"}]
+ *
+ * manip = Manipulator()
+ * Gui.addWorkbenchManipulator(manip)
+ * \endcode
+ * This manipulator removes the Macro toolbar, adds the
+ * Std_Quit to the File toolbar and adds Std_Cut the
+ * command to the toolbar where Std_New is part of.
+ */
+void WorkbenchManipulatorPython::tryModifyToolBar(ToolBarItem* toolBar)
+{
+ if (object.hasAttr(std::string("modifyToolBars"))) {
+ Py::Callable method(object.getAttr(std::string("modifyToolBars")));
+ Py::Tuple args;
+ Py::Object result = method.apply(args);
+ if (result.isDict()) {
+ tryModifyToolBar(Py::Dict(result), toolBar);
+ }
+ else if (result.isSequence()) {
+ Py::Sequence list(result);
+ for (const auto& it : list) {
+ if (it.isDict()) {
+ tryModifyToolBar(Py::Dict(it), toolBar);
+ }
+ }
+ }
+ }
+}
+
+// NOLINTNEXTLINE
+void WorkbenchManipulatorPython::tryModifyToolBar(const Py::Dict& dict, ToolBarItem* toolBar)
+{
+ std::string insert("insert");
+ std::string append("append");
+ std::string remove("remove");
+
+ // insert a new command
+ if (dict.hasKey(insert)) {
+
+ std::string command = static_cast(Py::String(dict.getItem(insert)));
+ std::string itemName = static_cast(Py::String(dict.getItem("toolItem")));
+
+ for (auto it : toolBar->getItems()) {
+ if (ToolBarItem* item = it->findItem(itemName)) {
+ auto add = new ToolBarItem(); // NOLINT
+ add->setCommand(command);
+ it->insertItem(item, add);
+ break;
+ }
+ }
+ }
+ // append a command
+ else if (dict.hasKey(append)) {
+ std::string command = static_cast(Py::String(dict.getItem(append)));
+ std::string itemName = static_cast(Py::String(dict.getItem("toolBar")));
+
+ if (ToolBarItem* item = toolBar->findItem(itemName)) {
+ auto add = new ToolBarItem(); // NOLINT
+ add->setCommand(command);
+ item->appendItem(add);
+ }
+ }
+ // remove a command or toolbar
+ else if (dict.hasKey(remove)) {
+ std::string command = static_cast(Py::String(dict.getItem(remove)));
+
+ if (ToolBarItem* item = toolBar->findItem(command)) {
+ toolBar->removeItem(item);
+ delete item; // NOLINT
+ }
+ else {
+ for (auto it : toolBar->getItems()) {
+ if (ToolBarItem* item = it->findItem(command)) {
+ it->removeItem(item);
+ delete item; // NOLINT
+ break;
+ }
+ }
+ }
+ }
+}
+
+void WorkbenchManipulatorPython::modifyDockWindows(DockWindowItems* dockWindow)
{
Base::PyGILStateLocker lock;
try {
- if (object.hasAttr(std::string("modifyDockWindows"))) {
- Py::Callable method(object.getAttr(std::string("modifyDockWindows")));
- Py::Tuple args(1);
- method.apply(args);
- }
+ tryModifyDockWindows(dockWindow);
}
catch (Py::Exception&) {
Base::PyException exc; // extract the Python error text
exc.ReportException();
}
}
+
+void WorkbenchManipulatorPython::tryModifyDockWindows(DockWindowItems* dockWindow)
+{
+ if (object.hasAttr(std::string("modifyDockWindows"))) {
+ Py::Callable method(object.getAttr(std::string("modifyDockWindows")));
+ Py::Tuple args;
+ Py::Object result = method.apply(args);
+ if (result.isDict()) {
+ tryModifyDockWindows(Py::Dict(result), dockWindow);
+ }
+ else if (result.isSequence()) {
+ Py::Sequence list(result);
+ for (const auto& it : list) {
+ if (it.isDict()) {
+ tryModifyDockWindows(Py::Dict(it), dockWindow);
+ }
+ }
+ }
+ }
+}
+
+void WorkbenchManipulatorPython::tryModifyDockWindows([[maybe_unused]]const Py::Dict& dict,
+ [[maybe_unused]]DockWindowItems* dockWindow)
+{
+}
diff --git a/src/Gui/WorkbenchManipulatorPython.h b/src/Gui/WorkbenchManipulatorPython.h
index 8b4d7b7405..573f916438 100644
--- a/src/Gui/WorkbenchManipulatorPython.h
+++ b/src/Gui/WorkbenchManipulatorPython.h
@@ -48,23 +48,22 @@ protected:
* \brief modifyMenuBar
* Method to manipulate the menu structure of a workbench.
*/
- void modifyMenuBar([[maybe_unused]] MenuItem* menuBar) override;
+ void modifyMenuBar(MenuItem* menuBar) override;
/*!
* \brief modifyContextMenu
* Method to manipulate the contextmenu structure of a workbench.
*/
- void modifyContextMenu([[maybe_unused]] const char* recipient,
- [[maybe_unused]] MenuItem* menuBar) override;
+ void modifyContextMenu(const char* recipient, MenuItem* menuBar) override;
/*!
* \brief modifyToolBars
* Method to manipulate the toolbar structure of a workbench
*/
- void modifyToolBars([[maybe_unused]] ToolBarItem* toolBar) override;
+ void modifyToolBars(ToolBarItem* toolBar) override;
/*!
* \brief modifyDockWindows
* Method to manipulate the dock window structure of a workbench
*/
- void modifyDockWindows([[maybe_unused]] DockWindowItems* dockWindow) override;
+ void modifyDockWindows(DockWindowItems* dockWindow) override;
public:
WorkbenchManipulatorPython(const WorkbenchManipulatorPython&) = delete;
@@ -72,6 +71,16 @@ public:
WorkbenchManipulatorPython& operator = (const WorkbenchManipulatorPython&) = delete;
WorkbenchManipulatorPython& operator = (WorkbenchManipulatorPython&&) = delete;
+private:
+ void tryModifyMenuBar(MenuItem* menuBar);
+ void tryModifyMenuBar(const Py::Dict& dict, MenuItem* menuBar);
+ void tryModifyContextMenu(const char* recipient, MenuItem* menuBar);
+ void tryModifyContextMenu(const Py::Dict& dict, MenuItem* menuBar);
+ void tryModifyToolBar(ToolBarItem* toolBar);
+ void tryModifyToolBar(const Py::Dict& dict, ToolBarItem* toolBar);
+ void tryModifyDockWindows(DockWindowItems* menuBar);
+ void tryModifyDockWindows(const Py::Dict& dict, DockWindowItems* dockWindow);
+
private:
Py::Object object;
};