5 #include <QOperatingSystemVersion>
12 #include "vymprocess.h"
14 #if defined(Q_OS_WINDOWS)
19 #if defined(Q_OS_MACX)
25 extern QString zipToolPath;
26 extern QString unzipToolPath;
27 extern bool zipToolAvailable;
28 extern bool unzipToolAvailable;
30 QString convertToRel(const QString &src, const QString &dst)
32 // Creates a relative path pointing from src to dst
39 // Special case, we just need the name of the file,
40 // not the complete path
41 i = d.lastIndexOf("/");
42 d = d.right(d.length() - i - 1);
45 // remove identical left parts
46 while (s.section("/", 0, 0) == d.section("/", 0, 0)) {
48 s = s.right(s.length() - i - 1);
49 d = d.right(d.length() - i - 1);
52 // Now take care of paths where we have to go back first
53 int srcsep = s.count("/");
62 QString convertToAbs(const QString &src, const QString &dst)
64 // Creates a relative path pointing from src to dst
66 return dd.absoluteFilePath(dst);
69 QString basename(const QString &path) { return path.section('/', -1); }
71 QString dirname(const QString &path) { return path.section('/', 0, -2); }
73 extern QString vymName;
74 bool confirmDirectoryOverwrite(const QDir &dir)
77 qWarning() << "Directory does not exist: " << dir.path();
81 QStringList eList = dir.entryList();
82 while (!eList.isEmpty() && (eList.first() == "." || eList.first() == ".."))
83 eList.pop_front(); // remove "." and ".."
85 if (!eList.isEmpty()) {
86 QMessageBox mb(vymName,
87 QObject::tr("The directory %1 is not empty.\nDo you "
88 "risk to overwrite its contents?",
91 QMessageBox::Warning, QMessageBox::Yes,
92 QMessageBox::Cancel | QMessageBox::Default,
93 QMessageBox::NoButton);
95 mb.setButtonText(QMessageBox::Yes, QObject::tr("Overwrite"));
96 mb.setButtonText(QMessageBox::No, QObject::tr("Cancel"));
98 case QMessageBox::Yes:
101 case QMessageBox::Cancel:
109 QString makeTmpDir(bool &ok, const QString &dirPath,
110 const QString &prefix)
112 QString path = makeUniqueDir(ok, dirPath + "/" + prefix + "-XXXXXX");
116 QString makeTmpDir(bool &ok, const QString &prefix)
118 return makeTmpDir(ok, QDir::tempPath(), prefix);
121 bool isInTmpDir(QString fn)
123 QString temp = QDir::tempPath();
124 int l = temp.length();
125 return fn.left(l) == temp;
128 QString makeUniqueDir(bool &ok, QString s) // FIXME-3 use QTemporaryDir
134 #if defined(Q_OS_WINDOWS)
137 // On Linux and friends use cstdlib
139 // Convert QString to string
142 int bytes = s.length();
143 p = (char *)malloc(bytes + 1);
145 for (i = 0; i < bytes; i++)
146 p[i] = s.at(i).unicode();
158 bool removeDir(QDir d)
160 // This check should_ not be necessary, but proved to be useful ;-)
161 if (!isInTmpDir(d.path())) {
162 qWarning() << "file.cpp::removeDir should remove " + d.path() +
167 return d.removeRecursively();
170 bool copyDir(QDir src, QDir dst, const bool &override)
173 src.entryList(QDir::AllDirs | QDir::Hidden | QDir::NoDotAndDotDot);
174 QStringList files = src.entryList(QDir::Files);
176 // Check if dst is a subdir of src, which would cause endless recursion...
177 if (dst.absolutePath().contains(src.absolutePath()))
180 // Traverse directories
181 QList<QString>::iterator d, f;
182 for (d = dirs.begin(); d != dirs.end(); ++d) {
183 if (!QFileInfo(src.path() + "/" + (*d)).isDir())
186 QDir cdir(dst.path() + "/" + (*d));
187 cdir.mkpath(cdir.path());
189 if (!copyDir(QDir(src.path() + "/" + (*d)),
190 QDir(dst.path() + "/" + (*d)), override))
195 for (f = files.begin(); f != files.end(); ++f) {
196 QFile cfile(src.path() + "/" + (*f));
197 QFile destFile(dst.path() + "/" +
198 src.relativeFilePath(cfile.fileName()));
199 if (destFile.exists() && override)
202 if (!cfile.copy(dst.path() + "/" +
203 src.relativeFilePath(cfile.fileName())))
214 dirList << "flags/user";
215 dirList << "flags/standard";
216 foreach (QString d, dirList)
217 if (QDir(d).exists() ) return true;
222 void makeSubDirs(const QString &s)
228 d.mkdir("flags/user");
229 d.mkdir("flags/standard");
234 zipToolAvailable = false;
235 #if defined(Q_OS_WINDOWS)
236 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10)
237 zipToolAvailable = true;
240 QFile tool(zipToolPath);
242 zipToolAvailable = tool.exists();
244 return zipToolAvailable;
247 bool checkUnzipTool()
249 unzipToolAvailable = false;
250 #if defined(Q_OS_WINDOWS)
251 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10)
252 zipToolAvailable = true;
254 QFile tool(unzipToolPath);
256 unzipToolAvailable = tool.exists();
258 return unzipToolAvailable;
261 ErrorCode zipDir(QDir zipInputDir, QString zipName)
263 zipName = QDir::toNativeSeparators(zipName);
264 ErrorCode err = Success;
266 QString symLinkTarget;
269 // Move existing file away
272 symLinkTarget = file.symLinkTarget();
273 QString zipNameTmp = zipName + ".tmp";
274 newName = zipNameTmp;
276 while (!file.rename(newName) && n < 5) {
278 zipNameTmp + QString().setNum(n);
282 QMessageBox::critical(0, QObject::tr("Critical Error"),
283 QObject::tr("Couldn't move existing file out "
284 "of the way before saving."));
289 // zip the temporary directory
290 VymProcess *zipProc = new VymProcess();
293 #if defined(Q_OS_WINDOWS)
294 zipProc->setWorkingDirectory(
295 QDir::toNativeSeparators(zipInputDir.path() + "\\"));
297 args << "-a" << "-c" << "--format" << "zip" << "-f" << zipName << "*";
299 zipProc->start(zipToolPath, args);
301 if (!zipProc->waitForStarted()) {
302 // zip could not be started
303 QMessageBox::critical(
304 0, QObject::tr("Critical Error"),
305 QObject::tr("Couldn't start %1 tool to compress data!\n"
306 "The map could not be saved, please check if "
308 "backup file is available or export as XML file!")
309 .arg("Windows zip") +
310 "\n\nziptoolpath: " + zipToolPath +
311 "\nargs: " + args.join(" "));
315 // zip could be started
316 zipProc->waitForFinished();
317 if (zipProc->exitStatus() != QProcess::NormalExit) {
318 QMessageBox::critical(0, QObject::tr("Critical Error"),
319 QObject::tr("zip didn't exit normally") +
320 "\n" + zipProc->getErrout());
325 QMessageBox::information( 0, QObject::tr( "Debug" ),
326 "Called:" + zipToolPath + "\n" +
327 "Args: " + args.join(" ") + "\n" +
328 "Exit: " + zipProc->exitCode() + "\n" +
329 "Err: " + zipProc->getErrout() + "\n" +
330 "Std: " + zipProc->getStdout() );
332 if (zipProc->exitCode() > 1) {
333 QMessageBox::critical(
334 0, QObject::tr("Error"),
335 "Called:" + zipToolPath + "\n" + "Args: " + args.join(" ") +
336 "\n" + "Exit: " + zipProc->exitCode() + "\n" +
337 "Err: " + zipProc->getErrout() + "\n" +
338 "Std: " + zipProc->getStdout());
341 else if (zipProc->exitCode() == 1) {
342 // Non fatal according to internet, but for example
343 // some file was locked and could not be compressed
344 QMessageBox::warning(
345 0, QObject::tr("Error"),
346 "Called:" + zipToolPath + "\n" + "Args: " + args.join(" ") +
347 "\n" + "Exit: " + zipProc->exitCode() + "\n" +
348 "Err: " + zipProc->getErrout() + "\n" +
349 "Std: " + zipProc->getStdout() +
351 "Please check the saved map, e.g. by opening in "
353 "Workaround if save failed: Export as xml");
357 // qDebug() <<"Output: " << zipProc->getStdout()<<flush;
359 zipProc->setWorkingDirectory(QDir::toNativeSeparators(zipInputDir.path()));
364 zipProc->start(zipToolPath, args);
365 if (!zipProc->waitForStarted()) {
366 // zip could not be started
367 QMessageBox::critical(
368 0, QObject::tr("Critical Error"),
369 QObject::tr("Couldn't start %1 tool to compress data!\n"
370 "The map could not be saved, please check if "
371 "backup file is available or export as XML file!")
373 "\n\nziptoolpath: " + zipToolPath +
374 "\nargs: " + args.join(" "));
378 // zip could be started
379 zipProc->waitForFinished();
380 if (zipProc->exitStatus() != QProcess::NormalExit) {
381 QMessageBox::critical(0, QObject::tr("Critical Error"),
382 QObject::tr("zip didn't exit normally") +
383 "\n" + zipProc->getErrout());
387 if (zipProc->exitCode() > 0) {
388 QMessageBox::critical(
389 0, QObject::tr("Critical Error"),
390 QString("zip exit code: %1").arg(zipProc->exitCode()) +
391 "\n" + zipProc->getErrout());
397 // Try to restore previous file, if zipping failed
398 if (err == Aborted && !newName.isEmpty() && !file.rename(zipName))
399 QMessageBox::critical(0, QObject::tr("Critical Error"),
400 QObject::tr("Couldn't rename %1 back to %2")
404 // Take care of symbolic link
405 if (!symLinkTarget.isEmpty()) {
406 if (!QFile(symLinkTarget).remove()) {
407 QMessageBox::critical(
408 0, QObject::tr("Critical Error"),
410 "Couldn't remove target of old symbolic link %1")
411 .arg(symLinkTarget));
416 if (!QFile(zipName).rename(symLinkTarget)) {
417 QMessageBox::critical(
418 0, QObject::tr("Critical Error"),
419 QObject::tr("Couldn't rename output to target of old "
421 .arg(symLinkTarget));
425 if (!QFile(symLinkTarget).link(zipName)) {
426 QMessageBox::critical(
427 0, QObject::tr("Critical Error"),
428 QObject::tr("Couldn't link from %1 to target of old "
431 .arg(symLinkTarget));
437 // Remove temporary file
438 if (!newName.isEmpty() && !file.remove())
439 QMessageBox::critical(
440 0, QObject::tr("Critical Error"),
441 QObject::tr("Saved %1, but couldn't remove %2")
449 File::ErrorCode unzipDir(QDir zipOutputDir, QString zipName)
451 ErrorCode err = Success;
453 VymProcess *zipProc = new VymProcess();
456 #if defined(Q_OS_WINDOWS)
457 zipProc->setWorkingDirectory(
458 QDir::toNativeSeparators(zipOutputDir.path() + "\\"));
459 args << "-x" << "-f" << zipName.toUtf8() << "-C" << zipOutputDir.path();
460 zipProc->start(zipToolPath, args);
462 zipProc->setWorkingDirectory(QDir::toNativeSeparators(zipOutputDir.path()));
463 args << "-o"; // overwrite existing files!
466 args << zipOutputDir.path();
468 zipProc->start(unzipToolPath, args);
470 if (!zipProc->waitForStarted()) {
471 QMessageBox::critical(
472 0, QObject::tr("Critical Error"),
473 QObject::tr("Couldn't start %1 tool to decompress data!\n")
474 .arg("Windows zip") +
475 "\n\nziptoolpath: " + zipToolPath +
476 "\nargs: " + args.join(" "));
480 zipProc->waitForFinished();
481 if (zipProc->exitStatus() != QProcess::NormalExit) {
482 QMessageBox::critical(
483 0, QObject::tr("Critical Error"),
484 QObject::tr("%1 didn't exit normally").arg(zipToolPath) +
485 zipProc->getErrout());
490 QMessageBox::information( 0, QObject::tr( "Debug" ),
491 "Called:" + zipToolPath + "\n" +
492 "Args: " + args.join(" ") + "\n" +
493 "Exit: " + zipProc->exitCode() + "\n" +
494 "Err: " + zipProc->getErrout() + "\n" +
495 "Std: " + zipProc->getStdout() );
497 if (zipProc->exitCode() > 1) {
498 QMessageBox::critical(
499 0, QObject::tr("Error"),
500 "Called:" + zipToolPath + "\n" + "Args: " + args.join(" ") +
501 "\n" + "Exit: " + zipProc->exitCode() + "\n" +
502 "Err: " + zipProc->getErrout() + "\n" +
503 "Std: " + zipProc->getStdout());
506 else if (zipProc->exitCode() == 1) {
507 // Non fatal according to internet, but for example
508 // some file was locked and could not be compressed
509 QMessageBox::warning(0, QObject::tr("Error"),
510 "Called:" + zipToolPath + "\n" +
511 "Args: " + args.join(" ") + "\n" +
512 "Exit: " + zipProc->exitCode() + "\n" +
513 "Err: " + zipProc->getErrout() + "\n" +
514 "Std: " + zipProc->getStdout() + "\n");
521 bool loadStringFromDisk(const QString &fname, QString &s)
525 if (!file.open(QFile::ReadOnly | QFile::Text)) {
526 qWarning() << QString("loadStringFromDisk: Cannot read file %1\n%2")
528 .arg(file.errorString());
532 QTextStream in(&file);
537 bool saveStringToDisk(const QString &fname, const QString &s)
540 // Write as binary (default), QFile::Text would convert linebreaks
541 if (!file.open(QFile::WriteOnly)) {
542 qWarning() << QString("saveStringToDisk: Cannot write file %1:\n%2.")
544 .arg(file.errorString());
548 QTextStream out(&file);
549 out.setCodec("UTF-8");
555 FileType getMapType(const QString &fn)
557 int i = fn.lastIndexOf(".");
559 QString postfix = fn.mid(i + 1);
560 if (postfix == "vym" || postfix == "vyp" || postfix == "xml" ||
571 // Create list with supported image types
572 // foreach (QByteArray format, QImageWriter::supportedImageFormats())
573 // imageTypes.append( tr("%1...").arg(QString(format).toUpper()));
575 "Images (*.png *.jpg *.jpeg *.bmp *.bmp *.ppm *.xpm *.xbm)");
576 imageTypes.append("PNG");
577 imageFilters.append("Portable Network Graphics (*.png)");
578 imageTypes.append("PNG");
579 imageFilters.append("Joint Photographic Experts Group (*.jpg)");
580 imageTypes.append("JPG");
581 imageFilters.append("Joint Photographic Experts Group (*.jpeg)");
582 imageTypes.append("JPG");
583 imageFilters.append("Windows Bitmap (*.bmp)");
584 imageTypes.append("BMP");
585 imageFilters.append("Portable Pixmap (*.ppm)");
586 imageTypes.append("PPM");
587 imageFilters.append("X11 Bitmap (*.xpm)");
588 imageTypes.append("XPM");
589 imageFilters.append("X11 Bitmap (*.xbm)");
590 imageTypes.append("XBM");
593 QStringList ImageIO::getFilters() { return imageFilters; }
595 QString ImageIO::getType(QString filter)
597 for (int i = 0; i < imageFilters.count() + 1; i++)
598 if (imageFilters.at(i) == filter)
599 return imageTypes.at(i);
603 QString ImageIO::guessType(QString fn)
605 int i = fn.lastIndexOf(".");
607 QString postfix = fn.mid(i + 1);
608 for (int i = 1; i < imageFilters.count(); i++)
609 if (imageFilters.at(i).contains(postfix))
610 return imageTypes.at(i);