From 58d12221a53b81ef70b097b8bbb26b88a89581bf Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 26 Nov 2025 20:53:11 +0100 Subject: [PATCH] Gui: Do not lose thumbnail when saving partially loaded doc (#25458) --- src/Gui/Document.cpp | 13 ++++++---- src/Gui/Thumbnail.cpp | 59 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index a9723a3e4d..07eae60f8a 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -1780,16 +1780,19 @@ void Document::Save(Base::Writer& writer) const int size = hGrp->GetInt("ThumbnailSize", 256); size = Base::clamp(size, 64, 512); std::list mdi = getMDIViews(); + + View3DInventorViewer* view = nullptr; for (const auto& it : mdi) { if (it->isDerivedFrom()) { - View3DInventorViewer* view = static_cast(it)->getViewer(); - d->thumb.setFileName(d->_pcDocument->FileName.getValue()); - d->thumb.setSize(size); - d->thumb.setViewer(view); - d->thumb.Save(writer); + view = static_cast(it)->getViewer(); break; } } + + d->thumb.setFileName(d->_pcDocument->FileName.getValue()); + d->thumb.setSize(size); + d->thumb.setViewer(view); + d->thumb.Save(writer); } } } diff --git a/src/Gui/Thumbnail.cpp b/src/Gui/Thumbnail.cpp index 9c324dfc45..824949bac8 100644 --- a/src/Gui/Thumbnail.cpp +++ b/src/Gui/Thumbnail.cpp @@ -32,6 +32,10 @@ #include #include #include +#ifdef _MSC_VER +# include +#endif +#include #include "Thumbnail.h" #include "BitmapFactory.h" @@ -82,17 +86,56 @@ void Thumbnail::Restore(Base::XMLReader& reader) void Thumbnail::SaveDocFile(Base::Writer& writer) const { + QImage img; + bool created = false; + + // 1. Try to create the thumbnail from the viewer + if (this->viewer) { + if (this->viewer->thread() != QThread::currentThread()) { + qWarning("Cannot create a thumbnail from non-GUI thread"); + } + else { + QColor invalid; + this->viewer->imageFromFramebuffer(this->size, this->size, 4, invalid, img); + created = !img.isNull(); + } + } + + // 2. If creation failed (e.g. no viewer or background thread), try to restore from the existing file + if (!created) { + QString filename = this->uri.toLocalFile(); + Base::FileInfo fi(filename.toUtf8().constData()); + if (fi.exists()) { + try { + zipios::ZipFile zf(fi.filePath()); + // getEntry uses default MatchPath=MATCH. + zipios::ConstEntryPointer entry = zf.getEntry("thumbnails/Thumbnail.png"); + if (entry && entry->isValid()) { + // getInputStream returns a pointer that must be deleted + std::istream* is = zf.getInputStream(entry); + if (is) { + if (is->good()) { + writer.Stream() << is->rdbuf(); + delete is; + return; + } + delete is; + } + } + } + catch (const std::exception&) { + // If the file isn't a zip or is locked, we ignore it and proceed to fallback + } + catch (...) { + // Ignore unknown exceptions + } + } + } + + // If we still have no image and no viewer to generate one, we can do nothing more if (!this->viewer) { return; } - QImage img; - if (this->viewer->thread() != QThread::currentThread()) { - qWarning("Cannot create a thumbnail from non-GUI thread"); - return; - } - - QColor invalid; - this->viewer->imageFromFramebuffer(this->size, this->size, 4, invalid, img); // Get app icon and resize to half size to insert in topbottom position over the current view // snapshot