From 8a80ce2ca44b7e992097be9dd23f99e172455a8c Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 15 Nov 2024 12:39:49 +0100 Subject: [PATCH] Start: fixes #17857: Icon-files of the startup screen are not removed from /tmp It's basically a port of #10951 to the new start page implementation. Note: Icon files are not removed but re-used instead. The commit adds some new functions: * getThumbnailsImage() Returns the name of the PNG inside a project file * getThumbnailsName() Returns the directory name containing the image files * getThumnailsParentDir() Returns the parent directory of the directory containing the image files * getThumbnailsDir() Returns the path to the thumbnail directory. There is no need to always create a unique directory after each restart because it doesn't harm if the thumbnail directoy contains deprecated files. * createThumbnailsDir() Creates the thumbnail directoy if it doesn't exist yet. * getSha1Hash Helper function to compute a SHA-1 hash of a given path. If the same path is passed then the hash value will be the same. This way it can be avoided to create a different image file from a project file after each restart. * getUniquePNG Computes the path of a PNG image file for a given project file. It's also possible to pass an arbitrary string as argument. * useCachedPNG If the PNG image exists and if it's newer than the project file True is returned and False otherwise. For a given project file it is checked if the thumbnail directory already contains a cached image. If it's newer than the project file it will used, otherwise it will be re-created. Fix freecadCanOpen() abd DisplayedFilesModel::addFile() to also check for lower-case file extensions. --- src/Mod/Start/App/DisplayedFilesModel.cpp | 107 +++++++++++++++++++--- src/Mod/Start/App/PreCompiled.h | 6 ++ 2 files changed, 102 insertions(+), 11 deletions(-) diff --git a/src/Mod/Start/App/DisplayedFilesModel.cpp b/src/Mod/Start/App/DisplayedFilesModel.cpp index 85ef1ff3a6..90fb26eeac 100644 --- a/src/Mod/Start/App/DisplayedFilesModel.cpp +++ b/src/Mod/Start/App/DisplayedFilesModel.cpp @@ -23,7 +23,11 @@ #include "PreCompiled.h" #ifndef _PreComp_ +#include #include +#include +#include +#include #include #include #endif @@ -31,6 +35,8 @@ #include "DisplayedFilesModel.h" #include #include +#include +#include using namespace Start; @@ -80,6 +86,68 @@ FileStats fileInfoFromFreeCADFile(const std::string& path) return result; } +std::string getThumbnailsImage() +{ + return "thumbnails/Thumbnail.png"; +} + +QString getThumbnailsName() +{ + return QString::fromLatin1("FreeCADStartThumbnails"); +} + +QDir getThumnailsParentDir() +{ + return QDir::temp(); +} + +QString getThumbnailsDir() +{ + QDir dir = getThumnailsParentDir(); + return dir.absoluteFilePath(getThumbnailsName()); +} + +void createThumbnailsDir() +{ + QString name = getThumbnailsName(); + QDir dir(getThumnailsParentDir()); + if (!dir.exists(name)) { + dir.mkpath(name); + } +} + +QString getSha1Hash(const std::string& path) +{ + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(path.c_str(), static_cast(path.size())); + QByteArray ba1 = hash.result().toHex(); + hash.reset(); + hash.addData(ba1); + QByteArray ba2 = hash.result().toHex(); + return QString::fromLatin1(ba2); +} + +QString getUniquePNG(const std::string& path) +{ + QDir dir = getThumbnailsDir(); + QString sha1 = getSha1Hash(path) + QLatin1String(".png"); + return dir.absoluteFilePath(sha1); +} + +bool useCachedPNG(const std::string& image, const std::string& project) +{ + Base::FileInfo f1(image); + Base::FileInfo f2(project); + if (!f1.exists()) { + return false; + } + if (!f2.exists()) { + return false; + } + + return f1.lastModified() > f2.lastModified(); +} + /// Load the thumbnail image data (if any) that is stored in an FCStd file. /// \returns The image bytes, or an empty QByteArray (if no thumbnail was stored) QByteArray loadFCStdThumbnail(const std::string& pathToFCStdFile) @@ -87,9 +155,20 @@ QByteArray loadFCStdThumbnail(const std::string& pathToFCStdFile) App::ProjectFile proj(pathToFCStdFile); if (proj.loadDocument()) { try { - std::string thumbnailFile = proj.extractInputFile("thumbnails/Thumbnail.png"); - if (!thumbnailFile.empty()) { - auto inputFile = QFile(QString::fromStdString(thumbnailFile)); + std::string thumbnailFile = getUniquePNG(pathToFCStdFile).toStdString(); + if (!useCachedPNG(thumbnailFile, pathToFCStdFile)) { + static std::string thumb = getThumbnailsImage(); + if (proj.containsFile(thumb)) { + createThumbnailsDir(); + Base::FileInfo fi(thumbnailFile); + Base::ofstream str(fi); + proj.readInputFileDirect(thumb, str); + str.close(); + } + } + + auto inputFile = QFile(QString::fromStdString(thumbnailFile)); + if (inputFile.exists()) { inputFile.open(QIODevice::OpenModeFlag::ReadOnly); return inputFile.readAll(); } @@ -115,6 +194,19 @@ FileStats getFileInfo(const std::string& path) result.insert(std::make_pair(DisplayedFilesModelRoles::baseName, file.fileName())); return result; } + +bool freecadCanOpen(const QString& extension) +{ + std::string ext = extension.toStdString(); + auto importTypes = App::GetApplication().getImportTypes(); + return std::find_if(importTypes.begin(), + importTypes.end(), + [&ext](const auto& item) { + return boost::iequals(item, ext); + }) + != importTypes.end(); +} + } // namespace DisplayedFilesModel::DisplayedFilesModel(QObject* parent) @@ -177,13 +269,6 @@ QVariant DisplayedFilesModel::data(const QModelIndex& index, int roleAsInt) cons return {}; } -bool freecadCanOpen(const QString& extension) -{ - auto importTypes = App::GetApplication().getImportTypes(); - return std::find(importTypes.begin(), importTypes.end(), extension.toStdString()) - != importTypes.end(); -} - void DisplayedFilesModel::addFile(const QString& filePath) { QFileInfo qfi(filePath); @@ -194,7 +279,7 @@ void DisplayedFilesModel::addFile(const QString& filePath) return; } _fileInfoCache.emplace_back(getFileInfo(filePath.toStdString())); - if (qfi.completeSuffix() == QLatin1String("FCStd")) { + if (qfi.completeSuffix().toLower() == QLatin1String("fcstd")) { auto thumbnail = loadFCStdThumbnail(filePath.toStdString()); if (!thumbnail.isEmpty()) { _imageCache.insert(filePath, thumbnail); diff --git a/src/Mod/Start/App/PreCompiled.h b/src/Mod/Start/App/PreCompiled.h index acbd41c945..7359854941 100644 --- a/src/Mod/Start/App/PreCompiled.h +++ b/src/Mod/Start/App/PreCompiled.h @@ -42,7 +42,13 @@ #include #include +// boost +#include + // Qt (should never include GUI files, only QtCore) +#include +#include +#include #include #include #include