Core: Import STEP: Cancel button does not cancel (#16499)

* Fix importing .step file when user cancelled import settings dialog
* Refactor object loading python code, fix not using settings when STEP options dialog not shown
* Use custom exception type for user cancelling import instead of `RuntimeError`
* Pull python code out to external file
This commit is contained in:
supermixed
2024-09-20 23:25:23 +10:00
committed by GitHub
parent 7e19990264
commit bbb6eeb1ed
7 changed files with 65 additions and 47 deletions

View File

@@ -427,6 +427,10 @@ void Application::setupPythonException(PyObject* module)
Base::PyExc_FC_PropertyError = PyErr_NewException("Base.PropertyError", PyExc_AttributeError, nullptr);
Py_INCREF(Base::PyExc_FC_PropertyError);
PyModule_AddObject(module, "PropertyError", Base::PyExc_FC_PropertyError);
Base::PyExc_FC_AbortIOException = PyErr_NewException("Base.PyExc_FC_AbortIOException", PyExc_BaseException, nullptr);
Py_INCREF(Base::PyExc_FC_AbortIOException);
PyModule_AddObject(module, "AbortIOException", Base::PyExc_FC_AbortIOException);
}
// clang-format on

View File

@@ -49,6 +49,7 @@ PyObject* Base::PyExc_FC_ExpressionError = nullptr;
PyObject* Base::PyExc_FC_ParserError = nullptr;
PyObject* Base::PyExc_FC_CADKernelError = nullptr;
PyObject* Base::PyExc_FC_PropertyError = nullptr;
PyObject* Base::PyExc_FC_AbortIOException = nullptr;
typedef struct { //NOLINT
PyObject_HEAD

View File

@@ -431,6 +431,7 @@ BaseExport extern PyObject* PyExc_FC_ExpressionError;
BaseExport extern PyObject* PyExc_FC_ParserError;
BaseExport extern PyObject* PyExc_FC_CADKernelError;
BaseExport extern PyObject* PyExc_FC_PropertyError;
BaseExport extern PyObject* PyExc_FC_AbortIOException;
/** Exception handling for python callback functions
* Is a convenience macro to manage the exception handling of python callback

View File

@@ -28,6 +28,7 @@ configure_file(__init__.py.template ${NAMESPACE_INIT})
set(EXT_FILES
freecad_doc.py
module_io.py
part.py
partdesign.py
project_utility.py

View File

@@ -0,0 +1,13 @@
def OpenInsertObject(importerModule, objectPath, importMethod, docName = ""):
try:
importArgs = []
importKwargs = {}
if docName:
importArgs.append(docName)
if hasattr(importerModule, "importOptions"):
importKwargs["options"] = importerModule.importOptions(objectPath)
getattr(importerModule, importMethod)(objectPath, *importArgs, **importKwargs)
except PyExc_FC_AbortIOException:
pass

View File

@@ -595,6 +595,7 @@ Application::~Application()
// creating std commands
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void Application::open(const char* FileName, const char* Module)
{
WaitCursor wc;
@@ -636,19 +637,21 @@ void Application::open(const char* FileName, const char* Module)
}
}
else {
// issue module loading
Command::doCommand(Command::App, "import %s", Module);
// check for additional import options
std::stringstream str;
str << "if hasattr(" << Module << ", \"importOptions\"):\n"
<< " options = " << Module << ".importOptions(u\"" << unicodepath << "\")\n"
<< " " << Module << ".open(u\"" << unicodepath << "\", options = options)\n"
<< "else:\n"
<< " " << Module << ".open(u\"" << unicodepath << "\")\n";
std::string code = str.str();
Gui::Command::runCommand(Gui::Command::App, code.c_str());
// Load using provided python module
{
Base::PyGILStateLocker locker;
Py::Module moduleIo(PyImport_ImportModule("freecad.module_io"));
const auto dictS = moduleIo.getDict().keys().as_string();
if (!moduleIo.isNull() && moduleIo.hasAttr("OpenInsertObject"))
{
const Py::TupleN args(
Py::Module(PyImport_ImportModule(Module)),
Py::String(unicodepath),
Py::String("open")
);
moduleIo.callMemberFunction("OpenInsertObject", args);
}
}
// ViewFit
if (sendHasMsgToActiveView("ViewFit")) {
@@ -713,30 +716,22 @@ void Application::importFrom(const char* FileName, const char* DocName, const ch
}
}
// check for additional import options
std::stringstream str;
if (DocName) {
str << "if hasattr(" << Module << ", \"importOptions\"):\n"
<< " options = " << Module << ".importOptions(u\"" << unicodepath
<< "\")\n"
<< " " << Module << ".insert(u\"" << unicodepath << "\", \"" << DocName
<< "\", options = options)\n"
<< "else:\n"
<< " " << Module << ".insert(u\"" << unicodepath << "\", \"" << DocName
<< "\")\n";
// Load using provided python module
{
Base::PyGILStateLocker locker;
Py::Module moduleIo(PyImport_ImportModule("freecad.module_io"));
const auto dictS = moduleIo.getDict().keys().as_string();
if (!moduleIo.isNull() && moduleIo.hasAttr("OpenInsertObject"))
{
const Py::TupleN args(
Py::Module(PyImport_ImportModule(Module)),
Py::String(unicodepath),
Py::String("insert"),
Py::String(DocName)
);
moduleIo.callMemberFunction("OpenInsertObject", args);
}
}
else {
str << "if hasattr(" << Module << ", \"importOptions\"):\n"
<< " options = " << Module << ".importOptions(u\"" << unicodepath
<< "\")\n"
<< " " << Module << ".insert(u\"" << unicodepath
<< "\", options = options)\n"
<< "else:\n"
<< " " << Module << ".insert(u\"" << unicodepath << "\")\n";
}
std::string code = str.str();
Gui::Command::runCommand(Gui::Command::App, code.c_str());
// Commit the transaction
if (doc && !pendingCommand) {

View File

@@ -128,18 +128,21 @@ private:
Base::FileInfo file(name8bit.c_str());
if (file.hasExtension({"stp", "step"})) {
PartGui::TaskImportStep dlg(Gui::getMainWindow());
if (!dlg.showDialog() || dlg.exec()) {
auto stepSettings = dlg.getSettings();
options.setItem("merge", Py::Boolean(stepSettings.merge));
options.setItem("useLinkGroup", Py::Boolean(stepSettings.useLinkGroup));
options.setItem("useBaseName", Py::Boolean(stepSettings.useBaseName));
options.setItem("importHidden", Py::Boolean(stepSettings.importHidden));
options.setItem("reduceObjects", Py::Boolean(stepSettings.reduceObjects));
options.setItem("showProgress", Py::Boolean(stepSettings.showProgress));
options.setItem("expandCompound", Py::Boolean(stepSettings.expandCompound));
options.setItem("mode", Py::Long(stepSettings.mode));
options.setItem("codePage", Py::Long(stepSettings.codePage));
if (dlg.showDialog()) {
if (!dlg.exec()) {
throw Py::Exception(Base::PyExc_FC_AbortIOException, "User cancelled import");
}
}
auto stepSettings = dlg.getSettings();
options.setItem("merge", Py::Boolean(stepSettings.merge));
options.setItem("useLinkGroup", Py::Boolean(stepSettings.useLinkGroup));
options.setItem("useBaseName", Py::Boolean(stepSettings.useBaseName));
options.setItem("importHidden", Py::Boolean(stepSettings.importHidden));
options.setItem("reduceObjects", Py::Boolean(stepSettings.reduceObjects));
options.setItem("showProgress", Py::Boolean(stepSettings.showProgress));
options.setItem("expandCompound", Py::Boolean(stepSettings.expandCompound));
options.setItem("mode", Py::Long(stepSettings.mode));
options.setItem("codePage", Py::Long(stepSettings.codePage));
}
return options;
}