cherry-pick #12: origin abstraction layer (7535a48ec4)

Application.cpp/ApplicationPy.cpp: register origin system.
Resolved add/add conflicts: kept Phase 1 versions of Kindred source files.
This commit is contained in:
forbes
2026-02-13 14:07:36 -06:00
parent 5456ffb34f
commit 9e031ef021
4 changed files with 192 additions and 0 deletions

View File

@@ -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();

View File

@@ -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<int>(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<int>(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<int>(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<int>(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;
}

View File

@@ -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);

View File

@@ -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