diff --git a/cMake/FreeCAD_Helpers/CreatePackagingTargets.cmake b/cMake/FreeCAD_Helpers/CreatePackagingTargets.cmake index 60cd19c758..de8b52c6d3 100644 --- a/cMake/FreeCAD_Helpers/CreatePackagingTargets.cmake +++ b/cMake/FreeCAD_Helpers/CreatePackagingTargets.cmake @@ -5,25 +5,37 @@ macro(CreatePackagingTargets) #add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) add_custom_target(dist-git COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py - --srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR} + --bindir=${CMAKE_BINARY_DIR} + --major=${PACKAGE_VERSION_MAJOR} + --minor=${PACKAGE_VERSION_MINOR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) add_custom_target(distdfsg-git COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py - --srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR} --dfsg + --bindir=${CMAKE_BINARY_DIR} + --major=${PACKAGE_VERSION_MAJOR} + --minor=${PACKAGE_VERSION_MINOR} + --dfsg WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - if(CMAKE_COMPILER_IS_GNUCXX OR MINGW) + if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX OR MINGW) add_custom_target(distcheck-git COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py - --srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR} --check + --bindir=${CMAKE_BINARY_DIR} + --major=${PACKAGE_VERSION_MAJOR} + --minor=${PACKAGE_VERSION_MINOR} + --check WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) add_custom_target(distcheckdfsg-git COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py - --srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR} --dfsg --check + --bindir=${CMAKE_BINARY_DIR} + --major=${PACKAGE_VERSION_MAJOR} + --minor=${PACKAGE_VERSION_MINOR} + --dfsg + --check WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif(CMAKE_COMPILER_IS_GNUCXX OR MINGW) + endif() endmacro(CreatePackagingTargets) diff --git a/cMake/FreeCAD_Helpers/SetupQt.cmake b/cMake/FreeCAD_Helpers/SetupQt.cmake index 1e5519fe23..230d4198a0 100644 --- a/cMake/FreeCAD_Helpers/SetupQt.cmake +++ b/cMake/FreeCAD_Helpers/SetupQt.cmake @@ -23,9 +23,9 @@ if(BUILD_GUI) elseif(${FREECAD_USE_QTWEBMODULE} MATCHES "Qt WebEngine") find_package(Qt5WebEngineWidgets REQUIRED) else() # Automatic - find_package(Qt5WebKitWidgets QUIET) - if(NOT Qt5WebKitWidgets_FOUND) - find_package(Qt5WebEngineWidgets REQUIRED) + find_package(Qt5WebEngineWidgets QUIET) + if(NOT Qt5WebEngineWidgets_FOUND) + find_package(Qt5WebKitWidgets REQUIRED) endif() endif() endif() diff --git a/data/examples/PartDesignExample.FCStd b/data/examples/PartDesignExample.FCStd index 8e5278bc54..58a0116085 100644 Binary files a/data/examples/PartDesignExample.FCStd and b/data/examples/PartDesignExample.FCStd differ diff --git a/src/App/Application.cpp b/src/App/Application.cpp index fb2755571f..faac993af3 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -55,6 +55,8 @@ #include #endif +#include + #include "Application.h" #include "Document.h" @@ -99,6 +101,7 @@ #include "Document.h" #include "DocumentObjectGroup.h" #include "DocumentObjectFileIncluded.h" +#include "DocumentObserver.h" #include "InventorObject.h" #include "VRMLObject.h" #include "Annotation.h" @@ -487,6 +490,7 @@ bool Application::closeDocument(const char* name) setActiveDocument((Document*)0); std::unique_ptr delDoc (pos->second); DocMap.erase( pos ); + DocFileMap.erase(FileInfo(delDoc->FileName.getValue()).filePath()); _objCount = -1; @@ -566,8 +570,10 @@ int Application::addPendingDocument(const char *FileName, const char *objName, b return -1; assert(FileName && FileName[0]); assert(objName && objName[0]); - auto ret = _pendingDocMap.emplace(FileName,std::set()); - ret.first->second.emplace(objName); + if(!_docReloadAttempts[FileName].emplace(objName).second) + return -1; + auto ret = _pendingDocMap.emplace(FileName,std::vector()); + ret.first->second.push_back(objName); if(ret.second) { _pendingDocs.push_back(ret.first->first.c_str()); return 1; @@ -623,6 +629,41 @@ Document* Application::openDocument(const char * FileName, bool createView) { return 0; } +Document *Application::getDocumentByPath(const char *path, PathMatchMode checkCanonical) const { + if(!path || !path[0]) + return nullptr; + if(DocFileMap.empty()) { + for(const auto &v : DocMap) { + const auto &file = v.second->FileName.getStrValue(); + if(file.size()) + DocFileMap[FileInfo(file.c_str()).filePath()] = v.second; + } + } + auto it = DocFileMap.find(FileInfo(path).filePath()); + if(it != DocFileMap.end()) + return it->second; + + if (checkCanonical == PathMatchMode::MatchAbsolute) + return nullptr; + + std::string filepath = FileInfo(path).filePath(); + QString canonicalPath = QFileInfo(QString::fromUtf8(path)).canonicalFilePath(); + for (const auto &v : DocMap) { + QFileInfo fi(QString::fromUtf8(v.second->FileName.getValue())); + if (canonicalPath == fi.canonicalFilePath()) { + if (checkCanonical == PathMatchMode::MatchCanonical) + return v.second; + bool samePath = (canonicalPath == QString::fromUtf8(filepath.c_str())); + FC_WARN("Identical physical path '" << canonicalPath.toUtf8().constData() << "'\n" + << (samePath?"":" for file '") << (samePath?"":filepath.c_str()) << (samePath?"":"'\n") + << " with existing document '" << v.second->Label.getValue() + << "' in path: '" << v.second->FileName.getValue() << "'"); + break; + } + } + return nullptr; +} + std::vector Application::openDocuments(const std::vector &filenames, const std::vector *paths, const std::vector *labels, @@ -640,6 +681,7 @@ std::vector Application::openDocuments(const std::vector _pendingDocs.clear(); _pendingDocsReopen.clear(); _pendingDocMap.clear(); + _docReloadAttempts.clear(); signalStartOpenDocument(); @@ -649,118 +691,162 @@ std::vector Application::openDocuments(const std::vector for (auto &name : filenames) _pendingDocs.push_back(name.c_str()); - std::map newDocs; + std::map timings; FC_TIME_INIT(t); - for (std::size_t count=0;; ++count) { - const char *name = _pendingDocs.front(); - _pendingDocs.pop_front(); - bool isMainDoc = count < filenames.size(); + std::vector openedDocs; - try { - _objCount = -1; - std::set objNames; - if (_allowPartial) { - auto it = _pendingDocMap.find(name); - if (it != _pendingDocMap.end()) - objNames.swap(it->second); - } + int pass = 0; + do { + std::set newDocs; + for (std::size_t count=0;; ++count) { + std::string name = std::move(_pendingDocs.front()); + _pendingDocs.pop_front(); + bool isMainDoc = (pass == 0 && count < filenames.size()); - FC_TIME_INIT(t1); - DocTiming timing; + try { + _objCount = -1; + std::vector objNames; + if (_allowPartial) { + auto it = _pendingDocMap.find(name); + if (it != _pendingDocMap.end()) { + if(isMainDoc) + it->second.clear(); + else + objNames.swap(it->second); + _pendingDocMap.erase(it); + } + } - const char *path = name; - const char *label = 0; - if (isMainDoc) { - if (paths && paths->size()>count) - path = (*paths)[count].c_str(); + FC_TIME_INIT(t1); + DocTiming timing; - if (labels && labels->size()>count) - label = (*labels)[count].c_str(); - } + const char *path = name.c_str(); + const char *label = 0; + if (isMainDoc) { + if (paths && paths->size()>count) + path = (*paths)[count].c_str(); - auto doc = openDocumentPrivate(path, name, label, isMainDoc, createView, objNames); - FC_DURATION_PLUS(timing.d1,t1); - if (doc) - newDocs.emplace(doc,timing); + if (labels && labels->size()>count) + label = (*labels)[count].c_str(); + } + + auto doc = openDocumentPrivate(path, name.c_str(), label, isMainDoc, createView, std::move(objNames)); + FC_DURATION_PLUS(timing.d1,t1); + if (doc) { + timings[doc].d1 += timing.d1; + newDocs.emplace(doc); + } - if (isMainDoc) - res[count] = doc; - _objCount = -1; - } - catch (const Base::Exception &e) { - if (!errs && isMainDoc) - throw; - if (errs && isMainDoc) - (*errs)[count] = e.what(); - else - Console().Error("Exception opening file: %s [%s]\n", name, e.what()); - } - catch (const std::exception &e) { - if (!errs && isMainDoc) - throw; - if (errs && isMainDoc) - (*errs)[count] = e.what(); - else - Console().Error("Exception opening file: %s [%s]\n", name, e.what()); - } - catch (...) { - if (errs) { if (isMainDoc) - (*errs)[count] = "unknown error"; + res[count] = doc; + _objCount = -1; } - else { - _pendingDocs.clear(); + catch (const Base::Exception &e) { + e.ReportException(); + if (!errs && isMainDoc) + throw; + if (errs && isMainDoc) + (*errs)[count] = e.what(); + else + Console().Error("Exception opening file: %s [%s]\n", name.c_str(), e.what()); + } + catch (const std::exception &e) { + if (!errs && isMainDoc) + throw; + if (errs && isMainDoc) + (*errs)[count] = e.what(); + else + Console().Error("Exception opening file: %s [%s]\n", name.c_str(), e.what()); + } + catch (...) { + if (errs) { + if (isMainDoc) + (*errs)[count] = "unknown error"; + } + else { + _pendingDocs.clear(); + _pendingDocsReopen.clear(); + _pendingDocMap.clear(); + throw; + } + } + + if (_pendingDocs.empty()) { + if(_pendingDocsReopen.empty()) + break; + _pendingDocs = std::move(_pendingDocsReopen); _pendingDocsReopen.clear(); - _pendingDocMap.clear(); - throw; + for(const auto &file : _pendingDocs) { + auto doc = getDocumentByPath(file.c_str()); + if(doc) + closeDocument(doc->getName()); + } } } - if (_pendingDocs.empty()) { - if (_pendingDocsReopen.empty()) - break; - _allowPartial = false; - _pendingDocs.swap(_pendingDocsReopen); + ++pass; + _pendingDocMap.clear(); + + std::vector docs; + docs.reserve(newDocs.size()); + for(const auto &d : newDocs) { + auto doc = d.getDocument(); + if(!doc) + continue; + // Notify PropertyXLink to attach newly opened documents and restore + // relevant external links + PropertyXLink::restoreDocument(*doc); + docs.push_back(doc); } - } - _pendingDocs.clear(); - _pendingDocsReopen.clear(); - _pendingDocMap.clear(); + Base::SequencerLauncher seq("Postprocessing...", docs.size()); - Base::SequencerLauncher seq("Postprocessing...", newDocs.size()); - - std::vector docs; - docs.reserve(newDocs.size()); - for (auto &v : newDocs) { - // Notify PropertyXLink to attach newly opened documents and restore - // relevant external links - PropertyXLink::restoreDocument(*v.first); - docs.push_back(v.first); - } - - // After external links has been restored, we can now sort the document - // according to their dependency order. - docs = Document::getDependentDocuments(docs, true); - for (auto it=docs.begin(); it!=docs.end();) { - Document *doc = *it; - // It is possible that the newly opened document depends on an existing - // document, which will be included with the above call to - // Document::getDependentDocuments(). Make sure to exclude that. - auto dit = newDocs.find(doc); - if (dit == newDocs.end()) { - it = docs.erase(it); - continue; + // After external links has been restored, we can now sort the document + // according to their dependency order. + try { + docs = Document::getDependentDocuments(docs, true); + } catch (Base::Exception &e) { + e.ReportException(); } - ++it; - FC_TIME_INIT(t1); - // Finalize document restoring with the correct order - doc->afterRestore(true); - FC_DURATION_PLUS(dit->second.d2,t1); - seq.next(); - } + for(auto it=docs.begin(); it!=docs.end();) { + auto doc = *it; + + // It is possible that the newly opened document depends on an existing + // document, which will be included with the above call to + // Document::getDependentDocuments(). Make sure to exclude that. + if(!newDocs.count(doc)) { + it = docs.erase(it); + continue; + } + + auto &timing = timings[doc]; + FC_TIME_INIT(t1); + // Finalize document restoring with the correct order + if(doc->afterRestore(true)) { + openedDocs.push_back(doc); + it = docs.erase(it); + } else { + ++it; + // Here means this is a partial loaded document, and we need to + // reload it fully because of touched objects. The reason of + // reloading a partial document with touched object is because + // partial document is supposed to be readonly, while a + // 'touched' object requires recomputation. And an object may + // become touched during restoring if externally linked + // document time stamp mismatches with the stamp saved. + _pendingDocs.push_back(doc->FileName.getValue()); + _pendingDocMap.erase(doc->FileName.getValue()); + } + FC_DURATION_PLUS(timing.d2,t1); + seq.next(); + } + // Close the document for reloading + for(const auto doc : docs) + closeDocument(doc->getName()); + + }while(!_pendingDocs.empty()); // Set the active document using the first successfully restored main // document (i.e. documents explicitly asked for by caller). @@ -771,14 +857,14 @@ std::vector Application::openDocuments(const std::vector } } - for (auto doc : docs) { - auto &timing = newDocs[doc]; - FC_DURATION_LOG(timing.d1, doc->getName() << " restore"); - FC_DURATION_LOG(timing.d2, doc->getName() << " postprocess"); + for (auto &doc : openedDocs) { + auto &timing = timings[doc]; + FC_DURATION_LOG(timing.d1, doc.getDocumentName() << " restore"); + FC_DURATION_LOG(timing.d2, doc.getDocumentName() << " postprocess"); } FC_TIME_LOG(t,"total"); - _isRestoring = false; + signalFinishOpenDocument(); return res; } @@ -786,7 +872,7 @@ std::vector Application::openDocuments(const std::vector Document* Application::openDocumentPrivate(const char * FileName, const char *propFileName, const char *label, bool isMainDoc, bool createView, - const std::set &objNames) + std::vector &&objNames) { FileInfo File(FileName); @@ -797,55 +883,51 @@ Document* Application::openDocumentPrivate(const char * FileName, } // Before creating a new document we check whether the document is already open - std::string filepath = File.filePath(); - QString canonicalPath = QFileInfo(QString::fromUtf8(FileName)).canonicalFilePath(); - for (std::map::iterator it = DocMap.begin(); it != DocMap.end(); ++it) { - // get unique path separators - std::string fi = FileInfo(it->second->FileName.getValue()).filePath(); - if (filepath != fi) { - if (canonicalPath == QFileInfo(QString::fromUtf8(fi.c_str())).canonicalFilePath()) { - bool samePath = (canonicalPath == QString::fromUtf8(FileName)); - FC_WARN("Identical physical path '" << canonicalPath.toUtf8().constData() << "'\n" - << (samePath?"":" for file '") << (samePath?"":FileName) << (samePath?"":"'\n") - << " with existing document '" << it->second->Label.getValue() - << "' in path: '" << it->second->FileName.getValue() << "'"); - } - continue; - } - if(it->second->testStatus(App::Document::PartialDoc) - || it->second->testStatus(App::Document::PartialRestore)) { + auto doc = getDocumentByPath(File.filePath().c_str(), PathMatchMode::MatchCanonicalWarning); + if(doc) { + if(doc->testStatus(App::Document::PartialDoc) + || doc->testStatus(App::Document::PartialRestore)) { // Here means a document is already partially loaded, but the document // is requested again, either partial or not. We must check if the // document contains the required object if(isMainDoc) { // Main document must be open fully, so close and reopen - closeDocument(it->first.c_str()); - break; - } - - if(_allowPartial) { + closeDocument(doc->getName()); + doc = nullptr; + } else if(_allowPartial) { bool reopen = false; - for(auto &name : objNames) { - auto obj = it->second->getObject(name.c_str()); + for(const auto &name : objNames) { + auto obj = doc->getObject(name.c_str()); if(!obj || obj->testStatus(App::PartialObject)) { reopen = true; + // NOTE: We are about to reload this document with + // extra objects. However, it is possible to repeat + // this process several times, if it is linked by + // multiple documents and each with a different set of + // objects. To partially solve this problem, we do not + // close and reopen the document immediately here, but + // add it to _pendingDocsReopen to delay reloading. + for(auto obj : doc->getObjects()) + objNames.push_back(obj->getNameInDocument()); + _pendingDocMap[doc->FileName.getValue()] = std::move(objNames); break; } } if(!reopen) return 0; } - auto &names = _pendingDocMap[FileName]; - names.clear(); - _pendingDocsReopen.push_back(FileName); - return 0; + + if(doc) { + _pendingDocsReopen.emplace_back(FileName); + return 0; + } } if(!isMainDoc) return 0; - - return it->second; + else if(doc) + return doc; } std::string name; @@ -867,6 +949,8 @@ Document* Application::openDocumentPrivate(const char * FileName, try { // read the document newDoc->restore(File.filePath().c_str(),true,objNames); + if(DocFileMap.size()) + DocFileMap[FileInfo(newDoc->FileName.getValue()).filePath()] = newDoc; return newDoc; } // if the project file itself is corrupt then @@ -956,14 +1040,14 @@ Application::TransactionSignaller::~TransactionSignaller() { } } -const char* Application::getHomePath(void) const +std::string Application::getHomePath() { - return _mConfig["AppHomePath"].c_str(); + return mConfig["AppHomePath"]; } -const char* Application::getExecutableName(void) const +std::string Application::getExecutableName() { - return _mConfig["ExeName"].c_str(); + return mConfig["ExeName"]; } std::string Application::getTempPath() @@ -1463,6 +1547,7 @@ void Application::slotStartSaveDocument(const App::Document& doc, const std::str void Application::slotFinishSaveDocument(const App::Document& doc, const std::string& filename) { + DocFileMap.clear(); this->signalFinishSaveDocument(doc, filename); } diff --git a/src/App/Application.h b/src/App/Application.h index 506c3a364e..2e7237ea9e 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -120,6 +120,33 @@ public: App::Document* getActiveDocument(void) const; /// Retrieve a named document App::Document* getDocument(const char *Name) const; + + /// Path matching mode for getDocumentByPath() + enum class PathMatchMode { + /// Match by resolving to absolute file path + MatchAbsolute = 0, + /** Match by absolute path first. If not found then match by resolving + * to canonical file path where any intermediate '.' '..' and symlinks + * are resolved. + */ + MatchCanonical = 1, + /** Same as MatchCanonical, but if a document is found by canonical + * path match, which means the document can be resolved using two + * different absolute path, a warning is printed and the found document + * is not returned. This is to allow the caller to intentionally load + * the same physical file as separate documents. + */ + MatchCanonicalWarning = 2, + }; + /** Retrieve a document based on file path + * + * @param path: file path + * @param checkCanonical: file path matching mode, @sa PathMatchMode. + * @return Return the document found by matching with the given path + */ + App::Document* getDocumentByPath(const char *path, + PathMatchMode checkCanonical = PathMatchMode::MatchAbsolute) const; + /// gets the (internal) name of the document const char * getDocumentName(const App::Document* ) const; /// get a list of all documents in the application @@ -190,6 +217,8 @@ public: boost::signals2::signal signalStartRestoreDocument; /// signal on restoring Document boost::signals2::signal signalFinishRestoreDocument; + /// signal on pending reloading of a partial Document + boost::signals2::signal signalPendingReloadDocument; /// signal on starting to save Document boost::signals2::signal signalStartSaveDocument; /// signal on saved Document @@ -366,8 +395,8 @@ public: /** @name Application directories */ //@{ - const char* getHomePath(void) const; - const char* getExecutableName(void) const; + static std::string getHomePath(); + static std::string getExecutableName(); /*! Returns the temporary directory. By default, this is set to the system's temporary directory but can be customized by the user. @@ -441,7 +470,7 @@ protected: /// open single document only App::Document* openDocumentPrivate(const char * FileName, const char *propFileName, - const char *label, bool isMainDoc, bool createView, const std::set &objNames); + const char *label, bool isMainDoc, bool createView, std::vector &&objNames); /// Helper class for App::Document to signal on close/abort transaction class AppExport TransactionSignaller { @@ -559,13 +588,19 @@ private: std::vector _mImportTypes; std::vector _mExportTypes; std::map DocMap; + mutable std::map DocFileMap; std::map mpcPramManager; std::map &_mConfig; App::Document* _pActiveDoc; - std::deque _pendingDocs; - std::deque _pendingDocsReopen; - std::map > _pendingDocMap; + std::deque _pendingDocs; + std::deque _pendingDocsReopen; + std::map > _pendingDocMap; + + // To prevent infinite recursion of reloading a partial document due a truly + // missing object + std::map > _docReloadAttempts; + bool _isRestoring; bool _allowPartial; bool _isClosingAll; diff --git a/src/App/ApplicationPy.cpp b/src/App/ApplicationPy.cpp index 0eaa6ac788..de213ff32e 100644 --- a/src/App/ApplicationPy.cpp +++ b/src/App/ApplicationPy.cpp @@ -691,7 +691,7 @@ PyObject* Application::sGetHomePath(PyObject * /*self*/, PyObject *args) if (!PyArg_ParseTuple(args, "")) // convert args: Python->C return NULL; // NULL triggers exception - Py::String homedir(GetApplication().getHomePath(),"utf-8"); + Py::String homedir(Application::getHomePath(),"utf-8"); return Py::new_reference_to(homedir); } diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 1f108b8df3..0c6fceb43f 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1685,7 +1685,7 @@ std::string Document::getTransientDirectoryName(const std::string& uuid, const s std::stringstream s; QCryptographicHash hash(QCryptographicHash::Sha1); hash.addData(filename.c_str(), filename.size()); - s << App::Application::getTempPath() << GetApplication().getExecutableName() + s << App::Application::getTempPath() << App::Application::getExecutableName() << "_Doc_" << uuid << "_" << hash.result().toHex().left(6).constData() << "_" << QCoreApplication::applicationPid(); @@ -1866,7 +1866,6 @@ void Document::exportObjects(const std::vector& obj, std:: #define FC_ELEMENT_OBJECT_DEPS "ObjectDeps" #define FC_ATTR_DEP_COUNT "Count" #define FC_ATTR_DEP_OBJ_NAME "Name" -#define FC_ATTR_DEP_COUNT "Count" #define FC_ATTR_DEP_ALLOW_PARTIAL "AllowPartial" #define FC_ELEMENT_OBJECT_DEP "Dep" @@ -2693,7 +2692,7 @@ bool Document::isAnyRestoring() { // Open the document void Document::restore (const char *filename, - bool delaySignal, const std::set &objNames) + bool delaySignal, const std::vector &objNames) { clearUndos(); d->activeObject = 0; @@ -2752,8 +2751,7 @@ void Document::restore (const char *filename, d->partialLoadObjects.emplace(name,true); try { Document::Restore(reader); - } - catch (const Base::Exception& e) { + } catch (const Base::Exception& e) { Base::Console().Error("Invalid Document.xml: %s\n", e.what()); setStatus(Document::RestoreError, true); } @@ -2777,15 +2775,16 @@ void Document::restore (const char *filename, afterRestore(true); } -void Document::afterRestore(bool checkPartial) { +bool Document::afterRestore(bool checkPartial) { Base::FlagToggler<> flag(_IsRestoring,false); if(!afterRestore(d->objectArray,checkPartial)) { FC_WARN("Reload partial document " << getName()); - restore(); - return; + GetApplication().signalPendingReloadDocument(*this); + return false; } GetApplication().signalFinishRestoreDocument(*this); setStatus(Document::Restoring, false); + return true; } bool Document::afterRestore(const std::vector &objArray, bool checkPartial) @@ -2861,9 +2860,12 @@ bool Document::afterRestore(const std::vector &objArray, bool std::string errMsg; if(link && (res=link->checkRestore(&errMsg))) { d->touchedObjs.insert(obj); - if(res==1) + if(res==1 || checkPartial) { FC_WARN(obj->getFullName() << '.' << prop->getName() << ": " << errMsg); - else { + setStatus(Document::LinkStampChanged, true); + if(checkPartial) + return false; + } else { FC_ERR(obj->getFullName() << '.' << prop->getName() << ": " << errMsg); d->addRecomputeLog(errMsg,obj); setStatus(Document::PartialRestore, true); diff --git a/src/App/Document.h b/src/App/Document.h index a4b2285cdc..6d0e7c5ec2 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -74,7 +74,8 @@ public: PartialDoc = 7, AllowPartialRecompute = 8, // allow recomputing editing object if SkipRecompute is set TempDoc = 9, // Mark as temporary document without prompt for save - RestoreError = 10 + RestoreError = 10, + LinkStampChanged = 11, // Indicates during restore time if any linked document's time stamp has changed }; /** @name Properties */ @@ -195,8 +196,8 @@ public: bool saveCopy(const char* file) const; /// Restore the document from the file in Property Path void restore (const char *filename=0, - bool delaySignal=false, const std::set &objNames={}); - void afterRestore(bool checkPartial=false); + bool delaySignal=false, const std::vector &objNames={}); + bool afterRestore(bool checkPartial=false); bool afterRestore(const std::vector &, bool checkPartial=false); enum ExportStatus { NotExporting, diff --git a/src/App/DocumentObserver.h b/src/App/DocumentObserver.h index c32c780a01..b93373ae2b 100644 --- a/src/App/DocumentObserver.h +++ b/src/App/DocumentObserver.h @@ -62,6 +62,14 @@ public: /*! Assignment operator */ void operator=(const std::string&); + bool operator==(const DocumentT &other) const { + return document == other.document; + } + + bool operator<(const DocumentT &other) const { + return document < other.document; + } + /*! Get a pointer to the document or 0 if it doesn't exist any more. */ Document* getDocument() const; /*! Get the name of the document. */ diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index e78abd3c22..f92879aa4e 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -2458,6 +2458,7 @@ class App::DocInfo : public: typedef boost::signals2::scoped_connection Connection; Connection connFinishRestoreDocument; + Connection connPendingReloadDocument; Connection connDeleteDocument; Connection connSaveDocument; Connection connDeletedObject; @@ -2589,6 +2590,7 @@ public: FC_LOG("deinit " << (pcDoc?pcDoc->getName():filePath())); assert(links.empty()); connFinishRestoreDocument.disconnect(); + connPendingReloadDocument.disconnect(); connDeleteDocument.disconnect(); connSaveDocument.disconnect(); connDeletedObject.disconnect(); @@ -2606,6 +2608,8 @@ public: App::Application &app = App::GetApplication(); connFinishRestoreDocument = app.signalFinishRestoreDocument.connect( boost::bind(&DocInfo::slotFinishRestoreDocument,this,bp::_1)); + connPendingReloadDocument = app.signalPendingReloadDocument.connect( + boost::bind(&DocInfo::slotFinishRestoreDocument,this,bp::_1)); connDeleteDocument = app.signalDeleteDocument.connect( boost::bind(&DocInfo::slotDeleteDocument,this,bp::_1)); connSaveDocument = app.signalSaveDocument.connect( @@ -2617,6 +2621,8 @@ public: else{ for(App::Document *doc : App::GetApplication().getDocuments()) { if(getFullPath(doc->getFileName()) == fullpath) { + if(doc->testStatus(App::Document::PartialDoc) && !doc->getObject(objName)) + break; attach(doc); return; } @@ -2642,22 +2648,36 @@ public: continue; } auto obj = doc->getObject(link->objectName.c_str()); - if(!obj) + if(obj) + link->restoreLink(obj); + else if (doc->testStatus(App::Document::PartialDoc)) { + App::GetApplication().addPendingDocument( + doc->FileName.getValue(), + link->objectName.c_str(), + false); + FC_WARN("reloading partial document '" << doc->FileName.getValue() + << "' due to object " << link->objectName); + } else FC_WARN("object '" << link->objectName << "' not found in document '" << doc->getName() << "'"); - else - link->restoreLink(obj); } for(auto &v : parentLinks) { v.first->setFlag(PropertyLinkBase::LinkRestoring); v.first->aboutToSetValue(); for(auto link : v.second) { auto obj = doc->getObject(link->objectName.c_str()); - if(!obj) + if(obj) + link->restoreLink(obj); + else if (doc->testStatus(App::Document::PartialDoc)) { + App::GetApplication().addPendingDocument( + doc->FileName.getValue(), + link->objectName.c_str(), + false); + FC_WARN("reloading partial document '" << doc->FileName.getValue() + << "' due to object " << link->objectName); + } else FC_WARN("object '" << link->objectName << "' not found in document '" << doc->getName() << "'"); - else - link->restoreLink(obj); } v.first->hasSetValue(); v.first->setFlag(PropertyLinkBase::LinkRestoring,false); @@ -2723,16 +2743,17 @@ public: } } - // time stamp changed, touch the linking document. Unfortunately, there - // is no way to setModfied() for an App::Document. We don't want to touch - // all PropertyXLink for a document, because the linked object is - // potentially unchanged. So we just touch at most one. + // time stamp changed, touch the linking document. std::set docs; for(auto link : links) { auto linkdoc = static_cast(link->getContainer())->getDocument(); auto ret = docs.insert(linkdoc); - if(ret.second && !linkdoc->isTouched()) - link->touch(); + if(ret.second) { + // This will signal the Gui::Document to call setModified(); + FC_LOG("touch document " << linkdoc->getName() + << " on time stamp change of " << link->getFullName()); + linkdoc->Comment.touch(); + } } } @@ -3473,7 +3494,12 @@ PropertyXLink::getDocumentOutList(App::Document *doc) { std::map > ret; for(auto &v : _DocInfoMap) { for(auto link : v.second->links) { - if(!v.second->pcDoc) continue; + if(!v.second->pcDoc + || link->getScope() == LinkScope::Hidden + || link->testStatus(Property::PropTransient) + || link->testStatus(Property::Transient) + || link->testStatus(Property::PropNoPersist)) + continue; auto obj = dynamic_cast(link->getContainer()); if(!obj || !obj->getNameInDocument() || !obj->getDocument()) continue; @@ -3493,6 +3519,11 @@ PropertyXLink::getDocumentInList(App::Document *doc) { continue; auto &docs = ret[v.second->pcDoc]; for(auto link : v.second->links) { + if(link->getScope() == LinkScope::Hidden + || link->testStatus(Property::PropTransient) + || link->testStatus(Property::Transient) + || link->testStatus(Property::PropNoPersist)) + continue; auto obj = dynamic_cast(link->getContainer()); if(obj && obj->getNameInDocument() && obj->getDocument()) docs.insert(obj->getDocument()); @@ -4460,12 +4491,12 @@ void PropertyXLinkContainer::breakLink(App::DocumentObject *obj, bool clear) { } int PropertyXLinkContainer::checkRestore(std::string *msg) const { - if(_LinkRestored) - return 1; - for(auto &v : _XLinks) { - int res = v.second->checkRestore(msg); - if(res) - return res; + if(_LinkRestored) { + for(auto &v : _XLinks) { + int res = v.second->checkRestore(msg); + if(res) + return res; + } } return 0; } diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index e0ce35be61..0dc5ed879a 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1955,13 +1955,13 @@ void Application::runApplication(void) mainApp.setApplicationName(QString::fromUtf8(it->second.c_str())); } else { - mainApp.setApplicationName(QString::fromUtf8(App::GetApplication().getExecutableName())); + mainApp.setApplicationName(QString::fromStdString(App::Application::getExecutableName())); } #ifndef Q_OS_MACX mainApp.setWindowIcon(Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str())); #endif QString plugin; - plugin = QString::fromUtf8(App::GetApplication().getHomePath()); + plugin = QString::fromStdString(App::Application::getHomePath()); plugin += QLatin1String("/plugins"); QCoreApplication::addLibraryPath(plugin); @@ -2127,7 +2127,7 @@ void Application::runApplication(void) // init the Inventor subsystem initOpenInventor(); - QString home = QString::fromUtf8(App::GetApplication().getHomePath()); + QString home = QString::fromStdString(App::Application::getHomePath()); it = cfg.find("WindowTitle"); if (it != cfg.end()) { @@ -2267,7 +2267,7 @@ void Application::runApplication(void) try { std::stringstream s; - s << App::Application::getTempPath() << App::GetApplication().getExecutableName() + s << App::Application::getTempPath() << App::Application::getExecutableName() << "_" << QCoreApplication::applicationPid() << ".lock"; // open a lock file with the PID Base::FileInfo fi(s.str()); diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index cf23554b0d..82a883cb1f 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -1029,7 +1029,7 @@ PyObject* Application::sAddResPath(PyObject * /*self*/, PyObject *args) PyMem_Free(filePath); if (QDir::isRelativePath(path)) { // Home path ends with '/' - QString home = QString::fromUtf8(App::GetApplication().getHomePath()); + QString home = QString::fromStdString(App::Application::getHomePath()); path = home + path; } @@ -1048,7 +1048,7 @@ PyObject* Application::sAddLangPath(PyObject * /*self*/, PyObject *args) PyMem_Free(filePath); if (QDir::isRelativePath(path)) { // Home path ends with '/' - QString home = QString::fromUtf8(App::GetApplication().getHomePath()); + QString home = QString::fromStdString(App::Application::getHomePath()); path = home + path; } @@ -1066,7 +1066,7 @@ PyObject* Application::sAddIconPath(PyObject * /*self*/, PyObject *args) PyMem_Free(filePath); if (QDir::isRelativePath(path)) { // Home path ends with '/' - QString home = QString::fromUtf8(App::GetApplication().getHomePath()); + QString home = QString::fromStdString(App::Application::getHomePath()); path = home + path; } diff --git a/src/Gui/Assistant.cpp b/src/Gui/Assistant.cpp index f903c7a28f..e905fe8dfd 100644 --- a/src/Gui/Assistant.cpp +++ b/src/Gui/Assistant.cpp @@ -85,8 +85,8 @@ bool Assistant::startAssistant() if (proc->state() != QProcess::Running) { #ifdef Q_OS_WIN QString app; - app = QDir::toNativeSeparators(QString::fromUtf8 - (App::GetApplication().getHomePath()) + QLatin1String("bin/")); + app = QDir::toNativeSeparators(QString::fromStdString + (App::Application::getHomePath()) + QLatin1String("bin/")); #elif defined(Q_OS_MAC) QString app = QCoreApplication::applicationDirPath() + QDir::separator(); #else @@ -95,8 +95,8 @@ bool Assistant::startAssistant() app += QLatin1String("assistant"); // get the name of the executable and the doc path - QString exe = QString::fromUtf8(App::GetApplication().getExecutableName()); - QString doc = QString::fromUtf8(App::Application::getHelpDir().c_str()); + QString exe = QString::fromStdString(App::Application::getExecutableName()); + QString doc = QString::fromStdString(App::Application::getHelpDir()); QString qhc = doc + exe.toLower() + QLatin1String(".qhc"); diff --git a/src/Gui/BitmapFactory.cpp b/src/Gui/BitmapFactory.cpp index bfa5317cf1..2e9ffd7156 100644 --- a/src/Gui/BitmapFactory.cpp +++ b/src/Gui/BitmapFactory.cpp @@ -97,15 +97,15 @@ BitmapFactoryInst& BitmapFactoryInst::instance(void) std::map::const_iterator it; it = App::GetApplication().Config().find("ProgramIcons"); if (it != App::GetApplication().Config().end()) { - QString home = QString::fromUtf8(App::GetApplication().getHomePath()); + QString home = QString::fromStdString(App::Application::getHomePath()); QString path = QString::fromUtf8(it->second.c_str()); if (QDir(path).isRelative()) { path = QFileInfo(QDir(home), path).absoluteFilePath(); } _pcSingleton->addPath(path); } - _pcSingleton->addPath(QString::fromLatin1("%1/icons").arg(QString::fromUtf8(App::GetApplication().getHomePath()))); - _pcSingleton->addPath(QString::fromLatin1("%1/icons").arg(QString::fromUtf8(App::GetApplication().Config()["UserAppData"].c_str()))); + _pcSingleton->addPath(QString::fromLatin1("%1/icons").arg(QString::fromStdString(App::Application::getHomePath()))); + _pcSingleton->addPath(QString::fromLatin1("%1/icons").arg(QString::fromStdString(App::Application::getUserAppDataDir()))); _pcSingleton->addPath(QLatin1String(":/icons/")); _pcSingleton->addPath(QLatin1String(":/Icons/")); } diff --git a/src/Gui/BlenderNavigationStyle.cpp b/src/Gui/BlenderNavigationStyle.cpp index b5b0cfbc42..563b124e86 100644 --- a/src/Gui/BlenderNavigationStyle.cpp +++ b/src/Gui/BlenderNavigationStyle.cpp @@ -88,12 +88,10 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + const SbVec2f posn = normalizePixelPos(pos); + const SbVec2f prevnormalized = this->lastmouseposition; this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not @@ -107,15 +105,7 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { @@ -126,41 +116,8 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { - const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; - const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; - switch (event->getKey()) { - case SoKeyboardEvent::LEFT_CONTROL: - case SoKeyboardEvent::RIGHT_CONTROL: - this->ctrldown = press; - break; - case SoKeyboardEvent::LEFT_SHIFT: - case SoKeyboardEvent::RIGHT_SHIFT: - this->shiftdown = press; - break; - case SoKeyboardEvent::LEFT_ALT: - case SoKeyboardEvent::RIGHT_ALT: - this->altdown = press; - break; - case SoKeyboardEvent::H: - processed = true; - viewer->saveHomePosition(); - break; - case SoKeyboardEvent::R: - processed = true; - viewer->resetToHomePosition(); - break; - case SoKeyboardEvent::S: - case SoKeyboardEvent::HOME: - case SoKeyboardEvent::LEFT_ARROW: - case SoKeyboardEvent::UP_ARROW: - case SoKeyboardEvent::RIGHT_ARROW: - case SoKeyboardEvent::DOWN_ARROW: - if (!this->isViewing()) - this->setViewing(true); - break; - default: - break; - } + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); } // Mouse Button / Spaceball Button handling @@ -179,10 +136,6 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = true; } - //else if (press && (this->currentmode == NavigationStyle::IDLE)) { - // this->setViewing(true); - // processed = true; - //} else if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; @@ -193,30 +146,8 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; } - // issue #0002433: avoid to swallow the UP event if down the - // scene graph somewhere a dialog gets opened - else if (press) { - SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // a double-click? - if (tmp.getValue() < dci) { - mouseDownConsumedEvent = *event; - mouseDownConsumedEvent.setTime(ev->getTime()); - processed = true; - } - else { - mouseDownConsumedEvent.setTime(ev->getTime()); - // 'ANY' is used to mark that we don't know yet if it will - // be a double-click event. - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } - } - else if (!press) { - if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { - // now handle the postponed event - inherited::processSoEvent(&mouseDownConsumedEvent); - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } + else { + processed = processClickEvent(event); } break; case SoMouseButtonEvent::BUTTON2: @@ -328,11 +259,6 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) this->lockButton1 = false; processed = true; } - - //if (curmode == NavigationStyle::DRAGGING) { - // if (doSpin()) - // newmode = NavigationStyle::SPINNING; - //} break; case BUTTON1DOWN: case CTRLDOWN|BUTTON1DOWN: @@ -354,9 +280,6 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) } newmode = NavigationStyle::DRAGGING; break; - //case BUTTON1DOWN|BUTTON2DOWN|BUTTON3DOWN: - // newmode = NavigationStyle::ZOOMING; - // break; case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN: case CTRLDOWN|BUTTON3DOWN: newmode = NavigationStyle::ZOOMING; @@ -378,10 +301,8 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) // If not handled in this class, pass on upwards in the inheritance // hierarchy. - if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) + if (!processed) processed = inherited::processSoEvent(ev); - else - return true; return processed; } diff --git a/src/Gui/CADNavigationStyle.cpp b/src/Gui/CADNavigationStyle.cpp index cd8067abb3..c9e351fb2b 100644 --- a/src/Gui/CADNavigationStyle.cpp +++ b/src/Gui/CADNavigationStyle.cpp @@ -92,12 +92,10 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + const SbVec2f posn = normalizePixelPos(pos); + const SbVec2f prevnormalized = this->lastmouseposition; this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not @@ -111,15 +109,7 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { @@ -130,37 +120,8 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { - const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; - const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; - switch (event->getKey()) { - case SoKeyboardEvent::LEFT_CONTROL: - case SoKeyboardEvent::RIGHT_CONTROL: - this->ctrldown = press; - break; - case SoKeyboardEvent::LEFT_SHIFT: - case SoKeyboardEvent::RIGHT_SHIFT: - this->shiftdown = press; - break; - case SoKeyboardEvent::LEFT_ALT: - case SoKeyboardEvent::RIGHT_ALT: - this->altdown = press; - break; - case SoKeyboardEvent::H: - processed = true; - viewer->saveHomePosition(); - break; - case SoKeyboardEvent::S: - case SoKeyboardEvent::HOME: - case SoKeyboardEvent::LEFT_ARROW: - case SoKeyboardEvent::UP_ARROW: - case SoKeyboardEvent::RIGHT_ARROW: - case SoKeyboardEvent::DOWN_ARROW: - if (!this->isViewing()) - this->setViewing(true); - break; - default: - break; - } + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); } // Mouse Button / Spaceball Button handling @@ -174,39 +135,11 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) case SoMouseButtonEvent::BUTTON1: this->lockrecenter = true; this->button1down = press; -#if 0 // disable to avoid interferences where this key combination is used, too - if (press && ev->wasShiftDown() && - (this->currentmode != NavigationStyle::SELECTION)) { - this->centerTime = ev->getTime(); - float ratio = vp.getViewportAspectRatio(); - SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio); - this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue()); - this->lockrecenter = false; - } - else if (!press && ev->wasShiftDown() && - (this->currentmode != NavigationStyle::SELECTION)) { - SbTime tmp = (ev->getTime() - this->centerTime); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // is it just a left click? - if (tmp.getValue() < dci && !this->lockrecenter) { - if (!this->moveToPoint(pos)) { - panToCenter(panningplane, posn); - this->interactiveCountDec(); - } - processed = true; - } - } - else -#endif if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) { newmode = NavigationStyle::SEEK_MODE; this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = true; } - //else if (press && (this->currentmode == NavigationStyle::IDLE)) { - // this->setViewing(true); - // processed = true; - //} else if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; @@ -225,30 +158,8 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; } - // issue #0002433: avoid to swallow the UP event if down the - // scene graph somewhere a dialog gets opened - else if (press) { - SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // a double-click? - if (tmp.getValue() < dci) { - mouseDownConsumedEvent = *event; - mouseDownConsumedEvent.setTime(ev->getTime()); - processed = true; - } - else { - mouseDownConsumedEvent.setTime(ev->getTime()); - // 'ANY' is used to mark that we don't know yet if it will - // be a double-click event. - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } - } - else if (!press) { - if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { - // now handle the postponed event - inherited::processSoEvent(&mouseDownConsumedEvent); - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } + else { + processed = processClickEvent(event); } break; case SoMouseButtonEvent::BUTTON2: @@ -366,11 +277,6 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) this->lockButton1 = false; processed = true; } - - //if (curmode == NavigationStyle::DRAGGING) { - // if (doSpin()) - // newmode = NavigationStyle::SPINNING; - //} break; case BUTTON1DOWN: // make sure not to change the selection when stopping spinning @@ -403,16 +309,6 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN: newmode = NavigationStyle::ZOOMING; break; - //case CTRLDOWN: - //case CTRLDOWN|BUTTON1DOWN: - //case CTRLDOWN|SHIFTDOWN: - //case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN: - // newmode = NavigationStyle::SELECTION; - // break; - //case BUTTON1DOWN|BUTTON3DOWN: - //case CTRLDOWN|BUTTON3DOWN: - // newmode = NavigationStyle::ZOOMING; - // break; // There are many cases we don't handle that just falls through to // the default case, like SHIFTDOWN, CTRLDOWN, CTRLDOWN|SHIFTDOWN, @@ -424,10 +320,6 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) default: // The default will make a spin stop and otherwise not do // anything. - //if ((curmode != NavigationStyle::SEEK_WAIT_MODE) && - // (curmode != NavigationStyle::SEEK_MODE)) { - // newmode = NavigationStyle::IDLE; - //} break; } @@ -443,10 +335,8 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) // If not handled in this class, pass on upwards in the inheritance // hierarchy. - if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) + if (!processed) processed = inherited::processSoEvent(ev); - else - return true; return processed; } diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index b901e97e8d..8990d7af4f 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -839,6 +839,7 @@ SET(View3D_CPP_SRCS MayaGestureNavigationStyle.cpp OpenCascadeNavigationStyle.cpp OpenSCADNavigationStyle.cpp + TinkerCADNavigationStyle.cpp TouchpadNavigationStyle.cpp GestureNavigationStyle.cpp SplitView3DInventor.cpp diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index cd95d3ae31..3f44c28d87 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -1117,7 +1117,7 @@ void MacroCommand::activated(int iMsg) d = QDir(QString::fromUtf8(cMacroPath.c_str())); } else { - QString dirstr = QString::fromUtf8(App::GetApplication().getHomePath()) + QString::fromUtf8("Macro"); + QString dirstr = QString::fromStdString(App::Application::getHomePath()) + QString::fromLatin1("Macro"); d = QDir(dirstr); } diff --git a/src/Gui/CommandT.h b/src/Gui/CommandT.h index 64154d8cca..a73095e3fd 100644 --- a/src/Gui/CommandT.h +++ b/src/Gui/CommandT.h @@ -279,11 +279,11 @@ inline void cmdAppObjectShow(const App::DocumentObject* obj) { * in-place editing an object, which may be brought in through linking to an * external group. */ -inline void cmdSetEdit(const App::DocumentObject* obj) { +inline void cmdSetEdit(const App::DocumentObject* obj, int mod = 0) { if (obj && obj->getNameInDocument()) { Gui::Command::doCommand(Gui::Command::Gui, - "Gui.ActiveDocument.setEdit(App.getDocument('%s').getObject('%s'))", - obj->getDocument()->getName(), obj->getNameInDocument()); + "Gui.ActiveDocument.setEdit(App.getDocument('%s').getObject('%s'), %d)", + obj->getDocument()->getName(), obj->getNameInDocument(), mod); } } diff --git a/src/Gui/DlgActionsImp.cpp b/src/Gui/DlgActionsImp.cpp index 35aa3b9f0b..f2c85ebb99 100644 --- a/src/Gui/DlgActionsImp.cpp +++ b/src/Gui/DlgActionsImp.cpp @@ -71,7 +71,7 @@ DlgCustomActionsImp::DlgCustomActionsImp( QWidget* parent ) for (unsigned int i=0; iactionMacros->insertItem(0,d[i],QVariant(false)); - QString systemMacroDirStr = QString::fromUtf8(App::GetApplication().getHomePath()) + QString::fromUtf8("Macro"); + QString systemMacroDirStr = QString::fromStdString(App::Application::getHomePath()) + QString::fromLatin1("Macro"); d = QDir(systemMacroDirStr, QLatin1String("*.FCMacro *.py")); if (d.exists()) { for (unsigned int i=0; isetText(0, dir[i]); } - QString dirstr = QString::fromUtf8(App::GetApplication().getHomePath()) + QString::fromUtf8("Macro"); + QString dirstr = QString::fromStdString(App::Application::getHomePath()) + QString::fromLatin1("Macro"); dir = QDir(dirstr, QLatin1String("*.FCMacro *.py")); ui->systemMacroListBox->clear(); @@ -268,7 +268,7 @@ void DlgMacroExecuteImp::accept() dir =QDir(this->macroPath); } else { - QString dirstr = QString::fromUtf8(App::GetApplication().getHomePath()) + QString::fromUtf8("Macro"); + QString dirstr = QString::fromStdString(App::Application::getHomePath()) + QString::fromLatin1("Macro"); dir = QDir(dirstr); } @@ -319,7 +319,7 @@ void DlgMacroExecuteImp::on_editButton_clicked() else { //index == 1 system-wide item = ui->systemMacroListBox->currentItem(); - dir.setPath(QString::fromUtf8(App::GetApplication().getHomePath()) + QString::fromUtf8("Macro")); + dir.setPath(QString::fromStdString(App::Application::getHomePath()) + QString::fromLatin1("Macro")); } if (!item) diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 589deecede..813e84a69f 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -1499,7 +1499,7 @@ void Document::slotFinishRestoreDocument(const App::Document& doc) } // reset modified flag - setModified(false); + setModified(doc.testStatus(App::Document::LinkStampChanged)); } void Document::slotShowHidden(const App::Document& doc) diff --git a/src/Gui/DocumentRecovery.cpp b/src/Gui/DocumentRecovery.cpp index 4f2d60006e..924c4e32fb 100644 --- a/src/Gui/DocumentRecovery.cpp +++ b/src/Gui/DocumentRecovery.cpp @@ -666,7 +666,7 @@ void DocumentRecoveryHandler::checkForPreviousCrashes(const std::function locks = tmp.entryInfoList(); for (QList::iterator it = locks.begin(); it != locks.end(); ++it) { QString bn = it->baseName(); diff --git a/src/Gui/DownloadItem.cpp b/src/Gui/DownloadItem.cpp index 43e59a26ba..6e87fbc5e8 100644 --- a/src/Gui/DownloadItem.cpp +++ b/src/Gui/DownloadItem.cpp @@ -273,7 +273,7 @@ void DownloadItem::init() QString DownloadItem::getDownloadDirectory() const { - QString exe = QString::fromLatin1(App::GetApplication().getExecutableName()); + QString exe = QString::fromStdString(App::Application::getExecutableName()); QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); QString dirPath = QDir(path).filePath(exe); Base::Reference hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp") diff --git a/src/Gui/GestureNavigationStyle.cpp b/src/Gui/GestureNavigationStyle.cpp index 98a1e3e2a7..946efb1dcf 100644 --- a/src/Gui/GestureNavigationStyle.cpp +++ b/src/Gui/GestureNavigationStyle.cpp @@ -72,6 +72,7 @@ #include "GestureNavigationStyle.h" #include +#include #include #include "View3DInventorViewer.h" #include "Application.h" @@ -918,9 +919,8 @@ SbBool GestureNavigationStyle::processSoEvent(const SoEvent* const ev) //whatever else, we don't track } } - this->ctrldown = ev->wasCtrlDown(); - this->shiftdown = ev->wasShiftDown(); - this->altdown = ev->wasAltDown(); + + syncModifierKeys(ev); smev.modifiers = (this->button1down ? NS::Event::BUTTON1DOWN : 0) | diff --git a/src/Gui/GuiApplication.cpp b/src/Gui/GuiApplication.cpp index b254658000..1a9e7e335f 100644 --- a/src/Gui/GuiApplication.cpp +++ b/src/Gui/GuiApplication.cpp @@ -177,7 +177,7 @@ public: , running(false) { timer->setSingleShot(true); - std::string exeName = App::GetApplication().getExecutableName(); + std::string exeName = App::Application::getExecutableName(); serverName = QString::fromStdString(exeName); } diff --git a/src/Gui/InventorNavigationStyle.cpp b/src/Gui/InventorNavigationStyle.cpp index 74062c51b8..b9bfe2986d 100644 --- a/src/Gui/InventorNavigationStyle.cpp +++ b/src/Gui/InventorNavigationStyle.cpp @@ -96,12 +96,10 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev) const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + const SbVec2f posn = normalizePixelPos(pos); + const SbVec2f prevnormalized = this->lastmouseposition; this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not @@ -115,15 +113,7 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { @@ -134,37 +124,8 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev) // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { - const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; - const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; - switch (event->getKey()) { - case SoKeyboardEvent::LEFT_CONTROL: - case SoKeyboardEvent::RIGHT_CONTROL: - this->ctrldown = press; - break; - case SoKeyboardEvent::LEFT_SHIFT: - case SoKeyboardEvent::RIGHT_SHIFT: - this->shiftdown = press; - break; - case SoKeyboardEvent::LEFT_ALT: - case SoKeyboardEvent::RIGHT_ALT: - this->altdown = press; - break; - case SoKeyboardEvent::H: - processed = true; - viewer->saveHomePosition(); - break; - case SoKeyboardEvent::S: - case SoKeyboardEvent::HOME: - case SoKeyboardEvent::LEFT_ARROW: - case SoKeyboardEvent::UP_ARROW: - case SoKeyboardEvent::RIGHT_ARROW: - case SoKeyboardEvent::DOWN_ARROW: - if (!this->isViewing()) - this->setViewing(true); - break; - default: - break; - } + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); } // Mouse Button / Spaceball Button handling @@ -218,30 +179,8 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev) processed = true; this->lockrecenter = true; } - // issue #0002433: avoid to swallow the UP event if down the - // scene graph somewhere a dialog gets opened - else if (press) { - SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // a double-click? - if (tmp.getValue() < dci) { - mouseDownConsumedEvent = *event; - mouseDownConsumedEvent.setTime(ev->getTime()); - processed = true; - } - else { - mouseDownConsumedEvent.setTime(ev->getTime()); - // 'ANY' is used to mark that we don't know yet if it will - // be a double-click event. - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } - } - else if (!press) { - if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { - // now handle the postponed event - inherited::processSoEvent(&mouseDownConsumedEvent); - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } + else { + processed = processClickEvent(event); } break; case SoMouseButtonEvent::BUTTON2: diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 35a335e9c3..b0dfe66630 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -1490,7 +1490,7 @@ QPixmap MainWindow::aboutImage() const if (!about_path.empty() && about_image.isNull()) { QString path = QString::fromUtf8(about_path.c_str()); if (QDir(path).isRelative()) { - QString home = QString::fromUtf8(App::GetApplication().getHomePath()); + QString home = QString::fromStdString(App::Application::getHomePath()); path = QFileInfo(QDir(home), path).absoluteFilePath(); } about_image.load(path); @@ -1517,7 +1517,7 @@ QPixmap MainWindow::splashImage() const if (splash_image.isNull()) { QString path = QString::fromUtf8(splash_path.c_str()); if (QDir(path).isRelative()) { - QString home = QString::fromUtf8(App::GetApplication().getHomePath()); + QString home = QString::fromStdString(App::Application::getHomePath()); path = QFileInfo(QDir(home), path).absoluteFilePath(); } diff --git a/src/Gui/MayaGestureNavigationStyle.cpp b/src/Gui/MayaGestureNavigationStyle.cpp index dbb5815a6c..8c9bd83c6c 100644 --- a/src/Gui/MayaGestureNavigationStyle.cpp +++ b/src/Gui/MayaGestureNavigationStyle.cpp @@ -190,9 +190,7 @@ SbBool MayaGestureNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - this->ctrldown = ev->wasCtrlDown(); - this->shiftdown = ev->wasShiftDown(); - this->altdown = ev->wasAltDown(); + syncModifierKeys(ev); //before this block, mouse button states in NavigationStyle::buttonXdown reflected those before current event arrived. //track mouse button states if (evIsButton) { @@ -380,11 +378,11 @@ SbBool MayaGestureNavigationStyle::processSoEvent(const SoEvent * const ev) this->mouseMoveThresholdBroken = false; pan(viewer->getSoRenderManager()->getCamera());//set up panningplane int &cnt = this->mousedownConsumedCount; - this->mousedownConsumedEvent[cnt] = *event;//hopefully, a shallow copy is enough. There are no pointers stored in events, apparently. Will lose a subclass, though. + this->mousedownConsumedEvents[cnt] = *event;//hopefully, a shallow copy is enough. There are no pointers stored in events, apparently. Will lose a subclass, though. cnt++; assert(cnt<=2); - if(cnt>static_cast(sizeof(mousedownConsumedEvent))){ - cnt=sizeof(mousedownConsumedEvent);//we are in trouble + if(cnt>static_cast(sizeof(mousedownConsumedEvents))){ + cnt=sizeof(mousedownConsumedEvents);//we are in trouble } processed = true;//just consume this event, and wait for the move threshold to be broken to start dragging/panning } @@ -398,7 +396,7 @@ SbBool MayaGestureNavigationStyle::processSoEvent(const SoEvent * const ev) if(! processed) { //re-synthesize all previously-consumed mouseDowns, if any. They might have been re-synthesized already when threshold was broken. for( int i=0; i < this->mousedownConsumedCount; i++ ){ - inherited::processSoEvent(& (this->mousedownConsumedEvent[i]));//simulate the previously-comsumed mousedown. + inherited::processSoEvent(& (this->mousedownConsumedEvents[i]));//simulate the previously-comsumed mousedown. } this->mousedownConsumedCount = 0; processed = inherited::processSoEvent(ev);//explicitly, just for clarity that we are sending a full click sequence. @@ -443,7 +441,7 @@ SbBool MayaGestureNavigationStyle::processSoEvent(const SoEvent * const ev) //no, we are not entering navigation. //re-synthesize all previously-consumed mouseDowns, if any, and propagate this mousemove. for( int i=0; i < this->mousedownConsumedCount; i++ ){ - inherited::processSoEvent(& (this->mousedownConsumedEvent[i]));//simulate the previously-comsumed mousedown. + inherited::processSoEvent(& (this->mousedownConsumedEvents[i]));//simulate the previously-comsumed mousedown. } this->mousedownConsumedCount = 0; processed = inherited::processSoEvent(ev);//explicitly, just for clarity that we are sending a full click sequence. diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index 43a4a73045..fb971292e1 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -64,7 +64,7 @@ struct NavigationStyleP { { this->animationsteps = 0; this->animationdelta = 0; - this->animsensor = 0; + this->animsensor = nullptr; this->sensitivity = 2.0f; this->resetcursorpos = false; this->rotationCenterFound = false; @@ -173,7 +173,7 @@ const Base::Type& NavigationStyleEvent::style() const TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStyle,Base::BaseClass) -NavigationStyle::NavigationStyle() : viewer(0), mouseSelection(0) +NavigationStyle::NavigationStyle() : viewer(nullptr), mouseSelection(nullptr) { PRIVATE(this) = new NavigationStyleP(); PRIVATE(this)->animsensor = new SoTimerSensor(NavigationStyleP::viewAnimationCB, this); @@ -261,17 +261,17 @@ void NavigationStyle::finalize() delete[] this->log.time; } -void NavigationStyle::interactiveCountInc(void) +void NavigationStyle::interactiveCountInc() { viewer->interactiveCountInc(); } -void NavigationStyle::interactiveCountDec(void) +void NavigationStyle::interactiveCountDec() { viewer->interactiveCountDec(); } -int NavigationStyle::getInteractiveCount(void) const +int NavigationStyle::getInteractiveCount() const { return viewer->getInteractiveCount(); } @@ -288,7 +288,7 @@ NavigationStyle::OrbitStyle NavigationStyle::getOrbitStyle() const return NavigationStyle::OrbitStyle(projector->getOrbitStyle()); } -SbBool NavigationStyle::isViewing(void) const +SbBool NavigationStyle::isViewing() const { return viewer->isViewing(); } @@ -298,7 +298,7 @@ void NavigationStyle::setViewing(SbBool enable) viewer->setViewing(enable); } -SbBool NavigationStyle::isSeekMode(void) const +SbBool NavigationStyle::isSeekMode() const { return viewer->isSeekMode(); } @@ -321,7 +321,7 @@ void NavigationStyle::seekToPoint(const SbVec3f& scenepos) SbBool NavigationStyle::lookAtPoint(const SbVec2s screenpos) { SoCamera* cam = viewer->getSoRenderManager()->getCamera(); - if (cam == 0) return false; + if (cam == nullptr) return false; SoRayPickAction rpaction(viewer->getSoRenderManager()->getViewportRegion()); rpaction.setPoint(screenpos); @@ -343,7 +343,7 @@ SbBool NavigationStyle::lookAtPoint(const SbVec2s screenpos) void NavigationStyle::lookAtPoint(const SbVec3f& pos) { SoCamera* cam = viewer->getSoRenderManager()->getCamera(); - if (cam == 0) return; + if (cam == nullptr) return; PRIVATE(this)->rotationCenterFound = false; // Find global coordinates of focal point. @@ -401,7 +401,7 @@ void NavigationStyle::lookAtPoint(const SbVec3f& pos) void NavigationStyle::setCameraOrientation(const SbRotation& rot, SbBool moveToCenter) { SoCamera* cam = viewer->getSoRenderManager()->getCamera(); - if (cam == 0) return; + if (cam == nullptr) return; // Find global coordinates of focal point. SbVec3f direction; @@ -611,7 +611,7 @@ void NavigationStyle::viewAll() */ void NavigationStyle::reorientCamera(SoCamera * cam, const SbRotation & rot) { - if (cam == NULL) return; + if (cam == nullptr) return; // Find global coordinates of focal point. SbVec3f direction; @@ -630,7 +630,7 @@ void NavigationStyle::reorientCamera(SoCamera * cam, const SbRotation & rot) void NavigationStyle::panCamera(SoCamera * cam, float aspectratio, const SbPlane & panplane, const SbVec2f & currpos, const SbVec2f & prevpos) { - if (cam == NULL) return; // can happen for empty scenegraph + if (cam == nullptr) return; // can happen for empty scenegraph if (currpos == prevpos) return; // useless invocation @@ -659,7 +659,7 @@ void NavigationStyle::pan(SoCamera* camera) // The plane we're projecting the mouse coordinates to get 3D // coordinates should stay the same during the whole pan // operation, so we should calculate this value here. - if (camera == NULL) { // can happen for empty scenegraph + if (camera == nullptr) { // can happen for empty scenegraph this->panningplane = SbPlane(SbVec3f(0, 0, 1), 0); } else { @@ -689,7 +689,7 @@ void NavigationStyle::panToCenter(const SbPlane & pplane, const SbVec2f & currpo */ void NavigationStyle::zoom(SoCamera * cam, float diffvalue) { - if (cam == NULL) return; // can happen for empty scenegraph + if (cam == nullptr) return; // can happen for empty scenegraph SoType t = cam->getTypeId(); SbName tname = t.getName(); @@ -870,7 +870,7 @@ void NavigationStyle::setRotationCenter(const SbVec3f& cnt) SbVec3f NavigationStyle::getFocalPoint() const { SoCamera* cam = viewer->getSoRenderManager()->getCamera(); - if (cam == 0) + if (cam == nullptr) return SbVec3f(0,0,0); // Find global coordinates of focal point. @@ -887,7 +887,7 @@ SbVec3f NavigationStyle::getFocalPoint() const void NavigationStyle::spin(const SbVec2f & pointerpos) { if (this->log.historysize < 2) return; - assert(this->spinprojector != NULL); + assert(this->spinprojector != nullptr); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); SbVec2s glsize(vp.getViewportSizePixels()); @@ -965,7 +965,7 @@ void NavigationStyle::spin(const SbVec2f & pointerpos) * \param prevpos previous normalized position of mouse pointer */ void NavigationStyle::spin_simplified(SoCamera* cam, SbVec2f curpos, SbVec2f prevpos){ - assert(this->spinprojector != NULL); + assert(this->spinprojector != nullptr); // 0000333: Turntable camera rotation SbMatrix mat; @@ -1163,7 +1163,7 @@ NavigationStyle::setAnimationEnabled(const SbBool enable) */ SbBool -NavigationStyle::isAnimationEnabled(void) const +NavigationStyle::isAnimationEnabled() const { return this->spinanimatingallowed; } @@ -1172,7 +1172,7 @@ NavigationStyle::isAnimationEnabled(void) const Query if the model in the viewer is currently in spinning mode after a user drag. */ -SbBool NavigationStyle::isAnimating(void) const +SbBool NavigationStyle::isAnimating() const { return this->currentmode == NavigationStyle::SPINNING; } @@ -1195,7 +1195,7 @@ void NavigationStyle::startAnimating(const SbVec3f& axis, float velocity) this->spinRotation = rot; } -void NavigationStyle::stopAnimating(void) +void NavigationStyle::stopAnimating() { if (this->currentmode != NavigationStyle::SPINNING) { return; @@ -1321,7 +1321,7 @@ void NavigationStyle::stopSelection() if (mouseSelection) { mouseSelection->releaseMouseModel(); delete mouseSelection; - mouseSelection = 0; + mouseSelection = nullptr; } } @@ -1367,11 +1367,26 @@ void NavigationStyle::addToLog(const SbVec2s pos, const SbTime time) // This method "clears" the mouse location log, used for spin // animation calculations. -void NavigationStyle::clearLog(void) +void NavigationStyle::clearLog() { this->log.historysize = 0; } +void NavigationStyle::syncModifierKeys(const SoEvent * const ev) +{ + // Mismatches in state of the modifier keys happens if the user + // presses or releases them outside the viewer window. + if (this->ctrldown != ev->wasCtrlDown()) { + this->ctrldown = ev->wasCtrlDown(); + } + if (this->shiftdown != ev->wasShiftDown()) { + this->shiftdown = ev->wasShiftDown(); + } + if (this->altdown != ev->wasAltDown()) { + this->altdown = ev->wasAltDown(); + } +} + // The viewer is a state machine, and all changes to the current state // are made through this call. void NavigationStyle::setViewingMode(const ViewerMode newmode) @@ -1446,14 +1461,14 @@ SbBool NavigationStyle::processEvent(const SoEvent * const ev) pcPolygon = mouseSelection->getPositions(); selectedRole = mouseSelection->selectedRole(); delete mouseSelection; - mouseSelection = 0; + mouseSelection = nullptr; syncWithEvent(ev); return NavigationStyle::processSoEvent(ev); } else if (hd==AbstractMouseSelection::Cancel) { pcPolygon.clear(); delete mouseSelection; - mouseSelection = 0; + mouseSelection = nullptr; syncWithEvent(ev); return NavigationStyle::processSoEvent(ev); } @@ -1480,27 +1495,19 @@ SbBool NavigationStyle::processEvent(const SoEvent * const ev) SbBool NavigationStyle::processSoEvent(const SoEvent * const ev) { - const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); bool processed = false; //handle mouse wheel zoom - if(ev->isOfType(SoMouseWheelEvent::getClassTypeId())){ - doZoom( - viewer->getSoRenderManager()->getCamera(), - static_cast(ev)->getDelta(), - posn - ); - processed = true; + if (ev->isOfType(SoMouseWheelEvent::getClassTypeId())) { + const SoMouseWheelEvent * const event = static_cast(ev); + processed = processWheelEvent(event); } - if (! processed) - return viewer->processSoEventBase(ev); - else - return processed; + if (!processed) { + processed = viewer->processSoEventBase(ev); + } + + return processed; } void NavigationStyle::syncWithEvent(const SoEvent * const ev) @@ -1514,15 +1521,7 @@ void NavigationStyle::syncWithEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { @@ -1600,12 +1599,111 @@ SbBool NavigationStyle::processMotionEvent(const SoMotion3Event * const ev) return true; } +SbBool NavigationStyle::processKeyboardEvent(const SoKeyboardEvent * const event) +{ + SbBool processed = false; + const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; + switch (event->getKey()) { + case SoKeyboardEvent::LEFT_CONTROL: + case SoKeyboardEvent::RIGHT_CONTROL: + this->ctrldown = press; + break; + case SoKeyboardEvent::LEFT_SHIFT: + case SoKeyboardEvent::RIGHT_SHIFT: + this->shiftdown = press; + break; + case SoKeyboardEvent::LEFT_ALT: + case SoKeyboardEvent::RIGHT_ALT: + this->altdown = press; + break; + case SoKeyboardEvent::H: + processed = true; + viewer->saveHomePosition(); + break; + case SoKeyboardEvent::R: + processed = true; + viewer->resetToHomePosition(); + break; + case SoKeyboardEvent::S: + case SoKeyboardEvent::HOME: + case SoKeyboardEvent::LEFT_ARROW: + case SoKeyboardEvent::UP_ARROW: + case SoKeyboardEvent::RIGHT_ARROW: + case SoKeyboardEvent::DOWN_ARROW: + if (!this->isViewing()) + this->setViewing(true); + break; + case SoKeyboardEvent::PAGE_UP: + { + processed = true; + const SbVec2f posn = normalizePixelPos(event->getPosition()); + doZoom(viewer->getSoRenderManager()->getCamera(), getDelta(), posn); + break; + } + case SoKeyboardEvent::PAGE_DOWN: + { + processed = true; + const SbVec2f posn = normalizePixelPos(event->getPosition()); + doZoom(viewer->getSoRenderManager()->getCamera(), -getDelta(), posn); + break; + } + default: + break; + } + + return processed; +} + +SbBool NavigationStyle::processClickEvent(const SoMouseButtonEvent * const event) +{ + // issue #0002433: avoid to swallow the UP event if down the + // scene graph somewhere a dialog gets opened + SbBool processed = false; + const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; + if (press) { + SbTime tmp = (event->getTime() - mouseDownConsumedEvent.getTime()); + float dci = (float)QApplication::doubleClickInterval()/1000.0f; + // a double-click? + if (tmp.getValue() < dci) { + mouseDownConsumedEvent = *event; + mouseDownConsumedEvent.setTime(event->getTime()); + processed = true; + } + else { + mouseDownConsumedEvent.setTime(event->getTime()); + // 'ANY' is used to mark that we don't know yet if it will + // be a double-click event. + mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); + } + } + else if (!press) { + if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { + // now handle the postponed event + NavigationStyle::processSoEvent(&mouseDownConsumedEvent); + mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); + } + } + + return processed; +} + +SbBool NavigationStyle::processWheelEvent(const SoMouseWheelEvent * const event) +{ + const SbVec2s pos(event->getPosition()); + const SbVec2f posn = normalizePixelPos(pos); + + //handle mouse wheel zoom + doZoom(viewer->getSoRenderManager()->getCamera(), + event->getDelta(), posn); + return true; +} + void NavigationStyle::setPopupMenuEnabled(const SbBool on) { this->menuenabled = on; } -SbBool NavigationStyle::isPopupMenuEnabled(void) const +SbBool NavigationStyle::isPopupMenuEnabled() const { return this->menuenabled; } diff --git a/src/Gui/NavigationStyle.h b/src/Gui/NavigationStyle.h index 659d8f9e03..7f493ec55a 100644 --- a/src/Gui/NavigationStyle.h +++ b/src/Gui/NavigationStyle.h @@ -37,9 +37,11 @@ #include #include #include +#include // forward declarations class SoEvent; +class SoMouseWheelEvent; class SoMotion3Event; class SoQtViewer; class SoCamera; @@ -115,11 +117,11 @@ public: void setViewer(View3DInventorViewer*); void setAnimationEnabled(const SbBool enable); - SbBool isAnimationEnabled(void) const; + SbBool isAnimationEnabled() const; void startAnimating(const SbVec3f& axis, float velocity); - void stopAnimating(void); - SbBool isAnimating(void) const; + void stopAnimating(); + SbBool isAnimating() const; void setSensitivity(float); float getSensitivity() const; @@ -151,16 +153,19 @@ public: int getViewingMode() const; virtual SbBool processEvent(const SoEvent * const ev); virtual SbBool processMotionEvent(const SoMotion3Event * const ev); + virtual SbBool processKeyboardEvent(const SoKeyboardEvent * const event); + virtual SbBool processClickEvent(const SoMouseButtonEvent * const event); + virtual SbBool processWheelEvent(const SoMouseWheelEvent * const event); void setPopupMenuEnabled(const SbBool on); - SbBool isPopupMenuEnabled(void) const; + SbBool isPopupMenuEnabled() const; void startSelection(AbstractMouseSelection*); void startSelection(SelectionMode = Lasso); void abortSelection(); void stopSelection(); SbBool isSelecting() const; - const std::vector& getPolygon(SelectionRole* role=0) const; + const std::vector& getPolygon(SelectionRole* role=nullptr) const; void setOrbitStyle(OrbitStyle style); OrbitStyle getOrbitStyle() const; @@ -169,13 +174,13 @@ protected: void initialize(); void finalize(); - void interactiveCountInc(void); - void interactiveCountDec(void); - int getInteractiveCount(void) const; + void interactiveCountInc(); + void interactiveCountDec(); + int getInteractiveCount() const; - SbBool isViewing(void) const; + SbBool isViewing() const; void setViewing(SbBool); - SbBool isSeekMode(void) const; + SbBool isSeekMode() const; void setSeekMode(SbBool enable); SbBool seekToPoint(const SbVec2s screenpos); void seekToPoint(const SbVec3f& scenepos); @@ -210,9 +215,10 @@ protected: void syncWithEvent(const SoEvent * const ev); virtual void openPopupMenu(const SbVec2s& position); - void clearLog(void); + void clearLog(); void addToLog(const SbVec2s pos, const SbTime time); + void syncModifierKeys(const SoEvent * const ev); protected: struct { // tracking mouse movement in a log @@ -224,6 +230,7 @@ protected: View3DInventorViewer* viewer; ViewerMode currentmode; + SoMouseButtonEvent mouseDownConsumedEvent; SbVec2f lastmouseposition; SbVec2s globalPos; SbVec2s localPos; @@ -293,9 +300,6 @@ public: protected: SbBool processSoEvent(const SoEvent * const ev); - -private: - SoMouseButtonEvent mouseDownConsumedEvent; }; class GuiExport CADNavigationStyle : public UserNavigationStyle { @@ -313,7 +317,6 @@ protected: private: SbBool lockButton1; - SoMouseButtonEvent mouseDownConsumedEvent; }; class GuiExport RevitNavigationStyle : public UserNavigationStyle { @@ -331,7 +334,6 @@ protected: private: SbBool lockButton1; - SoMouseButtonEvent mouseDownConsumedEvent; }; class GuiExport BlenderNavigationStyle : public UserNavigationStyle { @@ -349,7 +351,6 @@ protected: private: SbBool lockButton1; - SoMouseButtonEvent mouseDownConsumedEvent; }; class GuiExport MayaGestureNavigationStyle : public UserNavigationStyle { @@ -369,7 +370,7 @@ protected: short mouseMoveThreshold;//setting. Minimum move required to consider it a move (in pixels). bool mouseMoveThresholdBroken;//a flag that the move threshold was surpassed since last mousedown. int mousedownConsumedCount;//a flag for remembering that a mousedown of button1/button2 was consumed. - SoMouseButtonEvent mousedownConsumedEvent[5];//the event that was consumed and is to be refired. 2 should be enough, but just for a case of the maximum 5 buttons... + SoMouseButtonEvent mousedownConsumedEvents[5];//the event that was consumed and is to be refired. 2 should be enough, but just for a case of the maximum 5 buttons... bool testMoveThreshold(const SbVec2s currentPos) const; bool thisClickIsComplex;//a flag that becomes set when a complex clicking pattern is detected (i.e., two or more mouse buttons were down at the same time). @@ -388,9 +389,6 @@ public: protected: SbBool processSoEvent(const SoEvent * const ev); - -private: - SoMouseButtonEvent mouseDownConsumedEvent; }; class GuiExport OpenCascadeNavigationStyle : public UserNavigationStyle { @@ -405,9 +403,6 @@ public: protected: SbBool processSoEvent(const SoEvent * const ev); - -private: - SoMouseButtonEvent mouseDownConsumedEvent; }; class GuiExport OpenSCADNavigationStyle : public UserNavigationStyle { @@ -422,9 +417,20 @@ public: protected: SbBool processSoEvent(const SoEvent * const ev); +}; -private: - SoMouseButtonEvent mouseDownConsumedEvent; +class GuiExport TinkerCADNavigationStyle : public UserNavigationStyle { + typedef UserNavigationStyle inherited; + + TYPESYSTEM_HEADER(); + +public: + TinkerCADNavigationStyle(); + ~TinkerCADNavigationStyle(); + const char* mouseButtons(ViewerMode); + +protected: + SbBool processSoEvent(const SoEvent * const ev); }; } // namespace Gui diff --git a/src/Gui/NetworkRetriever.cpp b/src/Gui/NetworkRetriever.cpp index 8ba993e207..38e8528f62 100644 --- a/src/Gui/NetworkRetriever.cpp +++ b/src/Gui/NetworkRetriever.cpp @@ -418,7 +418,7 @@ Action * StdCmdDownloadOnlineHelp::createAction(void) { Action *pcAction; - QString exe = QString::fromLatin1(App::GetApplication().getExecutableName()); + QString exe = QString::fromStdString(App::Application::getExecutableName()); pcAction = new Action(this,getMainWindow()); pcAction->setText(QCoreApplication::translate( this->className(), getMenuText())); @@ -437,7 +437,7 @@ Action * StdCmdDownloadOnlineHelp::createAction(void) void StdCmdDownloadOnlineHelp::languageChange() { if (_pcAction) { - QString exe = QString::fromLatin1(App::GetApplication().getExecutableName()); + QString exe = QString::fromStdString(App::Application::getExecutableName()); _pcAction->setText(QCoreApplication::translate( this->className(), getMenuText())); _pcAction->setToolTip(QCoreApplication::translate( @@ -483,7 +483,7 @@ void StdCmdDownloadOnlineHelp::activated(int iMsg) bool canStart = false; // set output directory - QString path = QString::fromUtf8(App::GetApplication().getHomePath()); + QString path = QString::fromStdString(App::Application::getHomePath()); path += QString::fromLatin1("/doc/"); ParameterGrp::handle hURLGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/OnlineHelp"); path = QString::fromUtf8(hURLGrp->GetASCII( "DownloadLocation", path.toLatin1() ).c_str()); diff --git a/src/Gui/OpenCascadeNavigationStyle.cpp b/src/Gui/OpenCascadeNavigationStyle.cpp index b554327b66..1cbf7b322e 100644 --- a/src/Gui/OpenCascadeNavigationStyle.cpp +++ b/src/Gui/OpenCascadeNavigationStyle.cpp @@ -88,12 +88,10 @@ SbBool OpenCascadeNavigationStyle::processSoEvent(const SoEvent * const ev) const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + const SbVec2f posn = normalizePixelPos(pos); + const SbVec2f prevnormalized = this->lastmouseposition; this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not @@ -107,15 +105,7 @@ SbBool OpenCascadeNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { @@ -126,37 +116,8 @@ SbBool OpenCascadeNavigationStyle::processSoEvent(const SoEvent * const ev) // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { - const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; - const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; - switch (event->getKey()) { - case SoKeyboardEvent::LEFT_CONTROL: - case SoKeyboardEvent::RIGHT_CONTROL: - this->ctrldown = press; - break; - case SoKeyboardEvent::LEFT_SHIFT: - case SoKeyboardEvent::RIGHT_SHIFT: - this->shiftdown = press; - break; - case SoKeyboardEvent::LEFT_ALT: - case SoKeyboardEvent::RIGHT_ALT: - this->altdown = press; - break; - case SoKeyboardEvent::H: - processed = true; - viewer->saveHomePosition(); - break; - case SoKeyboardEvent::S: - case SoKeyboardEvent::HOME: - case SoKeyboardEvent::LEFT_ARROW: - case SoKeyboardEvent::UP_ARROW: - case SoKeyboardEvent::RIGHT_ARROW: - case SoKeyboardEvent::DOWN_ARROW: - if (!this->isViewing()) - this->setViewing(true); - break; - default: - break; - } + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); } // Mouse Button / Spaceball Button handling @@ -185,30 +146,8 @@ SbBool OpenCascadeNavigationStyle::processSoEvent(const SoEvent * const ev) else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; } - // issue #0002433: avoid to swallow the UP event if down the - // scene graph somewhere a dialog gets opened - else if (press) { - SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // a double-click? - if (tmp.getValue() < dci) { - mouseDownConsumedEvent = *event; - mouseDownConsumedEvent.setTime(ev->getTime()); - processed = true; - } - else { - mouseDownConsumedEvent.setTime(ev->getTime()); - // 'ANY' is used to mark that we don't know yet if it will - // be a double-click event. - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } - } - else if (!press) { - if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { - // now handle the postponed event - inherited::processSoEvent(&mouseDownConsumedEvent); - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } + else { + processed = processClickEvent(event); } break; case SoMouseButtonEvent::BUTTON2: @@ -342,10 +281,8 @@ SbBool OpenCascadeNavigationStyle::processSoEvent(const SoEvent * const ev) // If not handled in this class, pass on upwards in the inheritance // hierarchy. - if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) + if (!processed) processed = inherited::processSoEvent(ev); - else - return true; return processed; } diff --git a/src/Gui/OpenSCADNavigationStyle.cpp b/src/Gui/OpenSCADNavigationStyle.cpp index 0148e46eb3..c1c1ee1e6b 100644 --- a/src/Gui/OpenSCADNavigationStyle.cpp +++ b/src/Gui/OpenSCADNavigationStyle.cpp @@ -69,7 +69,7 @@ const char* OpenSCADNavigationStyle::mouseButtons(ViewerMode mode) case NavigationStyle::DRAGGING: return QT_TR_NOOP("Press left mouse button and move mouse"); case NavigationStyle::ZOOMING: - return QT_TR_NOOP("Press SHIFT and middle or right mouse button"); + return QT_TR_NOOP("Press middle mouse button or SHIFT and right mouse button"); default: return "No description"; } @@ -88,12 +88,10 @@ SbBool OpenSCADNavigationStyle::processSoEvent(const SoEvent * const ev) const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + const SbVec2f posn = normalizePixelPos(pos); + const SbVec2f prevnormalized = this->lastmouseposition; this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not @@ -107,15 +105,7 @@ SbBool OpenSCADNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { @@ -126,37 +116,8 @@ SbBool OpenSCADNavigationStyle::processSoEvent(const SoEvent * const ev) // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { - const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; - const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; - switch (event->getKey()) { - case SoKeyboardEvent::LEFT_CONTROL: - case SoKeyboardEvent::RIGHT_CONTROL: - this->ctrldown = press; - break; - case SoKeyboardEvent::LEFT_SHIFT: - case SoKeyboardEvent::RIGHT_SHIFT: - this->shiftdown = press; - break; - case SoKeyboardEvent::LEFT_ALT: - case SoKeyboardEvent::RIGHT_ALT: - this->altdown = press; - break; - case SoKeyboardEvent::H: - processed = true; - viewer->saveHomePosition(); - break; - case SoKeyboardEvent::S: - case SoKeyboardEvent::HOME: - case SoKeyboardEvent::LEFT_ARROW: - case SoKeyboardEvent::UP_ARROW: - case SoKeyboardEvent::RIGHT_ARROW: - case SoKeyboardEvent::DOWN_ARROW: - if (!this->isViewing()) - this->setViewing(true); - break; - default: - break; - } + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); } // Mouse Button / Spaceball Button handling @@ -185,30 +146,8 @@ SbBool OpenSCADNavigationStyle::processSoEvent(const SoEvent * const ev) else if (viewer->isEditing() && (curmode == NavigationStyle::SPINNING)) { processed = true; } - // issue #0002433: avoid to swallow the UP event if down the - // scene graph somewhere a dialog gets opened - else if (press) { - SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // a double-click? - if (tmp.getValue() < dci) { - mouseDownConsumedEvent = *event; - mouseDownConsumedEvent.setTime(ev->getTime()); - processed = true; - } - else { - mouseDownConsumedEvent.setTime(ev->getTime()); - // 'ANY' is used to mark that we don't know yet if it will - // be a double-click event. - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } - } - else if (!press) { - if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { - // now handle the postponed event - inherited::processSoEvent(&mouseDownConsumedEvent); - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } + else { + processed = processClickEvent(event); } break; case SoMouseButtonEvent::BUTTON2: diff --git a/src/Gui/Quarter/ContextMenu.cpp b/src/Gui/Quarter/ContextMenu.cpp index dc28d9500b..88c3535a5e 100644 --- a/src/Gui/Quarter/ContextMenu.cpp +++ b/src/Gui/Quarter/ContextMenu.cpp @@ -58,9 +58,9 @@ ContextMenu::ContextMenu(QuarterWidget * quarterwidget) SoRenderManager * sorendermanager = quarterwidget->getSoRenderManager(); - QActionGroup * rendermodegroup = NULL; - QActionGroup * stereomodegroup = NULL; - QActionGroup * transparencytypegroup = NULL; + QActionGroup * rendermodegroup = nullptr; + QActionGroup * stereomodegroup = nullptr; + QActionGroup * transparencytypegroup = nullptr; foreach (QAction * action, quarterwidget->renderModeActions()) { if (!rendermodegroup) { @@ -138,7 +138,7 @@ ContextMenu::~ContextMenu() } QMenu * -ContextMenu::getMenu(void) const +ContextMenu::getMenu() const { return this->contextmenu; } diff --git a/src/Gui/Quarter/ContextMenu.h b/src/Gui/Quarter/ContextMenu.h index a9965001e3..13603e194d 100644 --- a/src/Gui/Quarter/ContextMenu.h +++ b/src/Gui/Quarter/ContextMenu.h @@ -48,7 +48,7 @@ public: ContextMenu(QuarterWidget * quarterwidget); ~ContextMenu(); - QMenu * getMenu(void) const; + QMenu * getMenu() const; public Q_SLOTS: void changeRenderMode(QAction * action); diff --git a/src/Gui/Quarter/DragDropHandler.cpp b/src/Gui/Quarter/DragDropHandler.cpp index 55b4d9ee43..796295cde8 100644 --- a/src/Gui/Quarter/DragDropHandler.cpp +++ b/src/Gui/Quarter/DragDropHandler.cpp @@ -50,7 +50,7 @@ #include #include -#include +#include namespace SIM { namespace Coin3D { namespace Quarter { @@ -152,7 +152,7 @@ DragDropHandlerP::dropEvent(QDropEvent * event) // attempt to import it root = SoDB::readAll(&in); - if (root == NULL) return; + if (root == nullptr) return; // set new scenegraph this->quarterwidget->setSceneGraph(root); diff --git a/src/Gui/Quarter/EventFilter.cpp b/src/Gui/Quarter/EventFilter.cpp index 695159ceea..faf056d375 100644 --- a/src/Gui/Quarter/EventFilter.cpp +++ b/src/Gui/Quarter/EventFilter.cpp @@ -177,7 +177,7 @@ EventFilter::eventFilter(QObject * obj, QEvent * qevent) Returns mouse position in global coordinates */ const QPoint & -EventFilter::globalMousePosition(void) const +EventFilter::globalMousePosition() const { return PRIVATE(this)->globalmousepos; } diff --git a/src/Gui/Quarter/ImageReader.cpp b/src/Gui/Quarter/ImageReader.cpp index 9d8336e261..75c121db98 100644 --- a/src/Gui/Quarter/ImageReader.cpp +++ b/src/Gui/Quarter/ImageReader.cpp @@ -39,12 +39,12 @@ using namespace SIM::Coin3D::Quarter; -ImageReader::ImageReader(void) +ImageReader::ImageReader() { SbImage::addReadImageCB(ImageReader::readImageCB, this); } -ImageReader::~ImageReader(void) +ImageReader::~ImageReader() { SbImage::removeReadImageCB(ImageReader::readImageCB, this); } diff --git a/src/Gui/Quarter/ImageReader.h b/src/Gui/Quarter/ImageReader.h index a0da5ad526..9d8ad2c186 100644 --- a/src/Gui/Quarter/ImageReader.h +++ b/src/Gui/Quarter/ImageReader.h @@ -43,8 +43,8 @@ namespace SIM { namespace Coin3D { namespace Quarter { class ImageReader { public: - ImageReader(void); - ~ImageReader(void); + ImageReader(); + ~ImageReader(); SbBool readImage(const SbString & filename, SbImage & image) const; diff --git a/src/Gui/Quarter/InputDevice.cpp b/src/Gui/Quarter/InputDevice.cpp index a29d74d7fa..b2cc008b6a 100644 --- a/src/Gui/Quarter/InputDevice.cpp +++ b/src/Gui/Quarter/InputDevice.cpp @@ -48,7 +48,7 @@ using namespace SIM::Coin3D::Quarter; devices. */ -InputDevice::InputDevice(void) : quarter(nullptr) +InputDevice::InputDevice() : quarter(nullptr) { this->mousepos = SbVec2s(0, 0); } diff --git a/src/Gui/Quarter/InteractionMode.cpp b/src/Gui/Quarter/InteractionMode.cpp index d9a0375bcd..f7a577261f 100644 --- a/src/Gui/Quarter/InteractionMode.cpp +++ b/src/Gui/Quarter/InteractionMode.cpp @@ -34,7 +34,7 @@ InteractionMode::setEnabled(bool yes) } bool -InteractionMode::enabled(void) const +InteractionMode::enabled() const { return this->isenabled; } @@ -62,7 +62,7 @@ InteractionMode::setOn(bool on) } bool -InteractionMode::on(void) const +InteractionMode::on() const { return this->altkeydown; } diff --git a/src/Gui/Quarter/InteractionMode.h b/src/Gui/Quarter/InteractionMode.h index 0397b3290f..d2562844b8 100644 --- a/src/Gui/Quarter/InteractionMode.h +++ b/src/Gui/Quarter/InteractionMode.h @@ -54,10 +54,10 @@ public: virtual ~InteractionMode(); void setEnabled(bool yes); - bool enabled(void) const; + bool enabled() const; void setOn(bool on); - bool on(void) const; + bool on() const; protected: virtual bool eventFilter(QObject *, QEvent * event); diff --git a/src/Gui/Quarter/Keyboard.cpp b/src/Gui/Quarter/Keyboard.cpp index b7fbf9f028..e16e4a62f3 100644 --- a/src/Gui/Quarter/Keyboard.cpp +++ b/src/Gui/Quarter/Keyboard.cpp @@ -55,7 +55,7 @@ using namespace SIM::Coin3D::Quarter; #define PRIVATE(obj) obj->pimpl -Keyboard::Keyboard(void) +Keyboard::Keyboard() { PRIVATE(this) = new KeyboardP(this); } @@ -81,7 +81,7 @@ Keyboard::translateEvent(QEvent * event) case QEvent::KeyRelease: return PRIVATE(this)->keyEvent((QKeyEvent *) event); default: - return NULL; + return nullptr; } } diff --git a/src/Gui/Quarter/KeyboardP.cpp b/src/Gui/Quarter/KeyboardP.cpp index 6854ffae7d..1cbc87907c 100644 --- a/src/Gui/Quarter/KeyboardP.cpp +++ b/src/Gui/Quarter/KeyboardP.cpp @@ -44,7 +44,7 @@ KeyboardP::KeyboardP(Keyboard * publ) PUBLIC(this) = publ; this->keyboard = new SoKeyboardEvent; - if (keyboardmap == NULL) { + if (keyboardmap == nullptr) { keyboardmap = new KeyMap; keypadmap = new KeyMap; this->initKeyMap(); @@ -57,7 +57,7 @@ KeyboardP::~KeyboardP() } bool -KeyboardP::debugKeyEvents(void) +KeyboardP::debugKeyEvents() { const char * env = coin_getenv("QUARTER_DEBUG_KEYEVENTS"); return env && (atoi(env) > 0); @@ -103,11 +103,11 @@ KeyboardP::keyEvent(QKeyEvent * qevent) return this->keyboard; } -KeyboardP::KeyMap * KeyboardP::keyboardmap = NULL; -KeyboardP::KeyMap * KeyboardP::keypadmap = NULL; +KeyboardP::KeyMap * KeyboardP::keyboardmap = nullptr; +KeyboardP::KeyMap * KeyboardP::keypadmap = nullptr; void -KeyboardP::initKeyMap(void) +KeyboardP::initKeyMap() { // keyboard keyboardmap->insert(Qt::Key_Shift, SoKeyboardEvent::LEFT_SHIFT); diff --git a/src/Gui/Quarter/KeyboardP.h b/src/Gui/Quarter/KeyboardP.h index e5dfe6a998..fb0e5d2cbd 100644 --- a/src/Gui/Quarter/KeyboardP.h +++ b/src/Gui/Quarter/KeyboardP.h @@ -49,8 +49,8 @@ public: ~KeyboardP(); const SoEvent * keyEvent(QKeyEvent * event); - void initKeyMap(void); - static bool debugKeyEvents(void); + void initKeyMap(); + static bool debugKeyEvents(); typedef QMap KeyMap; static KeyMap * keyboardmap; diff --git a/src/Gui/Quarter/Mouse.cpp b/src/Gui/Quarter/Mouse.cpp index 6667dee6bd..fa182955fc 100644 --- a/src/Gui/Quarter/Mouse.cpp +++ b/src/Gui/Quarter/Mouse.cpp @@ -95,7 +95,7 @@ using namespace SIM::Coin3D::Quarter; #define PRIVATE(obj) obj->pimpl #define PUBLIC(obj) obj->publ -Mouse::Mouse(void) +Mouse::Mouse() { PRIVATE(this) = new MouseP(this); } @@ -131,9 +131,9 @@ Mouse::translateEvent(QEvent * event) return PRIVATE(this)->mouseWheelEvent((QWheelEvent *) event); case QEvent::Resize: PRIVATE(this)->resizeEvent((QResizeEvent *) event); - return NULL; + return nullptr; default: - return NULL; + return nullptr; } } diff --git a/src/Gui/Quarter/NativeEvent.cpp b/src/Gui/Quarter/NativeEvent.cpp index def9b09c02..790f21cd68 100644 --- a/src/Gui/Quarter/NativeEvent.cpp +++ b/src/Gui/Quarter/NativeEvent.cpp @@ -55,7 +55,7 @@ NativeEvent::getEvent() const NativeEvent::NativeEvent() : QEvent(QEvent::User) { - this->rawevent = NULL; + this->rawevent = nullptr; } #endif // !HAVE_SPACENAV_LIB diff --git a/src/Gui/Quarter/QtCoinCompatibility.cpp b/src/Gui/Quarter/QtCoinCompatibility.cpp index 3ffd38cf81..c62431a462 100644 --- a/src/Gui/Quarter/QtCoinCompatibility.cpp +++ b/src/Gui/Quarter/QtCoinCompatibility.cpp @@ -22,7 +22,7 @@ QtCoinCompatibility::QImageToSbImage(const QImage & image, SbImage & sbimage) } SbVec2s size((short) w, (short) h); - sbimage.setValue(size, c, NULL); + sbimage.setValue(size, c, nullptr); unsigned char * buffer = sbimage.getValue(size, c); if (c == 1) { diff --git a/src/Gui/Quarter/Quarter.cpp b/src/Gui/Quarter/Quarter.cpp index 5d48a0f64a..976b02e478 100644 --- a/src/Gui/Quarter/Quarter.cpp +++ b/src/Gui/Quarter/Quarter.cpp @@ -152,7 +152,7 @@ using namespace SIM::Coin3D::Quarter; -static QuarterP * self = NULL; +static QuarterP * self = nullptr; /*! initialize Quarter, and implicitly Coin @@ -182,14 +182,14 @@ Quarter::init(bool initCoin) clean up resources */ void -Quarter::clean(void) +Quarter::clean() { COMPILE_ONLY_BEFORE(2,0,0,"Should not be encapsulated in double Quarter namespace"); assert(self); bool initCoin = self->initCoin; delete self; - self = NULL; + self = nullptr; if (initCoin) { // SoDB::finish() will clean up everything that has been diff --git a/src/Gui/Quarter/Quarter.h b/src/Gui/Quarter/Quarter.h index 1853b5118e..22e538e7c2 100644 --- a/src/Gui/Quarter/Quarter.h +++ b/src/Gui/Quarter/Quarter.h @@ -39,7 +39,7 @@ namespace SIM { namespace Coin3D { namespace Quarter { namespace Quarter { void QUARTER_DLL_API init(bool initCoin = true); - void QUARTER_DLL_API clean(void); + void QUARTER_DLL_API clean(); void QUARTER_DLL_API setTimerEpsilon(double sec); } diff --git a/src/Gui/Quarter/QuarterP.cpp b/src/Gui/Quarter/QuarterP.cpp index fbfd30e380..f227527065 100644 --- a/src/Gui/Quarter/QuarterP.cpp +++ b/src/Gui/Quarter/QuarterP.cpp @@ -4,13 +4,13 @@ #include "KeyboardP.h" using namespace SIM::Coin3D::Quarter; -QuarterP::StateCursorMap * QuarterP::statecursormap = NULL; +QuarterP::StateCursorMap * QuarterP::statecursormap = nullptr; -QuarterP::QuarterP(void) +QuarterP::QuarterP() { this->sensormanager = new SensorManager; this->imagereader = new ImageReader; - assert(QuarterP::statecursormap == NULL); + assert(QuarterP::statecursormap == nullptr); QuarterP::statecursormap = new StateCursorMap; } @@ -20,17 +20,17 @@ QuarterP::~QuarterP() delete this->imagereader; delete this->sensormanager; - assert(QuarterP::statecursormap != NULL); + assert(QuarterP::statecursormap != nullptr); delete QuarterP::statecursormap; // FIXME: Why not use an atexit mechanism for this? - if (KeyboardP::keyboardmap != NULL) { + if (KeyboardP::keyboardmap != nullptr) { KeyboardP::keyboardmap->clear(); KeyboardP::keypadmap->clear(); delete KeyboardP::keyboardmap; delete KeyboardP::keypadmap; - KeyboardP::keyboardmap = NULL; - KeyboardP::keypadmap = NULL; + KeyboardP::keyboardmap = nullptr; + KeyboardP::keypadmap = nullptr; } diff --git a/src/Gui/Quarter/QuarterWidget.cpp b/src/Gui/Quarter/QuarterWidget.cpp index e7034760b9..b3376d851c 100644 --- a/src/Gui/Quarter/QuarterWidget.cpp +++ b/src/Gui/Quarter/QuarterWidget.cpp @@ -52,7 +52,7 @@ #pragma warning(disable : 4267) #endif -#include +#include #include #include @@ -152,7 +152,7 @@ class CustomGLWidget : public QOpenGLWidget { public: QSurfaceFormat myFormat; - CustomGLWidget(const QSurfaceFormat& format, QWidget* parent = 0, const QOpenGLWidget* shareWidget = 0, Qt::WindowFlags f = Qt::WindowFlags()) + CustomGLWidget(const QSurfaceFormat& format, QWidget* parent = nullptr, const QOpenGLWidget* shareWidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) : QOpenGLWidget(parent, f), myFormat(format) { Q_UNUSED(shareWidget); @@ -308,7 +308,7 @@ QuarterWidget::constructor(const QtGLFormat & format, const QtGLWidget * sharewi PRIVATE(this)->eventfilter = new EventFilter(this); PRIVATE(this)->interactionmode = new InteractionMode(this); - PRIVATE(this)->currentStateMachine = NULL; + PRIVATE(this)->currentStateMachine = nullptr; PRIVATE(this)->headlight = new SoDirectionalLight; PRIVATE(this)->headlight->ref(); @@ -364,10 +364,10 @@ QuarterWidget::~QuarterWidget() delete PRIVATE(this)->currentStateMachine; } PRIVATE(this)->headlight->unref(); - PRIVATE(this)->headlight = NULL; - this->setSceneGraph(NULL); - this->setSoRenderManager(NULL); - this->setSoEventManager(NULL); + PRIVATE(this)->headlight = nullptr; + this->setSceneGraph(nullptr); + this->setSoRenderManager(nullptr); + this->setSoEventManager(nullptr); delete PRIVATE(this)->eventfilter; delete PRIVATE(this); } @@ -418,7 +418,7 @@ QuarterWidget::setHeadlightEnabled(bool onoff) Returns true if the headlight is on, false if it is off */ bool -QuarterWidget::headlightEnabled(void) const +QuarterWidget::headlightEnabled() const { return PRIVATE(this)->headlight->on.getValue(); } @@ -427,7 +427,7 @@ QuarterWidget::headlightEnabled(void) const Returns the light used for the headlight. */ SoDirectionalLight * -QuarterWidget::getHeadlight(void) const +QuarterWidget::getHeadlight() const { return PRIVATE(this)->headlight; } @@ -452,7 +452,7 @@ QuarterWidget::setClearZBuffer(bool onoff) Returns true if the z buffer is cleared before rendering. */ bool -QuarterWidget::clearZBuffer(void) const +QuarterWidget::clearZBuffer() const { return PRIVATE(this)->clearzbuffer; } @@ -477,7 +477,7 @@ QuarterWidget::setClearWindow(bool onoff) Returns true if the rendering buffer is cleared before rendering. */ bool -QuarterWidget::clearWindow(void) const +QuarterWidget::clearWindow() const { return PRIVATE(this)->clearwindow; } @@ -503,7 +503,7 @@ QuarterWidget::setInteractionModeEnabled(bool onoff) Returns true if interaction mode is enabled, false otherwise. */ bool -QuarterWidget::interactionModeEnabled(void) const +QuarterWidget::interactionModeEnabled() const { return PRIVATE(this)->interactionmode->enabled(); } @@ -527,7 +527,7 @@ QuarterWidget::setInteractionModeOn(bool onoff) Returns true if interaction mode is on. */ bool -QuarterWidget::interactionModeOn(void) const +QuarterWidget::interactionModeOn() const { return PRIVATE(this)->interactionmode->on(); } @@ -536,7 +536,7 @@ QuarterWidget::interactionModeOn(void) const Returns the Coin cache context id for this widget. */ uint32_t -QuarterWidget::getCacheContextId(void) const +QuarterWidget::getCacheContextId() const { return PRIVATE(this)->getCacheContextId(); } @@ -562,7 +562,7 @@ QuarterWidget::setTransparencyType(TransparencyType type) \retval The current \ref TransparencyType */ QuarterWidget::TransparencyType -QuarterWidget::transparencyType(void) const +QuarterWidget::transparencyType() const { assert(PRIVATE(this)->sorendermanager); SoGLRenderAction * action = PRIVATE(this)->sorendermanager->getGLRenderAction(); @@ -590,7 +590,7 @@ QuarterWidget::setRenderMode(RenderMode mode) \retval The current \ref RenderMode */ QuarterWidget::RenderMode -QuarterWidget::renderMode(void) const +QuarterWidget::renderMode() const { assert(PRIVATE(this)->sorendermanager); return static_cast(PRIVATE(this)->sorendermanager->getRenderMode()); @@ -618,7 +618,7 @@ QuarterWidget::setStereoMode(StereoMode mode) \retval The current \ref StereoMode */ QuarterWidget::StereoMode -QuarterWidget::stereoMode(void) const +QuarterWidget::stereoMode() const { assert(PRIVATE(this)->sorendermanager); return static_cast(PRIVATE(this)->sorendermanager->getStereoMode()); @@ -636,7 +636,7 @@ the widget is located within, and updated whenever any change occurs, emitting a */ qreal -QuarterWidget::devicePixelRatio(void) const +QuarterWidget::devicePixelRatio() const { return PRIVATE(this)->device_pixel_ratio; } @@ -653,11 +653,11 @@ QuarterWidget::setSceneGraph(SoNode * node) if (PRIVATE(this)->scene) { PRIVATE(this)->scene->unref(); - PRIVATE(this)->scene = NULL; + PRIVATE(this)->scene = nullptr; } - SoCamera * camera = NULL; - SoSeparator * superscene = NULL; + SoCamera * camera = nullptr; + SoSeparator * superscene = nullptr; bool viewall = false; if (node) { @@ -690,7 +690,7 @@ QuarterWidget::setSceneGraph(SoNode * node) Returns pointer to root of scene graph */ SoNode * -QuarterWidget::getSceneGraph(void) const +QuarterWidget::getSceneGraph() const { return PRIVATE(this)->scene; } @@ -702,10 +702,10 @@ void QuarterWidget::setSoRenderManager(SoRenderManager * manager) { bool carrydata = false; - SoNode * scene = NULL; - SoCamera * camera = NULL; + SoNode * scene = nullptr; + SoCamera * camera = nullptr; SbViewportRegion vp; - if (PRIVATE(this)->sorendermanager && (manager != NULL)) { + if (PRIVATE(this)->sorendermanager && (manager != nullptr)) { scene = PRIVATE(this)->sorendermanager->getSceneGraph(); camera = PRIVATE(this)->sorendermanager->getCamera(); vp = PRIVATE(this)->sorendermanager->getViewportRegion(); @@ -735,7 +735,7 @@ QuarterWidget::setSoRenderManager(SoRenderManager * manager) Returns a pointer to the render manager. */ SoRenderManager * -QuarterWidget::getSoRenderManager(void) const +QuarterWidget::getSoRenderManager() const { return PRIVATE(this)->sorendermanager; } @@ -747,10 +747,10 @@ void QuarterWidget::setSoEventManager(SoEventManager * manager) { bool carrydata = false; - SoNode * scene = NULL; - SoCamera * camera = NULL; + SoNode * scene = nullptr; + SoCamera * camera = nullptr; SbViewportRegion vp; - if (PRIVATE(this)->soeventmanager && (manager != NULL)) { + if (PRIVATE(this)->soeventmanager && (manager != nullptr)) { scene = PRIVATE(this)->soeventmanager->getSceneGraph(); camera = PRIVATE(this)->soeventmanager->getCamera(); vp = PRIVATE(this)->soeventmanager->getViewportRegion(); @@ -780,7 +780,7 @@ QuarterWidget::setSoEventManager(SoEventManager * manager) Returns a pointer to the event manager */ SoEventManager * -QuarterWidget::getSoEventManager(void) const +QuarterWidget::getSoEventManager() const { return PRIVATE(this)->soeventmanager; } @@ -789,7 +789,7 @@ QuarterWidget::getSoEventManager(void) const Returns a pointer to the event filter */ EventFilter * -QuarterWidget::getEventFilter(void) const +QuarterWidget::getEventFilter() const { return PRIVATE(this)->eventfilter; } @@ -798,7 +798,7 @@ QuarterWidget::getEventFilter(void) const Reposition the current camera to display the entire scene */ void -QuarterWidget::viewAll(void) +QuarterWidget::viewAll() { const SbName viewallevent("sim.coin3d.coin.navigation.ViewAll"); for (int c = 0; c < PRIVATE(this)->soeventmanager->getNumSoScXMLStateMachines(); ++c) { @@ -816,7 +816,7 @@ QuarterWidget::viewAll(void) Camera typically seeks towards what the mouse is pointing at. */ void -QuarterWidget::seek(void) +QuarterWidget::seek() { const SbName seekevent("sim.coin3d.coin.navigation.Seek"); for (int c = 0; c < PRIVATE(this)->soeventmanager->getNumSoScXMLStateMachines(); ++c) { @@ -830,10 +830,10 @@ QuarterWidget::seek(void) } bool -QuarterWidget::updateDevicePixelRatio(void) { +QuarterWidget::updateDevicePixelRatio() { qreal dev_pix_ratio = 1.0; QWidget* winwidg = window(); - QWindow* win = NULL; + QWindow* win = nullptr; if(winwidg) { win = winwidg->windowHandle(); } @@ -1023,7 +1023,7 @@ bool QuarterWidget::viewportEvent(QEvent* event) render manager and render the scene by calling this method. */ void -QuarterWidget::redraw(void) +QuarterWidget::redraw() { // we're triggering the next paintGL(). Set a flag to remember this // to avoid that we process the delay queue in paintGL() @@ -1050,7 +1050,7 @@ QuarterWidget::redraw(void) Overridden from QGLWidget to render the scenegraph */ void -QuarterWidget::actualRedraw(void) +QuarterWidget::actualRedraw() { PRIVATE(this)->sorendermanager->render(PRIVATE(this)->clearwindow, PRIVATE(this)->clearzbuffer); @@ -1102,7 +1102,7 @@ QuarterWidget::setBackgroundColor(const QColor & color) rendering the scene. */ QColor -QuarterWidget::backgroundColor(void) const +QuarterWidget::backgroundColor() const { SbColor4f bg = PRIVATE(this)->sorendermanager->getBackgroundColor(); @@ -1116,7 +1116,7 @@ QuarterWidget::backgroundColor(void) const Returns the context menu used by the widget. */ QMenu * -QuarterWidget::getContextMenu(void) const +QuarterWidget::getContextMenu() const { return PRIVATE(this)->contextMenu(); } @@ -1125,7 +1125,7 @@ QuarterWidget::getContextMenu(void) const \retval Is context menu enabled? */ bool -QuarterWidget::contextMenuEnabled(void) const +QuarterWidget::contextMenuEnabled() const { return PRIVATE(this)->contextmenuenabled; } @@ -1175,8 +1175,8 @@ void QuarterWidget::removeStateMachine(SoScXMLStateMachine * statemachine) { SoEventManager * em = this->getSoEventManager(); - statemachine->setSceneGraphRoot(NULL); - statemachine->setActiveCamera(NULL); + statemachine->setSceneGraphRoot(nullptr); + statemachine->setActiveCamera(nullptr); em->removeSoScXMLStateMachine(statemachine); } @@ -1184,7 +1184,7 @@ QuarterWidget::removeStateMachine(SoScXMLStateMachine * statemachine) See \ref QWidget::minimumSizeHint */ QSize -QuarterWidget::minimumSizeHint(void) const +QuarterWidget::minimumSizeHint() const { return QSize(50, 50); } @@ -1195,7 +1195,7 @@ QuarterWidget::minimumSizeHint(void) const QuarterWidget, add these actions to the menu. */ QList -QuarterWidget::transparencyTypeActions(void) const +QuarterWidget::transparencyTypeActions() const { return PRIVATE(this)->transparencyTypeActions(); } @@ -1206,7 +1206,7 @@ QuarterWidget::transparencyTypeActions(void) const QuarterWidget, add these actions to the menu. */ QList -QuarterWidget::stereoModeActions(void) const +QuarterWidget::stereoModeActions() const { return PRIVATE(this)->stereoModeActions(); } @@ -1217,7 +1217,7 @@ QuarterWidget::stereoModeActions(void) const QuarterWidget, add these actions to the menu. */ QList -QuarterWidget::renderModeActions(void) const +QuarterWidget::renderModeActions() const { return PRIVATE(this)->renderModeActions(); } @@ -1239,7 +1239,7 @@ QuarterWidget::renderModeActions(void) const Removes any navigationModeFile set. */ void -QuarterWidget::resetNavigationModeFile(void) { +QuarterWidget::resetNavigationModeFile() { this->setNavigationModeFile(QUrl()); } @@ -1276,7 +1276,7 @@ QuarterWidget::setNavigationModeFile(const QUrl & url) if (PRIVATE(this)->currentStateMachine) { this->removeStateMachine(PRIVATE(this)->currentStateMachine); delete PRIVATE(this)->currentStateMachine; - PRIVATE(this)->currentStateMachine = NULL; + PRIVATE(this)->currentStateMachine = nullptr; PRIVATE(this)->navigationModeFile = url; } return; @@ -1287,7 +1287,7 @@ QuarterWidget::setNavigationModeFile(const QUrl & url) } QByteArray filenametmp = filename.toLocal8Bit(); - ScXMLStateMachine * stateMachine = NULL; + ScXMLStateMachine * stateMachine = nullptr; if (filenametmp.startsWith("coin:")){ stateMachine = ScXML::readFile(filenametmp.data()); @@ -1350,7 +1350,7 @@ QuarterWidget::setNavigationModeFile(const QUrl & url) \retval The current navigationModeFile */ const QUrl & -QuarterWidget::navigationModeFile(void) const +QuarterWidget::navigationModeFile() const { return PRIVATE(this)->navigationModeFile; } diff --git a/src/Gui/Quarter/QuarterWidget.h b/src/Gui/Quarter/QuarterWidget.h index d69bf2c5b6..80e781b613 100644 --- a/src/Gui/Quarter/QuarterWidget.h +++ b/src/Gui/Quarter/QuarterWidget.h @@ -81,9 +81,9 @@ class QUARTER_DLL_API QuarterWidget : public QGraphicsView { public: - explicit QuarterWidget(QWidget * parent = 0, const QtGLWidget * sharewidget = 0, Qt::WindowFlags f = Qt::WindowFlags()); - explicit QuarterWidget(QtGLContext * context, QWidget * parent = 0, const QtGLWidget * sharewidget = 0, Qt::WindowFlags f = Qt::WindowFlags()); - explicit QuarterWidget(const QtGLFormat & format, QWidget * parent = 0, const QtGLWidget * shareWidget = 0, Qt::WindowFlags f = Qt::WindowFlags()); + explicit QuarterWidget(QWidget * parent = nullptr, const QtGLWidget * sharewidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + explicit QuarterWidget(QtGLContext * context, QWidget * parent = nullptr, const QtGLWidget * sharewidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + explicit QuarterWidget(const QtGLFormat & format, QWidget * parent = nullptr, const QtGLWidget * shareWidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); virtual ~QuarterWidget(); enum TransparencyType { @@ -117,70 +117,70 @@ public: INTERLEAVED_COLUMNS = SoRenderManager::INTERLEAVED_COLUMNS }; - TransparencyType transparencyType(void) const; - RenderMode renderMode(void) const; - StereoMode stereoMode(void) const; + TransparencyType transparencyType() const; + RenderMode renderMode() const; + StereoMode stereoMode() const; void setBackgroundColor(const QColor & color); - QColor backgroundColor(void) const; + QColor backgroundColor() const; - qreal devicePixelRatio(void) const; + qreal devicePixelRatio() const; - void resetNavigationModeFile(void); + void resetNavigationModeFile(); void setNavigationModeFile(const QUrl & url = QUrl(QString::fromLatin1(DEFAULT_NAVIGATIONFILE))); - const QUrl & navigationModeFile(void) const; + const QUrl & navigationModeFile() const; void setContextMenuEnabled(bool yes); - bool contextMenuEnabled(void) const; - QMenu * getContextMenu(void) const; + bool contextMenuEnabled() const; + QMenu * getContextMenu() const; - bool headlightEnabled(void) const; + bool headlightEnabled() const; void setHeadlightEnabled(bool onoff); - SoDirectionalLight * getHeadlight(void) const; + SoDirectionalLight * getHeadlight() const; - bool clearZBuffer(void) const; + bool clearZBuffer() const; void setClearZBuffer(bool onoff); - bool clearWindow(void) const; + bool clearWindow() const; void setClearWindow(bool onoff); - bool interactionModeEnabled(void) const; + bool interactionModeEnabled() const; void setInteractionModeEnabled(bool onoff); - bool interactionModeOn(void) const; + bool interactionModeOn() const; void setInteractionModeOn(bool onoff); void setStateCursor(const SbName & state, const QCursor & cursor); QCursor stateCursor(const SbName & state); - uint32_t getCacheContextId(void) const; + uint32_t getCacheContextId() const; virtual void setSceneGraph(SoNode * root); - virtual SoNode * getSceneGraph(void) const; + virtual SoNode * getSceneGraph() const; void setSoEventManager(SoEventManager * manager); - SoEventManager * getSoEventManager(void) const; + SoEventManager * getSoEventManager() const; void setSoRenderManager(SoRenderManager * manager); - SoRenderManager * getSoRenderManager(void) const; + SoRenderManager * getSoRenderManager() const; - EventFilter * getEventFilter(void) const; + EventFilter * getEventFilter() const; void addStateMachine(SoScXMLStateMachine * statemachine); void removeStateMachine(SoScXMLStateMachine * statemachine); virtual bool processSoEvent(const SoEvent * event); - virtual QSize minimumSizeHint(void) const; + virtual QSize minimumSizeHint() const; - QList transparencyTypeActions(void) const; - QList stereoModeActions(void) const; - QList renderModeActions(void) const; + QList transparencyTypeActions() const; + QList stereoModeActions() const; + QList renderModeActions() const; public Q_SLOTS: - virtual void viewAll(void); - virtual void seek(void); + virtual void viewAll(); + virtual void seek(); - void redraw(void); + void redraw(); void setRenderMode(RenderMode mode); void setStereoMode(StereoMode mode); @@ -197,8 +197,8 @@ protected: virtual void paintEvent(QPaintEvent*); virtual void resizeEvent(QResizeEvent*); virtual bool viewportEvent(QEvent* event); - virtual void actualRedraw(void); - virtual bool updateDevicePixelRatio(void); + virtual void actualRedraw(); + virtual bool updateDevicePixelRatio(); private: void constructor(const QtGLFormat& format, const QtGLWidget* sharewidget); diff --git a/src/Gui/Quarter/QuarterWidgetP.cpp b/src/Gui/Quarter/QuarterWidgetP.cpp index 4cba6614b3..8c5a84c84f 100644 --- a/src/Gui/Quarter/QuarterWidgetP.cpp +++ b/src/Gui/Quarter/QuarterWidgetP.cpp @@ -57,7 +57,7 @@ #include "ContextMenu.h" #include "QuarterP.h" -#include +#include using namespace SIM::Coin3D::Quarter; @@ -67,19 +67,19 @@ public: SbList widgetlist; }; -static SbList * cachecontext_list = NULL; +static SbList * cachecontext_list = nullptr; QuarterWidgetP::QuarterWidgetP(QuarterWidget * masterptr, const QtGLWidget * sharewidget) : master(masterptr), - scene(NULL), - eventfilter(NULL), - interactionmode(NULL), - sorendermanager(NULL), - soeventmanager(NULL), + scene(nullptr), + eventfilter(nullptr), + interactionmode(nullptr), + sorendermanager(nullptr), + soeventmanager(nullptr), initialsorendermanager(false), initialsoeventmanager(false), - headlight(NULL), - cachecontext(NULL), + headlight(nullptr), + cachecontext(nullptr), contextmenuenabled(true), autoredrawenabled(true), interactionmodeenabled(false), @@ -87,7 +87,7 @@ QuarterWidgetP::QuarterWidgetP(QuarterWidget * masterptr, const QtGLWidget * sha clearwindow(true), addactions(true), device_pixel_ratio(1.0), - contextmenu(NULL) + contextmenu(nullptr) { this->cachecontext = findCacheContext(masterptr, sharewidget); @@ -121,11 +121,11 @@ QuarterWidgetP::searchForCamera(SoNode * root) return (SoCamera *) node; } } - return NULL; + return nullptr; } uint32_t -QuarterWidgetP::getCacheContextId(void) const +QuarterWidgetP::getCacheContextId() const { return this->cachecontext->id; } @@ -133,7 +133,7 @@ QuarterWidgetP::getCacheContextId(void) const QuarterWidgetP_cachecontext * QuarterWidgetP::findCacheContext(QuarterWidget * widget, const QtGLWidget * sharewidget) { - if (cachecontext_list == NULL) { + if (cachecontext_list == nullptr) { // FIXME: static memory leak cachecontext_list = new SbList ; } @@ -257,7 +257,7 @@ QuarterWidgetP::statechangecb(void * userdata, ScXMLStateMachine * statemachine, QList -QuarterWidgetP::transparencyTypeActions(void) const +QuarterWidgetP::transparencyTypeActions() const { if (this->transparencytypeactions.isEmpty()) { this->transparencytypegroup = new QActionGroup(this->master); @@ -277,7 +277,7 @@ QuarterWidgetP::transparencyTypeActions(void) const } QList -QuarterWidgetP::stereoModeActions(void) const +QuarterWidgetP::stereoModeActions() const { if (this->stereomodeactions.isEmpty()) { this->stereomodegroup = new QActionGroup(this->master); @@ -291,7 +291,7 @@ QuarterWidgetP::stereoModeActions(void) const } QList -QuarterWidgetP::renderModeActions(void) const +QuarterWidgetP::renderModeActions() const { if (this->rendermodeactions.isEmpty()) { this->rendermodegroup = new QActionGroup(this->master); @@ -308,7 +308,7 @@ QuarterWidgetP::renderModeActions(void) const #undef ADD_ACTION QMenu * -QuarterWidgetP::contextMenu(void) +QuarterWidgetP::contextMenu() { if (!this->contextmenu) { this->contextmenu = new ContextMenu(this->master); diff --git a/src/Gui/Quarter/QuarterWidgetP.h b/src/Gui/Quarter/QuarterWidgetP.h index 7b5c99dc78..d9373961cb 100644 --- a/src/Gui/Quarter/QuarterWidgetP.h +++ b/src/Gui/Quarter/QuarterWidgetP.h @@ -66,12 +66,12 @@ public: ~QuarterWidgetP(); SoCamera * searchForCamera(SoNode * root); - uint32_t getCacheContextId(void) const; - QMenu * contextMenu(void); + uint32_t getCacheContextId() const; + QMenu * contextMenu(); - QList transparencyTypeActions(void) const; - QList renderModeActions(void) const; - QList stereoModeActions(void) const; + QList transparencyTypeActions() const; + QList renderModeActions() const; + QList stereoModeActions() const; QuarterWidget * const master; SoNode * scene; diff --git a/src/Gui/Quarter/SensorManager.cpp b/src/Gui/Quarter/SensorManager.cpp index 59d2d13b55..5d2ebf115f 100644 --- a/src/Gui/Quarter/SensorManager.cpp +++ b/src/Gui/Quarter/SensorManager.cpp @@ -43,7 +43,7 @@ using namespace SIM::Coin3D::Quarter; -SensorManager::SensorManager(void) +SensorManager::SensorManager() : inherited() { this->mainthreadid = cc_thread_id(); @@ -74,7 +74,7 @@ SensorManager::SensorManager(void) SensorManager::~SensorManager() { // remove the Coin callback before shutting down - SoDB::getSensorManager()->setChangedCallback(NULL, NULL); + SoDB::getSensorManager()->setChangedCallback(nullptr, nullptr); if (this->signalthread->isRunning()) { this->signalthread->stopThread(); @@ -104,7 +104,7 @@ SensorManager::sensorQueueChangedCB(void * closure) } void -SensorManager::sensorQueueChanged(void) +SensorManager::sensorQueueChanged() { SoSensorManager * sensormanager = SoDB::getSensorManager(); assert(sensormanager); @@ -144,7 +144,7 @@ SensorManager::sensorQueueChanged(void) } void -SensorManager::idleTimeout(void) +SensorManager::idleTimeout() { SoDB::getSensorManager()->processTimerQueue(); SoDB::getSensorManager()->processDelayQueue(true); @@ -152,14 +152,14 @@ SensorManager::idleTimeout(void) } void -SensorManager::timerQueueTimeout(void) +SensorManager::timerQueueTimeout() { SoDB::getSensorManager()->processTimerQueue(); this->sensorQueueChanged(); } void -SensorManager::delayTimeout(void) +SensorManager::delayTimeout() { SoDB::getSensorManager()->processTimerQueue(); SoDB::getSensorManager()->processDelayQueue(false); diff --git a/src/Gui/Quarter/SensorManager.h b/src/Gui/Quarter/SensorManager.h index 6344cf93e6..6628ba9e3a 100644 --- a/src/Gui/Quarter/SensorManager.h +++ b/src/Gui/Quarter/SensorManager.h @@ -45,14 +45,14 @@ class SensorManager : public QObject { Q_OBJECT typedef QObject inherited; public: - SensorManager(void); + SensorManager(); ~SensorManager(); public Q_SLOTS: - void idleTimeout(void); - void delayTimeout(void); - void timerQueueTimeout(void); - void sensorQueueChanged(void); + void idleTimeout(); + void delayTimeout(); + void timerQueueTimeout(); + void sensorQueueChanged(); void setTimerEpsilon(double sec); private: diff --git a/src/Gui/Quarter/SignalThread.cpp b/src/Gui/Quarter/SignalThread.cpp index 6d18f8636d..a242286258 100644 --- a/src/Gui/Quarter/SignalThread.cpp +++ b/src/Gui/Quarter/SignalThread.cpp @@ -36,7 +36,7 @@ using namespace SIM::Coin3D::Quarter; -SignalThread::SignalThread(void) +SignalThread::SignalThread() : isstopped(false) { } @@ -46,7 +46,7 @@ SignalThread::~SignalThread() } void -SignalThread::trigger(void) +SignalThread::trigger() { // lock first to make sure the QThread is actually waiting for a signal QMutexLocker ml(&this->mutex); @@ -54,7 +54,7 @@ SignalThread::trigger(void) } void -SignalThread::stopThread(void) +SignalThread::stopThread() { QMutexLocker ml(&this->mutex); this->isstopped = true; @@ -63,7 +63,7 @@ SignalThread::stopThread(void) void -SignalThread::run(void) +SignalThread::run() { QMutexLocker ml(&this->mutex); while (!this->isstopped) { diff --git a/src/Gui/Quarter/SignalThread.h b/src/Gui/Quarter/SignalThread.h index e96117ae0c..718383991b 100644 --- a/src/Gui/Quarter/SignalThread.h +++ b/src/Gui/Quarter/SignalThread.h @@ -44,16 +44,16 @@ namespace SIM { namespace Coin3D { namespace Quarter { class SignalThread : public QThread { Q_OBJECT public: - SignalThread(void); + SignalThread(); virtual ~SignalThread(); - virtual void run(void); - void trigger(void); - void stopThread(void); + virtual void run(); + void trigger(); + void stopThread(); Q_SIGNALS: - void triggerSignal(void); + void triggerSignal(); private: QWaitCondition waitcond; diff --git a/src/Gui/Quarter/SoQTQuarterAdaptor.cpp b/src/Gui/Quarter/SoQTQuarterAdaptor.cpp index 552b055ebe..9d787b3694 100644 --- a/src/Gui/Quarter/SoQTQuarterAdaptor.cpp +++ b/src/Gui/Quarter/SoQTQuarterAdaptor.cpp @@ -168,7 +168,7 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::init() m_seekdistanceabs = false; m_seekperiod = 2.0f; m_inseekmode = false; - m_storedcamera = 0; + m_storedcamera = nullptr; m_viewingflag = false; pickRadius = 5.0; @@ -298,12 +298,12 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::convertPerspective2Ortho(const So out->height = 2.0f * focaldist * (float)tan(in->heightAngle.getValue() / 2.0); } -SoCamera* SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getCamera(void) const +SoCamera* SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getCamera() const { return getSoRenderManager()->getCamera(); } -const SbViewportRegion & SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getViewportRegion(void) const +const SbViewportRegion & SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getViewportRegion() const { return getSoRenderManager()->getViewportRegion(); } @@ -318,17 +318,17 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::setViewing(SbBool enable) if(m_viewingflag) { SoGLRenderAction* action = getSoRenderManager()->getGLRenderAction(); - if(action != NULL) + if(action != nullptr) SoLocateHighlight::turnOffCurrentHighlight(action); } } -SbBool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::isViewing(void) const +SbBool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::isViewing() const { return m_viewingflag; } -void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::interactiveCountInc(void) +void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::interactiveCountInc() { // Catch problems with missing interactiveCountDec() calls. assert(m_interactionnesting < 100); @@ -338,7 +338,7 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::interactiveCountInc(void) } } -void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::interactiveCountDec(void) +void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::interactiveCountDec() { if(--m_interactionnesting <= 0) { m_interactionEndCallback.invokeCallbacks(this); @@ -346,7 +346,7 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::interactiveCountDec(void) } } -int SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getInteractiveCount(void) const +int SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getInteractiveCount() const { return m_interactionnesting; } @@ -372,22 +372,22 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::removeFinishCallback(SIM::Coin3D: } -float SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getSeekDistance(void) const +float SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getSeekDistance() const { return m_seekdistance; } -float SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getSeekTime(void) const +float SIM::Coin3D::Quarter::SoQTQuarterAdaptor::getSeekTime() const { return m_seekperiod; } -SbBool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::isSeekMode(void) const +SbBool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::isSeekMode() const { return m_inseekmode; } -SbBool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::isSeekValuePercentage(void) const +SbBool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::isSeekValuePercentage() const { return m_seekdistanceabs ? false : true; } @@ -541,7 +541,7 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::seeksensorCB(void* data, SoSensor if(end) thisp->setSeekMode(false); } -void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::saveHomePosition(void) +void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::saveHomePosition() { SoCamera* cam = getSoRenderManager()->getCamera(); if (!cam) { @@ -562,7 +562,7 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::saveHomePosition(void) m_storedcamera->copyFieldValues(getSoRenderManager()->getCamera()); } -void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::resetToHomePosition(void) +void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::resetToHomePosition() { SoCamera* cam = getSoRenderManager()->getCamera(); if (!cam) { @@ -724,7 +724,7 @@ void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::paintEvent(QPaintEvent* event) this->framesPerSecond = addFrametime(start); } -void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::resetFrameCounter(void) +void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::resetFrameCounter() { this->framecount = 0; this->frametime = 0.0f; diff --git a/src/Gui/Quarter/SoQTQuarterAdaptor.h b/src/Gui/Quarter/SoQTQuarterAdaptor.h index 84956532d4..e9cee0b949 100644 --- a/src/Gui/Quarter/SoQTQuarterAdaptor.h +++ b/src/Gui/Quarter/SoQTQuarterAdaptor.h @@ -47,9 +47,9 @@ typedef void SoQTQuarterAdaptorCB(void* data, SoQTQuarterAdaptor* viewer); class QUARTER_DLL_API SoQTQuarterAdaptor : public QuarterWidget { public: - explicit SoQTQuarterAdaptor(QWidget* parent = 0, const QtGLWidget* sharewidget = 0, Qt::WindowFlags f = Qt::WindowFlags()); - explicit SoQTQuarterAdaptor(const QtGLFormat& format, QWidget* parent = 0, const QtGLWidget* shareWidget = 0, Qt::WindowFlags f = Qt::WindowFlags()); - explicit SoQTQuarterAdaptor(QtGLContext* context, QWidget* parent = 0, const QtGLWidget* sharewidget = 0, Qt::WindowFlags f = Qt::WindowFlags()); + explicit SoQTQuarterAdaptor(QWidget* parent = nullptr, const QtGLWidget* sharewidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + explicit SoQTQuarterAdaptor(const QtGLFormat& format, QWidget* parent = nullptr, const QtGLWidget* shareWidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + explicit SoQTQuarterAdaptor(QtGLContext* context, QWidget* parent = nullptr, const QtGLWidget* sharewidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); virtual ~SoQTQuarterAdaptor(); //the functions available in soqtviewer but missing in quarter @@ -59,38 +59,38 @@ public: QWidget* getGLWidget() const; virtual void setCameraType(SoType type); - SoCamera * getCamera(void) const; + SoCamera * getCamera() const; - const SbViewportRegion & getViewportRegion(void) const; + const SbViewportRegion & getViewportRegion() const; virtual void setViewing(SbBool enable); - SbBool isViewing(void) const; + SbBool isViewing() const; - void interactiveCountInc(void); - void interactiveCountDec(void); - int getInteractiveCount(void) const; + void interactiveCountInc(); + void interactiveCountDec(); + int getInteractiveCount() const; - void addStartCallback(SoQTQuarterAdaptorCB* func, void* data = NULL); - void addFinishCallback(SoQTQuarterAdaptorCB* func, void* data = NULL); - void removeStartCallback(SoQTQuarterAdaptorCB* func, void* data = NULL); - void removeFinishCallback(SoQTQuarterAdaptorCB* func, void* data = NULL); + void addStartCallback(SoQTQuarterAdaptorCB* func, void* data = nullptr); + void addFinishCallback(SoQTQuarterAdaptorCB* func, void* data = nullptr); + void removeStartCallback(SoQTQuarterAdaptorCB* func, void* data = nullptr); + void removeFinishCallback(SoQTQuarterAdaptorCB* func, void* data = nullptr); virtual void setSeekMode(SbBool enable); - SbBool isSeekMode(void) const; + SbBool isSeekMode() const; SbBool seekToPoint(const SbVec2s screenpos); void seekToPoint(const SbVec3f& scenepos); void setSeekTime(const float seconds); - float getSeekTime(void) const; + float getSeekTime() const; void setSeekDistance(const float distance); - float getSeekDistance(void) const; + float getSeekDistance() const; void setSeekValueAsPercentage(const SbBool on); - SbBool isSeekValuePercentage(void) const; + SbBool isSeekValuePercentage() const; - virtual float getPickRadius(void) const {return this->pickRadius;} + virtual float getPickRadius() const {return this->pickRadius;} virtual void setPickRadius(float pickRadius); - virtual void saveHomePosition(void); - virtual void resetToHomePosition(void); + virtual void saveHomePosition(); + virtual void resetToHomePosition(); virtual void setSceneGraph(SoNode* root) { QuarterWidget::setSceneGraph(root); @@ -100,7 +100,7 @@ public: virtual void paintEvent(QPaintEvent*); //this functions still need to be ported - virtual void afterRealizeHook(void) {} //enables spacenav and joystick in soqt, dunno if this is needed + virtual void afterRealizeHook() {} //enables spacenav and joystick in soqt, dunno if this is needed private: void init(); @@ -109,7 +109,7 @@ private: void getCameraCoordinateSystem(SoCamera * camera, SoNode * root, SbMatrix & matrix, SbMatrix & inverse); static void seeksensorCB(void * data, SoSensor * s); void moveCameraScreen(const SbVec2f & screenpos); - void resetFrameCounter(void); + void resetFrameCounter(); SbVec2f addFrametime(double ft); bool m_viewingflag; diff --git a/src/Gui/Quarter/SpaceNavigatorDevice.cpp b/src/Gui/Quarter/SpaceNavigatorDevice.cpp index 14fe49e871..5726845439 100644 --- a/src/Gui/Quarter/SpaceNavigatorDevice.cpp +++ b/src/Gui/Quarter/SpaceNavigatorDevice.cpp @@ -128,7 +128,7 @@ const SoEvent * SpaceNavigatorDevice::translateEvent(QEvent * event) { Q_UNUSED(event); - SoEvent * ret = NULL; + SoEvent * ret = nullptr; #ifdef HAVE_SPACENAV_LIB NativeEvent * ce = dynamic_cast(event); diff --git a/src/Gui/Quarter/devices/InputDevice.h b/src/Gui/Quarter/devices/InputDevice.h index bf2785d1eb..be46a1649a 100644 --- a/src/Gui/Quarter/devices/InputDevice.h +++ b/src/Gui/Quarter/devices/InputDevice.h @@ -47,7 +47,7 @@ class QuarterWidget; class QUARTER_DLL_API InputDevice { public: InputDevice(QuarterWidget * quarter); - InputDevice(void); + InputDevice(); virtual ~InputDevice() {} /*! diff --git a/src/Gui/Quarter/devices/Keyboard.h b/src/Gui/Quarter/devices/Keyboard.h index 8284798881..2299adf3d9 100644 --- a/src/Gui/Quarter/devices/Keyboard.h +++ b/src/Gui/Quarter/devices/Keyboard.h @@ -44,7 +44,7 @@ namespace SIM { namespace Coin3D { namespace Quarter { class QUARTER_DLL_API Keyboard : public InputDevice { public: Keyboard(QuarterWidget* quarter); - Keyboard(void); + Keyboard(); virtual ~Keyboard(); virtual const SoEvent * translateEvent(QEvent * event); diff --git a/src/Gui/Quarter/devices/Mouse.h b/src/Gui/Quarter/devices/Mouse.h index 49405368c2..6ac878063d 100644 --- a/src/Gui/Quarter/devices/Mouse.h +++ b/src/Gui/Quarter/devices/Mouse.h @@ -44,7 +44,7 @@ namespace SIM { namespace Coin3D { namespace Quarter { class QUARTER_DLL_API Mouse : public InputDevice { public: Mouse(QuarterWidget* quarter); - Mouse(void); + Mouse(); virtual ~Mouse(); virtual const SoEvent * translateEvent(QEvent * event); diff --git a/src/Gui/Quarter/devices/SpaceNavigatorDevice.h b/src/Gui/Quarter/devices/SpaceNavigatorDevice.h index 30224f6446..c8f6e8a5b3 100644 --- a/src/Gui/Quarter/devices/SpaceNavigatorDevice.h +++ b/src/Gui/Quarter/devices/SpaceNavigatorDevice.h @@ -43,7 +43,7 @@ namespace SIM { namespace Coin3D { namespace Quarter { class QUARTER_DLL_API SpaceNavigatorDevice : public InputDevice { public: SpaceNavigatorDevice(QuarterWidget* quarter); - SpaceNavigatorDevice(void); + SpaceNavigatorDevice(); virtual ~SpaceNavigatorDevice(); virtual const SoEvent * translateEvent(QEvent * event); diff --git a/src/Gui/Quarter/eventhandlers/EventFilter.h b/src/Gui/Quarter/eventhandlers/EventFilter.h index 68c7cbdf06..5f4f95bd1b 100644 --- a/src/Gui/Quarter/eventhandlers/EventFilter.h +++ b/src/Gui/Quarter/eventhandlers/EventFilter.h @@ -53,7 +53,7 @@ public: void registerInputDevice(InputDevice * device); void unregisterInputDevice(InputDevice * device); - const QPoint & globalMousePosition(void) const; + const QPoint & globalMousePosition() const; protected: bool eventFilter(QObject * obj, QEvent * event); diff --git a/src/Gui/RevitNavigationStyle.cpp b/src/Gui/RevitNavigationStyle.cpp index 977d0c01a2..6bc4ee8ced 100644 --- a/src/Gui/RevitNavigationStyle.cpp +++ b/src/Gui/RevitNavigationStyle.cpp @@ -88,12 +88,10 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + const SbVec2f posn = normalizePixelPos(pos); + const SbVec2f prevnormalized = this->lastmouseposition; this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not @@ -107,15 +105,7 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { @@ -126,37 +116,8 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { - const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; - const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; - switch (event->getKey()) { - case SoKeyboardEvent::LEFT_CONTROL: - case SoKeyboardEvent::RIGHT_CONTROL: - this->ctrldown = press; - break; - case SoKeyboardEvent::LEFT_SHIFT: - case SoKeyboardEvent::RIGHT_SHIFT: - this->shiftdown = press; - break; - case SoKeyboardEvent::LEFT_ALT: - case SoKeyboardEvent::RIGHT_ALT: - this->altdown = press; - break; - case SoKeyboardEvent::H: - processed = true; - viewer->saveHomePosition(); - break; - case SoKeyboardEvent::S: - case SoKeyboardEvent::HOME: - case SoKeyboardEvent::LEFT_ARROW: - case SoKeyboardEvent::UP_ARROW: - case SoKeyboardEvent::RIGHT_ARROW: - case SoKeyboardEvent::DOWN_ARROW: - if (!this->isViewing()) - this->setViewing(true); - break; - default: - break; - } + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); } // Mouse Button / Spaceball Button handling @@ -175,10 +136,6 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = true; } - //else if (press && (this->currentmode == NavigationStyle::IDLE)) { - // this->setViewing(true); - // processed = true; - //} else if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; @@ -189,30 +146,8 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; } - // issue #0002433: avoid to swallow the UP event if down the - // scene graph somewhere a dialog gets opened - else if (press) { - SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // a double-click? - if (tmp.getValue() < dci) { - mouseDownConsumedEvent = *event; - mouseDownConsumedEvent.setTime(ev->getTime()); - processed = true; - } - else { - mouseDownConsumedEvent.setTime(ev->getTime()); - // 'ANY' is used to mark that we don't know yet if it will - // be a double-click event. - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } - } - else if (!press) { - if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { - // now handle the postponed event - inherited::processSoEvent(&mouseDownConsumedEvent); - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } + else { + processed = processClickEvent(event); } break; case SoMouseButtonEvent::BUTTON2: @@ -322,11 +257,6 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) this->lockButton1 = false; processed = true; } - - //if (curmode == NavigationStyle::DRAGGING) { - // if (doSpin()) - // newmode = NavigationStyle::SPINNING; - //} break; case BUTTON1DOWN: case CTRLDOWN|BUTTON1DOWN: @@ -348,9 +278,6 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) } newmode = NavigationStyle::DRAGGING; break; - //case BUTTON1DOWN|BUTTON2DOWN|BUTTON3DOWN: - // newmode = NavigationStyle::ZOOMING; - // break; case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN: case CTRLDOWN|BUTTON3DOWN: newmode = NavigationStyle::ZOOMING; @@ -372,10 +299,7 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev) // If not handled in this class, pass on upwards in the inheritance // hierarchy. - if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) + if (!processed) processed = inherited::processSoEvent(ev); - else - return true; - return processed; } diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index 0dc42462fe..92e9045ad3 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -186,6 +186,7 @@ void Gui::SoFCDB::init() GestureNavigationStyle ::init(); OpenCascadeNavigationStyle ::init(); OpenSCADNavigationStyle ::init(); + TinkerCADNavigationStyle ::init(); GLGraphicsItem ::init(); GLFlagWindow ::init(); diff --git a/src/Gui/SoFCOffscreenRenderer.cpp b/src/Gui/SoFCOffscreenRenderer.cpp index a54220fac7..01c393fd46 100644 --- a/src/Gui/SoFCOffscreenRenderer.cpp +++ b/src/Gui/SoFCOffscreenRenderer.cpp @@ -166,7 +166,7 @@ void SoFCOffscreenRenderer::writeToImageFile(const char* filename, const char* c img.setText(QLatin1String("Description"), QString::fromUtf8(comment)); img.setText(QLatin1String("Creation Time"), QDateTime::currentDateTime().toString()); img.setText(QLatin1String("Software"), - QString::fromUtf8(App::GetApplication().getExecutableName())); + QString::fromStdString(App::Application::getExecutableName())); } QFile f(QString::fromUtf8(filename)); @@ -296,7 +296,7 @@ std::string SoFCOffscreenRenderer::createMIBA(const SbMatrix& mat) const com << " \n" ; com << " Unknown\n" ; com << " " << QDateTime::currentDateTime().toString().toLatin1().constData() << "\n" ; - com << " " << App::GetApplication().getExecutableName() << " " << major << "." << minor << "\n" ; + com << " " << App::Application::getExecutableName() << " " << major << "." << minor << "\n" ; com << " Unknown\n"; com << " 1.0\n"; com << " \n" ; diff --git a/src/Gui/Splashscreen.cpp b/src/Gui/Splashscreen.cpp index 4b8e5b53fd..c899f92ae9 100644 --- a/src/Gui/Splashscreen.cpp +++ b/src/Gui/Splashscreen.cpp @@ -680,7 +680,7 @@ void AboutDialog::on_copyButton_clicked() QTextStream str(&data); std::map& config = App::Application::Config(); std::map::iterator it; - QString exe = QString::fromLatin1(App::GetApplication().getExecutableName()); + QString exe = QString::fromStdString(App::Application::getExecutableName()); QString major = QString::fromLatin1(config["BuildVersionMajor"].c_str()); QString minor = QString::fromLatin1(config["BuildVersionMinor"].c_str()); diff --git a/src/Gui/TinkerCADNavigationStyle.cpp b/src/Gui/TinkerCADNavigationStyle.cpp new file mode 100644 index 0000000000..50b28e47ad --- /dev/null +++ b/src/Gui/TinkerCADNavigationStyle.cpp @@ -0,0 +1,263 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include "InventorAll.h" +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include "NavigationStyle.h" +#include "View3DInventorViewer.h" +#include "Application.h" +#include "MenuManager.h" +#include "MouseSelection.h" + +using namespace Gui; + +// ---------------------------------------------------------------------------------- + +/* TRANSLATOR Gui::TinkerCADNavigationStyle */ + +TYPESYSTEM_SOURCE(Gui::TinkerCADNavigationStyle, Gui::UserNavigationStyle) + +TinkerCADNavigationStyle::TinkerCADNavigationStyle() +{ +} + +TinkerCADNavigationStyle::~TinkerCADNavigationStyle() +{ +} + +const char* TinkerCADNavigationStyle::mouseButtons(ViewerMode mode) +{ + switch (mode) { + case NavigationStyle::SELECTION: + return QT_TR_NOOP("Press left mouse button"); + case NavigationStyle::PANNING: + return QT_TR_NOOP("Press middle mouse button"); + case NavigationStyle::DRAGGING: + return QT_TR_NOOP("Press right mouse button"); + case NavigationStyle::ZOOMING: + return QT_TR_NOOP("Scroll middle mouse button"); + default: + return "No description"; + } +} + +SbBool TinkerCADNavigationStyle::processSoEvent(const SoEvent * const ev) +{ + // Events when in "ready-to-seek" mode are ignored, except those + // which influence the seek mode itself -- these are handled further + // up the inheritance hierarchy. + if (this->isSeekMode()) { return inherited::processSoEvent(ev); } + // Switch off viewing mode + if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) + this->setViewing(false); // by default disable viewing mode to render the scene + + const SoType type(ev->getTypeId()); + + const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); + const SbVec2s pos(ev->getPosition()); + const SbVec2f posn = normalizePixelPos(pos); + + const SbVec2f prevnormalized = this->lastmouseposition; + this->lastmouseposition = posn; + + // Set to true if any event processing happened. Note that it is not + // necessary to restrict ourselves to only do one "action" for an + // event, we only need this flag to see if any processing happened + // at all. + SbBool processed = false; + + const ViewerMode curmode = this->currentmode; + ViewerMode newmode = curmode; + + // Mismatches in state of the modifier keys happens if the user + // presses or releases them outside the viewer window. + syncModifierKeys(ev); + + // give the nodes in the foreground root the chance to handle events (e.g color bar) + if (!viewer->isEditing()) { + processed = handleEventInForeground(ev); + if (processed) + return true; + } + + // Keyboard handling + if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); + } + + // Mouse Button / Spaceball Button handling + if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { + const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; + const int button = event->getButton(); + const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; + SbBool canOpenPopupMenu = false; + + switch (button) { + case SoMouseButtonEvent::BUTTON1: + this->button1down = press; + if (press && (curmode == NavigationStyle::SEEK_WAIT_MODE)) { + newmode = NavigationStyle::SEEK_MODE; + this->seekToPoint(pos); // implicitly calls interactiveCountInc() + processed = true; + } + else if (viewer->isEditing() && (curmode == NavigationStyle::SPINNING)) { + processed = true; + } + else { + processed = processClickEvent(event); + } + break; + case SoMouseButtonEvent::BUTTON2: + // If we are in edit mode then simply ignore the RMB events + // to pass the event to the base class. + this->button2down = press; + if (press) { + mouseDownConsumedEvent = *event; + mouseDownConsumedEvent.setTime(ev->getTime()); + } + else if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON2) { + SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); + float dci = float(QApplication::doubleClickInterval())/1000.0f; + // time between press and release event + if (tmp.getValue() < dci) { + canOpenPopupMenu = true; + } + } + + // About to start rotating + if (press && (curmode == NavigationStyle::IDLE)) { + // Use this variable to spot move events + saveCursorPosition(ev); + this->centerTime = ev->getTime(); + processed = true; + } + else if (!press && (curmode == NavigationStyle::DRAGGING)) { + if (!viewer->isEditing() && canOpenPopupMenu) { + // If we are in drag mode but mouse hasn't been moved open the context-menu + if (this->isPopupMenuEnabled()) { + this->openPopupMenu(event->getPosition()); + } + } + newmode = NavigationStyle::IDLE; + processed = true; + } + break; + case SoMouseButtonEvent::BUTTON3: + this->button3down = press; + if (press) { + this->centerTime = ev->getTime(); + float ratio = vp.getViewportAspectRatio(); + SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio); + this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue()); + } + else if (curmode == NavigationStyle::PANNING) { + newmode = NavigationStyle::IDLE; + processed = true; + } + break; + default: + break; + } + } + + // Mouse Movement handling + if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { + const SoLocation2Event * const event = (const SoLocation2Event *) ev; + if (curmode == NavigationStyle::PANNING) { + float ratio = vp.getViewportAspectRatio(); + panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized); + processed = true; + } + else if (curmode == NavigationStyle::DRAGGING) { + this->addToLog(event->getPosition(), event->getTime()); + this->spin(posn); + moveCursorPosition(); + processed = true; + } + } + + // Spaceball & Joystick handling + if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { + const SoMotion3Event * const event = static_cast(ev); + if (event) + this->processMotionEvent(event); + processed = true; + } + + enum { + BUTTON1DOWN = 1 << 0, + BUTTON3DOWN = 1 << 1, + CTRLDOWN = 1 << 2, + SHIFTDOWN = 1 << 3, + BUTTON2DOWN = 1 << 4 + }; + unsigned int combo = + (this->button1down ? BUTTON1DOWN : 0) | + (this->button2down ? BUTTON2DOWN : 0) | + (this->button3down ? BUTTON3DOWN : 0) | + (this->ctrldown ? CTRLDOWN : 0) | + (this->shiftdown ? SHIFTDOWN : 0); + + switch (combo) { + case 0: + if (curmode == NavigationStyle::SPINNING) { break; } + newmode = NavigationStyle::IDLE; + break; + case BUTTON1DOWN: + newmode = NavigationStyle::SELECTION; + break; + case BUTTON2DOWN: + newmode = NavigationStyle::DRAGGING; + break; + case BUTTON3DOWN: + newmode = NavigationStyle::PANNING; + break; + default: + break; + } + + if (newmode != curmode) { + this->setViewingMode(newmode); + } + + // If not handled in this class, pass on upwards in the inheritance + // hierarchy. + if (!processed) + processed = inherited::processSoEvent(ev); + return processed; +} diff --git a/src/Gui/TouchpadNavigationStyle.cpp b/src/Gui/TouchpadNavigationStyle.cpp index 7b279eefc4..dbb2dc8b6c 100644 --- a/src/Gui/TouchpadNavigationStyle.cpp +++ b/src/Gui/TouchpadNavigationStyle.cpp @@ -88,12 +88,10 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); - const SbVec2s size(vp.getViewportSizePixels()); - const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); - const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), - (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + const SbVec2f posn = normalizePixelPos(pos); + const SbVec2f prevnormalized = this->lastmouseposition; this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not @@ -107,15 +105,7 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. - if (this->ctrldown != ev->wasCtrlDown()) { - this->ctrldown = ev->wasCtrlDown(); - } - if (this->shiftdown != ev->wasShiftDown()) { - this->shiftdown = ev->wasShiftDown(); - } - if (this->altdown != ev->wasAltDown()) { - this->altdown = ev->wasAltDown(); - } + syncModifierKeys(ev); // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { @@ -126,45 +116,8 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { - const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; - const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; - switch (event->getKey()) { - case SoKeyboardEvent::LEFT_CONTROL: - case SoKeyboardEvent::RIGHT_CONTROL: - this->ctrldown = press; - break; - case SoKeyboardEvent::LEFT_SHIFT: - case SoKeyboardEvent::RIGHT_SHIFT: - this->shiftdown = press; - break; - case SoKeyboardEvent::LEFT_ALT: - case SoKeyboardEvent::RIGHT_ALT: - this->altdown = press; - break; - case SoKeyboardEvent::H: - processed = true; - viewer->saveHomePosition(); - break; - case SoKeyboardEvent::S: - case SoKeyboardEvent::HOME: - case SoKeyboardEvent::LEFT_ARROW: - case SoKeyboardEvent::UP_ARROW: - case SoKeyboardEvent::RIGHT_ARROW: - case SoKeyboardEvent::DOWN_ARROW: - if (!this->isViewing()) - this->setViewing(true); - break; - case SoKeyboardEvent::PAGE_UP: - doZoom(viewer->getSoRenderManager()->getCamera(), getDelta(), posn); - processed = true; - break; - case SoKeyboardEvent::PAGE_DOWN: - doZoom(viewer->getSoRenderManager()->getCamera(), -getDelta(), posn); - processed = true; - break; - default: - break; - } + const SoKeyboardEvent * const event = static_cast(ev); + processed = processKeyboardEvent(event); } // Mouse Button / Spaceball Button handling @@ -193,30 +146,8 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; } - // issue #0002433: avoid to swallow the UP event if down the - // scene graph somewhere a dialog gets opened - else if (press) { - SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); - float dci = (float)QApplication::doubleClickInterval()/1000.0f; - // a double-click? - if (tmp.getValue() < dci) { - mouseDownConsumedEvent = *event; - mouseDownConsumedEvent.setTime(ev->getTime()); - processed = true; - } - else { - mouseDownConsumedEvent.setTime(ev->getTime()); - // 'ANY' is used to mark that we don't know yet if it will - // be a double-click event. - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } - } - else if (!press) { - if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { - // now handle the postponed event - inherited::processSoEvent(&mouseDownConsumedEvent); - mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); - } + else { + processed = processClickEvent(event); } break; case SoMouseButtonEvent::BUTTON2: @@ -346,8 +277,5 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) // hierarchy. if (!processed) processed = inherited::processSoEvent(ev); - else - return true; - return processed; } diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index 2ca90e415f..0576eae5da 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -115,6 +115,8 @@ void View3DInventorPy::init_type() add_varargs_method("stopAnimating",&View3DInventorPy::stopAnimating,"stopAnimating()"); add_varargs_method("setAnimationEnabled",&View3DInventorPy::setAnimationEnabled,"setAnimationEnabled()"); add_varargs_method("isAnimationEnabled",&View3DInventorPy::isAnimationEnabled,"isAnimationEnabled()"); + add_varargs_method("setPopupMenuEnabled",&View3DInventorPy::setPopupMenuEnabled,"setPopupMenuEnabled()"); + add_varargs_method("isPopupMenuEnabled",&View3DInventorPy::isPopupMenuEnabled,"isPopupMenuEnabled()"); add_varargs_method("dump",&View3DInventorPy::dump,"dump(filename, [onlyVisible=False])"); add_varargs_method("dumpNode",&View3DInventorPy::dumpNode,"dumpNode(node)"); add_varargs_method("setStereoType",&View3DInventorPy::setStereoType,"setStereoType()"); @@ -953,6 +955,23 @@ Py::Object View3DInventorPy::isAnimationEnabled(const Py::Tuple& args) return Py::Boolean(ok ? true : false); } +Py::Object View3DInventorPy::setPopupMenuEnabled(const Py::Tuple& args) +{ + int ok; + if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) + throw Py::Exception(); + _view->getViewer()->setPopupMenuEnabled(ok!=0); + return Py::None(); +} + +Py::Object View3DInventorPy::isPopupMenuEnabled(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + SbBool ok = _view->getViewer()->isPopupMenuEnabled(); + return Py::Boolean(ok ? true : false); +} + Py::Object View3DInventorPy::saveImage(const Py::Tuple& args) { char *cFileName,*cColor="Current",*cComment="$MIBA"; diff --git a/src/Gui/View3DPy.h b/src/Gui/View3DPy.h index 71e2557bad..d84c073c34 100644 --- a/src/Gui/View3DPy.h +++ b/src/Gui/View3DPy.h @@ -87,6 +87,8 @@ public: Py::Object stopAnimating(const Py::Tuple&); Py::Object setAnimationEnabled(const Py::Tuple&); Py::Object isAnimationEnabled(const Py::Tuple&); + Py::Object setPopupMenuEnabled(const Py::Tuple&); + Py::Object isPopupMenuEnabled(const Py::Tuple&); Py::Object dump(const Py::Tuple&); Py::Object dumpNode(const Py::Tuple&); Py::Object setStereoType(const Py::Tuple&); diff --git a/src/Gui/ViewProviderDocumentObject.cpp b/src/Gui/ViewProviderDocumentObject.cpp index 0230117675..e4cc2bbb2b 100644 --- a/src/Gui/ViewProviderDocumentObject.cpp +++ b/src/Gui/ViewProviderDocumentObject.cpp @@ -196,12 +196,19 @@ void ViewProviderDocumentObject::onChanged(const App::Property* prop) // this is undesired behaviour. So, if this change marks the document as // modified then it must be be reversed. if (!testStatus(Gui::ViewStatus::TouchDocument)) { - bool mod = false; - if (pcDocument) - mod = pcDocument->isModified(); + // Note: reverting document modified status like that is not + // appropriate because we can't tell if there is any other + // property being changed due to the change of Visibility here. + // Temporary setting the Visibility property as 'NoModify' is + // the proper way. + Base::ObjectStatusLocker guard( + App::Property::NoModify, &Visibility); + // bool mod = false; + // if (pcDocument) + // mod = pcDocument->isModified(); getObject()->Visibility.setValue(Visibility.getValue()); - if (pcDocument) - pcDocument->setModified(mod); + // if (pcDocument) + // pcDocument->setModified(mod); } else { getObject()->Visibility.setValue(Visibility.getValue()); @@ -215,7 +222,10 @@ void ViewProviderDocumentObject::onChanged(const App::Property* prop) } } - if (pcDocument && !pcDocument->isModified() && testStatus(Gui::ViewStatus::TouchDocument)) { + if (prop && !prop->testStatus(App::Property::NoModify) + && pcDocument + && !pcDocument->isModified() + && testStatus(Gui::ViewStatus::TouchDocument)) { if (prop) FC_LOG(prop->getFullName() << " changed"); pcDocument->setModified(true); diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index b68456e7a4..241c35f655 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -431,7 +431,7 @@ void PyResource::load(const char* name) // checks whether it's a relative path if (fi.isRelative()) { QString cwd = QDir::currentPath (); - QString home= QDir(QString::fromUtf8(App::GetApplication().getHomePath())).path(); + QString home= QDir(QString::fromStdString(App::Application::getHomePath())).path(); // search in cwd and home path for the file // diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index 519816fcab..d3e9cd8076 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -2094,13 +2094,110 @@ void PropertyMatrixItem::setA44(double A44) // --------------------------------------------------------------- -PROPERTYITEM_SOURCE(Gui::PropertyEditor::PropertyRotationItem) - -PropertyRotationItem::PropertyRotationItem() +RotationHelper::RotationHelper() : init_axis(false) , changed_value(false) , rot_angle(0) , rot_axis(0,0,1) +{ +} + +void RotationHelper::setChanged(bool value) +{ + changed_value = value; +} + +bool RotationHelper::hasChangedAndReset() +{ + if (!changed_value) + return false; + + changed_value = false; + return true; +} + +bool RotationHelper::isAxisInitialized() const +{ + return init_axis; +} + +void RotationHelper::setValue(const Base::Vector3d& axis, double angle) +{ + rot_axis = axis; + rot_angle = angle; + init_axis = true; +} + +void RotationHelper::getValue(Base::Vector3d& axis, double& angle) const +{ + axis = rot_axis; + angle = rot_angle; +} + +double RotationHelper::getAngle(const Base::Rotation& val) const +{ + double angle; + Base::Vector3d dir; + val.getRawValue(dir, angle); + if (dir * this->rot_axis < 0.0) + angle = -angle; + return angle; +} + +Base::Rotation RotationHelper::setAngle(double angle) +{ + Base::Rotation rot; + rot.setValue(this->rot_axis, Base::toRadians(angle)); + changed_value = true; + rot_angle = angle; + return rot; +} + +Base::Vector3d RotationHelper::getAxis() const +{ + // We must store the rotation axis in a member because + // if we read the value from the property we would always + // get a normalized vector which makes it quite unhandy + // to work with + return this->rot_axis; +} + +Base::Rotation RotationHelper::setAxis(const Base::Rotation& value, const Base::Vector3d& axis) +{ + this->rot_axis = axis; + Base::Rotation rot = value; + Base::Vector3d dummy; double angle; + rot.getValue(dummy, angle); + if (dummy * axis < 0.0) + angle = -angle; + rot.setValue(axis, angle); + changed_value = true; + return rot; +} + +void RotationHelper::assignProperty(const Base::Rotation& value, double eps) +{ + double angle; + Base::Vector3d dir; + value.getRawValue(dir, angle); + Base::Vector3d cross = this->rot_axis.Cross(dir); + double len2 = cross.Sqr(); + if (angle != 0) { + // vectors are not parallel + if (len2 > eps) + this->rot_axis = dir; + // vectors point into opposite directions + else if (this->rot_axis.Dot(dir) < 0) + this->rot_axis = -this->rot_axis; + } + this->rot_angle = Base::toDegrees(angle); +} + +// --------------------------------------------------------------- + +PROPERTYITEM_SOURCE(Gui::PropertyEditor::PropertyRotationItem) + +PropertyRotationItem::PropertyRotationItem() { m_a = static_cast(PropertyUnitItem::create()); m_a->setParent(this); @@ -2122,12 +2219,9 @@ Base::Quantity PropertyRotationItem::getAngle() const QVariant value = data(1, Qt::EditRole); if (!value.canConvert()) return Base::Quantity(0.0); + const Base::Rotation& val = value.value(); - double angle; - Base::Vector3d dir; - val.getRawValue(dir, angle); - if (dir * this->rot_axis < 0.0) - angle = -angle; + double angle = h.getAngle(val); return Base::Quantity(Base::toDegrees(angle), Base::Unit::Angle); } @@ -2137,20 +2231,13 @@ void PropertyRotationItem::setAngle(Base::Quantity angle) if (!value.canConvert()) return; - Base::Rotation rot; - rot.setValue(this->rot_axis, Base::toRadians(angle.getValue())); - changed_value = true; - rot_angle = angle.getValue(); + Base::Rotation rot = h.setAngle(angle.getValue()); setValue(QVariant::fromValue(rot)); } Base::Vector3d PropertyRotationItem::getAxis() const { - // We must store the rotation axis in a member because - // if we read the value from the property we would always - // get a normalized vector which makes it quite unhandy - // to work with - return this->rot_axis; + return h.getAxis(); } void PropertyRotationItem::setAxis(const Base::Vector3d& axis) @@ -2158,14 +2245,9 @@ void PropertyRotationItem::setAxis(const Base::Vector3d& axis) QVariant value = data(1, Qt::EditRole); if (!value.canConvert()) return; - this->rot_axis = axis; + Base::Rotation rot = value.value(); - Base::Vector3d dummy; double angle; - rot.getValue(dummy, angle); - if (dummy * axis < 0.0) - angle = -angle; - rot.setValue(axis, angle); - changed_value = true; + rot = h.setAxis(rot, axis); setValue(QVariant::fromValue(rot)); } @@ -2176,20 +2258,7 @@ void PropertyRotationItem::assignProperty(const App::Property* prop) double eps = std::pow(10.0, -2*(decimals()+1)); if (prop->getTypeId().isDerivedFrom(App::PropertyRotation::getClassTypeId())) { const Base::Rotation& value = static_cast(prop)->getValue(); - double angle; - Base::Vector3d dir; - value.getRawValue(dir, angle); - Base::Vector3d cross = this->rot_axis.Cross(dir); - double len2 = cross.Sqr(); - if (angle != 0) { - // vectors are not parallel - if (len2 > eps) - this->rot_axis = dir; - // vectors point into opposite directions - else if (this->rot_axis.Dot(dir) < 0) - this->rot_axis = -this->rot_axis; - } - this->rot_angle = Base::toDegrees(angle); + h.assignProperty(value, eps); } } @@ -2201,13 +2270,13 @@ QVariant PropertyRotationItem::value(const App::Property* prop) const double angle; Base::Vector3d dir; value.getRawValue(dir, angle); - if (!init_axis) { + if (!h.isAxisInitialized()) { if (m_a->hasExpression()) { QString str = m_a->expressionAsString(); - const_cast(this)->rot_angle = str.toDouble(); + angle = str.toDouble(); } else { - const_cast(this)->rot_angle = Base::toDegrees(angle); + angle = Base::toDegrees(angle); } PropertyItem* x = m_d->child(0); @@ -2225,8 +2294,7 @@ QVariant PropertyRotationItem::value(const App::Property* prop) const QString str = z->expressionAsString(); dir.z = str.toDouble(); } - const_cast(this)->rot_axis = dir; - const_cast(this)->init_axis = true; + h.setValue(dir, angle); } return QVariant::fromValue(value); } @@ -2274,16 +2342,18 @@ void PropertyRotationItem::setValue(const QVariant& value) return; // Accept this only if the user changed the axis, angle or position but // not if >this< item loses focus - if (!changed_value) + if (!h.hasChangedAndReset()) return; - changed_value = false; + Base::Vector3d axis; + double angle; + h.getValue(axis, angle); Base::QuantityFormat format(Base::QuantityFormat::Fixed, decimals()); QString data = QString::fromLatin1("App.Rotation(App.Vector(%1,%2,%3),%4)") - .arg(Base::UnitsApi::toNumber(rot_axis.x, format)) - .arg(Base::UnitsApi::toNumber(rot_axis.y, format)) - .arg(Base::UnitsApi::toNumber(rot_axis.z, format)) - .arg(Base::UnitsApi::toNumber(rot_angle, format)); + .arg(Base::UnitsApi::toNumber(axis.x, format)) + .arg(Base::UnitsApi::toNumber(axis.y, format)) + .arg(Base::UnitsApi::toNumber(axis.z, format)) + .arg(Base::UnitsApi::toNumber(angle, format)); setPropertyValue(data); } @@ -2394,7 +2464,7 @@ void PlacementEditor::updateValue(const QVariant& v, bool incr, bool data) PROPERTYITEM_SOURCE(Gui::PropertyEditor::PropertyPlacementItem) -PropertyPlacementItem::PropertyPlacementItem() : init_axis(false), changed_value(false), rot_angle(0), rot_axis(0,0,1) +PropertyPlacementItem::PropertyPlacementItem() { m_a = static_cast(PropertyUnitItem::create()); m_a->setParent(this); @@ -2421,12 +2491,9 @@ Base::Quantity PropertyPlacementItem::getAngle() const QVariant value = data(1, Qt::EditRole); if (!value.canConvert()) return Base::Quantity(0.0); + const Base::Placement& val = value.value(); - double angle; - Base::Vector3d dir; - val.getRotation().getRawValue(dir, angle); - if (dir * this->rot_axis < 0.0) - angle = -angle; + double angle = h.getAngle(val.getRotation()); return Base::Quantity(Base::toDegrees(angle), Base::Unit::Angle); } @@ -2437,21 +2504,14 @@ void PropertyPlacementItem::setAngle(Base::Quantity angle) return; Base::Placement val = value.value(); - Base::Rotation rot; - rot.setValue(this->rot_axis, Base::toRadians(angle.getValue())); + Base::Rotation rot = h.setAngle(angle.getValue()); val.setRotation(rot); - changed_value = true; - rot_angle = angle.getValue(); setValue(QVariant::fromValue(val)); } Base::Vector3d PropertyPlacementItem::getAxis() const { - // We must store the rotation axis in a member because - // if we read the value from the property we would always - // get a normalized vector which makes it quite unhandy - // to work with - return this->rot_axis; + return h.getAxis(); } void PropertyPlacementItem::setAxis(const Base::Vector3d& axis) @@ -2459,16 +2519,11 @@ void PropertyPlacementItem::setAxis(const Base::Vector3d& axis) QVariant value = data(1, Qt::EditRole); if (!value.canConvert()) return; - this->rot_axis = axis; + Base::Placement val = value.value(); Base::Rotation rot = val.getRotation(); - Base::Vector3d dummy; double angle; - rot.getValue(dummy, angle); - if (dummy * axis < 0.0) - angle = -angle; - rot.setValue(axis, angle); + rot = h.setAxis(rot, axis); val.setRotation(rot); - changed_value = true; setValue(QVariant::fromValue(val)); } @@ -2486,9 +2541,10 @@ void PropertyPlacementItem::setPosition(const Base::Vector3d& pos) QVariant value = data(1, Qt::EditRole); if (!value.canConvert()) return; + Base::Placement val = value.value(); val.setPosition(pos); - changed_value = true; + h.setChanged(true); setValue(QVariant::fromValue(val)); } @@ -2499,20 +2555,7 @@ void PropertyPlacementItem::assignProperty(const App::Property* prop) double eps = std::pow(10.0, -2*(decimals()+1)); if (prop->getTypeId().isDerivedFrom(App::PropertyPlacement::getClassTypeId())) { const Base::Placement& value = static_cast(prop)->getValue(); - double angle; - Base::Vector3d dir; - value.getRotation().getRawValue(dir, angle); - Base::Vector3d cross = this->rot_axis.Cross(dir); - double len2 = cross.Sqr(); - if (angle != 0) { - // vectors are not parallel - if (len2 > eps) - this->rot_axis = dir; - // vectors point into opposite directions - else if (this->rot_axis.Dot(dir) < 0) - this->rot_axis = -this->rot_axis; - } - this->rot_angle = Base::toDegrees(angle); + h.assignProperty(value.getRotation(), eps); } } @@ -2524,13 +2567,13 @@ QVariant PropertyPlacementItem::value(const App::Property* prop) const double angle; Base::Vector3d dir; value.getRotation().getRawValue(dir, angle); - if (!init_axis) { + if (!h.isAxisInitialized()) { if (m_a->hasExpression()) { QString str = m_a->expressionAsString(); - const_cast(this)->rot_angle = str.toDouble(); + angle = str.toDouble(); } else { - const_cast(this)->rot_angle = Base::toDegrees(angle); + angle = Base::toDegrees(angle); } PropertyItem* x = m_d->child(0); @@ -2548,8 +2591,7 @@ QVariant PropertyPlacementItem::value(const App::Property* prop) const QString str = z->expressionAsString(); dir.z = str.toDouble(); } - const_cast(this)->rot_axis = dir; - const_cast(this)->init_axis = true; + h.setValue(dir, angle); } return QVariant::fromValue(value); } @@ -2606,12 +2648,16 @@ void PropertyPlacementItem::setValue(const QVariant& value) return; // Accept this only if the user changed the axis, angle or position but // not if >this< item loses focus - if (!changed_value) + if (!h.hasChangedAndReset()) return; - changed_value = false; + const Base::Placement& val = value.value(); Base::Vector3d pos = val.getPosition(); + Base::Vector3d axis; + double angle; + h.getValue(axis, angle); + Base::QuantityFormat format(Base::QuantityFormat::Fixed, decimals()); QString data = QString::fromLatin1("App.Placement(" "App.Vector(%1,%2,%3)," @@ -2619,10 +2665,10 @@ void PropertyPlacementItem::setValue(const QVariant& value) .arg(Base::UnitsApi::toNumber(pos.x, format)) .arg(Base::UnitsApi::toNumber(pos.y, format)) .arg(Base::UnitsApi::toNumber(pos.z, format)) - .arg(Base::UnitsApi::toNumber(rot_axis.x, format)) - .arg(Base::UnitsApi::toNumber(rot_axis.y, format)) - .arg(Base::UnitsApi::toNumber(rot_axis.z, format)) - .arg(Base::UnitsApi::toNumber(rot_angle, format)); + .arg(Base::UnitsApi::toNumber(axis.x, format)) + .arg(Base::UnitsApi::toNumber(axis.y, format)) + .arg(Base::UnitsApi::toNumber(axis.z, format)) + .arg(Base::UnitsApi::toNumber(angle, format)); setPropertyValue(data); } diff --git a/src/Gui/propertyeditor/PropertyItem.h b/src/Gui/propertyeditor/PropertyItem.h index 20ac165fdb..9483b4d3b6 100644 --- a/src/Gui/propertyeditor/PropertyItem.h +++ b/src/Gui/propertyeditor/PropertyItem.h @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef Q_MOC_RUN Q_DECLARE_METATYPE(Base::Vector3f) @@ -657,6 +658,28 @@ private: PropertyFloatItem* m_a44; }; +class RotationHelper +{ +public: + RotationHelper(); + void setChanged(bool); + bool hasChangedAndReset(); + bool isAxisInitialized() const; + void setValue(const Base::Vector3d& axis, double angle); + void getValue(Base::Vector3d& axis, double& angle) const; + double getAngle(const Base::Rotation& val) const; + Base::Rotation setAngle(double); + Base::Vector3d getAxis() const; + Base::Rotation setAxis(const Base::Rotation& value, const Base::Vector3d& axis); + void assignProperty(const Base::Rotation& value, double eps); + +private: + bool init_axis; + bool changed_value; + double rot_angle; + Base::Vector3d rot_axis; +}; + /** * Edit properties of rotation type. * \author Werner Mayer @@ -689,10 +712,7 @@ protected: virtual void setValue(const QVariant&); private: - bool init_axis; - bool changed_value; - double rot_angle; - Base::Vector3d rot_axis; + mutable RotationHelper h; PropertyUnitItem * m_a; PropertyVectorItem* m_d; }; @@ -752,10 +772,7 @@ protected: virtual void setValue(const QVariant&); private: - bool init_axis; - bool changed_value; - double rot_angle; - Base::Vector3d rot_axis; + mutable RotationHelper h; PropertyUnitItem * m_a; PropertyVectorItem* m_d; PropertyVectorDistanceItem* m_p; diff --git a/src/Main/MainCmd.cpp b/src/Main/MainCmd.cpp index fa230acacc..ae4e36ffd9 100644 --- a/src/Main/MainCmd.cpp +++ b/src/Main/MainCmd.cpp @@ -108,7 +108,7 @@ int main( int argc, char ** argv ) std::string appName = App::Application::Config()["ExeName"]; std::stringstream msg; msg << "While initializing " << appName << " the following exception occurred: '" << e.what() << "'\n\n"; - msg << "Python is searching for its runtime files in the following directories:\n" << Py_GetPath() << "\n\n"; + msg << "Python is searching for its runtime files in the following directories:\n" << Py_EncodeLocale(Py_GetPath(),nullptr) << "\n\n"; msg << "Python version information:\n" << Py_GetVersion() << "\n"; const char* pythonhome = getenv("PYTHONHOME"); if ( pythonhome ) { diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index 3e130699dc..b155d74c13 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -652,14 +652,14 @@ class Plane: if not geom_is_shape: FreeCAD.Console.PrintError(translate( "draft", - "Object without Part.Shape geometry:'{}'\n".format( - obj.ObjectName))) + "Object without Part.Shape geometry:'{}'".format( + obj.ObjectName)) + "\n") return False if geom.isNull(): FreeCAD.Console.PrintError(translate( "draft", - "Object with null Part.Shape geometry:'{}'\n".format( - obj.ObjectName))) + "Object with null Part.Shape geometry:'{}'".format( + obj.ObjectName)) + "\n") return False if obj.HasSubObjects: shapes.extend(obj.SubObjects) @@ -672,7 +672,7 @@ class Plane: for n in range(len(shapes)): if not DraftGeomUtils.is_planar(shapes[n]): FreeCAD.Console.PrintError(translate( - "draft","'{}' object is not planar\n".format(names[n]))) + "draft", "'{}' object is not planar".format(names[n])) + "\n") return False if not normal: normal = DraftGeomUtils.get_normal(shapes[n]) @@ -683,8 +683,8 @@ class Plane: for n in range(len(shapes)): if not DraftGeomUtils.are_coplanar(shapes[shape_ref], shapes[n]): FreeCAD.Console.PrintError(translate( - "draft","{} and {} aren't coplanar\n".format( - names[shape_ref],names[n]))) + "draft", "{} and {} aren't coplanar".format( + names[shape_ref],names[n])) + "\n") return False else: # suppose all geometries are straight lines or points @@ -693,7 +693,7 @@ class Plane: poly = Part.makePolygon(points) if not DraftGeomUtils.is_planar(poly): FreeCAD.Console.PrintError(translate( - "draft","All Shapes must be coplanar\n")) + "draft", "All Shapes must be coplanar") + "\n") return False normal = DraftGeomUtils.get_normal(poly) else: @@ -701,7 +701,7 @@ class Plane: if not normal: FreeCAD.Console.PrintError(translate( - "draft","Selected Shapes must define a plane\n")) + "draft", "Selected Shapes must define a plane") + "\n") return False # set center of mass diff --git a/src/Mod/Draft/draftguitools/gui_dimensions.py b/src/Mod/Draft/draftguitools/gui_dimensions.py index 45f12e8991..d091568ea8 100644 --- a/src/Mod/Draft/draftguitools/gui_dimensions.py +++ b/src/Mod/Draft/draftguitools/gui_dimensions.py @@ -106,7 +106,7 @@ class Dimension(gui_base_original.Creator): self.arctrack = trackers.arcTracker() self.link = None self.edges = [] - self.pts = [] + self.angles = [] self.angledata = None self.indices = [] self.center = None @@ -397,7 +397,7 @@ class Dimension(gui_base_original.Creator): r = self.point.sub(self.center) self.arctrack.setRadius(r.Length) a = self.arctrack.getAngle(self.point) - pair = DraftGeomUtils.getBoundaryAngles(a, self.pts) + pair = DraftGeomUtils.getBoundaryAngles(a, self.angles) if not (pair[0] < a < pair[1]): self.angledata = [4 * math.pi - pair[0], 2 * math.pi - pair[1]] @@ -504,8 +504,15 @@ class Dimension(gui_base_original.Creator): self.arctrack.setCenter(self.center) self.arctrack.on() for e in self.edges: - for v in e.Vertexes: - self.pts.append(self.arctrack.getAngle(v.Point)) + if e.Length < 0.00003: # Edge must be long enough for the tolerance of 0.00001mm to make sense. + _msg(translate("draft", "Edge too short!")) + self.finish() + return + for i in [0, 1]: + pt = e.Vertexes[i].Point + if pt.isEqual(self.center, 0.00001): # A relatively high tolerance is required. + pt = e.Vertexes[i - 1].Point # Use the other point instead. + self.angles.append(self.arctrack.getAngle(pt)) self.link = [self.link[0], ob] else: _msg(translate("draft", "Edges don't intersect!")) diff --git a/src/Mod/Draft/draftmake/make_sketch.py b/src/Mod/Draft/draftmake/make_sketch.py index 52d6fde7e1..b136c944bc 100644 --- a/src/Mod/Draft/draftmake/make_sketch.py +++ b/src/Mod/Draft/draftmake/make_sketch.py @@ -100,13 +100,15 @@ def make_sketch(objects_list, autoconstraints=False, addTo=None, if isinstance(obj,Part.Shape): shape = obj elif not hasattr(obj,'Shape'): - App.Console.PrintError(translate("draft","No shape found\n")) + App.Console.PrintError(translate("draft", + "No shape found")+"\n") return None else: shape = obj.Shape if not DraftGeomUtils.is_planar(shape, tol): - App.Console.PrintError(translate("draft","All Shapes must be planar\n")) + App.Console.PrintError(translate("draft", + "All Shapes must be planar")+"\n") return None if DraftGeomUtils.get_normal(shape, tol): @@ -121,7 +123,8 @@ def make_sketch(objects_list, autoconstraints=False, addTo=None, if len(shape_norm_yes) >= 1: for shape in shapes_list[1:]: if not DraftGeomUtils.are_coplanar(shapes_list[0], shape, tol): - App.Console.PrintError(translate("draft","All Shapes must be coplanar\n")) + App.Console.PrintError(translate("draft", + "All Shapes must be coplanar")+"\n") return None # define sketch normal normal = DraftGeomUtils.get_normal(shapes_list[0], tol) @@ -132,7 +135,8 @@ def make_sketch(objects_list, autoconstraints=False, addTo=None, if len(points) >= 2: poly = Part.makePolygon(points) if not DraftGeomUtils.is_planar(poly, tol): - App.Console.PrintError(translate("draft","All Shapes must be coplanar\n")) + App.Console.PrintError(translate("draft", + "All Shapes must be coplanar")+"\n") return None normal = DraftGeomUtils.get_normal(poly, tol) if not normal: diff --git a/src/Mod/Draft/draftobjects/array.py b/src/Mod/Draft/draftobjects/array.py index 946d474804..8292c60751 100644 --- a/src/Mod/Draft/draftobjects/array.py +++ b/src/Mod/Draft/draftobjects/array.py @@ -287,7 +287,7 @@ class Array(DraftLink): _tip = QT_TRANSLATE_NOOP("App::Property", "A parameter that determines " "how many symmetry planes " - " the circular array will have.") + "the circular array will have.") obj.addProperty("App::PropertyInteger", "Symmetry", "Circular array", @@ -380,7 +380,7 @@ class Array(DraftLink): obj.setPropertyStatus(pr, "Hidden") def execute(self, obj): - """Execture when the object is created or recomputed.""" + """Execute when the object is created or recomputed.""" if not obj.Base: return diff --git a/src/Mod/Draft/draftobjects/dimension.py b/src/Mod/Draft/draftobjects/dimension.py index a7143a655b..bc4bcbecdb 100644 --- a/src/Mod/Draft/draftobjects/dimension.py +++ b/src/Mod/Draft/draftobjects/dimension.py @@ -163,7 +163,7 @@ class DimensionBase(DraftAnnotation): "There are various possibilities:\n" "- An object, and one of its edges.\n" "- An object, and two of its vertices.\n" - "- An arc object, and its edge.\n") + "- An arc object, and its edge.") obj.addProperty("App::PropertyLinkSubList", "LinkedGeometry", "Dimension", diff --git a/src/Mod/Draft/draftviewproviders/view_layer.py b/src/Mod/Draft/draftviewproviders/view_layer.py index b7231ae1f1..1f88700105 100644 --- a/src/Mod/Draft/draftviewproviders/view_layer.py +++ b/src/Mod/Draft/draftviewproviders/view_layer.py @@ -1,6 +1,7 @@ # *************************************************************************** # * Copyright (c) 2014 Yorik van Havre * # * Copyright (c) 2020 Eliud Cabrera Castillo * +# * Copyright (c) 2021 FreeCAD Developers * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -37,7 +38,7 @@ import FreeCAD as App import FreeCADGui as Gui from draftutils.messages import _msg -from draftutils.translate import translate +from draftutils.translate import _tr from draftobjects.layer import Layer @@ -355,13 +356,13 @@ class ViewProviderLayer: def setupContextMenu(self, vobj, menu): """Set up actions to perform in the context menu.""" action1 = QtGui.QAction(QtGui.QIcon(":/icons/button_right.svg"), - translate("draft", "Activate this layer"), + _tr("Activate this layer"), menu) action1.triggered.connect(self.activate) menu.addAction(action1) action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectGroup.svg"), - translate("draft", "Select layer contents"), + _tr("Select layer contents"), menu) action2.triggered.connect(self.select_contents) menu.addAction(action2) @@ -399,80 +400,76 @@ class ViewProviderLayerContainer: def setupContextMenu(self, vobj, menu): """Set up actions to perform in the context menu.""" action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Layer.svg"), - translate("Draft", "Merge layer duplicates"), + _tr("Merge layer duplicates"), menu) action1.triggered.connect(self.merge_by_name) menu.addAction(action1) action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_NewLayer.svg"), - translate("Draft", "Add new layer"), + _tr("Add new layer"), menu) action2.triggered.connect(self.add_layer) menu.addAction(action2) def merge_by_name(self): - """Merge the layers that have the same name.""" + """Merge the layers that have the same base label.""" if not hasattr(self, "Object") or not hasattr(self.Object, "Group"): return - obj = self.Object + doc = App.ActiveDocument + doc.openTransaction(_tr("Merge layer duplicates")) - layers = list() - for iobj in obj.Group: - if hasattr(iobj, "Proxy") and isinstance(iobj.Proxy, Layer): - layers.append(iobj) + layer_container = self.Object + layers = [] + for obj in layer_container.Group: + if hasattr(obj, "Proxy") and isinstance(obj.Proxy, Layer): + layers.append(obj) - to_delete = list() + to_delete = [] for layer in layers: - # Test the last three characters of the layer's Label to see - # if it's a number, like `'Layer017'` - if (layer.Label[-1].isdigit() - and layer.Label[-2].isdigit() - and layer.Label[-3].isdigit()): - # If the object inside the layer has the same Label - # as the layer, save this object - orig = None - for ol in layer.OutList: - if ol.Label == layer.Label[:-3].strip(): - orig = ol - break + # Remove trailing digits (usually 3 but there might be more) and + # trailing spaces from Label before comparing: + base_label = layer.Label.rstrip("0123456789 ") - # Go into the objects that reference this layer object - # and set the layer property with the previous `orig` - # object found - # Editor: when is this possible? Maybe if a layer is inside - # another layer? Currently the code doesn't allow this - # so maybe this was a previous behavior that was disabled - # in `ViewProviderLayer`. - if orig: - for par in layer.InList: - for prop in par.PropertiesList: - if getattr(par, prop) == layer: - _msg("Changed property '" + prop - + "' of object " + par.Label - + " from " + layer.Label - + " to " + orig.Label) - setattr(par, prop, orig) - to_delete.append(layer) + # Try to find the `'base'` layer: + base = None + for other_layer in layers: + if ((not other_layer in to_delete) # Required if there are duplicate labels. + and other_layer != layer + and other_layer.Label.upper() == base_label.upper()): + base = other_layer + break + + if base: + if layer.Group: + base_group = base.Group + for obj in layer.Group: + if not obj in base_group: + base_group.append(obj) + base.Group = base_group + to_delete.append(layer) + elif layer.Label != base_label: + _msg(_tr("Relabeling layer:") + + " '{}' -> '{}'".format(layer.Label, base_label)) + layer.Label = base_label for layer in to_delete: - if not layer.InList: - _msg("Merging duplicate layer: " + layer.Label) - App.ActiveDocument.removeObject(layer.Name) - elif len(layer.InList) == 1: - first = layer.InList[0] + _msg(_tr("Merging layer:") + " '{}'".format(layer.Label)) + doc.removeObject(layer.Name) - if first.isDerivedFrom("App::DocumentObjectGroup"): - _msg("Merging duplicate layer: " + layer.Label) - App.ActiveDocument.removeObject(layer.Name) - else: - _msg("InList not empty. " - "Unable to delete layer: " + layer.Label) + doc.recompute() + doc.commitTransaction() def add_layer(self): """Creates a new layer""" import Draft + + doc = App.ActiveDocument + doc.openTransaction(_tr("Add new layer")) + Draft.make_layer() - App.ActiveDocument.recompute() + + doc.recompute() + doc.commitTransaction() def __getstate__(self): """Return a tuple of objects to save or None.""" diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py index 782fffc61f..051be66cb3 100644 --- a/src/Mod/Fem/femcommands/commands.py +++ b/src/Mod/Fem/femcommands/commands.py @@ -31,17 +31,21 @@ __url__ = "https://www.freecadweb.org" import FreeCAD import FreeCADGui +from FreeCAD import Qt from .manager import CommandManager from femtools.femutils import is_of_type -# Python command definitions +# Python command definitions: # for C++ command definitions see src/Mod/Fem/Command.cpp # TODO, may be even more generic class creation # with type() and identifier instead of class for # the commands which add new document objects. # see https://www.python-course.eu/python3_classes_and_type.php +# Translation: +# some information in the regard of translation can be found in forum post +# https://forum.freecadweb.org/viewtopic.php?f=18&t=62449&p=543845#p543593 class _Analysis(CommandManager): @@ -49,9 +53,12 @@ class _Analysis(CommandManager): def __init__(self): super(_Analysis, self).__init__() - self.menutext = "Analysis container" + self.menutext = Qt.QT_TRANSLATE_NOOP("FEM_Analysis", "Analysis container") self.accel = "S, A" - self.tooltip = "Creates an analysis container with standard solver CalculiX" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_Analysis", + "Creates an analysis container with standard solver CalculiX" + ) self.is_active = "with_document" def Activated(self): @@ -74,8 +81,11 @@ class _ClippingPlaneAdd(CommandManager): def __init__(self): super(_ClippingPlaneAdd, self).__init__() - self.menutext = "Clipping plane on face" - self.tooltip = "Add a clipping plane on a selected face" + self.menutext = Qt.QT_TRANSLATE_NOOP("FEM_ClippingPlaneAdd", "Clipping plane on face") + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ClippingPlaneAdd", + "Add a clipping plane on a selected face" + ) self.is_active = "with_document" def Activated(self): @@ -123,8 +133,14 @@ class _ClippingPlaneRemoveAll(CommandManager): def __init__(self): super(_ClippingPlaneRemoveAll, self).__init__() - self.menutext = "Remove all clipping planes" - self.tooltip = "Remove all clipping planes" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ClippingPlaneRemoveAll", + "Remove all clipping planes" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ClippingPlaneRemoveAll", + "Remove all clipping planes" + ) self.is_active = "with_document" def Activated(self): @@ -143,8 +159,14 @@ class _ConstantVacuumPermittivity(CommandManager): def __init__(self): super(_ConstantVacuumPermittivity, self).__init__() self.pixmap = "fem-solver-analysis-thermomechanical.svg" - self.menutext = "Constant vacuum permittivity" - self.tooltip = "Creates a FEM constant vacuum permittivity to overwrite standard value" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstantVacuumPermittivity", + "Constant vacuum permittivity" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstantVacuumPermittivity", + "Creates a FEM constant vacuum permittivity to overwrite standard value" + ) self.is_active = "with_document" self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" @@ -156,8 +178,14 @@ class _ConstraintBodyHeatSource(CommandManager): def __init__(self): super(_ConstraintBodyHeatSource, self).__init__() self.pixmap = "FEM_ConstraintHeatflux" # the heatflux icon is used - self.menutext = "Constraint body heat source" - self.tooltip = "Creates a FEM constraint body heat source" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintBodyHeatSource", + "Constraint body heat source" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintBodyHeatSource", + "Creates a FEM constraint body heat source" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" @@ -167,8 +195,14 @@ class _ConstraintCentrif(CommandManager): def __init__(self): super(_ConstraintCentrif, self).__init__() - self.menutext = "Constraint centrif" - self.tooltip = "Creates a FEM constraint centrif" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintCentrif", + "Constraint centrif" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintCentrif", + "Creates a FEM constraint centrif" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -178,8 +212,14 @@ class _ConstraintElectrostaticPotential(CommandManager): def __init__(self): super(_ConstraintElectrostaticPotential, self).__init__() - self.menutext = "Constraint electrostatic potential" - self.tooltip = "Creates a FEM constraint electrostatic potential" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintElectrostaticPotential", + "Constraint electrostatic potential" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintElectrostaticPotential", + "Creates a FEM constraint electrostatic potential" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -189,8 +229,14 @@ class _ConstraintFlowVelocity(CommandManager): def __init__(self): super(_ConstraintFlowVelocity, self).__init__() - self.menutext = "Constraint flow velocity" - self.tooltip = "Creates a FEM constraint flow velocity" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintFlowVelocity", + "Constraint flow velocity" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintFlowVelocity", + "Creates a FEM constraint flow velocity" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -200,8 +246,14 @@ class _ConstraintInitialFlowVelocity(CommandManager): def __init__(self): super(_ConstraintInitialFlowVelocity, self).__init__() - self.menutext = "Constraint initial flow velocity" - self.tooltip = "Creates a FEM constraint initial flow velocity" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintInitialFlowVelocity", + "Constraint initial flow velocity" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintInitialFlowVelocity", + "Creates a FEM constraint initial flow velocity" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -211,8 +263,14 @@ class _ConstraintSectionPrint(CommandManager): def __init__(self): super(_ConstraintSectionPrint, self).__init__() - self.menutext = "Constraint sectionprint" - self.tooltip = "Creates a FEM constraint sectionprint" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintSectionPrint", + "Constraint sectionprint" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintSectionPrint", + "Creates a FEM constraint sectionprint" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -222,8 +280,14 @@ class _ConstraintSelfWeight(CommandManager): def __init__(self): super(_ConstraintSelfWeight, self).__init__() - self.menutext = "Constraint self weight" - self.tooltip = "Creates a FEM constraint self weight" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintSelfWeight", + "Constraint self weight" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintSelfWeight", + "Creates a FEM constraint self weight" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" @@ -233,8 +297,14 @@ class _ConstraintTie(CommandManager): def __init__(self): super(_ConstraintTie, self).__init__() - self.menutext = "Constraint tie" - self.tooltip = "Creates a FEM constraint tie" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintTie", + "Constraint tie" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ConstraintTie", + "Creates a FEM constraint tie" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -244,8 +314,14 @@ class _ElementFluid1D(CommandManager): def __init__(self): super(_ElementFluid1D, self).__init__() - self.menutext = "Fluid section for 1D flow" - self.tooltip = "Creates a FEM fluid section for 1D flow" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementFluid1D", + "Fluid section for 1D flow" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementFluid1D", + "Creates a FEM fluid section for 1D flow" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -255,8 +331,14 @@ class _ElementGeometry1D(CommandManager): def __init__(self): super(_ElementGeometry1D, self).__init__() - self.menutext = "Beam cross section" - self.tooltip = "Creates a FEM beam cross section" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementGeometry1D", + "Beam cross section" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementGeometry1D", + "Creates a FEM beam cross section" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -266,8 +348,14 @@ class _ElementGeometry2D(CommandManager): def __init__(self): super(_ElementGeometry2D, self).__init__() - self.menutext = "Shell plate thickness" - self.tooltip = "Creates a FEM shell plate thickness" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementGeometry2D", + "Shell plate thickness" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementGeometry2D", + "Creates a FEM shell plate thickness" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -277,8 +365,14 @@ class _ElementRotation1D(CommandManager): def __init__(self): super(_ElementRotation1D, self).__init__() - self.menutext = "Beam rotation" - self.tooltip = "Creates a FEM beam rotation" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementRotation1D", + "Beam rotation" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ElementRotation1D", + "Creates a FEM beam rotation" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" @@ -288,8 +382,14 @@ class _EquationElectrostatic(CommandManager): def __init__(self): super(_EquationElectrostatic, self).__init__() - self.menutext = "Electrostatic equation" - self.tooltip = "Creates a FEM equation for electrostatic" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationElectrostatic", + "Electrostatic equation" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationElectrostatic", + "Creates a FEM equation for electrostatic" + ) self.is_active = "with_solver_elmer" self.do_activated = "add_obj_on_gui_selobj_noset_edit" @@ -299,8 +399,14 @@ class _EquationElasticity(CommandManager): def __init__(self): super(_EquationElasticity, self).__init__() - self.menutext = "Elasticity equation" - self.tooltip = "Creates a FEM equation for elasticity" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationElasticity", + "Elasticity equation" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationElasticity", + "Creates a FEM equation for elasticity" + ) self.is_active = "with_solver_elmer" self.do_activated = "add_obj_on_gui_selobj_noset_edit" @@ -310,8 +416,14 @@ class _EquationFlow(CommandManager): def __init__(self): super(_EquationFlow, self).__init__() - self.menutext = "Flow equation" - self.tooltip = "Creates a FEM equation for flow" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationFlow", + "Flow equation" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationFlow", + "Creates a FEM equation for flow" + ) self.is_active = "with_solver_elmer" self.do_activated = "add_obj_on_gui_selobj_noset_edit" @@ -321,8 +433,14 @@ class _EquationFlux(CommandManager): def __init__(self): super(_EquationFlux, self).__init__() - self.menutext = "Flux equation" - self.tooltip = "Creates a FEM equation for flux" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationFlux", + "Flux equation" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationFlux", + "Creates a FEM equation for flux" + ) self.is_active = "with_solver_elmer" self.do_activated = "add_obj_on_gui_selobj_noset_edit" @@ -332,8 +450,14 @@ class _EquationElectricforce(CommandManager): def __init__(self): super(_EquationElectricforce, self).__init__() - self.menutext = "Electricforce equation" - self.tooltip = "Creates a FEM equation for electric forces" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationElectricforce", + "Electricforce equation" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationElectricforce", + "Creates a FEM equation for electric forces" + ) self.is_active = "with_solver_elmer" self.do_activated = "add_obj_on_gui_selobj_noset_edit" @@ -343,8 +467,14 @@ class _EquationHeat(CommandManager): def __init__(self): super(_EquationHeat, self).__init__() - self.menutext = "Heat equation" - self.tooltip = "Creates a FEM equation for heat" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationHeat", + "Heat equation" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_EquationHeat", + "Creates a FEM equation for heat" + ) self.is_active = "with_solver_elmer" self.do_activated = "add_obj_on_gui_selobj_noset_edit" @@ -355,8 +485,14 @@ class _Examples(CommandManager): def __init__(self): super(_Examples, self).__init__() self.pixmap = "FemWorkbench" - self.menutext = "Open FEM examples" - self.tooltip = "Open FEM examples" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_Examples", + "Open FEM examples" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_Examples", + "Open FEM examples" + ) self.is_active = "always" def Activated(self): @@ -370,8 +506,14 @@ class _MaterialEditor(CommandManager): def __init__(self): super(_MaterialEditor, self).__init__() self.pixmap = "Arch_Material_Group" - self.menutext = "Material editor" - self.tooltip = "Opens the FreeCAD material editor" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialEditor", + "Material editor" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialEditor", + "Opens the FreeCAD material editor" + ) self.is_active = "always" def Activated(self): @@ -384,8 +526,14 @@ class _MaterialFluid(CommandManager): def __init__(self): super(_MaterialFluid, self).__init__() - self.menutext = "Material for fluid" - self.tooltip = "Creates a FEM material for fluid" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialFluid", + "Material for fluid" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialFluid", + "Creates a FEM material for fluid" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -395,8 +543,14 @@ class _MaterialMechanicalNonlinear(CommandManager): def __init__(self): super(_MaterialMechanicalNonlinear, self).__init__() - self.menutext = "Nonlinear mechanical material" - self.tooltip = "Creates a nonlinear mechanical material" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialMechanicalNonlinear", + "Nonlinear mechanical material" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialMechanicalNonlinear", + "Creates a nonlinear mechanical material" + ) self.is_active = "with_material_solid" def Activated(self): @@ -459,8 +613,14 @@ class _MaterialReinforced(CommandManager): def __init__(self): super(_MaterialReinforced, self).__init__() - self.menutext = "Reinforced material (concrete)" - self.tooltip = "Creates a material for reinforced matrix material such as concrete" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialReinforced", + "Reinforced material (concrete)" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialReinforced", + "Creates a material for reinforced matrix material such as concrete" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -470,9 +630,15 @@ class _MaterialSolid(CommandManager): def __init__(self): super(_MaterialSolid, self).__init__() - self.menutext = "Material for solid" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialSolid", + "Material for solid" + ) self.accel = "M, S" - self.tooltip = "Creates a FEM material for solid" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MaterialSolid", + "Creates a FEM material for solid" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_set_edit" @@ -482,8 +648,14 @@ class _FEMMesh2Mesh(CommandManager): def __init__(self): super(_FEMMesh2Mesh, self).__init__() - self.menutext = "FEM mesh to mesh" - self.tooltip = "Convert the surface of a FEM mesh to a mesh" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_FEMMesh2Mesh", + "FEM mesh to mesh" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_FEMMesh2Mesh", + "Convert the surface of a FEM mesh to a mesh" + ) self.is_active = "with_femmesh_andor_res" def Activated(self): @@ -523,8 +695,14 @@ class _MeshBoundaryLayer(CommandManager): def __init__(self): super(_MeshBoundaryLayer, self).__init__() - self.menutext = "FEM mesh boundary layer" - self.tooltip = "Creates a FEM mesh boundary layer" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshBoundaryLayer", + "FEM mesh boundary layer" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshBoundaryLayer", + "Creates a FEM mesh boundary layer" + ) self.is_active = "with_gmsh_femmesh" self.do_activated = "add_obj_on_gui_selobj_set_edit" @@ -534,8 +712,14 @@ class _MeshClear(CommandManager): def __init__(self): super(_MeshClear, self).__init__() - self.menutext = "Clear FEM mesh" - self.tooltip = "Clear the Mesh of a FEM mesh object" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshClear", + "Clear FEM mesh" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshClear", + "Clear the Mesh of a FEM mesh object" + ) self.is_active = "with_femmesh" def Activated(self): @@ -553,8 +737,14 @@ class _MeshDisplayInfo(CommandManager): def __init__(self): super(_MeshDisplayInfo, self).__init__() - self.menutext = "Display FEM mesh info" - self.tooltip = "Display FEM mesh info" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshDisplayInfo", + "Display FEM mesh info" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshDisplayInfo", + "Display FEM mesh info" + ) self.is_active = "with_femmesh" def Activated(self): @@ -576,8 +766,14 @@ class _MeshGmshFromShape(CommandManager): def __init__(self): super(_MeshGmshFromShape, self).__init__() - self.menutext = "FEM mesh from shape by Gmsh" - self.tooltip = "Create a FEM mesh from a shape by Gmsh mesher" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshGmshFromShape", + "FEM mesh from shape by Gmsh" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshGmshFromShape", + "Create a FEM mesh from a shape by Gmsh mesher" + ) self.is_active = "with_part_feature" def Activated(self): @@ -615,8 +811,14 @@ class _MeshGroup(CommandManager): def __init__(self): super(_MeshGroup, self).__init__() - self.menutext = "FEM mesh group" - self.tooltip = "Creates a FEM mesh group" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshGroup", + "FEM mesh group" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshGroup", + "Creates a FEM mesh group" + ) self.is_active = "with_gmsh_femmesh" self.do_activated = "add_obj_on_gui_selobj_set_edit" @@ -626,8 +828,14 @@ class _MeshNetgenFromShape(CommandManager): def __init__(self): super(_MeshNetgenFromShape, self).__init__() - self.menutext = "FEM mesh from shape by Netgen" - self.tooltip = "Create a FEM mesh from a solid or face shape by Netgen internal mesher" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshNetgenFromShape", + "FEM mesh from shape by Netgen" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshNetgenFromShape", + "Create a FEM mesh from a solid or face shape by Netgen internal mesher" + ) self.is_active = "with_part_feature" def Activated(self): @@ -665,8 +873,14 @@ class _MeshRegion(CommandManager): def __init__(self): super(_MeshRegion, self).__init__() - self.menutext = "FEM mesh region" - self.tooltip = "Creates a FEM mesh region" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshRegion", + "FEM mesh region" + ) + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_MeshRegion", + "Creates a FEM mesh region" + ) self.is_active = "with_gmsh_femmesh" self.do_activated = "add_obj_on_gui_selobj_set_edit" @@ -676,9 +890,15 @@ class _ResultShow(CommandManager): def __init__(self): super(_ResultShow, self).__init__() - self.menutext = "Show result" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ResultShow", + "Show result" + ) self.accel = "R, S" - self.tooltip = "Shows and visualizes selected result data" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ResultShow", + "Shows and visualizes selected result data" + ) self.is_active = "with_selresult" def Activated(self): @@ -690,9 +910,15 @@ class _ResultsPurge(CommandManager): def __init__(self): super(_ResultsPurge, self).__init__() - self.menutext = "Purge results" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_ResultsPurge", + "Purge results" + ) self.accel = "R, P" - self.tooltip = "Purges all results from active analysis" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_ResultsPurge", + "Purges all results from active analysis" + ) self.is_active = "with_results" def Activated(self): @@ -706,9 +932,15 @@ class _SolverCxxtools(CommandManager): def __init__(self): super(_SolverCxxtools, self).__init__() self.pixmap = "FEM_SolverStandard" - self.menutext = "Solver CalculiX Standard" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverCxxtools", + "Solver CalculiX Standard" + ) self.accel = "S, X" - self.tooltip = "Creates a standard FEM solver CalculiX with ccx tools" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverCxxtools", + "Creates a standard FEM solver CalculiX with ccx tools" + ) self.is_active = "with_analysis" def Activated(self): @@ -741,9 +973,15 @@ class _SolverCalculix(CommandManager): def __init__(self): super(_SolverCalculix, self).__init__() self.pixmap = "FEM_SolverStandard" - self.menutext = "Solver CalculiX (new framework)" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverCalculix", + "Solver CalculiX (new framework)" + ) self.accel = "S, C" - self.tooltip = "Creates a FEM solver CalculiX new framework (less result error handling)" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverCalculix", + "Creates a FEM solver CalculiX new framework (less result error handling)" + ) self.is_active = "with_analysis" self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" @@ -754,9 +992,15 @@ class _SolverControl(CommandManager): def __init__(self): super(_SolverControl, self).__init__() - self.menutext = "Solver job control" + self.menutext = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverControl", + "Solver job control" + ) self.accel = "S, T" - self.tooltip = "Changes solver attributes and runs the calculations for the selected solver" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverControl", + "Changes solver attributes and runs the calculations for the selected solver" + ) self.is_active = "with_solver" def Activated(self): @@ -768,9 +1012,12 @@ class _SolverElmer(CommandManager): def __init__(self): super(_SolverElmer, self).__init__() - self.menutext = "Solver Elmer" + self.menutext = Qt.QT_TRANSLATE_NOOP("FEM_SolverElmer", "Solver Elmer") self.accel = "S, E" - self.tooltip = "Creates a FEM solver Elmer" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverElmer", + "Creates a FEM solver Elmer" + ) self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" @@ -781,9 +1028,9 @@ class _SolverMystran(CommandManager): def __init__(self): super(_SolverMystran, self).__init__() self.pixmap = "FEM_SolverStandard" - self.menutext = "Solver Mystran" + self.menutext = Qt.QT_TRANSLATE_NOOP("FEM_SolverMystran", "Solver Mystran") self.accel = "S, M" - self.tooltip = "Creates a FEM solver Mystran" + self.tooltip = Qt.QT_TRANSLATE_NOOP("FEM_SolverMystran", "Creates a FEM solver Mystran") self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" @@ -793,9 +1040,12 @@ class _SolverRun(CommandManager): def __init__(self): super(_SolverRun, self).__init__() - self.menutext = "Run solver calculations" + self.menutext = Qt.QT_TRANSLATE_NOOP("FEM_SolverRun", "Run solver calculations") self.accel = "S, R" - self.tooltip = "Runs the calculations for the selected solver" + self.tooltip = Qt.QT_TRANSLATE_NOOP( + "FEM_SolverRun", + "Runs the calculations for the selected solver" + ) self.is_active = "with_solver" def Activated(self): @@ -810,9 +1060,9 @@ class _SolverZ88(CommandManager): def __init__(self): super(_SolverZ88, self).__init__() - self.menutext = "Solver Z88" + self.menutext = Qt.QT_TRANSLATE_NOOP("FEM_SolverZ88", "Solver Z88") self.accel = "S, Z" - self.tooltip = "Creates a FEM solver Z88" + self.tooltip = Qt.QT_TRANSLATE_NOOP("FEM_SolverZ88", "Creates a FEM solver Z88") self.is_active = "with_analysis" self.do_activated = "add_obj_on_gui_noset_edit" diff --git a/src/Mod/Fem/femtaskpanels/task_material_common.py b/src/Mod/Fem/femtaskpanels/task_material_common.py index 1ce0320928..4ceb7fa941 100644 --- a/src/Mod/Fem/femtaskpanels/task_material_common.py +++ b/src/Mod/Fem/femtaskpanels/task_material_common.py @@ -549,7 +549,7 @@ class _TaskPanel: # for example PoissonRatio value = Units.Quantity(inputfield_text).Value old_value = Units.Quantity(self.material[matProperty]).Value - # value = float(inputfield_text) # this fails on locale with komma + # value = float(inputfield_text) # this fails on locale with comma # https://forum.freecadweb.org/viewtopic.php?f=18&t=56912&p=523313#p523313 if value: if not (1 - variation < float(old_value) / value < 1 + variation): diff --git a/src/Mod/Import/App/AppImportPy.cpp b/src/Mod/Import/App/AppImportPy.cpp index f76e59bf15..88e7f2be6e 100644 --- a/src/Mod/Import/App/AppImportPy.cpp +++ b/src/Mod/Import/App/AppImportPy.cpp @@ -368,7 +368,7 @@ private: //makeHeader.SetName(new TCollection_HAsciiString((Standard_CString)Utf8Name.c_str())); makeHeader.SetAuthorValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Author", "Author").c_str())); makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Company").c_str())); - makeHeader.SetOriginatingSystem(new TCollection_HAsciiString(App::GetApplication().getExecutableName())); + makeHeader.SetOriginatingSystem(new TCollection_HAsciiString(App::Application::getExecutableName().c_str())); makeHeader.SetDescriptionValue(1, new TCollection_HAsciiString("FreeCAD Model")); IFSelect_ReturnStatus ret = writer.Write(name8bit.c_str()); if (ret == IFSelect_RetError || ret == IFSelect_RetFail || ret == IFSelect_RetStop) { diff --git a/src/Mod/Import/Gui/AppImportGuiPy.cpp b/src/Mod/Import/Gui/AppImportGuiPy.cpp index 774c40e2f9..8f855a3a32 100644 --- a/src/Mod/Import/Gui/AppImportGuiPy.cpp +++ b/src/Mod/Import/Gui/AppImportGuiPy.cpp @@ -668,7 +668,7 @@ private: //makeHeader.SetName(new TCollection_HAsciiString((Standard_CString)Utf8Name.c_str())); makeHeader.SetAuthorValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Author", "Author").c_str())); makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString(hGrp->GetASCII("Company").c_str())); - makeHeader.SetOriginatingSystem(new TCollection_HAsciiString(App::GetApplication().getExecutableName())); + makeHeader.SetOriginatingSystem(new TCollection_HAsciiString(App::Application::getExecutableName().c_str())); makeHeader.SetDescriptionValue(1, new TCollection_HAsciiString("FreeCAD Model")); IFSelect_ReturnStatus ret = writer.Write(name8bit.c_str()); if (ret == IFSelect_RetError || ret == IFSelect_RetFail || ret == IFSelect_RetStop) { diff --git a/src/Mod/Mesh/App/Core/Approximation.h b/src/Mod/Mesh/App/Core/Approximation.h index 99d73be059..524fca7d25 100644 --- a/src/Mod/Mesh/App/Core/Approximation.h +++ b/src/Mod/Mesh/App/Core/Approximation.h @@ -514,7 +514,7 @@ public: dKoeff[ ct ] = pKoef[ ct ]; } /** - * Destruktor. Deletes the ImpicitSurface instance + * Destructor. Deletes the ImpicitSurface instance * of the WildMagic library */ ~FunctionContainer(){ delete pImplSurf; } diff --git a/src/Mod/Mesh/App/Core/Elements.cpp b/src/Mod/Mesh/App/Core/Elements.cpp index bd434698ce..53bc252add 100644 --- a/src/Mod/Mesh/App/Core/Elements.cpp +++ b/src/Mod/Mesh/App/Core/Elements.cpp @@ -180,22 +180,22 @@ MeshFacetArray& MeshFacetArray::operator = (const MeshFacetArray &rclFAry) bool MeshGeomEdge::ContainedByOrIntersectBoundingBox ( const Base::BoundBox3f &rclBB ) const { - // Test, ob alle Eckpunkte der Edge sich auf einer der 6 Seiten der BB befinden + // Test whether all corner points of the Edge are on one of the 6 sides of the BB if ((GetBoundBox() && rclBB) == false) return false; - // Test, ob Edge-BB komplett in BB liegt + // Test whether Edge-BB is completely in BB if (rclBB.IsInBox(GetBoundBox())) return true; - // Test, ob einer der Eckpunkte in BB liegt + // Test whether one of the corner points is in BB for (int i=0;i<2;i++) { if (rclBB.IsInBox(_aclPoints[i])) return true; } - // "echter" Test auf Schnitt + // "real" test for cut if (IntersectBoundingBox(rclBB)) return true; @@ -487,7 +487,7 @@ bool MeshGeomFacet::IsPointOf (const Base::Vector3f &rclPoint, float fDistance) clProjPt.ProjectToPlane(_aclPoints[0], clNorm); - // Kante P0 --> P1 + // Edge P0 --> P1 clEdge = clP1 - clP0; fLP = clProjPt.DistanceToLine(clP0, clEdge); if (fLP > 0.0f) @@ -500,9 +500,9 @@ bool MeshGeomFacet::IsPointOf (const Base::Vector3f &rclPoint, float fDistance) } else return false; - } + } - // Kante P0 --> P2 + // Edge P0 --> P2 clEdge = clP2 - clP0; fLP = clProjPt.DistanceToLine(clP0, clEdge); if (fLP > 0.0f) @@ -515,9 +515,9 @@ bool MeshGeomFacet::IsPointOf (const Base::Vector3f &rclPoint, float fDistance) } else return false; - } + } - // Kante P1 --> P2 + // Edge P1 --> P2 clEdge = clP2 - clP1; fLP = clProjPt.DistanceToLine(clP1, clEdge); if (fLP > 0.0f) @@ -537,7 +537,7 @@ bool MeshGeomFacet::IsPointOf (const Base::Vector3f &rclPoint, float fDistance) bool MeshGeomFacet::IsPointOfFace (const Base::Vector3f& rclP, float fDistance) const { - // effektivere Implementierung als in MeshGeomFacet::IsPointOf + // more effective implementation than in MeshGeomFacet::IsPointOf // Base::Vector3f a(_aclPoints[0].x, _aclPoints[0].y, _aclPoints[0].z); Base::Vector3f b(_aclPoints[1].x, _aclPoints[1].y, _aclPoints[1].z); @@ -907,7 +907,7 @@ bool MeshGeomFacet::Foraminate (const Base::Vector3f &P, const Base::Vector3f &d bool MeshGeomFacet::IntersectPlaneWithLine (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir, Base::Vector3f &rclRes) const { - // berechne den Schnittpunkt Gerade <-> Ebene + // calculate the intersection of the straight line <-> plane if ( fabs(rclDir * GetNormal()) < 1e-3f ) return false; // line and plane are parallel @@ -979,7 +979,7 @@ void MeshGeomFacet::SubSample (float fStep, std::vector &rclPoin Base::Vector3f clVecAC(C - A); Base::Vector3f clVecBC(C - B); - // laengste Achse entspricht AB + // longest axis corresponds to AB float fLenAB = clVecAB.Length(); float fLenAC = clVecAC.Length(); float fLenBC = clVecBC.Length(); diff --git a/src/Mod/Mesh/Gui/Resources/Mesh.qrc b/src/Mod/Mesh/Gui/Resources/Mesh.qrc index 3c358b6c78..5dbfb6d409 100644 --- a/src/Mod/Mesh/Gui/Resources/Mesh.qrc +++ b/src/Mod/Mesh/Gui/Resources/Mesh.qrc @@ -42,6 +42,8 @@ icons/RegularSolids/Mesh_Ellipsoid.svg icons/RegularSolids/Mesh_Sphere.svg icons/RegularSolids/Mesh_Torus.svg + + translations/Mesh_af.qm translations/Mesh_de.qm translations/Mesh_fi.qm diff --git a/src/Mod/MeshPart/App/AppMeshPart.cpp b/src/Mod/MeshPart/App/AppMeshPart.cpp index fbd6d1da92..e4cc0d004b 100644 --- a/src/Mod/MeshPart/App/AppMeshPart.cpp +++ b/src/Mod/MeshPart/App/AppMeshPart.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/App/AppMeshPartPy.cpp b/src/Mod/MeshPart/App/AppMeshPartPy.cpp index 489ae76933..a1b96ff51e 100644 --- a/src/Mod/MeshPart/App/AppMeshPartPy.cpp +++ b/src/Mod/MeshPart/App/AppMeshPartPy.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/App/CurveProjector.cpp b/src/Mod/MeshPart/App/CurveProjector.cpp index e559834e66..5731521aa3 100644 --- a/src/Mod/MeshPart/App/CurveProjector.cpp +++ b/src/Mod/MeshPart/App/CurveProjector.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Juergen Riegel * + * Copyright (c) 2008 Juergen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/App/CurveProjector.h b/src/Mod/MeshPart/App/CurveProjector.h index 20d2479fea..5efcd7566d 100644 --- a/src/Mod/MeshPart/App/CurveProjector.h +++ b/src/Mod/MeshPart/App/CurveProjector.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Juergen Riegel * + * Copyright (c) 2008 Juergen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/App/MeshAlgos.cpp b/src/Mod/MeshPart/App/MeshAlgos.cpp index 0f1f2439d2..3551766207 100644 --- a/src/Mod/MeshPart/App/MeshAlgos.cpp +++ b/src/Mod/MeshPart/App/MeshAlgos.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Juergen Riegel * + * Copyright (c) 2008 Juergen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/App/MeshAlgos.h b/src/Mod/MeshPart/App/MeshAlgos.h index d524f7effd..a0f482421d 100644 --- a/src/Mod/MeshPart/App/MeshAlgos.h +++ b/src/Mod/MeshPart/App/MeshAlgos.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Juergen Riegel * + * Copyright (c) 2008 Juergen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/App/PreCompiled.cpp b/src/Mod/MeshPart/App/PreCompiled.cpp index 46269e9671..1e5d389dd2 100644 --- a/src/Mod/MeshPart/App/PreCompiled.cpp +++ b/src/Mod/MeshPart/App/PreCompiled.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/App/PreCompiled.h b/src/Mod/MeshPart/App/PreCompiled.h index 07eac4d2e8..754261f3a7 100644 --- a/src/Mod/MeshPart/App/PreCompiled.h +++ b/src/Mod/MeshPart/App/PreCompiled.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp b/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp index 5bd034c4eb..64aa198feb 100644 --- a/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp +++ b/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/Gui/Command.cpp b/src/Mod/MeshPart/Gui/Command.cpp index 22f2ff929e..f91ff09030 100644 --- a/src/Mod/MeshPart/Gui/Command.cpp +++ b/src/Mod/MeshPart/Gui/Command.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py index ed0d1aec6e..8d09f86c82 100644 --- a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py +++ b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py @@ -1,3 +1,25 @@ +#*************************************************************************** +#* Copyright (c) 2017 Lorenz Lechner * +#* * +#* This file is part of the FreeCAD CAx development system. * +#* * +#* This library is free software; you can redistribute it and/or * +#* modify it under the terms of the GNU Library General Public * +#* License as published by the Free Software Foundation; either * +#* version 2 of the License, or (at your option) any later version. * +#* * +#* This library is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this library; see the file COPYING.LIB. If not, * +#* write to the Free Software Foundation, Inc., 59 Temple Place, * +#* Suite 330, Boston, MA 02111-1307, USA * +#* * +#***************************************************************************/ + import Mesh import FreeCAD as App import FreeCADGui as Gui diff --git a/src/Mod/MeshPart/Gui/PreCompiled.cpp b/src/Mod/MeshPart/Gui/PreCompiled.cpp index 46269e9671..1e5d389dd2 100644 --- a/src/Mod/MeshPart/Gui/PreCompiled.cpp +++ b/src/Mod/MeshPart/Gui/PreCompiled.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/Gui/PreCompiled.h b/src/Mod/MeshPart/Gui/PreCompiled.h index 7cef9ef237..9f90acb0d8 100644 --- a/src/Mod/MeshPart/Gui/PreCompiled.h +++ b/src/Mod/MeshPart/Gui/PreCompiled.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * Copyright (c) 2008 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Mod/MeshPart/Init.py b/src/Mod/MeshPart/Init.py index c9c37c802b..dd8dea3aee 100644 --- a/src/Mod/MeshPart/Init.py +++ b/src/Mod/MeshPart/Init.py @@ -1,8 +1,8 @@ -# FreeCAD init script of the MeshPart module +# FreeCAD init script of the MeshPart module # (c) 2001 Juergen Riegel #*************************************************************************** -#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 * +#* Copyright (c) 2002 Juergen Riegel * #* * #* This file is part of the FreeCAD CAx development system. * #* * @@ -13,14 +13,13 @@ #* for detail see the LICENCE text file. * #* * #* FreeCAD is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* GNU Lesser General Public License for more details. * #* * #* You should have received a copy of the GNU Library General Public * -#* License along with FreeCAD; if not, write to the Free Software * +#* License along with FreeCAD; if not, write to the Free Software * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * #* USA * #* * -#* Juergen Riegel 2002 * #***************************************************************************/ diff --git a/src/Mod/MeshPart/InitGui.py b/src/Mod/MeshPart/InitGui.py index 82a917f2ea..17d0102f1f 100644 --- a/src/Mod/MeshPart/InitGui.py +++ b/src/Mod/MeshPart/InitGui.py @@ -1,4 +1,4 @@ -# MeshPart gui init module +# MeshPart gui init module # (c) 2003 Juergen Riegel # # Gathering all the information to start FreeCAD @@ -6,7 +6,7 @@ # runs when the gui is up #*************************************************************************** -#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 * +#* Copyright (c) 2002 Juergen Riegel * #* * #* This file is part of the FreeCAD CAx development system. * #* * @@ -26,44 +26,46 @@ #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * #* USA * #* * -#* Juergen Riegel 2002 * #***************************************************************************/ class MeshPartWorkbench ( Workbench ): - "MeshPart workbench object" - Icon = """ - /* XPM */ - static const char *MeshPart_Box[]={ - "16 16 3 1", - ". c None", - "# c #000000", - "a c #c6c642", - "................", - ".......#######..", - "......#aaaaa##..", - ".....#aaaaa###..", - "....#aaaaa##a#..", - "...#aaaaa##aa#..", - "..#aaaaa##aaa#..", - ".########aaaa#..", - ".#aaaaa#aaaaa#..", - ".#aaaaa#aaaa##..", - ".#aaaaa#aaa##...", - ".#aaaaa#aa##....", - ".#aaaaa#a##... .", - ".#aaaaa###......", - ".########.......", - "................"}; - """ - MenuText = "MeshPart" - ToolTip = "MeshPart workbench" + "MeshPart workbench object" + Icon = """ + /* XPM */ + static const char *MeshPart_Box[]={ + "16 16 3 1", + ". c None", + "# c #000000", + "a c #c6c642", + "................", + ".......#######..", + "......#aaaaa##..", + ".....#aaaaa###..", + "....#aaaaa##a#..", + "...#aaaaa##aa#..", + "..#aaaaa##aaa#..", + ".########aaaa#..", + ".#aaaaa#aaaaa#..", + ".#aaaaa#aaaa##..", + ".#aaaaa#aaa##...", + ".#aaaaa#aa##....", + ".#aaaaa#a##... .", + ".#aaaaa###......", + ".########.......", + "................"}; + """ + MenuText = "MeshPart" + ToolTip = "MeshPart workbench" - def Initialize(self): - # load the module - import MeshPartGui - import MeshPart - def GetClassName(self): - return "MeshPartGui::Workbench" -#Gui.addWorkbench(MeshPartWorkbench()) + def Initialize(self): + # load the module + import MeshPartGui + import MeshPart + + + def GetClassName(self): + return "MeshPartGui::Workbench" + +# Gui.addWorkbench(MeshPartWorkbench()) diff --git a/src/Mod/OpenSCAD/OpenSCADFeatures.py b/src/Mod/OpenSCAD/OpenSCADFeatures.py index 93332b67a2..4f3f4d21d8 100644 --- a/src/Mod/OpenSCAD/OpenSCADFeatures.py +++ b/src/Mod/OpenSCAD/OpenSCADFeatures.py @@ -200,13 +200,11 @@ class Resize : self.createGeometry(fp) def createGeometry(self, fp) : - print("Resize create Geometry") import FreeCAD mat = FreeCAD.Matrix() mat.A11 = self.Vector[0] mat.A22 = self.Vector[1] mat.A33 = self.Vector[2] - print(mat) fp.Shape = self.Target.Shape.transformGeometry(mat) def __getstate__(self): @@ -387,7 +385,7 @@ class Frustum: fp.Placement = plm class Twist: - def __init__(self, obj,child=None,h=1.0,angle=0.0,scale=[1.0,1.0]): + def __init__(self, obj, child=None, h=1.0, angle=0.0, scale=[1.0,1.0]): import FreeCAD obj.addProperty("App::PropertyLink","Base","Base", "The base object that must be transformed") @@ -406,10 +404,10 @@ class Twist: self.createGeometry(fp) def onChanged(self, fp, prop): - if prop in ["Angle","Height"]: + if prop in ["Angle","Height","Scale"]: self.createGeometry(fp) - def createGeometry(self,fp): + def createGeometry(self, fp): import FreeCAD,Part,math,sys if fp.Base and fp.Height and fp.Base.Shape.isValid(): solids = [] @@ -443,7 +441,6 @@ class Twist: pipe_shell.add(wire1) pipe_shell.add(wire2) pipe_shell.setAuxiliarySpine(auxiliary_spine,True,0) - print(pipe_shell.getStatus()) assert(pipe_shell.isReady()) pipe_shell.build() faces.extend(pipe_shell.shape().Faces) @@ -534,10 +531,9 @@ class PrismaticToroid: solid = Part.makeSolid (clean_shell) if solid.Volume < 0: solid.reverse() - print (f"Solid volume is {solid.Volume}") solids.append(solid) except Part.OCCError: - print ("Could not create solid: creating compound instead") + FreeCAD.Console.PrintWarning("Could not create solid: creating compound instead") solids.append(Part.Compound(faces)) fp.Shape = Part.Compound(solids) @@ -587,139 +583,146 @@ class CGALFeature: raise ValueError def makeSurfaceVolume(filename): - import FreeCAD,Part,sys + import FreeCAD + import Part + import sys + coords = [] with open(filename) as f1: - coords = [] min_z = sys.float_info.max for line in f1.readlines(): - sline=line.strip() + sline = line.strip() if sline and not sline.startswith('#'): - ycoord=len(coords) - lcoords=[] + ycoord = len(coords) + lcoords = [] for xcoord, num in enumerate(sline.split()): - fnum=float(num) + fnum = float(num) lcoords.append(FreeCAD.Vector(float(xcoord),float(ycoord),fnum)) min_z = min(fnum,min_z) coords.append(lcoords) - - num_rows = len(coords) - num_cols = len(coords[0]) - # OpenSCAD does not spline this surface, so neither do we: just create a bunch of faces, - # using four triangles per quadrilateral - faces = [] - for row in range(num_rows-1): - for col in range(num_cols-1): - a = coords[row+0][col+0] - b = coords[row+0][col+1] - c = coords[row+1][col+1] - d = coords[row+1][col+0] - centroid = 0.25 * (a + b + c + d) - ab = Part.makeLine(a,b) - bc = Part.makeLine(b,c) - cd = Part.makeLine(c,d) - da = Part.makeLine(d,a) + num_rows = len(coords) + if num_rows == 0: + FreeCAD.Console.PrintWarning(f"No data found in surface file {filename}") + return None,0,0 + num_cols = len(coords[0]) - diag_a = Part.makeLine(a, centroid) - diag_b = Part.makeLine(b, centroid) - diag_c = Part.makeLine(c, centroid) - diag_d = Part.makeLine(d, centroid) + # OpenSCAD does not spline this surface, so neither do we: just create a + # bunch of faces, + # using four triangles per quadrilateral + faces = [] + for row in range(num_rows - 1): + for col in range(num_cols - 1): + a = coords[row + 0][col + 0] + b = coords[row + 0][col + 1] + c = coords[row + 1][col + 1] + d = coords[row + 1][col + 0] + centroid = 0.25 * (a + b + c + d) + ab = Part.makeLine(a,b) + bc = Part.makeLine(b,c) + cd = Part.makeLine(c,d) + da = Part.makeLine(d,a) - wire1 = Part.Wire([ab,diag_a,diag_b]) - wire2 = Part.Wire([bc,diag_b,diag_c]) - wire3 = Part.Wire([cd,diag_c,diag_d]) - wire4 = Part.Wire([da,diag_d,diag_a]) + diag_a = Part.makeLine(a, centroid) + diag_b = Part.makeLine(b, centroid) + diag_c = Part.makeLine(c, centroid) + diag_d = Part.makeLine(d, centroid) - try: - face = Part.Face(wire1) - faces.append(face) - face = Part.Face(wire2) - faces.append(face) - face = Part.Face(wire3) - faces.append(face) - face = Part.Face(wire4) - faces.append(face) - except Exception: - print ("Failed to create the face from {},{},{},{}".format(coords[row+0][col+0],\ - coords[row+0][col+1],coords[row+1][col+1],coords[row+1][col+0])) - - last_row = num_rows-1 - last_col = num_cols-1 + wire1 = Part.Wire([ab,diag_a,diag_b]) + wire2 = Part.Wire([bc,diag_b,diag_c]) + wire3 = Part.Wire([cd,diag_c,diag_d]) + wire4 = Part.Wire([da,diag_d,diag_a]) - # Create the face to close off the y-min border: OpenSCAD places the lower surface of the shell - # at 1 unit below the lowest coordinate in the surface - lines = [] - corner1 = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z-1) - lines.append (Part.makeLine(corner1,coords[0][0])) - for col in range(num_cols-1): - a = coords[0][col] - b = coords[0][col+1] - lines.append (Part.makeLine(a, b)) - corner2 = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z-1) - lines.append (Part.makeLine(corner2,coords[0][last_col])) - lines.append (Part.makeLine(corner1,corner2)) - wire = Part.Wire(lines) - face = Part.Face(wire) - faces.append(face) - - # Create the face to close off the y-max border - lines = [] - corner1 = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z-1) - lines.append (Part.makeLine(corner1,coords[last_row][0])) - for col in range(num_cols-1): - a = coords[last_row][col] - b = coords[last_row][col+1] - lines.append (Part.makeLine(a, b)) - corner2 = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z-1) - lines.append (Part.makeLine(corner2,coords[last_row][last_col])) - lines.append (Part.makeLine(corner1,corner2)) - wire = Part.Wire(lines) - face = Part.Face(wire) - faces.append(face) + try: + face = Part.Face(wire1) + faces.append(face) + face = Part.Face(wire2) + faces.append(face) + face = Part.Face(wire3) + faces.append(face) + face = Part.Face(wire4) + faces.append(face) + except Exception: + FreeCAD.Console.PrintWarning("Failed to create the face from {},{},{},{}".format(coords[row + 0][col + 0],\ + coords[row + 0][col + 1],coords[row + 1][col + 1],coords[row + 1][col + 0])) - # Create the face to close off the x-min border - lines = [] - corner1 = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z-1) - lines.append (Part.makeLine(corner1,coords[0][0])) - for row in range(num_rows-1): - a = coords[row][0] - b = coords[row+1][0] - lines.append (Part.makeLine(a, b)) - corner2 = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z-1) - lines.append (Part.makeLine(corner2,coords[last_row][0])) - lines.append (Part.makeLine(corner1,corner2)) - wire = Part.Wire(lines) - face = Part.Face(wire) - faces.append(face) + last_row = num_rows - 1 + last_col = num_cols - 1 - # Create the face to close off the x-max border - lines = [] - corner1 = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z-1) - lines.append (Part.makeLine(corner1,coords[0][last_col])) - for row in range(num_rows-1): - a = coords[row][last_col] - b = coords[row+1][last_col] - lines.append (Part.makeLine(a, b)) - corner2 = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z-1) - lines.append (Part.makeLine(corner2,coords[last_row][last_col])) - lines.append (Part.makeLine(corner1,corner2)) - wire = Part.Wire(lines) - face = Part.Face(wire) - faces.append(face) + # Create the face to close off the y-min border: OpenSCAD places the lower + # surface of the shell + # at 1 unit below the lowest coordinate in the surface + lines = [] + corner1 = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z - 1) + lines.append(Part.makeLine(corner1,coords[0][0])) + for col in range(num_cols - 1): + a = coords[0][col] + b = coords[0][col + 1] + lines.append(Part.makeLine(a, b)) + corner2 = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z - 1) + lines.append(Part.makeLine(corner2,coords[0][last_col])) + lines.append(Part.makeLine(corner1,corner2)) + wire = Part.Wire(lines) + face = Part.Face(wire) + faces.append(face) - # Create a bottom surface to close off the shell - a = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z-1) - b = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z-1) - c = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z-1) - d = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z-1) - ab = Part.makeLine(a,b) - bc = Part.makeLine(b,c) - cd = Part.makeLine(c,d) - da = Part.makeLine(d,a) - wire = Part.Wire([ab,bc,cd,da]) - face = Part.Face(wire) - faces.append(face) + # Create the face to close off the y-max border + lines = [] + corner1 = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z - 1) + lines.append(Part.makeLine(corner1,coords[last_row][0])) + for col in range(num_cols - 1): + a = coords[last_row][col] + b = coords[last_row][col + 1] + lines.append(Part.makeLine(a, b)) + corner2 = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z - 1) + lines.append(Part.makeLine(corner2,coords[last_row][last_col])) + lines.append(Part.makeLine(corner1,corner2)) + wire = Part.Wire(lines) + face = Part.Face(wire) + faces.append(face) - s = Part.Shell(faces) - solid = Part.Solid(s) - return solid,last_col,last_row + # Create the face to close off the x-min border + lines = [] + corner1 = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z - 1) + lines.append(Part.makeLine(corner1,coords[0][0])) + for row in range(num_rows - 1): + a = coords[row][0] + b = coords[row + 1][0] + lines.append(Part.makeLine(a, b)) + corner2 = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z - 1) + lines.append(Part.makeLine(corner2,coords[last_row][0])) + lines.append(Part.makeLine(corner1,corner2)) + wire = Part.Wire(lines) + face = Part.Face(wire) + faces.append(face) + + # Create the face to close off the x-max border + lines = [] + corner1 = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z - 1) + lines.append(Part.makeLine(corner1,coords[0][last_col])) + for row in range(num_rows - 1): + a = coords[row][last_col] + b = coords[row + 1][last_col] + lines.append(Part.makeLine(a, b)) + corner2 = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z - 1) + lines.append(Part.makeLine(corner2,coords[last_row][last_col])) + lines.append(Part.makeLine(corner1,corner2)) + wire = Part.Wire(lines) + face = Part.Face(wire) + faces.append(face) + + # Create a bottom surface to close off the shell + a = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z - 1) + b = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z - 1) + c = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z - 1) + d = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z - 1) + ab = Part.makeLine(a,b) + bc = Part.makeLine(b,c) + cd = Part.makeLine(c,d) + da = Part.makeLine(d,a) + wire = Part.Wire([ab,bc,cd,da]) + face = Part.Face(wire) + faces.append(face) + + s = Part.Shell(faces) + solid = Part.Solid(s) + return solid,last_col,last_row diff --git a/src/Mod/OpenSCAD/OpenSCADTest/app/test_importCSG.py b/src/Mod/OpenSCAD/OpenSCADTest/app/test_importCSG.py index 59759a7c47..24dda152a2 100644 --- a/src/Mod/OpenSCAD/OpenSCADTest/app/test_importCSG.py +++ b/src/Mod/OpenSCAD/OpenSCADTest/app/test_importCSG.py @@ -38,6 +38,7 @@ __url__ = "https://www.freecadweb.org" class TestImportCSG(unittest.TestCase): MODULE = 'test_importCSG' # file name without extension + temp_dir = tempfile.TemporaryDirectory() def setUp(self): @@ -73,113 +74,78 @@ class TestImportCSG(unittest.TestCase): FreeCAD.closeDocument("CSG") + def utility_create_scad(self, scadCode, name): + filename = self.temp_dir.name + os.path.sep + name + ".scad" + print (f"Creating {filename}") + f = open(filename,"w+") + f.write(scadCode) + f.close() + return importCSG.open(filename) + def test_import_sphere(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "sphere.scad" - f = open(filename,"w+") - f.write("sphere(10.0);") - f.close() - doc = importCSG.open(filename) - sphere = doc.getObject("sphere") - self.assertTrue (sphere is not None) - self.assertTrue (sphere.Radius == 10.0) - FreeCAD.closeDocument(doc.Name) + doc = self.utility_create_scad("sphere(10.0);","sphere") + sphere = doc.getObject("sphere") + self.assertTrue (sphere is not None) + self.assertTrue (sphere.Radius == 10.0) + FreeCAD.closeDocument(doc.Name) def test_import_cylinder(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "cylinder.scad" - f = open(filename,"w+") - f.write("cylinder(50.0,d=10.0);") - f.close() - doc = importCSG.open(filename) - cylinder = doc.getObject("cylinder") - self.assertTrue (cylinder is not None) - self.assertTrue (cylinder.Radius == 5.0) - self.assertTrue (cylinder.Height == 50.0) - FreeCAD.closeDocument(doc.Name) + doc = self.utility_create_scad("cylinder(50.0,d=10.0);","cylinder") + cylinder = doc.getObject("cylinder") + self.assertTrue (cylinder is not None) + self.assertTrue (cylinder.Radius == 5.0) + self.assertTrue (cylinder.Height == 50.0) + FreeCAD.closeDocument(doc.Name) def test_import_cube(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "cube.scad" - f = open(filename,"w+") - f.write("cube([1.0,2.0,3.0]);") - f.close() - doc = importCSG.open(filename) - cube = doc.getObject("cube") - self.assertTrue (cube is not None) - self.assertTrue (cube.Length == 1.0) - self.assertTrue (cube.Width == 2.0) - self.assertTrue (cube.Height == 3.0) - FreeCAD.closeDocument(doc.Name) + doc = self.utility_create_scad("cube([1.0,2.0,3.0]);","cube") + cube = doc.getObject("cube") + self.assertTrue (cube is not None) + self.assertTrue (cube.Length == 1.0) + self.assertTrue (cube.Width == 2.0) + self.assertTrue (cube.Height == 3.0) + FreeCAD.closeDocument(doc.Name) def test_import_circle(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "circle.scad" - f = open(filename,"w+") - f.write("circle(10.0);") - f.close() - doc = importCSG.open(filename) - circle = doc.getObject("circle") - self.assertTrue (circle is not None) - self.assertTrue (circle.Radius == 10.0) - FreeCAD.closeDocument(doc.Name) + doc = self.utility_create_scad("circle(10.0);","circle") + circle = doc.getObject("circle") + self.assertTrue (circle is not None) + self.assertTrue (circle.Radius == 10.0) + FreeCAD.closeDocument(doc.Name) def test_import_square(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "square.scad" - f = open(filename,"w+") - f.write("square([1.0,2.0]);") - f.close() - doc = importCSG.open(filename) - square = doc.getObject("square") - self.assertTrue (square is not None) - self.assertTrue (square.Length == 1.0) - self.assertTrue (square.Width == 2.0) - FreeCAD.closeDocument(doc.Name) + doc = self.utility_create_scad("square([1.0,2.0]);","square") + square = doc.getObject("square") + self.assertTrue (square is not None) + self.assertTrue (square.Length == 1.0) + self.assertTrue (square.Width == 2.0) + FreeCAD.closeDocument(doc.Name) def test_import_text(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "text.scad" - f = open(filename,"w+") - f.write("text(\"X\");") # Keep it short to keep the test fast-ish - f.close() - try: - doc = importCSG.open(filename) - text = doc.getObject("text") - self.assertTrue (text is not None) - FreeCAD.closeDocument(doc.Name) - except Exception: - pass # We may not have the DXF importer available + try: + doc = self.utility_create_scad("text(\"X\");","text") # Keep it short to keep the test fast-ish + text = doc.getObject("text") + self.assertTrue (text is not None) + FreeCAD.closeDocument(doc.Name) + except Exception: + pass # We may not have the DXF importer available def test_import_polygon_nopath(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "polygon_nopath.scad" - f = open(filename,"w+") - f.write("polygon(points=[[0,0],[100,0],[130,50],[30,50]]);") - f.close() - doc = importCSG.open(filename) - polygon = doc.getObject("polygon") - self.assertTrue (polygon is not None) - self.assertAlmostEqual (polygon.Shape.Area, 5000.0) - FreeCAD.closeDocument(doc.Name) + doc = self.utility_create_scad("polygon(points=[[0,0],[100,0],[130,50],[30,50]]);","polygon_nopath") + polygon = doc.getObject("polygon") + self.assertTrue (polygon is not None) + self.assertAlmostEqual (polygon.Shape.Area, 5000.0) + FreeCAD.closeDocument(doc.Name) def test_import_polygon_path(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "polygon_path.scad" - f = open(filename,"w+") - f.write("polygon([[0,0],[100,0],[130,50],[30,50]], paths=[[0,1,2,3]]);") - f.close() - doc = importCSG.open(filename) - wire = doc.ActiveObject # With paths, the polygon gets created as a wire... - self.assertTrue (wire is not None) - self.assertAlmostEqual (wire.Shape.Area, 5000.0) - FreeCAD.closeDocument(doc.Name) + doc = self.utility_create_scad("polygon([[0,0],[100,0],[130,50],[30,50]], paths=[[0,1,2,3]]);","polygon_path") + wire = doc.ActiveObject # With paths, the polygon gets created as a wire... + self.assertTrue (wire is not None) + self.assertAlmostEqual (wire.Shape.Area, 5000.0) + FreeCAD.closeDocument(doc.Name) def test_import_polyhedron(self): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + "polyhedron.scad" - f = open(filename,"w+") - f.write( + doc = self.utility_create_scad( """ polyhedron( points=[ [10,10,0],[10,-10,0],[-10,-10,0],[-10,10,0], // the four points at base @@ -187,22 +153,12 @@ polyhedron( faces=[ [0,1,4],[1,2,4],[2,3,4],[3,0,4], // each triangle side [1,0,3],[2,1,3] ] // two triangles for square base ); -""" +""","polyhedron" ) - f.close() - doc = importCSG.open(filename) - polyhedron = doc.ActiveObject # With paths, the polygon gets created as a wire... - self.assertTrue (polyhedron is not None) - self.assertAlmostEqual (polyhedron.Shape.Volume, 1333.3333, 4) - FreeCAD.closeDocument(doc.Name) - - def utility_create_scad(self, scadCode, name): - with tempfile.TemporaryDirectory() as temp_dir: - filename = temp_dir + os.path.sep + name + ".scad" - f = open(filename,"w+") - f.write(scadCode) - f.close() - return importCSG.open(filename) + polyhedron = doc.ActiveObject # With paths, the polygon gets created as a wire... + self.assertTrue (polyhedron is not None) + self.assertAlmostEqual (polyhedron.Shape.Volume, 1333.3333, 4) + FreeCAD.closeDocument(doc.Name) def test_import_difference(self): doc = self.utility_create_scad("difference() { cube(15, center=true); sphere(10); }", "difference") diff --git a/src/Mod/OpenSCAD/importCSG.py b/src/Mod/OpenSCAD/importCSG.py index c59dc778ce..9007750f34 100644 --- a/src/Mod/OpenSCAD/importCSG.py +++ b/src/Mod/OpenSCAD/importCSG.py @@ -79,7 +79,7 @@ def setColorRecursively(obj, color, transp): "Part::Common", "Part::MultiCommon"] if obj.TypeId in boolean_features: for currentObject in obj.OutList: - print(f"Fixing up colors for: {currentObject.FullName}") + if printverbose: print(f"Fixing up colors for: {currentObject.FullName}") if currentObject not in hassetcolor: setColorRecursively(currentObject, color, transp) @@ -767,14 +767,15 @@ def p_linear_extrude_with_transform(p): 'linear_extrude_with_transform : linear_extrude LPAREN keywordargument_list RPAREN OBRACE block_list EBRACE' if printverbose: print("Linear Extrude With Transform") h = float(p[3]['height']) - s = 1.0 + if printverbose: print("Height : ",h) + s = [1.0,1.0] t = 0.0 - if printverbose: print("Twist : ",p[3]) if 'scale' in p[3]: s = [float(p[3]['scale'][0]), float(p[3]['scale'][1])] - print ("Scale: " + str(s)) + if printverbose: print ("Scale: " + str(s)) if 'twist' in p[3]: t = float(p[3]['twist']) + if printverbose: print("Twist : ",t) # Test if null object like from null text if (len(p[6]) == 0) : p[0] = [] @@ -783,7 +784,7 @@ def p_linear_extrude_with_transform(p): obj = fuse(p[6],"Linear Extrude Union") else : obj = p[6][0] - if t != 0.0 or s != 1.0: + if t != 0.0 or s[0] != 1.0 or s[1] != 1.0: newobj = process_linear_extrude_with_transform(obj,h,t,s) else: newobj = process_linear_extrude(obj,h) @@ -1286,11 +1287,7 @@ def p_polyhedron_action(p) : pp =[v2(v[k]) for k in i] # Add first point to end of list to close polygon pp.append(pp[0]) - print("pp") - print(pp) w = Part.makePolygon(pp) - print("w") - print(w) try: f = Part.Face(w) except Exception: @@ -1315,7 +1312,6 @@ def p_projection_action(p) : for shape in p[6]: shape.Shape.tessellate(0.05) bbox.add(shape.Shape.BoundBox) - print (bbox) plane = doc.addObject("Part::Plane","xy_plane_used_for_projection") plane.Length = bbox.XLength plane.Width = bbox.YLength diff --git a/src/Mod/Part/App/Tools.cpp b/src/Mod/Part/App/Tools.cpp index d95e49eaf4..7c6792a2ef 100644 --- a/src/Mod/Part/App/Tools.cpp +++ b/src/Mod/Part/App/Tools.cpp @@ -25,6 +25,11 @@ # include # include # include +# include +# include +# include +# include +# include # include # include # include @@ -590,3 +595,64 @@ void Part::Tools::applyTransformationOnNormals(const TopLoc_Location& loc, std:: } } } + +Handle (Poly_Triangulation) Part::Tools::triangulationOfFace(const TopoDS_Face& face) +{ + TopLoc_Location loc; + Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(face, loc); + if (!mesh.IsNull()) + return mesh; + + // If no triangulation exists then the shape is probably infinite + BRepAdaptor_Surface adapt(face); + double u1 = adapt.FirstUParameter(); + double u2 = adapt.LastUParameter(); + double v1 = adapt.FirstVParameter(); + double v2 = adapt.LastVParameter(); + + // recreate a face with a clear boundary + u1 = std::max(-50.0, u1); + u2 = std::min( 50.0, u2); + v1 = std::max(-50.0, v1); + v2 = std::min( 50.0, v2); + + Handle(Geom_Surface) surface = BRep_Tool::Surface(face); + BRepBuilderAPI_MakeFace mkBuilder(surface, u1, u2, v1, v2 +#if OCC_VERSION_HEX >= 0x060502 + , Precision::Confusion() +#endif + ); + + TopoDS_Shape shape = mkBuilder.Shape(); + shape.Location(loc); + + BRepMesh_IncrementalMesh(shape, 0.1); + return BRep_Tool::Triangulation(TopoDS::Face(shape), loc); +} + +Handle(Poly_Polygon3D) Part::Tools::polygonOfEdge(const TopoDS_Edge& edge, TopLoc_Location& loc) +{ + BRepAdaptor_Curve adapt(edge); + double u = adapt.FirstParameter(); + double v = adapt.LastParameter(); + Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(edge, loc); + if (!aPoly.IsNull() && !Precision::IsInfinite(u) && !Precision::IsInfinite(v)) + return aPoly; + + // recreate an edge with a clear range + u = std::max(-50.0, u); + v = std::min( 50.0, v); + + double uv; + Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, uv, uv); + + BRepBuilderAPI_MakeEdge mkBuilder(curve, u, v); + TopoDS_Shape shape = mkBuilder.Shape(); + // why do we have to set the inverted location here? + TopLoc_Location inv = loc.Inverted(); + shape.Location(inv); + + BRepMesh_IncrementalMesh(shape, 0.1); + TopLoc_Location tmp; + return BRep_Tool::Polygon3D(TopoDS::Edge(shape), tmp); +} diff --git a/src/Mod/Part/App/Tools.h b/src/Mod/Part/App/Tools.h index 425032a12d..3bb543804e 100644 --- a/src/Mod/Part/App/Tools.h +++ b/src/Mod/Part/App/Tools.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include class gp_Lin; class gp_Pln; @@ -177,6 +179,22 @@ public: * \param normals */ static void applyTransformationOnNormals(const TopLoc_Location& loc, std::vector& normals); + /*! + * \brief triangulationOfInfinite + * Returns the triangulation of the face of the tessellated shape. In case the face has infinite lengths + * the triangulation of a limited parameter range is computed. + * \param edge + * \param loc + */ + static Handle (Poly_Triangulation) triangulationOfFace(const TopoDS_Face& face); + /*! + * \brief polygonOfEdge + * Returns the polygon of the edge of the tessellated shape. In case the edge has infinite length + * the polygon of a limited parameter range is computed. + * \param edge + * \param loc + */ + static Handle(Poly_Polygon3D) polygonOfEdge(const TopoDS_Edge& edge, TopLoc_Location& loc); }; } //namespace Part diff --git a/src/Mod/Part/Gui/ViewProvider2DObject.cpp b/src/Mod/Part/Gui/ViewProvider2DObject.cpp index 3c1ad047a4..a19a47803c 100644 --- a/src/Mod/Part/Gui/ViewProvider2DObject.cpp +++ b/src/Mod/Part/Gui/ViewProvider2DObject.cpp @@ -274,7 +274,7 @@ void ViewProvider2DObjectGrid::onChanged(const App::Property* prop) ViewProviderPart::onChanged(prop); if (prop == &ShowGrid || prop == &ShowOnlyInEditMode || prop == &Visibility) { - if (ShowGrid.getValue() && Visibility.getValue() && !(ShowOnlyInEditMode.getValue() && !this->isEditing())) + if (ShowGrid.getValue() && ((Visibility.getValue() && !ShowOnlyInEditMode.getValue()) || this->isEditing())) createGrid(); else Gui::coinRemoveAllChildren(GridRoot); diff --git a/src/Mod/Part/Gui/ViewProvider2DObject.h b/src/Mod/Part/Gui/ViewProvider2DObject.h index a6fd7b9221..135265d0b8 100644 --- a/src/Mod/Part/Gui/ViewProvider2DObject.h +++ b/src/Mod/Part/Gui/ViewProvider2DObject.h @@ -21,8 +21,8 @@ ***************************************************************************/ -#ifndef PARTGUI_IEWPROVIDER2DOBJECT_H -#define PARTGUI_IEWPROVIDER2DOBJECT_H +#ifndef PARTGUI_VIEWPROVIDER2DOBJECT_H +#define PARTGUI_VIEWPROVIDER2DOBJECT_H #include "ViewProvider.h" #include @@ -103,5 +103,5 @@ typedef Gui::ViewProviderPythonFeatureT ViewProvider2DObje } // namespace PartGui -#endif // PARTGUI_IEWPROVIDER2DOBJECT_H +#endif // PARTGUI_VIEWPROVIDER2DOBJECT_H diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index daf355e909..8fb9c9fe0d 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -104,6 +104,7 @@ #include #include #include +#include #include #include @@ -396,6 +397,12 @@ void ViewProviderPartExt::onChanged(const App::Property* prop) // if the object was invisible and has been changed, recreate the visual if (prop == &Visibility && (isUpdateForced() || Visibility.getValue()) && VisualTouched) { updateVisual(); + // updateVisual() may not be triggered by any change (e.g. + // triggered by an external object through forceUpdate()). And + // since DiffuseColor is not changed here either, do not falsely set + // the document modified status + Base::ObjectStatusLocker guard( + App::Property::NoModify, &DiffuseColor); // The material has to be checked again (#0001736) onChanged(&DiffuseColor); } @@ -985,6 +992,9 @@ void ViewProviderPartExt::updateVisual() TopExp::MapShapes(cShape, TopAbs_FACE, faceMap); for (int i=1; i <= faceMap.Extent(); i++) { Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(faceMap(i)), aLoc); + if (mesh.IsNull()) { + mesh = Part::Tools::triangulationOfFace(TopoDS::Face(faceMap(i))); + } // Note: we must also count empty faces if (!mesh.IsNull()) { numTriangles += mesh->NbTriangles(); @@ -1024,7 +1034,7 @@ void ViewProviderPartExt::updateVisual() // a free edge. int hash = aEdge.HashCode(INT_MAX); if (faceEdges.find(hash) == faceEdges.end()) { - Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc); + Handle(Poly_Polygon3D) aPoly = Part::Tools::polygonOfEdge(aEdge, aLoc); if (!aPoly.IsNull()) { int nbNodesInEdge = aPoly->NbNodes(); numNodes += nbNodesInEdge; @@ -1058,6 +1068,9 @@ void ViewProviderPartExt::updateVisual() const TopoDS_Face &actFace = TopoDS::Face(faceMap(i)); // get the mesh of the shape Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc); + if (mesh.IsNull()) { + mesh = Part::Tools::triangulationOfFace(actFace); + } if (mesh.IsNull()) { parts[ii] = 0; continue; @@ -1220,7 +1233,7 @@ void ViewProviderPartExt::updateVisual() // handling of the free edge that are not associated to a face int hash = aEdge.HashCode(INT_MAX); if (faceEdges.find(hash) == faceEdges.end()) { - Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc); + Handle(Poly_Polygon3D) aPoly = Part::Tools::polygonOfEdge(aEdge, aLoc); if (!aPoly.IsNull()) { if (!aLoc.IsIdentity()) { identity = false; @@ -1292,8 +1305,8 @@ void ViewProviderPartExt::updateVisual() void ViewProviderPartExt::forceUpdate(bool enable) { if(enable) { if(++forceUpdateCount == 1) { - if(!isShow()) - Visibility.touch(); + if(!isShow() && VisualTouched) + updateVisual(); } }else if(forceUpdateCount) --forceUpdateCount; diff --git a/src/Mod/Part/Gui/ViewProviderExt.h b/src/Mod/Part/Gui/ViewProviderExt.h index 2cb55c1873..4dcbd6ac5c 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.h +++ b/src/Mod/Part/Gui/ViewProviderExt.h @@ -34,6 +34,7 @@ #include #include #include +#include class TopoDS_Shape; class TopoDS_Edge; diff --git a/src/Mod/Part/Gui/ViewProviderSpline.cpp b/src/Mod/Part/Gui/ViewProviderSpline.cpp index e9d1ce23c4..fa6d67a912 100644 --- a/src/Mod/Part/Gui/ViewProviderSpline.cpp +++ b/src/Mod/Part/Gui/ViewProviderSpline.cpp @@ -63,10 +63,9 @@ namespace bp = boost::placeholders; PROPERTY_SOURCE(PartGui::ViewProviderSpline, PartGui::ViewProviderPartExt) ViewProviderSpline::ViewProviderSpline() - : pcControlPoints(0) { sPixmap = "Part_Spline_Parametric"; - ADD_PROPERTY(ControlPoints,(false)); + extension.initExtension(this); } ViewProviderSpline::~ViewProviderSpline() @@ -78,243 +77,6 @@ QIcon ViewProviderSpline::getIcon(void) const return Gui::BitmapFactory().pixmap(sPixmap); } -void ViewProviderSpline::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) -{ - ViewProviderPartExt::setupContextMenu(menu, receiver, member); - - // toggle command to display components - Gui::ActionFunction* func = new Gui::ActionFunction(menu); - QAction* act = menu->addAction(QObject::tr("Show control points")); - act->setCheckable(true); - act->setChecked(ControlPoints.getValue()); - func->toggle(act, boost::bind(&ViewProviderSpline::toggleControlPoints, this, bp::_1)); -} - -void ViewProviderSpline::toggleControlPoints(bool on) -{ - ControlPoints.setValue(on); -} - -void ViewProviderSpline::updateData(const App::Property* prop) -{ - ViewProviderPartExt::updateData(prop); - if (prop->getTypeId() == Part::PropertyPartShape::getClassTypeId() && strcmp(prop->getName(), "Shape") == 0) { - // update control points if there - if (pcControlPoints) { - Gui::coinRemoveAllChildren(pcControlPoints); - showControlPoints(this->ControlPoints.getValue(), prop); - } - } -} - -void ViewProviderSpline::onChanged(const App::Property* prop) -{ - if (prop == &ControlPoints) { - App::DocumentObject* obj = this->pcObject; - App::Property* shape = obj->getPropertyByName("Shape"); - showControlPoints(ControlPoints.getValue(), shape); - } - else { - ViewProviderPartExt::onChanged(prop); - } -} - -void ViewProviderSpline::showControlPoints(bool show, const App::Property* prop) -{ - if (!pcControlPoints && show) { - pcControlPoints = new SoSwitch(); - pcRoot->addChild(pcControlPoints); - } - - if (pcControlPoints) { - pcControlPoints->whichChild = (show ? SO_SWITCH_ALL : SO_SWITCH_NONE); - } - - if (!show || !pcControlPoints || pcControlPoints->getNumChildren() > 0) - return; - - // ask for the property we are interested in - if (prop && prop->getTypeId() == Part::PropertyPartShape::getClassTypeId()) { - const TopoDS_Shape& shape = static_cast(prop)->getValue(); - if (shape.IsNull()) - return; // empty shape - - for (TopExp_Explorer xp(shape, TopAbs_SHELL); xp.More(); xp.Next()) { - const TopoDS_Shell& shell = TopoDS::Shell(xp.Current()); - for (TopExp_Explorer xp2(shell, TopAbs_FACE); xp2.More(); xp2.Next()) { - const TopoDS_Face& face = TopoDS::Face(xp2.Current()); - showControlPointsOfFace(face); - } - } - for (TopExp_Explorer xp(shape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) { - const TopoDS_Face& face = TopoDS::Face(xp.Current()); - showControlPointsOfFace(face); - } - for (TopExp_Explorer xp(shape, TopAbs_WIRE, TopAbs_FACE); xp.More(); xp.Next()) { - const TopoDS_Wire& wire = TopoDS::Wire(xp.Current()); - for (TopExp_Explorer xp2(wire, TopAbs_EDGE); xp2.More(); xp2.Next()) { - const TopoDS_Edge& edge = TopoDS::Edge(xp2.Current()); - showControlPointsOfEdge(edge); - } - } - for (TopExp_Explorer xp(shape, TopAbs_EDGE, TopAbs_WIRE); xp.More(); xp.Next()) { - const TopoDS_Edge& edge = TopoDS::Edge(xp.Current()); - showControlPointsOfEdge(edge); - } - } -} - -void ViewProviderSpline::showControlPointsOfEdge(const TopoDS_Edge& edge) -{ - std::list poles, knots; - Standard_Integer nCt=0; - - TopoDS_Edge edge_loc(edge); - TopLoc_Location aLoc; - edge_loc.Location(aLoc); - - BRepAdaptor_Curve curve(edge_loc); - switch (curve.GetType()) - { - case GeomAbs_BezierCurve: - { - Handle(Geom_BezierCurve) hBezier = curve.Bezier(); - nCt = hBezier->NbPoles(); - for (Standard_Integer i = 1; i <= nCt; i++) - poles.push_back(hBezier->Pole(i)); - if (hBezier->IsClosed()) { - nCt++; - poles.push_back(hBezier->Pole(1)); - } - } break; - case GeomAbs_BSplineCurve: - { - Handle(Geom_BSplineCurve) hBSpline = curve.BSpline(); - nCt = hBSpline->NbPoles(); - for (Standard_Integer i = 1; i <= nCt; i++) - poles.push_back(hBSpline->Pole(i)); - if (hBSpline->IsClosed()) { - nCt++; - poles.push_back(hBSpline->Pole(1)); - } - for (Standard_Integer i = hBSpline->FirstUKnotIndex()+1; i <= hBSpline->LastUKnotIndex()-1; i++) - knots.push_back(hBSpline->Value(hBSpline->Knot(i))); - } break; - default: - break; - } - - if (poles.empty()) - return; // nothing to do - - SoCoordinate3 * controlcoords = new SoCoordinate3; - controlcoords->point.setNum(nCt + knots.size()); - - int index=0; - SbVec3f* verts = controlcoords->point.startEditing(); - for (std::list::iterator p = poles.begin(); p != poles.end(); ++p) { - verts[index++].setValue((float)p->X(), (float)p->Y(), (float)p->Z()); - } - for (std::list::iterator k = knots.begin(); k != knots.end(); ++k) { - verts[index++].setValue((float)k->X(), (float)k->Y(), (float)k->Z()); - } - controlcoords->point.finishEditing(); - - - SoFCControlPoints* controlpoints = new SoFCControlPoints(); - controlpoints->numPolesU = nCt; - controlpoints->numPolesV = 1; - - SoSeparator* nodes = new SoSeparator(); - nodes->addChild(controlcoords); - nodes->addChild(controlpoints); - - pcControlPoints->addChild(nodes); -} - -void ViewProviderSpline::showControlPointsOfFace(const TopoDS_Face& face) -{ - std::list knots; - std::vector > poles; - Standard_Integer nCtU=0, nCtV=0; - - TopoDS_Face face_loc(face); - TopLoc_Location aLoc; - face_loc.Location(aLoc); - - BRepAdaptor_Surface surface(face_loc); - switch (surface.GetType()) - { - case GeomAbs_BezierSurface: - { - Handle(Geom_BezierSurface) hBezier = surface.Bezier(); - nCtU = hBezier->NbUPoles(); - nCtV = hBezier->NbVPoles(); - poles.resize(nCtU); - for (Standard_Integer u = 1; u <= nCtU; u++) { - poles[u-1].resize(nCtV); - for (Standard_Integer v = 1; v <= nCtV; v++) - poles[u-1][v-1] = hBezier->Pole(u, v); - } - } break; - case GeomAbs_BSplineSurface: - { - Handle(Geom_BSplineSurface) hBSpline = surface.BSpline(); - nCtU = hBSpline->NbUPoles(); - nCtV = hBSpline->NbVPoles(); - poles.resize(nCtU); - for (Standard_Integer u = 1; u <= nCtU; u++) { - poles[u-1].resize(nCtV); - for (Standard_Integer v = 1; v <= nCtV; v++) - poles[u-1][v-1] = hBSpline->Pole(u, v); - } - - //Standard_Integer nKnU = hBSpline->NbUKnots(); - //Standard_Integer nKnV = hBSpline->NbVKnots(); - for (Standard_Integer u = 1; u <= hBSpline->NbUKnots(); u++) { - for (Standard_Integer v = 1; v <= hBSpline->NbVKnots(); v++) - knots.push_back(hBSpline->Value(hBSpline->UKnot(u), hBSpline->VKnot(v))); - } - } break; - default: - break; - } - - if (poles.empty()) - return; // nothing to do - - SoCoordinate3 * coords = new SoCoordinate3; - coords->point.setNum(nCtU * nCtV + knots.size()); - - int index=0; - SbVec3f* verts = coords->point.startEditing(); - for (std::vector >::iterator u = poles.begin(); u != poles.end(); ++u) { - for (std::vector::iterator v = u->begin(); v != u->end(); ++v) { - verts[index++].setValue((float)v->X(), (float)v->Y(), (float)v->Z()); - } - } - for (std::list::iterator k = knots.begin(); k != knots.end(); ++k) { - verts[index++].setValue((float)k->X(), (float)k->Y(), (float)k->Z()); - } - coords->point.finishEditing(); - - - SoFCControlPoints* control = new SoFCControlPoints(); - control->numPolesU = nCtU; - control->numPolesV = nCtV; - - //if (knots.size() > 0) { - // control->numKnotsU = nKnU; - // control->numKnotsV = nKnV; - //} - - SoSeparator* nodes = new SoSeparator(); - nodes->addChild(coords); - nodes->addChild(control); - - pcControlPoints->addChild(nodes); -} - // ---------------------------------------------------------------------------- EXTENSION_PROPERTY_SOURCE(PartGui::ViewProviderSplineExtension, Gui::ViewProviderExtension) diff --git a/src/Mod/Part/Gui/ViewProviderSpline.h b/src/Mod/Part/Gui/ViewProviderSpline.h index 6861a2cdfe..2786e9fe01 100644 --- a/src/Mod/Part/Gui/ViewProviderSpline.h +++ b/src/Mod/Part/Gui/ViewProviderSpline.h @@ -23,46 +23,19 @@ #ifndef PARTGUI_VIEWPROVIDERPARTSPLINE_H #define PARTGUI_VIEWPROVIDERPARTSPLINE_H -#include "ViewProviderExt.h" +#include #include namespace PartGui { -class PartGuiExport ViewProviderSpline : public ViewProviderPartExt -{ - PROPERTY_HEADER(PartGui::ViewProviderSpline); - -public: - /// constructor - ViewProviderSpline(); - /// destructor - virtual ~ViewProviderSpline(); - - // Display properties - App::PropertyBool ControlPoints; - - QIcon getIcon(void) const; - void updateData(const App::Property* prop); - void setupContextMenu(QMenu* menu, QObject* receiver, const char* member); - -protected: - void onChanged(const App::Property* prop); - void toggleControlPoints(bool); - void showControlPoints(bool, const App::Property* prop); - void showControlPointsOfEdge(const TopoDS_Edge&); - void showControlPointsOfFace(const TopoDS_Face&); - - SoSwitch *pcControlPoints; -}; - class PartGuiExport ViewProviderSplineExtension : public Gui::ViewProviderExtension { EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(PartGui::ViewProviderSplineExtension); public: /// Constructor - ViewProviderSplineExtension(void); + ViewProviderSplineExtension(); virtual ~ViewProviderSplineExtension() = default; App::PropertyBool ControlPoints; @@ -80,6 +53,22 @@ protected: SoSwitch *pcControlPoints; }; +class PartGuiExport ViewProviderSpline : public ViewProviderPartExt +{ + PROPERTY_HEADER(PartGui::ViewProviderSpline); + +public: + /// constructor + ViewProviderSpline(); + /// destructor + virtual ~ViewProviderSpline(); + + QIcon getIcon() const; + +private: + ViewProviderSplineExtension extension; +}; + typedef Gui::ViewProviderExtensionPythonT ViewProviderSplineExtensionPython; } //namespace PartGui diff --git a/src/Mod/Part/PartGlobal.h b/src/Mod/Part/PartGlobal.h new file mode 100644 index 0000000000..a6d29ec10c --- /dev/null +++ b/src/Mod/Part/PartGlobal.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include + +#ifndef PART_GLOBAL_H +#define PART_GLOBAL_H + + +// Part +#ifndef PartExport +#ifdef Part_EXPORTS +# define PartExport FREECAD_DECL_EXPORT +#else +# define PartExport FREECAD_DECL_IMPORT +#endif +#endif + +// PartGui +#ifndef PartGuiExport +#ifdef PartGui_EXPORTS +# define PartGuiExport FREECAD_DECL_EXPORT +#else +# define PartGuiExport FREECAD_DECL_IMPORT +#endif +#endif + +#endif //PART_GLOBAL_H diff --git a/src/Mod/PartDesign/Gui/DlgActiveBody.cpp b/src/Mod/PartDesign/Gui/DlgActiveBody.cpp index aa916d6208..fb4841d94f 100644 --- a/src/Mod/PartDesign/Gui/DlgActiveBody.cpp +++ b/src/Mod/PartDesign/Gui/DlgActiveBody.cpp @@ -28,6 +28,7 @@ # include #endif +#include #include #include "DlgActiveBody.h" @@ -74,6 +75,14 @@ DlgActiveBody::DlgActiveBody(QWidget *parent, App::Document*& doc, // TODO: Any other logic (hover, select effects on view etc.) } + + if (!bodyOfActiveObject) { + // by default select the first item so that the user + // can continue by clicking Ok without further action + QListWidgetItem* first = ui->bodySelect->item(0); + if (first) + first->setSelected(true); + } } void DlgActiveBody::accept() @@ -84,10 +93,15 @@ void DlgActiveBody::accept() App::DocumentObject* selectedBody = selectedItems[0]->data(Qt::UserRole).value(); - if (selectedBody) + if (selectedBody) { activeBody = makeBodyActive(selectedBody, _doc); - else + } + else { + // A transaction must be created as otherwise the undo/redo is broken + App::GetApplication().setActiveTransaction(QT_TRANSLATE_NOOP("Command", "Add a Body"), true); activeBody = makeBody(_doc); + App::GetApplication().closeActiveTransaction(); + } QDialog::accept(); } diff --git a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp index 36cab259a2..9ae610ef18 100644 --- a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp @@ -55,7 +55,7 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskLoftParameters */ -TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView,bool /*newObj*/, QWidget *parent) +TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView, bool /*newObj*/, QWidget *parent) : TaskSketchBasedParameters(LoftView, parent, "PartDesign_AdditiveLoft", tr("Loft parameters")) , ui(new Ui_TaskLoftParameters) { @@ -69,7 +69,7 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView,bool /*newObj* connect(ui->buttonRefAdd, SIGNAL(toggled(bool)), this, SLOT(onRefButtonAdd(bool))); connect(ui->buttonRefRemove, SIGNAL(toggled(bool)), - this, SLOT(onRefButtonRemvove(bool))); + this, SLOT(onRefButtonRemove(bool))); connect(ui->checkBoxRuled, SIGNAL(toggled(bool)), this, SLOT(onRuled(bool))); connect(ui->checkBoxClosed, SIGNAL(toggled(bool)), @@ -129,16 +129,15 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView,bool /*newObj* for (QWidget* child : proxy->findChildren()) child->blockSignals(false); - updateUI(0); + updateUI(); } TaskLoftParameters::~TaskLoftParameters() { } -void TaskLoftParameters::updateUI(int index) +void TaskLoftParameters::updateUI() { - Q_UNUSED(index); } void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) @@ -324,7 +323,7 @@ void TaskLoftParameters::onRefButtonAdd(bool checked) { } } -void TaskLoftParameters::onRefButtonRemvove(bool checked) { +void TaskLoftParameters::onRefButtonRemove(bool checked) { if (checked) { Gui::Selection().clearSelection(); @@ -359,7 +358,7 @@ bool TaskDlgLoftParameters::accept() // TODO Fill this with commands (2015-09-11, Fat-Zer) PartDesign::Loft* pcLoft = static_cast(vp->getObject()); - for(App::DocumentObject* obj : pcLoft->Sections.getValues()) { + for (App::DocumentObject* obj : pcLoft->Sections.getValues()) { FCMD_OBJ_HIDE(obj); } diff --git a/src/Mod/PartDesign/Gui/TaskLoftParameters.h b/src/Mod/PartDesign/Gui/TaskLoftParameters.h index b99a771edf..e04011ef4b 100644 --- a/src/Mod/PartDesign/Gui/TaskLoftParameters.h +++ b/src/Mod/PartDesign/Gui/TaskLoftParameters.h @@ -56,7 +56,7 @@ public: private Q_SLOTS: void onProfileButton(bool); void onRefButtonAdd(bool); - void onRefButtonRemvove(bool); + void onRefButtonRemove(bool); void onClosed(bool); void onRuled(bool); void onDeleteSection(); @@ -67,7 +67,7 @@ protected: private: void onSelectionChanged(const Gui::SelectionChanges& msg); - void updateUI(int index); + void updateUI(); bool referenceSelected(const Gui::SelectionChanges& msg) const; void removeFromListWidget(QListWidget*w, QString name); void clearButtons(); diff --git a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp index 66465f3814..6dd611b873 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp @@ -94,6 +94,7 @@ TaskPipeParameters::TaskPipeParameters(ViewProviderPipe *PipeView, bool /*newObj // Create context menu QAction* remove = new QAction(tr("Remove"), this); remove->setShortcut(QKeySequence::Delete); + remove->setShortcutContext(Qt::WidgetShortcut); #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // display shortcut behind the context menu entry remove->setShortcutVisibleInContextMenu(true); @@ -587,6 +588,7 @@ TaskPipeOrientation::TaskPipeOrientation(ViewProviderPipe* PipeView, bool /*newO // Create context menu QAction* remove = new QAction(tr("Remove"), this); remove->setShortcut(QKeySequence::Delete); + remove->setShortcutContext(Qt::WidgetShortcut); #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // display shortcut behind the context menu entry remove->setShortcutVisibleInContextMenu(true); @@ -902,6 +904,7 @@ TaskPipeScaling::TaskPipeScaling(ViewProviderPipe* PipeView, bool /*newObj*/, QW // Create context menu QAction* remove = new QAction(tr("Remove"), this); remove->setShortcut(QKeySequence::Delete); + remove->setShortcutContext(Qt::WidgetShortcut); #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // display shortcut behind the context menu entry remove->setShortcutVisibleInContextMenu(true); diff --git a/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp b/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp index 8cbb387b47..6f260f3b78 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderLoft.cpp @@ -81,11 +81,6 @@ void ViewProviderLoft::setupContextMenu(QMenu* menu, QObject* receiver, const ch PartDesignGui::ViewProvider::setupContextMenu(menu, receiver, member); } -bool ViewProviderLoft::doubleClicked(void) -{ - return PartDesignGui::setEdit(pcObject); -} - bool ViewProviderLoft::setEdit(int ModNum) { if (ModNum == ViewProvider::Default) diff --git a/src/Mod/PartDesign/Gui/ViewProviderLoft.h b/src/Mod/PartDesign/Gui/ViewProviderLoft.h index dcec346ee3..01f24e76c5 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderLoft.h +++ b/src/Mod/PartDesign/Gui/ViewProviderLoft.h @@ -41,7 +41,6 @@ public: /// grouping handling std::vector claimChildren(void)const; void setupContextMenu(QMenu*, QObject*, const char*); - bool doubleClicked(); virtual bool onDelete(const std::vector &); void highlightReferences(const bool on, bool auxiliary); diff --git a/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp b/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp index 490bddf704..5c875153be 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPipe.cpp @@ -89,11 +89,6 @@ void ViewProviderPipe::setupContextMenu(QMenu* menu, QObject* receiver, const ch PartDesignGui::ViewProvider::setupContextMenu(menu, receiver, member); } -bool ViewProviderPipe::doubleClicked(void) -{ - return PartDesignGui::setEdit(pcObject); -} - bool ViewProviderPipe::setEdit(int ModNum) { if (ModNum == ViewProvider::Default ) setPreviewDisplayMode(true); diff --git a/src/Mod/PartDesign/Gui/ViewProviderPipe.h b/src/Mod/PartDesign/Gui/ViewProviderPipe.h index 7fbf6647ed..e3efe3a695 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPipe.h +++ b/src/Mod/PartDesign/Gui/ViewProviderPipe.h @@ -49,7 +49,6 @@ public: /// grouping handling std::vector claimChildren(void)const; void setupContextMenu(QMenu*, QObject*, const char*); - bool doubleClicked(); virtual bool onDelete(const std::vector &); void highlightReferences(Reference mode, bool on); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 94cd370dc7..4ae7939dda 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -65,6 +65,8 @@ namespace bp = boost::placeholders; qApp->translate("Gui::TaskView::TaskWatcherCommands", "Create Geometry"); // qApp->translate("Workbench", "Measure"); + qApp->translate("Workbench", "Refresh"); + qApp->translate("Workbench", "Toggle 3D"); qApp->translate("Workbench", "Part Design Helper"); qApp->translate("Workbench", "Part Design Modeling"); #endif diff --git a/src/Mod/Path/App/Area.cpp b/src/Mod/Path/App/Area.cpp index 11f11fc63f..d91652788f 100644 --- a/src/Mod/Path/App/Area.cpp +++ b/src/Mod/Path/App/Area.cpp @@ -1230,7 +1230,7 @@ int Area::project(TopoDS_Shape &shape_out, const TopoDS_Shape *work_plane) { FC_TIME_INIT2(t,t1); - Handle_HLRBRep_Algo brep_hlr = NULL; + Handle_HLRBRep_Algo brep_hlr; gp_Dir dir(0,0,1); try { brep_hlr = new HLRBRep_Algo(); diff --git a/src/Mod/Path/Gui/AppPathGuiPy.cpp b/src/Mod/Path/Gui/AppPathGuiPy.cpp index a442244b41..062da3a069 100644 --- a/src/Mod/Path/Gui/AppPathGuiPy.cpp +++ b/src/Mod/Path/Gui/AppPathGuiPy.cpp @@ -82,7 +82,7 @@ private: wc.restoreCursor(); try { - std::string path = App::GetApplication().getHomePath(); + std::string path = App::Application::getHomePath(); path += "Mod/Path/PathScripts/post/"; QDir dir1(QString::fromUtf8(path.c_str()), QString::fromLatin1("*_pre.py")); std::string cMacroPath = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Macro") @@ -149,7 +149,7 @@ private: wc.restoreCursor(); try { - std::string path = App::GetApplication().getHomePath(); + std::string path = App::Application::getHomePath(); path += "Mod/Path/PathScripts/post/"; QDir dir1(QString::fromUtf8(path.c_str()), QString::fromLatin1("*_pre.py")); std::string cMacroPath = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Macro") @@ -225,7 +225,7 @@ private: if (objlist.size() == 0) throw Py::RuntimeError("No object to export"); - std::string path = App::GetApplication().getHomePath(); + std::string path = App::Application::getHomePath(); path += "Mod/Path/PathScripts/post/"; QDir dir1(QString::fromUtf8(path.c_str()), QString::fromLatin1("*_post.py")); std::string cMacroPath = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Macro") diff --git a/src/Mod/Raytracing/App/AppRaytracingPy.cpp b/src/Mod/Raytracing/App/AppRaytracingPy.cpp index 5b124e91fc..dc6a528415 100644 --- a/src/Mod/Raytracing/App/AppRaytracingPy.cpp +++ b/src/Mod/Raytracing/App/AppRaytracingPy.cpp @@ -222,7 +222,7 @@ private: if (! PyArg_ParseTuple(args.ptr(), "ss",&FileName,&DestDir)) throw Py::Exception(); - std::string resName = App::GetApplication().getHomePath(); + std::string resName = App::Application::getHomePath(); resName += "Mod"; resName += PATHSEP ; resName += "Raytracing"; diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index f7d00610ee..ba1496e225 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -555,7 +555,8 @@ public: "conList.append(Sketcher.Constraint('Horizontal',%i))\n" "conList.append(Sketcher.Constraint('Vertical',%i))\n" "conList.append(Sketcher.Constraint('Vertical',%i))\n" - "%s.addConstraint(conList)\n", + "%s.addConstraint(conList)\n" + "del geoList, conList\n", EditCurve[0].x,EditCurve[0].y,EditCurve[1].x,EditCurve[1].y, // line 1 EditCurve[1].x,EditCurve[1].y,EditCurve[2].x,EditCurve[2].y, // line 2 EditCurve[2].x,EditCurve[2].y,EditCurve[3].x,EditCurve[3].y, // line 3 @@ -594,7 +595,8 @@ public: "conList.append(Sketcher.Constraint('Vertical',%i))\n" "conList.append(Sketcher.Constraint('Vertical',%i))\n" "conList.append(Sketcher.Constraint('Symmetric',%i,2,%i,1,%i,1))\n" - "%s.addConstraint(conList)\n", + "%s.addConstraint(conList)\n" + "del geoList, conList\n", EditCurve[0].x,EditCurve[0].y,EditCurve[1].x,EditCurve[1].y, // line 1 EditCurve[1].x,EditCurve[1].y,EditCurve[2].x,EditCurve[2].y, // line 2 EditCurve[2].x,EditCurve[2].y,EditCurve[3].x,EditCurve[3].y, // line 3 @@ -930,7 +932,8 @@ public: "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" - "%s.addConstraint(conList)\n", + "%s.addConstraint(conList)\n" + "del geoList, conList\n", StartPos.x + (signX * radius), StartPos.y + (signY * radius), // center of the arc 1 radius, start, end, // start and end angle of arc1 @@ -984,7 +987,8 @@ public: "conList.append(Sketcher.Constraint('PointOnObject', %i, 1, %i, ))\n" "conList.append(Sketcher.Constraint('PointOnObject', %i, 1, %i, ))\n" "conList.append(Sketcher.Constraint('PointOnObject', %i, 1, %i, ))\n" - "%s.addConstraint(conList)\n", + "%s.addConstraint(conList)\n" + "del geoList, conList\n", StartPos.x, StartPos.y, // point at StartPos EndPos.x, EndPos.y, // point at EndPos Gui::Command::getObjectCmd(sketchgui->getObject()).c_str(), // the sketch @@ -4843,6 +4847,7 @@ public: } cstream << Gui::Command::getObjectCmd(sketchgui->getObject()) << ".addConstraint(conList)\n"; + cstream << "del conList\n"; Gui::Command::doCommand(Gui::Command::Doc, cstream.str().c_str()); @@ -7129,7 +7134,8 @@ public: "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 1))\n" "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 1))\n" "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" - "%s.addConstraint(conList)\n", + "%s.addConstraint(conList)\n" + "del geoList, conList\n", StartPos.x, StartPos.y, // center of the arc1 r, // radius arc1 start, end, // start and end angle of arc1 diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstraints.cpp b/src/Mod/Sketcher/Gui/TaskSketcherConstraints.cpp index acfb48c942..93ec845a5e 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstraints.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstraints.cpp @@ -379,7 +379,7 @@ public: class ExpressionDelegate : public QStyledItemDelegate { public: - ExpressionDelegate(QListWidget * _view) : view(_view) { } + ExpressionDelegate(QListWidget * _view) : QStyledItemDelegate(_view), view(_view) { } protected: QPixmap getIcon(const char* name, const QSize& size) const { diff --git a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp index bebd6a5844..81a2ec0077 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp @@ -264,9 +264,6 @@ void TaskSketcherGeneral::onChangedSketchView(const Gui::ViewProvider& vp, QSignalBlocker block(widget); widget->checkGridView(sketchView->ShowGrid.getValue()); widget->enableGridSettings(sketchView->ShowGrid.getValue()); - if (sketchView->ShowGrid.getValue()) { - sketchView->createGrid(); - } } else if (&sketchView->GridSize == &prop) { QSignalBlocker block(widget); @@ -293,7 +290,6 @@ void TaskSketcherGeneral::onToggleGridView(bool on) Base::ConnectionBlocker block(changedSketchView); sketchView->ShowGrid.setValue(on); widget->enableGridSettings(on); - if (on) sketchView->createGrid(); } void TaskSketcherGeneral::onSetGridSize(double val) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherValidation.ui b/src/Mod/Sketcher/Gui/TaskSketcherValidation.ui index 4cf647b8cf..bde339ba91 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherValidation.ui +++ b/src/Mod/Sketcher/Gui/TaskSketcherValidation.ui @@ -6,32 +6,57 @@ 0 0 - 311 - 453 + 266 + 684 Sketcher validation - - + + + + Reversed external geometry + + + + + + Finds reversed external geometries + + + Find + + + + + + + Fixes found reversed external geometries by swapping their endpoints + + + Swap endpoints in constraints + + + + + + + + + + Fixes found missing coincidences by adding extra coincident constrains + Missing coincidences - - - - Tolerance: - - - - - - + + If checked, construction geometries are ignored in the search + Ignore construction geometry @@ -42,11 +67,22 @@ + + Finds and displays missing coincidences found in the sketch +This is done by analyzing the sketch geometries and constraints + Find + + + + Tolerance: + + + @@ -54,17 +90,17 @@ - - - - Highlight open vertexes + + + + Defines the X/Y tolerance inside which missing coincidences are searched. - + Invalid constraints @@ -72,6 +108,9 @@ + + Finds invalid/malformed constrains in the sketch + Find @@ -79,6 +118,9 @@ + + Tries to fix found invalid constraints + Fix @@ -86,6 +128,9 @@ + + Deletes constrains refering to external geometry + Delete constraints to external geom. @@ -94,7 +139,39 @@ - + + + + Open and non-manifold vertexes + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Highlights open and non-manifold vertexes that could lead to error if sketch is used to generate solids +This is purely based on topological shape of the sketch and not on its geometry/constrain set. + + + Highlight troublesome vertexes + + + + + + + Degenerated geometry @@ -102,6 +179,9 @@ + + Finds degenerated geometries in the sketch + Find @@ -109,6 +189,9 @@ + + Tries to fix found degenerated geometries + Fix @@ -117,30 +200,7 @@ - - - - Reversed external geometry - - - - - - Find - - - - - - - Swap endpoints in constraints - - - - - - - + Constraint orientation locking @@ -148,6 +208,9 @@ + + Enables/updates constraint orientation locking + Enable/Update @@ -155,6 +218,9 @@ + + Disables constraint orientation locking + Disable diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index c3a89f5c12..e22254d2af 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -6376,6 +6376,7 @@ bool ViewProviderSketch::setEdit(int ModNum) " tv.sketchClipPlane(ActiveSketch, ActiveSketch.ViewObject.SectionView)\n" "tv.hide(ActiveSketch)\n" "del(tv)\n" + "del(ActiveSketch)\n" ).arg(QString::fromLatin1(getDocument()->getDocument()->getName()), QString::fromLatin1(getSketchObject()->getNameInDocument()), QString::fromLatin1(Gui::Command::getObjectCmd(editObj).c_str()), @@ -6907,6 +6908,7 @@ void ViewProviderSketch::unsetEdit(int ModNum) " tv.restore()\n" "ActiveSketch.ViewObject.TempoVis = None\n" "del(tv)\n" + "del(ActiveSketch)\n" ).arg(QString::fromLatin1(getDocument()->getDocument()->getName())).arg( QString::fromLatin1(getSketchObject()->getNameInDocument())); QByteArray cmdstr_bytearray = cmdstr.toLatin1(); diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index 286b72890f..265f8d7697 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -351,7 +351,7 @@ void PropertySheet::copyCells(Base::Writer& writer, const std::vector& ra writer.incInd(); do { auto cell = getValue(*range); - if (cell) { + if (cell && cell->isUsed()) { cell->save(writer); } else { diff --git a/src/Mod/Spreadsheet/Gui/Sheet.ui b/src/Mod/Spreadsheet/Gui/Sheet.ui index 5704291d1e..68aa09998e 100644 --- a/src/Mod/Spreadsheet/Gui/Sheet.ui +++ b/src/Mod/Spreadsheet/Gui/Sheet.ui @@ -27,7 +27,7 @@ - + false @@ -44,7 +44,7 @@ - + false @@ -68,9 +68,9 @@ Spreadsheet.my_alias_name instead of Spreadsheet.B1
SheetTableView.h
- SpreadsheetGui::LineEdit + Gui::ExpressionLineEdit QLineEdit -
SpreadsheetView.h
+
Gui/ExpressionCompleter.h
diff --git a/src/Mod/Spreadsheet/Gui/SheetModel.cpp b/src/Mod/Spreadsheet/Gui/SheetModel.cpp index 341466214f..c289dcc121 100644 --- a/src/Mod/Spreadsheet/Gui/SheetModel.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetModel.cpp @@ -277,18 +277,34 @@ QVariant SheetModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(f); } - if (!prop) { + auto dirtyCells = sheet->getCells()->getDirty(); + auto dirty = (dirtyCells.find(CellAddress(row,col)) != dirtyCells.end()); + + if (!prop || dirty) { switch (role) { case Qt::ForegroundRole: { - return QColor(0, 0, 255.0); + return QColor(0, 0, 255.0); // TODO: Remove this hardcoded color, replace with preference } case Qt::TextAlignmentRole: { qtAlignment = Qt::AlignHCenter | Qt::AlignVCenter; return QVariant::fromValue(qtAlignment); } case Qt::DisplayRole: - if(cell->getExpression()) - return QVariant(QLatin1String("#PENDING")); + if(cell->getExpression()) { + std::string str; + if (cell->getStringContent(str)) + if (str.size() > 0 && str[0] == '=') + // If this is a real computed value, indicate that a recompute is + // needed before we can display it + return QVariant(QLatin1String("#PENDING")); + else + // If it's just a simple value, display the new value, but still + // format it as a pending value to indicate to the user that + // a recompute is needed + return QVariant(QString::fromUtf8(str.c_str())); + else + return QVariant(); + } else return QVariant(); default: @@ -531,6 +547,16 @@ bool SheetModel::setData(const QModelIndex & index, const QVariant & value, int try { QString str = value.toString(); + + // Check to see if this is already the value in the cell, and skip the update if so + auto cell = sheet->getCell(address); + if (cell) { + std::string oldContent; + cell->getStringContent(oldContent); + if (str == QString::fromStdString(oldContent)) + return true; + } + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Edit cell")); // Because of possible complication of recursively escaped // characters, let's take a shortcut and bypass the command diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp index 634a30e815..e65365c3eb 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp @@ -163,8 +163,8 @@ SheetTableView::SheetTableView(QWidget *parent) auto cellProperties = new QAction(tr("Properties..."), this); addAction(cellProperties); - horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu); - verticalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu); + horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); + verticalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); contextMenu = new QMenu(this); diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp index 3d2056cb3f..4103c2fd91 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp @@ -99,10 +99,8 @@ SheetView::SheetView(Gui::Document *pcDocument, App::DocumentObject *docObj, QWi this, SLOT(rowResized(int, int, int))); connect(delegate, &SpreadsheetDelegate::finishedWithKey, this, &SheetView::editingFinishedWithKey); - connect(ui->cellContent, &LineEdit::finishedWithKey, this, [this](int, Qt::KeyboardModifiers) {confirmContentChanged(ui->cellContent->text()); }); - connect(ui->cellContent, &LineEdit::returnPressed, this, [this]() {confirmContentChanged(ui->cellContent->text()); }); - connect(ui->cellAlias, &LineEdit::finishedWithKey, this, [this](int, Qt::KeyboardModifiers) {confirmAliasChanged(ui->cellAlias->text()); }); - connect(ui->cellAlias, &LineEdit::returnPressed, this, [this]() {confirmAliasChanged(ui->cellAlias->text()); }); + connect(ui->cellContent, &ExpressionLineEdit::returnPressed, this, [this]() {confirmContentChanged(ui->cellContent->text()); }); + connect(ui->cellAlias, &ExpressionLineEdit::returnPressed, this, [this]() {confirmAliasChanged(ui->cellAlias->text()); }); connect(ui->cellAlias, &LineEdit::textEdited, this, &SheetView::aliasChanged); columnWidthChangedConnection = sheet->columnWidthChanged.connect(bind(&SheetView::resizeColumn, this, bp::_1, bp::_2)); @@ -314,7 +312,6 @@ void SheetView::editingFinishedWithKey(int key, Qt::KeyboardModifiers modifiers) QModelIndex i = ui->cells->currentIndex(); if (i.isValid()) { - ui->cells->model()->setData(i, QVariant(ui->cellContent->text()), Qt::EditRole); ui->cells->finishEditWithMove(key, modifiers); } } diff --git a/src/Mod/Test/BaseTests.py b/src/Mod/Test/BaseTests.py index 61a47a1b44..857e55d41b 100644 --- a/src/Mod/Test/BaseTests.py +++ b/src/Mod/Test/BaseTests.py @@ -244,6 +244,58 @@ class ParameterTestCase(unittest.TestCase): r.invert() self.assertTrue(r.isSame(s)) + # gimbal lock (north pole) + r=FreeCAD.Rotation() + r.setYawPitchRoll(20, 90, 10) + a=r.getYawPitchRoll() + s=FreeCAD.Rotation() + s.setYawPitchRoll(*a) + self.assertAlmostEqual(a[0], 0.0) + self.assertAlmostEqual(a[1], 90.0) + self.assertAlmostEqual(a[2], -10.0) + self.assertTrue(r.isSame(s, 1e-12)) + + # gimbal lock (south pole) + r=FreeCAD.Rotation() + r.setYawPitchRoll(20, -90, 10) + a=r.getYawPitchRoll() + s=FreeCAD.Rotation() + s.setYawPitchRoll(*a) + self.assertAlmostEqual(a[0], 0.0) + self.assertAlmostEqual(a[1], -90.0) + self.assertAlmostEqual(a[2], 30.0) + self.assertTrue(r.isSame(s, 1e-12)) + + def testYawPitchRoll(self): + def getYPR1(yaw, pitch, roll): + r = FreeCAD.Rotation() + r.setYawPitchRoll(yaw, pitch, roll) + return r + def getYPR2(yaw, pitch, roll): + rx = FreeCAD.Rotation() + ry = FreeCAD.Rotation() + rz = FreeCAD.Rotation() + + rx.Axis = FreeCAD.Vector(1,0,0) + ry.Axis = FreeCAD.Vector(0,1,0) + rz.Axis = FreeCAD.Vector(0,0,1) + + rx.Angle = math.radians(roll) + ry.Angle = math.radians(pitch) + rz.Angle = math.radians(yaw) + + return rz.multiply(ry).multiply(rx) + + angles = [] + angles.append((10,10,10)) + angles.append((13,45,-24)) + angles.append((10,-90,20)) + + for i in angles: + r = getYPR1(*i) + s = getYPR2(*i) + self.assertTrue(r.isSame(s, 1e-12)) + def testBounding(self): b=FreeCAD.BoundBox() b.setVoid() diff --git a/src/Mod/Tux/NavigationIndicatorGui.py b/src/Mod/Tux/NavigationIndicatorGui.py index 516c17258b..c49048c42c 100644 --- a/src/Mod/Tux/NavigationIndicatorGui.py +++ b/src/Mod/Tux/NavigationIndicatorGui.py @@ -288,6 +288,42 @@ def retranslateUi(): """ + global t9 + t9 = "

OpenSCAD " + text06 + """

+ + + + + + + + + + + + + + + +
""" + text01 + """""" + text02 + """""" + text02 + """""" + text03 + """""" + text04 + """
""" + + global t10 + t10 = "

TinkerCAD " + text06 + """

+ + + + + + + + + + + + + +
""" + text01 + """""" + text02 + """""" + text03 + """""" + text04 + """
""" + menuSettings.setTitle(translate("NavigationIndicator", "Settings")) menuOrbit.setTitle(translate("NavigationIndicator", "Orbit style")) aCompact.setText(translate("NavigationIndicator", "Compact")) @@ -384,6 +420,18 @@ a8.setText("OpenCascade") a8.setData("Gui::OpenCascadeNavigationStyle") a8.setObjectName("Indicator_NavigationOpenCascade") +a9 = QtGui.QAction(gStyle) +a9.setIcon(QtGui.QIcon(":/icons/NavigationOpenSCAD_dark.svg")) +a9.setText("OpenSCAD") +a9.setData("Gui::OpenSCADNavigationStyle") +a9.setObjectName("Indicator_NavigationOpenSCAD") + +a10 = QtGui.QAction(gStyle) +a10.setIcon(QtGui.QIcon(":/icons/NavigationTinkerCAD_dark.svg")) +a10.setText("TinkerCAD") +a10.setData("Gui::TinkerCADNavigationStyle") +a10.setObjectName("Indicator_NavigationTinkerCAD") + menu.addMenu(menuSettings) menu.addSeparator() menu.addAction(a0) @@ -395,6 +443,8 @@ menu.addAction(a5) menu.addAction(a6) menu.addAction(a7) menu.addAction(a8) +menu.addAction(a9) +menu.addAction(a10) def onCompact(): @@ -430,6 +480,8 @@ def onTooltip(): a6.setToolTip(t6) a7.setToolTip(t7) a8.setToolTip(t8) + a9.setToolTip(t9) + a10.setToolTip(t10) p.SetBool("Tooltip", 1) else: for i in gStyle.actions(): diff --git a/src/Mod/Tux/Resources/Tux.qrc b/src/Mod/Tux/Resources/Tux.qrc index e503675307..471f97fcc8 100644 --- a/src/Mod/Tux/Resources/Tux.qrc +++ b/src/Mod/Tux/Resources/Tux.qrc @@ -58,6 +58,17 @@ icons/NavigationOpenInventor_dark.svg icons/NavigationOpenInventor_ZoomAlt.svg icons/NavigationOpenInventor_Zoom.svg + icons/NavigationCAD_dark.svg + icons/NavigationOpenCascade_Select.svg + icons/NavigationOpenCascade_PanAlt.svg + icons/NavigationOpenCascade_PanAlt.svg + icons/NavigationOpenCascade_Select.svg + icons/NavigationGesture_Pan.svg + icons/NavigationCAD_dark.svg + icons/NavigationOpenCascade_Select.svg + icons/NavigationOpenCascade_Zoom.svg + icons/NavigationGesture_Pan.svg + icons/NavigationOpenCascade_PanAlt.svg icons/NavigationRevit_Pan.svg icons/NavigationRevit_Rotate.svg icons/NavigationRevit_light.svg diff --git a/src/Tools/makedist.py b/src/Tools/makedist.py index f4118fe68c..c054534fe8 100644 --- a/src/Tools/makedist.py +++ b/src/Tools/makedist.py @@ -5,23 +5,29 @@ # Python script to make source tarballs. # -import sys, os, getopt, tarfile, gzip, time, io, platform, shutil +import sys, os, getopt, tarfile, gzip, time, io, platform, shutil, subprocess def main(): bindir="." + major="0" + minor="0" dfsg=False check=False - wta="" + wta=None try: - opts, args = getopt.getopt(sys.argv[1:], "sb:", ["srcdir=","bindir=","dfsg", "check"]) + opts, args = getopt.getopt(sys.argv[1:], "sb:", ["srcdir=","bindir=","major=","minor=","dfsg", "check"]) except getopt.GetoptError: pass for o, a in opts: if o in ("-s", "--srcdir"): - print("%s is deprecated -- ignoring" % (o)) + print("{} is deprecated -- ignoring".format(o)) if o in ("-b", "--bindir"): bindir = a + if o in ("--major"): + major = a + if o in ("--minor"): + minor = a if o in ("--dfsg"): dfsg = True wta = "--worktree-attributes" @@ -41,14 +47,15 @@ def main(): info=os.popen("git rev-list HEAD").read() revision='%04d' % (info.count('\n')) - verfile = open("%s/src/Build/Version.h" % (bindir), 'r') - verstream = io.StringIO(verfile.read()) + verfile = open("{}/src/Build/Version.h".format(bindir), 'rb') + verstream = io.BytesIO(verfile.read()) verfile.close() - version_minor = verstream.getvalue().split('FCVersionMinor "')[1][:2] + version_major = major + version_minor = minor PACKAGE_NAME = 'freecad' - version = "0.%s.%s" % (version_minor, revision) + version = "{}.{}.{}".format(version_major, version_minor, revision) DIRNAME = "%(p)s-%(v)s" % {'p': PACKAGE_NAME, 'v': version} TARNAME = DIRNAME + '.tar' @@ -61,10 +68,13 @@ def main(): verinfo.size = len(verstream.getvalue()) verinfo.mtime = time.time() - print(("git archive %s --prefix=%s/ HEAD" % (wta, DIRNAME))) + if wta is None: + print(("git archive --prefix={}/ HEAD".format(DIRNAME))) + else: + print(("git archive {} --prefix={}/ HEAD".format(wta, DIRNAME))) + if platform.system() == 'Windows': - os.popen("git archive %s --prefix=%s/ --output=%s HEAD" - % (wta, DIRNAME, TARNAME)).read() + os.popen("git archive {} --prefix={}/ --output={} HEAD".format(wta, DIRNAME, TARNAME)).read() tar = tarfile.TarFile(mode="a", name=TARNAME) tar.addfile(verinfo, verstream) @@ -77,9 +87,15 @@ def main(): tardata.close() os.remove(TARNAME) else: - tardata = os.popen("git archive %s --prefix=%s/ HEAD" - % (wta, DIRNAME)).read() - tarstream = io.StringIO(tardata) + cmd_line = ["git", "archive"] + if not wta is None: + cmd_line.append(wta) + cmd_line.append("--prefix={}/".format(DIRNAME)) + cmd_line.append("HEAD") + + tardata = subprocess.Popen(cmd_line, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out,err = tardata.communicate() + tarstream = io.BytesIO(out) tar = tarfile.TarFile(mode="a", fileobj=tarstream) tar.addfile(verinfo, verstream) diff --git a/src/WindowsInstaller/README.md b/src/WindowsInstaller/README.md index 542f264de7..777ce80e43 100644 --- a/src/WindowsInstaller/README.md +++ b/src/WindowsInstaller/README.md @@ -20,7 +20,7 @@ To build the installer you can do the following: (You can alternatively get nsProcess from https://nsis.sourceforge.io/NsProcess_plugin) 7. Copy all FreeCAD files to the folder "~\FreeCAD" e.g. "C:\FreeCAD\Installer\FreeCAD" -8. If you use a version of FreeCAD that was compiled using another MSVC version than MSVC 2017, +8. If you use a version of FreeCAD that was compiled using another MSVC version than MSVC 2019, copy its distributable DLLs to the folder FILES_DEPS (see step 3). 9. Right-click on the file FreeCAD-installer.nsi and choose "Compile NSIS script" to compile the installer. diff --git a/src/WindowsInstaller/include/declarations.nsh b/src/WindowsInstaller/include/declarations.nsh index 03e26d9b6a..c63da6e971 100644 --- a/src/WindowsInstaller/include/declarations.nsh +++ b/src/WindowsInstaller/include/declarations.nsh @@ -26,9 +26,9 @@ Configuration and variables of FreeCAD installer !define APP_DIR_USERDATA ${APP_NAME} #!define APP_DIR_USERDATA "${APP_NAME}${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}" !define APP_INFO "${APP_NAME} - Your Own 3D Parametric Modeler" -!define APP_WEBPAGE "https://freecadweb.org/" +!define APP_WEBPAGE "https://freecad.org/" !define APP_WEBPAGE_INFO "${APP_NAME} Website" -!define APP_WIKI "https://www.freecadweb.org/wiki/Main_Page" +!define APP_WIKI "https://www.freecad.org/wiki/Main_Page" !define APP_WIKI_INFO "${APP_NAME} Wiki" !define APP_COPYRIGHT "${APP_NAME} is Copyright © 2001-${COPYRIGHT_YEAR} by the ${APP_NAME} Team" diff --git a/src/WindowsInstaller/include/gui.nsh b/src/WindowsInstaller/include/gui.nsh index ac0d6b5c80..16a285284f 100644 --- a/src/WindowsInstaller/include/gui.nsh +++ b/src/WindowsInstaller/include/gui.nsh @@ -66,7 +66,7 @@ BrandingText " " !define MUI_FINISHPAGE_SHOWREADME_FUNCTION StartFreeCAD !define MUI_FINISHPAGE_SHOWREADME_TEXT $(FinishPageRun) !define MUI_FINISHPAGE_LINK $(TEXT_FINISH_WEBSITE) -!define MUI_FINISHPAGE_LINK_LOCATION "https://freecadweb.org/" +!define MUI_FINISHPAGE_LINK_LOCATION "https://freecad.org/" #!define MUI_PAGE_CUSTOMFUNCTION_SHOW CheckDesktopShortcut !insertmacro MUI_PAGE_FINISH diff --git a/src/WindowsInstaller/lang/arabic.nsh b/src/WindowsInstaller/lang/arabic.nsh index a97346e770..f7771f51af 100644 --- a/src/WindowsInstaller/lang/arabic.nsh +++ b/src/WindowsInstaller/lang/arabic.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "هذا المساعد سوف يرشدك خلال #${LangFileString} TEXT_CONFIGURE_PYTHON "بناء سكربتات بايثون..." ${LangFileString} TEXT_FINISH_DESKTOP "إنشاء اختصار سطح المكتب" -${LangFileString} TEXT_FINISH_WEBSITE "زيارة freecadweb.org لمشاهدة آخر الاخبار, الدعم والأفكار" +${LangFileString} TEXT_FINISH_WEBSITE "زيارة freecad.org لمشاهدة آخر الاخبار, الدعم والأفكار" #${LangFileString} FileTypeTitle "مستند - ليك" diff --git a/src/WindowsInstaller/lang/basque.nsh b/src/WindowsInstaller/lang/basque.nsh index 981d11bf20..7f4bfe2c86 100644 --- a/src/WindowsInstaller/lang/basque.nsh +++ b/src/WindowsInstaller/lang/basque.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Morroi honek $(^NameDA) aplikazioaren instalazio #${LangFileString} TEXT_CONFIGURE_PYTHON "Python script-ak konpilatzen..." ${LangFileString} TEXT_FINISH_DESKTOP "Sortu mahaigaineko lasterbidea" -${LangFileString} TEXT_FINISH_WEBSITE "Bisitatu freecadweb.org azken berriak, aholkuak eta laguntza lortzeko" +${LangFileString} TEXT_FINISH_WEBSITE "Bisitatu freecad.org azken berriak, aholkuak eta laguntza lortzeko" #${LangFileString} FileTypeTitle "FreeCAD-dokumentua" diff --git a/src/WindowsInstaller/lang/catalan.nsh b/src/WindowsInstaller/lang/catalan.nsh index 12a77adc31..2c9c5d32dc 100644 --- a/src/WindowsInstaller/lang/catalan.nsh +++ b/src/WindowsInstaller/lang/catalan.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Aquest assistent us guiarà en la instal·lació #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org for the latest news, support and tips" #${LangFileString} FileTypeTitle "Document FreeCAD" diff --git a/src/WindowsInstaller/lang/czech.nsh b/src/WindowsInstaller/lang/czech.nsh index 807cf7c82e..399945e327 100644 --- a/src/WindowsInstaller/lang/czech.nsh +++ b/src/WindowsInstaller/lang/czech.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Tento pomocník vás provede instalací FreeCADu #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org for the latest news, support and tips" #${LangFileString} FileTypeTitle "FreeCAD-dokumentů" diff --git a/src/WindowsInstaller/lang/danish.nsh b/src/WindowsInstaller/lang/danish.nsh index 9c43044e6f..9ef681a349 100644 --- a/src/WindowsInstaller/lang/danish.nsh +++ b/src/WindowsInstaller/lang/danish.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Denne guide vil installere FreeCAD på din compu #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org for the latest news, support and tips" #${LangFileString} FileTypeTitle "FreeCAD-Dokument" diff --git a/src/WindowsInstaller/lang/dutch.nsh b/src/WindowsInstaller/lang/dutch.nsh index e3cc15322f..07ddce249d 100644 --- a/src/WindowsInstaller/lang/dutch.nsh +++ b/src/WindowsInstaller/lang/dutch.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Dit installatie programma zal FreeCAD op uw syst #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org for the latest news, support and tips" #${LangFileString} FileTypeTitle "FreeCAD-Document" diff --git a/src/WindowsInstaller/lang/english.nsh b/src/WindowsInstaller/lang/english.nsh index 138c5aada0..fcf401586c 100644 --- a/src/WindowsInstaller/lang/english.nsh +++ b/src/WindowsInstaller/lang/english.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "This wizard will guide you through the installat #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org/ for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org/ for the latest news, support and tips" #${LangFileString} FileTypeTitle "FreeCAD-Document" diff --git a/src/WindowsInstaller/lang/french.nsh b/src/WindowsInstaller/lang/french.nsh index 5b4132444f..c75e5b9ce5 100644 --- a/src/WindowsInstaller/lang/french.nsh +++ b/src/WindowsInstaller/lang/french.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Cet assistant va vous guider tout au long de l'i #${LangFileString} TEXT_CONFIGURE_PYTHON "Compilation des scripts Python..." ${LangFileString} TEXT_FINISH_DESKTOP "Créer un raccourci sur le bureau" -${LangFileString} TEXT_FINISH_WEBSITE "Consulter les dernières nouvelles, trucs et astuces sur le site freecadweb.org" +${LangFileString} TEXT_FINISH_WEBSITE "Consulter les dernières nouvelles, trucs et astuces sur le site freecad.org" #${LangFileString} FileTypeTitle "Document FreeCAD" diff --git a/src/WindowsInstaller/lang/galician.nsh b/src/WindowsInstaller/lang/galician.nsh index 48d684f2d9..f66e93e863 100644 --- a/src/WindowsInstaller/lang/galician.nsh +++ b/src/WindowsInstaller/lang/galician.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Este asistente vai-no guiar na instalación do F #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org for the latest news, support and tips" #${LangFileString} FileTypeTitle "Documento FreeCAD" diff --git a/src/WindowsInstaller/lang/german.nsh b/src/WindowsInstaller/lang/german.nsh index 44e831d58e..dbb04b10df 100644 --- a/src/WindowsInstaller/lang/german.nsh +++ b/src/WindowsInstaller/lang/german.nsh @@ -15,7 +15,7 @@ ${LangFileString} TEXT_WELCOME "Dieser Assistent wird Sie durch die Installation #${LangFileString} TEXT_CONFIGURE_PYTHON "Kompiliere Python Skripte..." ${LangFileString} TEXT_FINISH_DESKTOP "Ein Symbol auf der Arbeitsoberfläche erzeugen" -${LangFileString} TEXT_FINISH_WEBSITE "Besuchen Sie freecadweb.org für aktuelle Neuigkeiten" +${LangFileString} TEXT_FINISH_WEBSITE "Besuchen Sie freecad.org für aktuelle Neuigkeiten" #${LangFileString} FileTypeTitle "FreeCAD-Dokument" diff --git a/src/WindowsInstaller/lang/hungarian.nsh b/src/WindowsInstaller/lang/hungarian.nsh index 5230dc66a4..55e6ac43d5 100644 --- a/src/WindowsInstaller/lang/hungarian.nsh +++ b/src/WindowsInstaller/lang/hungarian.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "A varázsló segítségével tudja telepíteni a #${LangFileString} TEXT_CONFIGURE_PYTHON "Python parancsfájlok fordítása..." ${LangFileString} TEXT_FINISH_DESKTOP "Indítóikon létrehozása Asztalon" -${LangFileString} TEXT_FINISH_WEBSITE "Látogasson el a freecadweb.org oldalra az aktuális hírekért, támogatásért és tippekért" +${LangFileString} TEXT_FINISH_WEBSITE "Látogasson el a freecad.org oldalra az aktuális hírekért, támogatásért és tippekért" #${LangFileString} FileTypeTitle "FreeCAD-dokumentum" diff --git a/src/WindowsInstaller/lang/indonesian.nsh b/src/WindowsInstaller/lang/indonesian.nsh index 1b92dd13b3..09282cc38a 100644 --- a/src/WindowsInstaller/lang/indonesian.nsh +++ b/src/WindowsInstaller/lang/indonesian.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Program ini akan memandu anda dalam melakukan in #${LangFileString} TEXT_CONFIGURE_PYTHON "Proses kompilasi skrip Python ..." ${LangFileString} TEXT_FINISH_DESKTOP "Membuat pintasan ikon di destop" -${LangFileString} TEXT_FINISH_WEBSITE "Kunjungi freecadweb.org untuk berita terbaru serta dukungan" +${LangFileString} TEXT_FINISH_WEBSITE "Kunjungi freecad.org untuk berita terbaru serta dukungan" #${LangFileString} FileTypeTitle "Dokumen-FreeCAD" diff --git a/src/WindowsInstaller/lang/italian.nsh b/src/WindowsInstaller/lang/italian.nsh index 589ac1e945..4eff2860c0 100644 --- a/src/WindowsInstaller/lang/italian.nsh +++ b/src/WindowsInstaller/lang/italian.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Verrete guidati nell'installazione di $(^NameDA) #${LangFileString} TEXT_CONFIGURE_PYTHON "Compilazione degli script Python in corso..." ${LangFileString} TEXT_FINISH_DESKTOP "Crea icona sul desktop" -${LangFileString} TEXT_FINISH_WEBSITE "Visitate freecadweb.org per ultime novità, aiuto e suggerimenti" +${LangFileString} TEXT_FINISH_WEBSITE "Visitate freecad.org per ultime novità, aiuto e suggerimenti" #${LangFileString} FileTypeTitle "Documento di FreeCAD" diff --git a/src/WindowsInstaller/lang/japanese.nsh b/src/WindowsInstaller/lang/japanese.nsh index b973095539..7320c9cfdc 100644 --- a/src/WindowsInstaller/lang/japanese.nsh +++ b/src/WindowsInstaller/lang/japanese.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "このウィザードが、あなたのFreeCAD #${LangFileString} TEXT_CONFIGURE_PYTHON "Pythonスクリプトをコンパイルしています..." ${LangFileString} TEXT_FINISH_DESKTOP "デスクトップにショートカットを作成する" -${LangFileString} TEXT_FINISH_WEBSITE "freecadweb.orgを開いて最新ニュースやサポート、ヒントなどを入手する" +${LangFileString} TEXT_FINISH_WEBSITE "freecad.orgを開いて最新ニュースやサポート、ヒントなどを入手する" #${LangFileString} FileTypeTitle "FreeCAD文書" diff --git a/src/WindowsInstaller/lang/norwegian.nsh b/src/WindowsInstaller/lang/norwegian.nsh index 6069b9278f..2e3293b4f1 100644 --- a/src/WindowsInstaller/lang/norwegian.nsh +++ b/src/WindowsInstaller/lang/norwegian.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Denne veiviseren installerer FreeCAD på datamas #${LangFileString} TEXT_CONFIGURE_PYTHON "Kompilerer Python script..." ${LangFileString} TEXT_FINISH_DESKTOP "Lager snarveg på skrivebordet" -${LangFileString} TEXT_FINISH_WEBSITE "Besøk freecadweb.org for de seneste nyhetene, hjelp og støtte" +${LangFileString} TEXT_FINISH_WEBSITE "Besøk freecad.org for de seneste nyhetene, hjelp og støtte" #${LangFileString} FileTypeTitle "FreeCAD-dokument" diff --git a/src/WindowsInstaller/lang/polish.nsh b/src/WindowsInstaller/lang/polish.nsh index 861959f5a4..8e9ad43d90 100644 --- a/src/WindowsInstaller/lang/polish.nsh +++ b/src/WindowsInstaller/lang/polish.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Kreator przeprowadzi Ciebie przez proces instala #${LangFileString} TEXT_CONFIGURE_PYTHON "Kompilowanie skryptów Python..." ${LangFileString} TEXT_FINISH_DESKTOP "Utwórz skrót na pulpicie" -${LangFileString} TEXT_FINISH_WEBSITE "Odwiedź freecadweb.org by poznać wiadomości i wskazówki lub skorzystać ze wsparcia" +${LangFileString} TEXT_FINISH_WEBSITE "Odwiedź freecad.org by poznać wiadomości i wskazówki lub skorzystać ze wsparcia" #${LangFileString} FileTypeTitle "Dokument FreeCAD" diff --git a/src/WindowsInstaller/lang/portuguese.nsh b/src/WindowsInstaller/lang/portuguese.nsh index df7aa3fbb5..24757e9b59 100644 --- a/src/WindowsInstaller/lang/portuguese.nsh +++ b/src/WindowsInstaller/lang/portuguese.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Este assistente de instalação irá guiá-lo at #${LangFileString} TEXT_CONFIGURE_PYTHON "Compilando os scripts de Python..." ${LangFileString} TEXT_FINISH_DESKTOP "Criar um atalho no ambiente de trabalho" -${LangFileString} TEXT_FINISH_WEBSITE "Visite freecadweb.org para as últimas notícias, suporte e dicas" +${LangFileString} TEXT_FINISH_WEBSITE "Visite freecad.org para as últimas notícias, suporte e dicas" #${LangFileString} FileTypeTitle "Documento FreeCAD" diff --git a/src/WindowsInstaller/lang/portugueseBR.nsh b/src/WindowsInstaller/lang/portugueseBR.nsh index b2925508e4..2658c70d98 100644 --- a/src/WindowsInstaller/lang/portugueseBR.nsh +++ b/src/WindowsInstaller/lang/portugueseBR.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Este assistente guiará você durante a instala #${LangFileString} TEXT_CONFIGURE_PYTHON "Compilando scripts Python..." ${LangFileString} TEXT_FINISH_DESKTOP "Criar atalho na área de trabalho" -${LangFileString} TEXT_FINISH_WEBSITE "Visite freecadweb.org para ver as últimas novidades do FreeCAD!" +${LangFileString} TEXT_FINISH_WEBSITE "Visite freecad.org para ver as últimas novidades do FreeCAD!" #${LangFileString} FileTypeTitle "Documento-FreeCAD" diff --git a/src/WindowsInstaller/lang/romanian.nsh b/src/WindowsInstaller/lang/romanian.nsh index c95950fe2c..2dadf8a9c5 100644 --- a/src/WindowsInstaller/lang/romanian.nsh +++ b/src/WindowsInstaller/lang/romanian.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Acest asistent vă va ghida în procesul de inst #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org for the latest news, support and tips" #${LangFileString} FileTypeTitle "Document FreeCAD" diff --git a/src/WindowsInstaller/lang/russian.nsh b/src/WindowsInstaller/lang/russian.nsh index 92cc4169fd..879ebce14f 100644 --- a/src/WindowsInstaller/lang/russian.nsh +++ b/src/WindowsInstaller/lang/russian.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Этот мастер проведет вас ч #${LangFileString} TEXT_CONFIGURE_PYTHON "Компиляция скриптов Python..." ${LangFileString} TEXT_FINISH_DESKTOP "Создать ярлык на рабочем столе" -${LangFileString} TEXT_FINISH_WEBSITE "Перейти на freecadweb.org за новостями, поддержкой и советами" +${LangFileString} TEXT_FINISH_WEBSITE "Перейти на freecad.org за новостями, поддержкой и советами" #${LangFileString} FileTypeTitle "FreeCAD-Document" diff --git a/src/WindowsInstaller/lang/slovak.nsh b/src/WindowsInstaller/lang/slovak.nsh index 14e0aef61e..910538a125 100644 --- a/src/WindowsInstaller/lang/slovak.nsh +++ b/src/WindowsInstaller/lang/slovak.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Tento sprievodca Vám pomáha inštalovať FreeC #${LangFileString} TEXT_CONFIGURE_PYTHON "Kompilácia Python skriptov..." ${LangFileString} TEXT_FINISH_DESKTOP "Vytvoriť skratku pre pracovnú plochu" -${LangFileString} TEXT_FINISH_WEBSITE "Navštívte freecadweb.org pre posledné novinky, podporu a tipy" +${LangFileString} TEXT_FINISH_WEBSITE "Navštívte freecad.org pre posledné novinky, podporu a tipy" #${LangFileString} FileTypeTitle "FreeCAD dokument" diff --git a/src/WindowsInstaller/lang/spanish.nsh b/src/WindowsInstaller/lang/spanish.nsh index eb6c5a2079..3540bf480b 100644 --- a/src/WindowsInstaller/lang/spanish.nsh +++ b/src/WindowsInstaller/lang/spanish.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Este programa instalará FreeCAD en su ordenador #${LangFileString} TEXT_CONFIGURE_PYTHON "Compilando guiones Python..." ${LangFileString} TEXT_FINISH_DESKTOP "Crear acceso directo en el escritorio" -${LangFileString} TEXT_FINISH_WEBSITE "Visite freecadweb.org para últimas noticias, ayuda y consejos" +${LangFileString} TEXT_FINISH_WEBSITE "Visite freecad.org para últimas noticias, ayuda y consejos" #${LangFileString} FileTypeTitle "Documento FreeCAD" diff --git a/src/WindowsInstaller/lang/swedish.nsh b/src/WindowsInstaller/lang/swedish.nsh index 22bb333d20..0176d07b3f 100644 --- a/src/WindowsInstaller/lang/swedish.nsh +++ b/src/WindowsInstaller/lang/swedish.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Denna guide tar dig igenom installationen av $(^ #${LangFileString} TEXT_CONFIGURE_PYTHON "Kompilerar Pythonskript..." ${LangFileString} TEXT_FINISH_DESKTOP "Skapa skrivbordsgenväg" -${LangFileString} TEXT_FINISH_WEBSITE "Besök freecadweb.org för de senaste nyheterna, support och tips" +${LangFileString} TEXT_FINISH_WEBSITE "Besök freecad.org för de senaste nyheterna, support och tips" #${LangFileString} FileTypeTitle "FreeCAD-dokument" diff --git a/src/WindowsInstaller/lang/turkish.nsh b/src/WindowsInstaller/lang/turkish.nsh index dd1511abcf..12f4eedab2 100644 --- a/src/WindowsInstaller/lang/turkish.nsh +++ b/src/WindowsInstaller/lang/turkish.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "Bu sihirbaz size FreeCAD programını kuracak.$\ #${LangFileString} TEXT_CONFIGURE_PYTHON "Compiling Python scripts..." ${LangFileString} TEXT_FINISH_DESKTOP "Create desktop shortcut" -${LangFileString} TEXT_FINISH_WEBSITE "Visit freecadweb.org for the latest news, support and tips" +${LangFileString} TEXT_FINISH_WEBSITE "Visit freecad.org for the latest news, support and tips" #${LangFileString} FileTypeTitle "FreeCAD-Document" diff --git a/src/WindowsInstaller/lang/ukrainian.nsh b/src/WindowsInstaller/lang/ukrainian.nsh index d1e4f975f2..fac5191ab4 100644 --- a/src/WindowsInstaller/lang/ukrainian.nsh +++ b/src/WindowsInstaller/lang/ukrainian.nsh @@ -14,7 +14,7 @@ ${LangFileString} TEXT_WELCOME "За допомогою цього майстр #${LangFileString} TEXT_CONFIGURE_PYTHON "Обробка скриптів Python..." ${LangFileString} TEXT_FINISH_DESKTOP "Створити значок на стільниці" -${LangFileString} TEXT_FINISH_WEBSITE "Відвідати freecadweb.org, щоб ознайомитися з новинами, довідковими матеріалами та підказками" +${LangFileString} TEXT_FINISH_WEBSITE "Відвідати freecad.org, щоб ознайомитися з новинами, довідковими матеріалами та підказками" #${LangFileString} FileTypeTitle "Документ FreeCAD" diff --git a/src/WindowsInstaller/setup/configure.nsh b/src/WindowsInstaller/setup/configure.nsh index dae07512f0..d42ef4d6bb 100644 --- a/src/WindowsInstaller/setup/configure.nsh +++ b/src/WindowsInstaller/setup/configure.nsh @@ -45,9 +45,9 @@ Section -InstallData WriteRegStr SHCTX ${APP_UNINST_KEY} "DisplayVersion" "${APP_VERSION}" WriteRegStr SHCTX ${APP_UNINST_KEY} "DisplayIcon" "$INSTDIR\${APP_RUN}" WriteRegStr SHCTX ${APP_UNINST_KEY} "URLUpdateInfo" "${APP_WEBPAGE}" - WriteRegStr SHCTX ${APP_UNINST_KEY} "URLInfoAbout" "https://www.freecadweb.org/" + WriteRegStr SHCTX ${APP_UNINST_KEY} "URLInfoAbout" "https://www.freecad.org/" WriteRegStr SHCTX ${APP_UNINST_KEY} "Publisher" "${APP_NAME} Team" - WriteRegStr SHCTX ${APP_UNINST_KEY} "HelpLink" "https://forum.freecadweb.org/" + WriteRegStr SHCTX ${APP_UNINST_KEY} "HelpLink" "https://forum.freecad.org/" WriteRegDWORD SHCTX ${APP_UNINST_KEY} "NoModify" 0x00000001 WriteRegDWORD SHCTX ${APP_UNINST_KEY} "NoRepair" 0x00000001 WriteRegStr SHCTX ${APP_UNINST_KEY} "StartMenu" "$SMPROGRAMS\$StartmenuFolder"