From 2799aa27005abb370b5ff8a893fd96f396778b2f Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 27 Feb 2025 10:20:39 +0100 Subject: [PATCH 1/9] App: Simplify and fix code for ifcopenshell version check --- src/App/Application.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index fe2b62ebf2..b658d196b9 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -3702,24 +3702,23 @@ void Application::getVerboseCommonInfo(QTextStream& str, const std::map(version); + str << "IfcOpenShell " << ver_str.c_str() << ", "; } - Py_DECREF(ifcopenshellVer); + else { + Base::Console().log("Module 'ifcopenshell' not found (safe to ignore, unless using " + "the BIM workbench and IFC).\n"); + } + } + catch (const Py::Exception&) { + Base::PyGILStateLocker lock; + Base::PyException e; + Base::Console().log("%s\n", e.what()); } #if defined(HAVE_OCC_VERSION) From 3fba5870446fd7f0d84688507b065b38e5de2ec0 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 1 Mar 2025 08:31:39 +0100 Subject: [PATCH 2/9] App: In ExpressionParser::parse add the failing expression text to the error message --- src/App/Expression.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp index d87d381dae..1afb5ec56e 100644 --- a/src/App/Expression.cpp +++ b/src/App/Expression.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -3786,14 +3787,17 @@ Expression * App::ExpressionParser::parse(const App::DocumentObject *owner, cons // run the parser int result = ExpressionParser::ExpressionParser_yyparse (); - if (result != 0) - throw ParserError("Failed to parse expression."); + if (result != 0) { + throw ParserError(fmt::format("Failed to parse expression '{}'", buffer)); + } - if (!ScanResult) - throw ParserError("Unknown error in expression"); + if (!ScanResult) { + throw ParserError(fmt::format("Unknown error in expression '{}'", buffer)); + } - if (valueExpression) + if (valueExpression) { return ScanResult; + } else { delete ScanResult; throw Expression::Exception("Expression can not evaluate to a value."); From 56e687d9cc8a62cf0c66b109cc89a13348e514ac Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 1 Mar 2025 08:36:05 +0100 Subject: [PATCH 3/9] App: Refactor PropertyExpressionEngine::afterRestore() Put the reading of each expression of an object into a try/catch block. This is to avoid that all expressions of an object may be lost. This mitigates the issue 19866 --- src/App/PropertyExpressionEngine.cpp | 33 ++++++++++++++++++++-------- src/App/PropertyExpressionEngine.h | 2 ++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/App/PropertyExpressionEngine.cpp b/src/App/PropertyExpressionEngine.cpp index 241a93ead7..c0fa969562 100644 --- a/src/App/PropertyExpressionEngine.cpp +++ b/src/App/PropertyExpressionEngine.cpp @@ -467,21 +467,36 @@ void PropertyExpressionEngine::afterRestore() ObjectIdentifier::DocumentMapper mapper(this->_DocMap); for (auto& info : *restoredExpressions) { - ObjectIdentifier path = ObjectIdentifier::parse(docObj, info.path); - if (!info.expr.empty()) { - std::shared_ptr expression( - Expression::parse(docObj, info.expr.c_str())); - if (expression) { - expression->comment = std::move(info.comment); - } - setValue(path, expression); - } + tryRestoreExpression(docObj, info); } signaller.tryInvoke(); } restoredExpressions.reset(); } +void PropertyExpressionEngine::tryRestoreExpression(DocumentObject* docObj, + const RestoredExpression& info) +{ + try { + ObjectIdentifier path = ObjectIdentifier::parse(docObj, info.path); + if (!info.expr.empty()) { + std::shared_ptr expression( + Expression::parse(docObj, info.expr)); + if (expression) { + expression->comment = info.comment; + } + setValue(path, expression); + } + } + catch (const Base::Exception& e) { + FC_ERR("Failed to restore " << docObj->getFullName() + << '.' + << getName() + << ": " + << e.what()); + } +} + void PropertyExpressionEngine::onContainerRestored() { Base::FlagToggler flag(restoring); diff --git a/src/App/PropertyExpressionEngine.h b/src/App/PropertyExpressionEngine.h index b1d83e0a56..6322892347 100644 --- a/src/App/PropertyExpressionEngine.h +++ b/src/App/PropertyExpressionEngine.h @@ -244,6 +244,8 @@ private: * into the actual map */ std::unique_ptr> restoredExpressions; + void tryRestoreExpression(DocumentObject* docObj, const RestoredExpression& info); + struct Private; std::unique_ptr pimpl; From dace71205f10090996c38400cba82103b976b3aa Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 10 Mar 2025 18:02:07 +0100 Subject: [PATCH 4/9] App: In ProjectFile::loadDocument() check for parse errors In case a parse error occurred then return with false and do not set the DOMDocument --- src/App/ProjectFile.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/App/ProjectFile.cpp b/src/App/ProjectFile.cpp index 38cc61f582..bf6ec236d9 100644 --- a/src/App/ProjectFile.cpp +++ b/src/App/ProjectFile.cpp @@ -243,6 +243,9 @@ bool ProjectFile::loadDocument() try { Base::StdInputSource inputSource(*str, stdFile.c_str()); parser->parse(inputSource); + if (parser->getErrorCount() > 0) { + return false; + } xmlDocument = parser->adoptDocument(); return true; } From 93ee3a34759c88c96760be74fccfb1f9cebba15c Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 12 Mar 2025 11:43:47 +0100 Subject: [PATCH 5/9] App: Remove assert() from PropertyXLink::Restore If the property is added to a view provider then in debug mode this will cause a crash while in release mode this will cause undefined behaviour because of a static_cast. To fix crashes remove the assert() and replace the static_cast with freecad_cast. --- src/App/PropertyLinks.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index 3d090cc384..f7d65a4187 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -4281,14 +4281,12 @@ void PropertyXLink::Restore(Base::XMLReader& reader) name = reader.getAttribute("name"); } - assert(getContainer()->isDerivedFrom()); DocumentObject* object = nullptr; if (!name.empty() && file.empty()) { - DocumentObject* parent = static_cast(getContainer()); - Document* document = parent->getDocument(); - object = document ? document->getObject(name.c_str()) : nullptr; - if (!object) { - if (reader.isVerbose()) { + if (auto parent = freecad_cast(getContainer())) { + Document* document = parent->getDocument(); + object = document ? document->getObject(name.c_str()) : nullptr; + if (!object && reader.isVerbose()) { FC_WARN("Lost link to '" << name << "' while loading, maybe " "an object was not loaded correctly"); From 8062fadbd4a2b7b5f67a201423add40b86ddff0c Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 27 Apr 2025 19:45:50 +0200 Subject: [PATCH 6/9] App: Replace C macros with lambda expression --- src/App/PreCompiled.h | 1 + src/App/Property.cpp | 45 ++++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/App/PreCompiled.h b/src/App/PreCompiled.h index 8b32f51627..973723687d 100644 --- a/src/App/PreCompiled.h +++ b/src/App/PreCompiled.h @@ -50,6 +50,7 @@ #include // STL +#include #include #include #if defined(FC_OS_WIN32) diff --git a/src/App/Property.cpp b/src/App/Property.cpp index 491e060b35..a00a6e6ab9 100644 --- a/src/App/Property.cpp +++ b/src/App/Property.cpp @@ -23,6 +23,8 @@ ***************************************************************************/ #include +#include +#include #include #include @@ -114,36 +116,35 @@ std::string Property::getFileName(const char* postfix, const char* prefix) const return ss.str(); } +// clang-format off +static constexpr auto mapProps = std::to_array>({ + {App::Property::PropReadOnly, Prop_ReadOnly}, + {App::Property::PropHidden, Prop_Hidden}, + {App::Property::PropOutput, Prop_Output}, + {App::Property::PropTransient, Prop_Transient}, + {App::Property::PropNoRecompute, Prop_NoRecompute}, + {App::Property::PropNoPersist, Prop_NoPersist} +}); +// clang-format on + short Property::getType() const { short type = 0; -#define GET_PTYPE(_name) \ - do { \ - if (testStatus(App::Property::Prop##_name)) \ - type |= Prop_##_name; \ - } while (0) - GET_PTYPE(ReadOnly); - GET_PTYPE(Hidden); - GET_PTYPE(Output); - GET_PTYPE(Transient); - GET_PTYPE(NoRecompute); - GET_PTYPE(NoPersist); + for (const auto& [propertyStatus, propertyType] : mapProps) { + if (testStatus(propertyStatus)) { + type |= propertyType; + } + } return type; } void Property::syncType(unsigned type) { -#define SYNC_PTYPE(_name) \ - do { \ - if (type & Prop_##_name) \ - StatusBits.set((size_t)Prop##_name); \ - } while (0) - SYNC_PTYPE(ReadOnly); - SYNC_PTYPE(Transient); - SYNC_PTYPE(Hidden); - SYNC_PTYPE(Output); - SYNC_PTYPE(NoRecompute); - SYNC_PTYPE(NoPersist); + for (const auto& [propertyStatus, propertyType] : mapProps) { + if (type & propertyType) { + StatusBits.set((size_t)propertyStatus); + } + } } const char* Property::getGroup() const From 60b022140227d8ab373041f569910a0d36a7203f Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 29 Apr 2025 18:47:10 +0200 Subject: [PATCH 7/9] App: Optimize PropertyMaterialList::getDiffuseColors()/getTransparencies() --- src/App/PropertyStandard.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 57f70d9886..7530e0fd8e 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -3194,6 +3194,7 @@ const Base::Color& PropertyMaterialList::getDiffuseColor(int index) const std::vector PropertyMaterialList::getDiffuseColors() const { std::vector list; + list.reserve(_lValueList.size()); for (auto& material : _lValueList) { list.push_back(material.diffuseColor); } @@ -3244,6 +3245,7 @@ float PropertyMaterialList::getTransparency(int index) const std::vector PropertyMaterialList::getTransparencies() const { std::vector list; + list.reserve(_lValueList.size()); for (auto& material : _lValueList) { list.push_back(material.transparency); } From 1886bcda00a4ac46aa4206cf45fe7f1c631bc8ad Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 2 May 2025 10:56:43 +0200 Subject: [PATCH 8/9] App: Fix crash in Transaction::addObjectChange It can happen that TransactionFactory::createTransaction() fails to create a transaction object because an unsuitable type is passed (like BadType) and returns a null pointer. The calling instances (Transaction::addObjectChange, Transaction::addObjectDel, Transaction::addObjectNew, Transaction::addOrRemoveProperty) do not check for a null pointer and thus cause a segmentation fault by dereferencing it. To fix the issue change the above methods to explicitly handle a null pointer. This fixes issue 21095. Note: In this case it's caused by the class ViewProviderFace which on purpose isn't added to the type system so that its type will be BadType. --- src/App/Transactions.cpp | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/App/Transactions.cpp b/src/App/Transactions.cpp index a15a2789ac..c840b3e76a 100644 --- a/src/App/Transactions.cpp +++ b/src/App/Transactions.cpp @@ -147,18 +147,15 @@ void Transaction::changeProperty(TransactionalObject* Obj, auto& index = _Objects.get<1>(); auto pos = index.find(Obj); - TransactionObject* To; - if (pos != index.end()) { - To = pos->second; + auto To = pos->second; + changeFunc(To); } - else { - To = TransactionFactory::instance().createTransaction(Obj->getTypeId()); + else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) { To->status = TransactionObject::Chn; index.emplace(Obj, To); + changeFunc(To); } - - changeFunc(To); } void Transaction::renameProperty(TransactionalObject* Obj, const Property* pcProp, const char* oldName) @@ -230,8 +227,7 @@ void Transaction::addObjectNew(TransactionalObject* Obj) seq.relocate(seq.end(), _Objects.project<0>(pos)); } } - else { - TransactionObject* To = TransactionFactory::instance().createTransaction(Obj->getTypeId()); + else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) { To->status = TransactionObject::New; To->_NameInDocument = Obj->detachFromDocument(); index.emplace(Obj, To); @@ -252,8 +248,7 @@ void Transaction::addObjectDel(const TransactionalObject* Obj) else if (pos != index.end() && pos->second->status == TransactionObject::Chn) { pos->second->status = TransactionObject::Del; } - else { - TransactionObject* To = TransactionFactory::instance().createTransaction(Obj->getTypeId()); + else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) { To->status = TransactionObject::Del; index.emplace(Obj, To); } @@ -264,18 +259,15 @@ void Transaction::addObjectChange(const TransactionalObject* Obj, const Property auto& index = _Objects.get<1>(); auto pos = index.find(Obj); - TransactionObject* To; - if (pos != index.end()) { - To = pos->second; + auto To = pos->second; + To->setProperty(Prop); } - else { - To = TransactionFactory::instance().createTransaction(Obj->getTypeId()); + else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) { To->status = TransactionObject::Chn; index.emplace(Obj, To); + To->setProperty(Prop); } - - To->setProperty(Prop); } @@ -556,13 +548,12 @@ void TransactionFactory::addProducer(const Base::Type& type, Base::AbstractProdu */ TransactionObject* TransactionFactory::createTransaction(const Base::Type& type) const { - std::map::const_iterator it; - for (it = producers.begin(); it != producers.end(); ++it) { - if (type.isDerivedFrom(it->first)) { - return static_cast(it->second->Produce()); + for (const auto& it : producers) { + if (type.isDerivedFrom(it.first)) { + return static_cast(it.second->Produce()); } } - assert(0); + Base::Console().log("Cannot create transaction object from %s\n", type.getName()); return nullptr; } From 0831f7e39213d27494292c7e65e1627153e53c1a Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Mon, 26 Jan 2026 18:31:04 +0100 Subject: [PATCH 9/9] App: Avoid C string compare Since we are linking to boost anyway, use boost function for case insensitive string compare. While there, make affected methods accept std::string arguments, which simplifies code a bit. --- src/App/Application.cpp | 61 ++++++++++++++------------------------- src/App/Application.h | 16 +++++----- src/App/ApplicationPy.cpp | 2 +- src/Gui/FileDialog.cpp | 8 ++--- src/Gui/MainWindow.cpp | 4 +-- 5 files changed, 36 insertions(+), 55 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index b658d196b9..1486a0463a 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -34,6 +34,7 @@ # define WINVER 0x502 // needed for SetDllDirectory # include # endif +# include # include # include # include @@ -1339,18 +1340,15 @@ void Application::changeImportModule(const char* filter, const char* oldModuleNa } } -std::vector Application::getImportModules(const char* extension) const +std::vector Application::getImportModules(const std::string& extension) const { std::vector modules; for (const auto & it : _mImportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { -#ifdef __GNUC__ - if (strcasecmp(extension, jt.c_str()) == 0) -#else - if (_stricmp(extension, jt.c_str()) == 0) -#endif + if (boost::iequals(extension, jt)) { modules.push_back(it.module); + } } } @@ -1369,16 +1367,13 @@ std::vector Application::getImportModules() const return modules; } -std::vector Application::getImportTypes(const char* Module) const +std::vector Application::getImportTypes(const std::string& Module) const { std::vector types; for (const auto & it : _mImportTypes) { -#ifdef __GNUC__ - if (strcasecmp(Module,it.module.c_str()) == 0) -#else - if (_stricmp(Module,it.module.c_str()) == 0) -#endif + if (boost::iequals(Module, it.module)) { types.insert(types.end(), it.types.begin(), it.types.end()); + } } return types; @@ -1397,18 +1392,15 @@ std::vector Application::getImportTypes() const return types; } -std::map Application::getImportFilters(const char* extension) const +std::map Application::getImportFilters(const std::string& extension) const { std::map moduleFilter; for (const auto & it : _mImportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { -#ifdef __GNUC__ - if (strcasecmp(extension,jt.c_str()) == 0) -#else - if (_stricmp(extension,jt.c_str()) == 0) -#endif + if (boost::iequals(extension, jt)) { moduleFilter[it.filter] = it.module; + } } } @@ -1464,18 +1456,15 @@ void Application::changeExportModule(const char* filter, const char* oldModuleNa } } -std::vector Application::getExportModules(const char* extension) const +std::vector Application::getExportModules(const std::string& extension) const { std::vector modules; for (const auto & it : _mExportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { -#ifdef __GNUC__ - if (strcasecmp(extension,jt.c_str()) == 0) -#else - if (_stricmp(extension,jt.c_str()) == 0) -#endif + if (boost::iequals(extension, jt)) { modules.push_back(it.module); + } } } @@ -1494,16 +1483,13 @@ std::vector Application::getExportModules() const return modules; } -std::vector Application::getExportTypes(const char* Module) const +std::vector Application::getExportTypes(const std::string& Module) const { std::vector types; for (const auto & it : _mExportTypes) { -#ifdef __GNUC__ - if (strcasecmp(Module,it.module.c_str()) == 0) -#else - if (_stricmp(Module,it.module.c_str()) == 0) -#endif + if (boost::iequals(Module, it.module)) { types.insert(types.end(), it.types.begin(), it.types.end()); + } } return types; @@ -1522,18 +1508,15 @@ std::vector Application::getExportTypes() const return types; } -std::map Application::getExportFilters(const char* extension) const +std::map Application::getExportFilters(const std::string& extension) const { std::map moduleFilter; for (const auto & it : _mExportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { -#ifdef __GNUC__ - if (strcasecmp(extension,jt.c_str()) == 0) -#else - if (_stricmp(extension,jt.c_str()) == 0) -#endif + if (boost::iequals(extension, jt)) { moduleFilter[it.filter] = it.module; + } } } @@ -2847,8 +2830,7 @@ std::list Application::processFiles(const std::list& f } } else { - std::string ext = file.extension(); - std::vector mods = GetApplication().getImportModules(ext.c_str()); + std::vector mods = GetApplication().getImportModules(file.extension()); if (!mods.empty()) { std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(file.filePath().c_str()); escapedstr = Base::Tools::escapeEncodeFilename(escapedstr); @@ -2905,9 +2887,8 @@ void Application::processCmdLineFiles() output = Base::Tools::escapeEncodeFilename(output); const Base::FileInfo fi(output); - const std::string ext = fi.extension(); try { - const std::vector mods = GetApplication().getExportModules(ext.c_str()); + const std::vector mods = GetApplication().getExportModules(fi.extension()); if (!mods.empty()) { Base::Interpreter().loadModule(mods.front().c_str()); Base::Interpreter().runStringArg("import %s",mods.front().c_str()); diff --git a/src/App/Application.h b/src/App/Application.h index 68331e12cf..38d7adb39e 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -561,7 +561,7 @@ public: * * @param[in] extension The file type extension. */ - std::vector getImportModules(const char* extension) const; + std::vector getImportModules(const std::string& extension) const; /// Get a list of all import modules. std::vector getImportModules() const; @@ -572,7 +572,7 @@ public: * @param[in] Module The module name. * @return A list of file types (extensions) supported by the module. */ - std::vector getImportTypes(const char* Module) const; + std::vector getImportTypes(const std::string& Module) const; /// Get a list of all import filetypes represented as extensions. std::vector getImportTypes() const; @@ -583,7 +583,7 @@ public: * @param[in] extension The file type represented by its extension. * @return A map of filter description to module name. */ - std::map getImportFilters(const char* extension) const; + std::map getImportFilters(const std::string& extension) const; /// Get a mapping of all import filters to their modules. std::map getImportFilters() const; @@ -605,7 +605,7 @@ public: * * @copydetails getImportModules */ - std::vector getExportModules(const char* extension) const; + std::vector getExportModules(const std::string& extension) const; /// Get a list of all export modules. std::vector getExportModules() const; @@ -613,9 +613,9 @@ public: /** * @brief Get a list of filetypes that are supported by a module for export. * - * @copydetails App::Application::getImportTypes(const char*) const + * @copydetails App::Application::getImportTypes(const std::string&) const */ - std::vector getExportTypes(const char* Module) const; + std::vector getExportTypes(const std::string& Module) const; /// Get a list of all export filetypes. std::vector getExportTypes() const; @@ -623,9 +623,9 @@ public: /** * @brief Get the export filters with modules of a given filetype. * - * @copydetails App::Application::getImportFilters(const char*) const + * @copydetails App::Application::getImportFilters(const std::string&) const */ - std::map getExportFilters(const char* extension) const; + std::map getExportFilters(const std::string& extension) const; /// Get a mapping of all export filters to their modules. std::map getExportFilters() const; diff --git a/src/App/ApplicationPy.cpp b/src/App/ApplicationPy.cpp index 406b88a745..c1315679ae 100644 --- a/src/App/ApplicationPy.cpp +++ b/src/App/ApplicationPy.cpp @@ -760,7 +760,7 @@ PyObject* Application::sGetExportType(PyObject* /*self*/, PyObject* args) Py::Dict dict; std::vector types = GetApplication().getExportTypes(); for (const auto& it : types) { - std::vector modules = GetApplication().getExportModules(it.c_str()); + std::vector modules = GetApplication().getExportModules(it); if (modules.empty()) { dict.setItem(it.c_str(), Py::None()); } diff --git a/src/Gui/FileDialog.cpp b/src/Gui/FileDialog.cpp index 58c3cf725c..40b8065c05 100644 --- a/src/Gui/FileDialog.cpp +++ b/src/Gui/FileDialog.cpp @@ -1098,12 +1098,12 @@ SelectModule::Dict SelectModule::exportHandler(const QStringList& fileNames, con QFileInfo fi(fileName); QString ext = fi.completeSuffix().toLower(); std::map filters = App::GetApplication().getExportFilters( - ext.toLatin1() + ext.toStdString() ); if (filters.empty()) { ext = fi.suffix().toLower(); - filters = App::GetApplication().getExportFilters(ext.toLatin1()); + filters = App::GetApplication().getExportFilters(ext.toStdString()); } fileExtension[ext].push_back(fileName); @@ -1168,12 +1168,12 @@ SelectModule::Dict SelectModule::importHandler(const QStringList& fileNames, con QFileInfo fi(fileName); QString ext = fi.completeSuffix().toLower(); std::map filters = App::GetApplication().getImportFilters( - ext.toLatin1() + ext.toStdString() ); if (filters.empty()) { ext = fi.suffix().toLower(); - filters = App::GetApplication().getImportFilters(ext.toLatin1()); + filters = App::GetApplication().getImportFilters(ext.toStdString()); } fileExtension[ext].push_back(fileName); diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 70f5d207d5..0bb8e02ddf 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -2453,10 +2453,10 @@ void MainWindow::loadUrls(App::Document* doc, const QList& urls) info.setFile(info.symLinkTarget()); } std::vector module = App::GetApplication().getImportModules( - info.completeSuffix().toLatin1() + info.completeSuffix().toStdString() ); if (module.empty()) { - module = App::GetApplication().getImportModules(info.suffix().toLatin1()); + module = App::GetApplication().getImportModules(info.suffix().toStdString()); } if (!module.empty()) { // ok, we support files with this extension