diff --git a/src/App/Application.cpp b/src/App/Application.cpp index fe2b62ebf2..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()); @@ -3702,24 +3683,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) 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/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."); 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/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; } 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 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; 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"); 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); } 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; } 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