diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 20abafd6f4..ac7eda9c4d 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -137,6 +137,7 @@ #include "Workbench.h" #include "WorkbenchManager.h" #include "WorkbenchManipulator.h" +#include "OriginManager.h" #include "WidgetFactory.h" #include "3Dconnexion/navlib/NavlibInterface.h" #include "Inventor/SoFCPlacementIndicatorKit.h" @@ -691,6 +692,9 @@ Application::Application(bool GUIenabled) if (GUIenabled) { createStandardOperations(); MacroCommand::load(); + + // Initialize the origin manager (creates local origin by default) + OriginManager::instance(); } } // clang-format on @@ -702,6 +706,7 @@ Application::~Application() delete pNavlibInterface; #endif WorkbenchManager::destruct(); + OriginManager::destruct(); WorkbenchManipulator::removeAll(); SelectionSingleton::destruct(); Translator::destruct(); diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index a93b009774..5686d8f52a 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -66,6 +66,8 @@ #include "Workbench.h" #include "WorkbenchManager.h" #include "WorkbenchManipulatorPython.h" +#include "FileOriginPython.h" +#include "OriginManager.h" #include "Inventor/MarkerBitmaps.h" #include "Language/Translator.h" @@ -550,6 +552,50 @@ PyMethodDef ApplicationPy::Methods[] = { METH_VARARGS, "resumeWaitCursor() -> None\n\n" "Resumes the application's wait cursor and event filter."}, + {"addOrigin", + (PyCFunction)ApplicationPy::sAddOrigin, + METH_VARARGS, + "addOrigin(obj) -> None\n" + "\n" + "Register a Python origin handler for document operations.\n" + "\n" + "obj : object\n Origin object implementing the FileOrigin interface."}, + {"removeOrigin", + (PyCFunction)ApplicationPy::sRemoveOrigin, + METH_VARARGS, + "removeOrigin(obj) -> None\n" + "\n" + "Unregister a Python origin handler.\n" + "\n" + "obj : object\n Origin object to unregister."}, + {"getOrigin", + (PyCFunction)ApplicationPy::sGetOrigin, + METH_VARARGS, + "getOrigin(id) -> object or None\n" + "\n" + "Get an origin by its ID.\n" + "\n" + "id : str\n The origin ID."}, + {"listOrigins", + (PyCFunction)ApplicationPy::sListOrigins, + METH_VARARGS, + "listOrigins() -> list\n" + "\n" + "Get a list of all registered origin IDs."}, + {"activeOrigin", + (PyCFunction)ApplicationPy::sActiveOrigin, + METH_VARARGS, + "activeOrigin() -> object or None\n" + "\n" + "Get the currently active origin."}, + {"setActiveOrigin", + (PyCFunction)ApplicationPy::sSetActiveOrigin, + METH_VARARGS, + "setActiveOrigin(id) -> bool\n" + "\n" + "Set the active origin by ID.\n" + "\n" + "id : str\n The origin ID to activate."}, {nullptr, nullptr, 0, nullptr} /* Sentinel */ }; @@ -1966,3 +2012,130 @@ PyObject* ApplicationPy::sResumeWaitCursor(PyObject* /*self*/, PyObject* args) WaitCursor::resume(); Py_RETURN_NONE; } + +// Origin management methods + +PyObject* ApplicationPy::sAddOrigin(PyObject* /*self*/, PyObject* args) +{ + PyObject* o = nullptr; + if (!PyArg_ParseTuple(args, "O", &o)) { + return nullptr; + } + + PY_TRY + { + FileOriginPython::addOrigin(Py::Object(o)); + Py_Return; + } + PY_CATCH; +} + +PyObject* ApplicationPy::sRemoveOrigin(PyObject* /*self*/, PyObject* args) +{ + PyObject* o = nullptr; + if (!PyArg_ParseTuple(args, "O", &o)) { + return nullptr; + } + + PY_TRY + { + FileOriginPython::removeOrigin(Py::Object(o)); + Py_Return; + } + PY_CATCH; +} + +PyObject* ApplicationPy::sGetOrigin(PyObject* /*self*/, PyObject* args) +{ + const char* originId = nullptr; + if (!PyArg_ParseTuple(args, "s", &originId)) { + return nullptr; + } + + PY_TRY + { + FileOrigin* origin = OriginManager::instance()->getOrigin(originId); + if (!origin) { + Py_Return; // Return None if not found + } + + // Return origin info as a dictionary + Py::Dict result; + result.setItem("id", Py::String(origin->id())); + result.setItem("name", Py::String(origin->name())); + result.setItem("nickname", Py::String(origin->nickname())); + result.setItem("type", Py::Long(static_cast(origin->type()))); + result.setItem("tracksExternally", Py::Boolean(origin->tracksExternally())); + result.setItem("requiresAuthentication", Py::Boolean(origin->requiresAuthentication())); + result.setItem("supportsRevisions", Py::Boolean(origin->supportsRevisions())); + result.setItem("supportsBOM", Py::Boolean(origin->supportsBOM())); + result.setItem("supportsPartNumbers", Py::Boolean(origin->supportsPartNumbers())); + result.setItem("connectionState", Py::Long(static_cast(origin->connectionState()))); + + return Py::new_reference_to(result); + } + PY_CATCH; +} + +PyObject* ApplicationPy::sListOrigins(PyObject* /*self*/, PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) { + return nullptr; + } + + PY_TRY + { + Py::List result; + for (const auto& id : OriginManager::instance()->originIds()) { + result.append(Py::String(id)); + } + return Py::new_reference_to(result); + } + PY_CATCH; +} + +PyObject* ApplicationPy::sActiveOrigin(PyObject* /*self*/, PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) { + return nullptr; + } + + PY_TRY + { + FileOrigin* origin = OriginManager::instance()->currentOrigin(); + if (!origin) { + Py_Return; + } + + // Return origin info as a dictionary + Py::Dict result; + result.setItem("id", Py::String(origin->id())); + result.setItem("name", Py::String(origin->name())); + result.setItem("nickname", Py::String(origin->nickname())); + result.setItem("type", Py::Long(static_cast(origin->type()))); + result.setItem("tracksExternally", Py::Boolean(origin->tracksExternally())); + result.setItem("requiresAuthentication", Py::Boolean(origin->requiresAuthentication())); + result.setItem("supportsRevisions", Py::Boolean(origin->supportsRevisions())); + result.setItem("supportsBOM", Py::Boolean(origin->supportsBOM())); + result.setItem("supportsPartNumbers", Py::Boolean(origin->supportsPartNumbers())); + result.setItem("connectionState", Py::Long(static_cast(origin->connectionState()))); + + return Py::new_reference_to(result); + } + PY_CATCH; +} + +PyObject* ApplicationPy::sSetActiveOrigin(PyObject* /*self*/, PyObject* args) +{ + const char* originId = nullptr; + if (!PyArg_ParseTuple(args, "s", &originId)) { + return nullptr; + } + + PY_TRY + { + bool success = OriginManager::instance()->setCurrentOrigin(originId); + return Py::new_reference_to(Py::Boolean(success)); + } + PY_CATCH; +} diff --git a/src/Gui/ApplicationPy.h b/src/Gui/ApplicationPy.h index 203c346b51..e92211e8db 100644 --- a/src/Gui/ApplicationPy.h +++ b/src/Gui/ApplicationPy.h @@ -108,6 +108,14 @@ public: static PyObject* sAddWbManipulator (PyObject *self,PyObject *args); static PyObject* sRemoveWbManipulator (PyObject *self,PyObject *args); + // Origin management + static PyObject* sAddOrigin (PyObject *self,PyObject *args); + static PyObject* sRemoveOrigin (PyObject *self,PyObject *args); + static PyObject* sGetOrigin (PyObject *self,PyObject *args); + static PyObject* sListOrigins (PyObject *self,PyObject *args); + static PyObject* sActiveOrigin (PyObject *self,PyObject *args); + static PyObject* sSetActiveOrigin (PyObject *self,PyObject *args); + static PyObject* sListUserEditModes (PyObject *self,PyObject *args); static PyObject* sGetUserEditMode (PyObject *self,PyObject *args); static PyObject* sSetUserEditMode (PyObject *self,PyObject *args); diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 64b1723df0..da3115b7e8 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1317,6 +1317,7 @@ SET(Workbench_CPP_SRCS OverlayManager.cpp OverlayWidgets.cpp MenuManager.cpp + OriginManager.cpp PythonWorkbenchPyImp.cpp ToolBarAreaWidget.cpp ToolBarManager.cpp @@ -1334,6 +1335,7 @@ SET(Workbench_SRCS OverlayManager.h OverlayWidgets.h MenuManager.h + OriginManager.h ToolBarAreaWidget.h ToolBarManager.h ToolBoxManager.h @@ -1374,6 +1376,8 @@ SET(FreeCADGui_CPP_SRCS DocumentObserver.cpp DocumentObserverPython.cpp EditableDatumLabel.cpp + FileOrigin.cpp + FileOriginPython.cpp ExpressionBinding.cpp ExpressionBindingPy.cpp GraphicsViewZoom.cpp @@ -1414,6 +1418,8 @@ SET(FreeCADGui_SRCS DocumentObserver.h DocumentObserverPython.h EditableDatumLabel.h + FileOrigin.h + FileOriginPython.h ExpressionBinding.h ExpressionBindingPy.h ExpressionCompleter.h