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 }