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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
13
src/Ext/freecad/module_io.py
Normal file
13
src/Ext/freecad/module_io.py
Normal 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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user