File indexing completed on 2024-05-19 16:01:26

0001 /*  This file is part of the KDE libraries
0002     Copyright (C) 2002 Simon MacMullen <calligra@babysimon.co.uk>
0003     Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
0004 
0005     This library is free software; you can redistribute it and/or
0006     modify it under the terms of the GNU Library General Public
0007     License as published by the Free Software Foundation; either
0008     version 2 of the License, or (at your option) any later version.
0009 
0010     This library is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013     Library General Public License for more details.
0014 
0015     You should have received a copy of the GNU Library General Public License
0016     along with this library; see the file COPYING.LIB.  If not, write to
0017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 #include "calligracreator.h"
0021 
0022 // Calligra
0023 #include <KoPart.h>
0024 #include <KoStore.h>
0025 #include <KoDocument.h>
0026 #include <KoDocumentEntry.h>
0027 
0028 // Qt
0029 #include <QPainter>
0030 #include <QTimer>
0031 #include <QMimeDatabase>
0032 #include <QMimeType>
0033 
0034 static const int minThumbnailSize = 400;
0035 static const int timeoutTime = 5000; // in msec
0036 
0037 extern "C"
0038 {
0039     Q_DECL_EXPORT ThumbCreator *new_creator()
0040     {
0041         return new CalligraCreator;
0042     }
0043 }
0044 
0045 CalligraCreator::CalligraCreator()
0046     : m_part(0)
0047     , m_doc(0)
0048 {
0049 }
0050 
0051 CalligraCreator::~CalligraCreator()
0052 {
0053     delete m_doc;
0054 }
0055 
0056 bool CalligraCreator::create(const QString &path, int width, int height, QImage &image)
0057 {
0058     // try to use any embedded thumbnail
0059     KoStore *store = KoStore::createStore(path, KoStore::Read);
0060 
0061     if (store &&
0062          // ODF thumbnail?
0063         (store->open(QLatin1String("Thumbnails/thumbnail.png")) ||
0064          // old KOffice/Calligra thumbnail?
0065          store->open(QLatin1String("preview.png")) ||
0066          // OOXML?
0067          store->open(QLatin1String("docProps/thumbnail.jpeg")))) {
0068         // Hooray! No long delay for the user...
0069         const QByteArray thumbnailData = store->read(store->size());
0070 
0071         QImage thumbnail;
0072         if (thumbnail.loadFromData(thumbnailData) &&
0073             thumbnail.width() >= width && thumbnail.height() >= height) {
0074             // put a white background behind the thumbnail
0075             // as lots of old(?) OOo files have thumbnails with transparent background
0076             image = QImage(thumbnail.size(), QImage::Format_RGB32);
0077             image.fill(QColor(Qt::white).rgb());
0078             QPainter p(&image);
0079             p.drawImage(QPoint(0, 0), thumbnail);
0080             delete store;
0081             return true;
0082         }
0083     }
0084     delete store;
0085 
0086     // load document and render the thumbnail ourselves
0087     const QString mimetype = QMimeDatabase().mimeTypeForFile(path).name();
0088     QString error;
0089     KoDocumentEntry documentEntry = KoDocumentEntry::queryByMimeType(mimetype);
0090     m_part = documentEntry.createKoPart(&error);
0091 
0092 
0093     if (!m_part) return false;
0094 
0095     m_doc = m_part->document();
0096 
0097     // prepare the document object
0098     m_doc->setCheckAutoSaveFile(false);
0099     m_doc->setAutoErrorHandlingEnabled(false); // don't show message boxes
0100     connect(m_doc, SIGNAL(completed()), SLOT(onLoadingCompleted()));
0101 
0102     // load the document content
0103     m_loadingCompleted = false;
0104 
0105     const QUrl url = QUrl::fromLocalFile(path);
0106     if (!m_doc->openUrl(url)) {
0107         delete m_doc;
0108         m_doc = 0;
0109         return false;
0110     }
0111 
0112     if (! m_loadingCompleted) {
0113         // loading is done async, so wait here for a while
0114         // Using a QEventLoop here seems fine, thumbnailers are only used inside the
0115         // thumbnail protocol slave, it seems
0116         QTimer::singleShot(timeoutTime, &m_eventLoop, SLOT(quit()));
0117         m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
0118     }
0119 
0120     if (m_loadingCompleted) {
0121         // render the page on a bigger pixmap and use smoothScale,
0122         // looks better than directly scaling with the QPainter (malte)
0123         const bool usePassedSize = (width > minThumbnailSize && height > minThumbnailSize);
0124         const QSize size = usePassedSize ? QSize(width, height) : QSize(minThumbnailSize, minThumbnailSize);
0125         image = m_doc->generatePreview(size).toImage();
0126     }
0127 
0128     m_doc->closeUrl();
0129     delete m_doc;
0130     m_doc = 0;
0131 
0132     return m_loadingCompleted;
0133 }
0134 
0135 void CalligraCreator::onLoadingCompleted()
0136 {
0137     m_loadingCompleted = true;
0138     m_eventLoop.quit();
0139 }
0140 
0141 ThumbCreator::Flags CalligraCreator::flags() const
0142 {
0143 #ifdef NO_ICON_BLENDING
0144     return DrawFrame;
0145 #else
0146     return (Flags)(DrawFrame | BlendIcon);
0147 #endif
0148 }