diff --git a/src/Mod/Start/App/DisplayedFilesModel.cpp b/src/Mod/Start/App/DisplayedFilesModel.cpp index 85ef1ff3a60b..90fb26eeacca 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 acbd41c9450e..7359854941bb 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