File indexing completed on 2024-05-12 16:28:26

0001 /*
0002  * This file is part of Calligra
0003  *
0004  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
0005  *
0006  * Contact: Thorsten Zachmann thorsten.zachmann@nokia.com
0007  *
0008  * This library is free software; you can redistribute it and/or
0009  * modify it under the terms of the GNU Lesser General Public License
0010  * version 2.1 as published by the Free Software Foundation.
0011  *
0012  * This library is distributed in the hope that it will be useful, but
0013  * WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library; if not, write to the Free Software
0019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020  * 02110-1301 USA
0021  *
0022  */
0023 #include <KoDocument.h>
0024 #include <KoPADocument.h>
0025 #include <KWDocument.h>
0026 #include <sheets/part/Doc.h>
0027 #include <KoPart.h>
0028 #include <KoPluginLoader.h>
0029 #include <KoDocumentEntry.h>
0030 
0031 #include <QApplication>
0032 #include <QCommandLineParser>
0033 #include <QBuffer>
0034 #include <QDir>
0035 #include <QFileInfo>
0036 #include <QImage>
0037 #include <QTimer>
0038 #include <QMimeDatabase>
0039 #include <QDebug>
0040 
0041 #include "CSThumbProviderStage.h"
0042 #include "CSThumbProviderTables.h"
0043 #include "CSThumbProviderWords.h"
0044 
0045 #include "config_cstester.h"
0046 
0047 #ifdef BUILD_KARBON
0048 #include <KarbonPart.h>
0049 #include <KarbonDocument.h>
0050 #include "CSThumbProviderKarbon.h"
0051 #endif
0052 
0053 KoDocument* openFile(const QString &filename)
0054 {
0055     const QString mimetype = QMimeDatabase().mimeTypeForFile(filename).name();
0056 
0057     KoPart *part;
0058     QString error;
0059     QList<QPluginLoader *> pluginLoaders = KoPluginLoader::pluginLoaders(QStringLiteral("calligra/parts"), mimetype);
0060     if (!pluginLoaders.isEmpty()) {
0061         // take first
0062         KoDocumentEntry entry(pluginLoaders.takeFirst());
0063         qDeleteAll(pluginLoaders);
0064         part = entry.createKoPart(&error);
0065     } else {
0066         error = "Could not find component";
0067     }
0068 
0069     if (!error.isEmpty()) {
0070         qWarning() << "Error creating document" << mimetype << error;
0071         return 0;
0072     }
0073 
0074     KoDocument *document = part->document();
0075 
0076     if (0 != document) {
0077         QUrl url = QUrl::fromLocalFile(filename);
0078 
0079         document->setCheckAutoSaveFile(false);
0080         document->setAutoErrorHandlingEnabled(false);
0081 
0082         if (document->openUrl(url)) {
0083             document->setReadWrite(false);
0084         }
0085         else {
0086             qWarning()<< "openUrl failed" << filename << mimetype << error;
0087             delete document;
0088             document = 0;
0089         }
0090     }
0091     return document;
0092 }
0093 
0094 QString saveFile(KoDocument *document, const QString &filename, const QString &outname)
0095 {
0096     QString saveAs = outname;
0097     // use the name and add -roundtrip
0098     if (outname.isEmpty()) {
0099         saveAs = filename;
0100         int dotPos = saveAs.lastIndexOf('.');
0101         if (dotPos != -1) {
0102             saveAs.truncate(dotPos);
0103         }
0104         saveAs += "-roundtrip";
0105     }
0106 
0107     QByteArray mimetype = document->nativeFormatMimeType();
0108     QMimeType mime = QMimeDatabase().mimeTypeForName(mimetype);
0109     Q_ASSERT(mime.isValid());
0110     QString extension = mime.preferredSuffix();
0111     saveAs += extension;
0112 
0113     QUrl url = QUrl::fromLocalFile(saveAs);
0114     document->setOutputMimeType(mimetype, 0);
0115     document->saveAs(url);
0116     qDebug() << "save done";
0117     return saveAs;
0118 }
0119 
0120 QVector<QImage> createThumbnails(KoDocument *document, const QSize &thumbSize)
0121 {
0122     CSThumbProvider *tp = 0;
0123 
0124     if (KoPADocument *doc = qobject_cast<KoPADocument*>(document)) {
0125         tp = new CSThumbProviderStage(doc);
0126     }
0127     else if (Calligra::Sheets::Doc *doc = qobject_cast<Calligra::Sheets::Doc*>(document)) {
0128         tp = new CSThumbProviderTables(doc);
0129     }
0130     else if (KWDocument *doc = qobject_cast<KWDocument*>(document)) {
0131         tp = new CSThumbProviderWords(doc);
0132     }
0133 #ifdef BUILD_KARBON
0134     else if (KarbonDocument *doc = qobject_cast<KarbonDocument *>(document)) {
0135         tp = new CSThumbProviderKarbon(doc);
0136     }
0137 #endif
0138 
0139     return tp ? tp->createThumbnails(thumbSize) : QVector<QImage>();
0140 }
0141 
0142 void saveThumbnails(const QVector<QImage> &thumbnails, const QString &dir)
0143 {
0144     int i = 0;
0145     for (QVector<QImage>::const_iterator it(thumbnails.constBegin()); it != thumbnails.constEnd(); ++it) {
0146         // it is not possible to use QString("%1/thumb_%2.png").arg(dir).arg(++i);
0147         // as dir can contain % values which then might or might not be overwritten by the second arg
0148         QString thumbFilename = dir + QString("/thumb_%2.png").arg(++i);
0149         it->save(thumbFilename, "PNG");
0150     }
0151 }
0152 
0153 void saveThumbnails(const QFileInfo &file, const QVector<QImage> &thumbnails, const QString &outdir)
0154 {
0155     QDir dir(outdir);
0156     QString checkSubDir(file.fileName() + ".check");
0157     dir.mkdir(checkSubDir);
0158     saveThumbnails(thumbnails, outdir + '/' + checkSubDir);
0159 }
0160 
0161 bool checkThumbnails(const QVector<QImage> &thumbnails, const QString &dir, bool verbose)
0162 {
0163     bool success = true;
0164     int i = 0;
0165     for (QVector<QImage>::const_iterator it(thumbnails.constBegin()); it != thumbnails.constEnd(); ++it) {
0166         QString thumbFilename = dir + QString("/thumb_%2.png").arg(++i);
0167 
0168         QByteArray ba;
0169         QBuffer buffer(&ba);
0170         buffer.open(QIODevice::WriteOnly);
0171         it->save(&buffer, "PNG");
0172 
0173         QFile file(thumbFilename);
0174         if (!file.open(QFile::ReadOnly)) {
0175             return false;
0176         }
0177         QByteArray baCheck(file.readAll());
0178 
0179         if (ba != baCheck) {
0180             qDebug() << "Check failed:" << dir << "Page" << i << "differ";
0181             success = false;
0182         }
0183         else if (verbose) {
0184             qDebug() << "Check successful:" << dir << "Page" << i << "identical";
0185         }
0186     }
0187     return success;
0188 }
0189 
0190 bool checkThumbnails(const QVector<QImage> &thumbnails, const QVector<QImage> &others, bool verbose)
0191 {
0192     bool success = true;
0193     if (thumbnails.size() != others.size()) {
0194         qDebug() << "Check failed: number of pages different" << thumbnails.size() << "!=" << others.size();
0195         return false;
0196     }
0197     int i = 1;
0198     QVector<QImage>::const_iterator it(thumbnails.constBegin());
0199     QVector<QImage>::const_iterator oIt(others.constBegin());
0200 
0201     for (; it != thumbnails.constEnd(); ++it, ++oIt, ++i) {
0202         QByteArray ba;
0203         QBuffer buffer(&ba);
0204         buffer.open(QIODevice::WriteOnly);
0205         it->save(&buffer, "PNG");
0206 
0207         QByteArray baCheck;
0208         QBuffer oBuffer(&baCheck);
0209         oBuffer.open(QIODevice::WriteOnly);
0210         oIt->save(&oBuffer, "PNG");
0211 
0212         if (ba != baCheck) {
0213             qDebug() << "Check failed:" << "Page" << i << "differ";
0214             success = false;
0215         }
0216         else if (verbose) {
0217             qDebug() << "Check successful:" << "Page" << i << "identical";
0218         }
0219     }
0220     return success;
0221 }
0222 
0223 int main(int argc, char *argv[])
0224 {
0225     QApplication app(argc, argv);
0226     QApplication::setApplicationName("cstester");
0227 
0228     QCommandLineParser parser;
0229     parser.addHelpOption();
0230     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("create"), i18n("create verification data for file")));
0231     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("indir"), i18n("directory to read the data from"), QStringLiteral("dir")));
0232     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("outdir"), i18n("directory to save the data to"), QStringLiteral("dir")));
0233     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("roundtrip"), i18n("load/save/load and check the document is the same after load and save/load")));
0234     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("verbose"), i18n("be verbose")));
0235     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("verify"), i18n("verify the file")));
0236 
0237     parser.addPositionalArgument(QStringLiteral("file"), i18n("file to use"));
0238 
0239     parser.process(app);
0240 
0241     bool create = false;
0242     bool roundtrip = false;
0243     bool verify = false;
0244     int optionCount = 0;
0245 
0246     if (parser.isSet("create")) {
0247         create = true;
0248         optionCount++;
0249     }
0250     if (parser.isSet("roundtrip")) {
0251         roundtrip = true;
0252         optionCount++;
0253     }
0254     if (parser.isSet("verify")) {
0255         verify = true;
0256         optionCount++;
0257     }
0258 
0259     if (optionCount > 1) {
0260         qCritical() << "create, roundtrip and verify cannot be used the same time";
0261         exit(1);
0262     }
0263     else if (optionCount < 1) {
0264         qCritical() << "one of the options create, roundtrip or verify needs to be specified";
0265         exit(1);
0266     }
0267 
0268     QString outDir;
0269     if (parser.isSet("outdir")) {
0270         // check if it is a directory
0271         QDir dir(parser.value("outdir"));
0272         if (!dir.exists()) {
0273             qCritical() << "outdir" << parser.value("outdir") << "does not exist";
0274             exit(1);
0275         }
0276         outDir = dir.path();
0277     }
0278 
0279     QString inDir;
0280     if (parser.isSet("indir")) {
0281         // check if it is a directory
0282         QDir dir(parser.value("indir"));
0283         if (!dir.exists()) {
0284             qCritical() << "indir" << parser.value("indir") << "does not exist";
0285             exit(1);
0286         }
0287         inDir = dir.path();
0288     }
0289 
0290     bool verbose = parser.isSet("verbose");
0291 
0292     int exitValue = 0;
0293 
0294     int successful = 0;
0295     int failed = 0;
0296     foreach(const QString &filename, parser.positionalArguments()) {
0297         QFileInfo file(filename);
0298         QString checkDir;
0299         if (!parser.isSet("indir")) {
0300             checkDir = filename + ".check";
0301         }
0302         else {
0303             checkDir = inDir + '/' + file.fileName() + ".check";
0304         }
0305 
0306         // this is wrong for multiple files in different dirs
0307         if (!parser.isSet("outdir")) {
0308             outDir = file.path();
0309         }
0310 
0311         qDebug() << "filename" << filename << "path" << file.path() << file.completeBaseName() << checkDir << file.absoluteFilePath();
0312         qDebug() << "inDir" << inDir << "outDir" << outDir << "checkDir" << checkDir;
0313 
0314         // filename must be a absolute path
0315         KoDocument* document = openFile(file.absoluteFilePath());
0316         if (!document) {
0317             exit(2);
0318         }
0319 
0320         QVector<QImage> thumbnails(createThumbnails(document, QSize(800,800)));
0321 
0322         qDebug() << "created" << thumbnails.size() << "thumbnails";
0323         if (create) {
0324             saveThumbnails(file, thumbnails, outDir);
0325         }
0326         else if (verify) {
0327             if (parser.isSet("outdir")) {
0328                 saveThumbnails(file, thumbnails, outDir);
0329             }
0330             if (checkThumbnails(thumbnails, checkDir, verbose)) {
0331                 ++successful;
0332             }
0333             else {
0334                 ++failed;
0335                 exitValue = 2;
0336             }
0337         }
0338         else if (roundtrip) {
0339             QString rFilename = saveFile(document, filename, "cstester-roundtrip");
0340             delete document;
0341             QFileInfo rFile(rFilename);
0342             qDebug() << roundtrip << "rFilename" << rFilename << rFile.absoluteFilePath();
0343             document = openFile(rFile.absoluteFilePath());
0344             QVector<QImage> others(createThumbnails(document, QSize(800,800)));
0345             if (parser.isSet("outdir")) {
0346                 saveThumbnails(file, others, outDir);
0347                 saveThumbnails(file, thumbnails, outDir + "/before");
0348             }
0349             if (checkThumbnails(thumbnails, others, verbose)) {
0350                 ++successful;
0351             }
0352             else {
0353                 ++failed;
0354                 exitValue = 2;
0355             }
0356         }
0357         delete document;
0358     }
0359 
0360     if (verify || roundtrip) {
0361         qDebug() << "Totals:" << successful << "passed" << failed << "failed";
0362     }
0363 
0364     QTimer::singleShot(1, &app, SLOT(quit()));
0365     app.exec();
0366     return exitValue;
0367 }