File indexing completed on 2024-05-12 16:01:44

0001 /*
0002  * SPDX-FileCopyrightText: 2015 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  */
0006 #include "KisApplicationArguments.h"
0007 
0008 #include <QCommandLineParser>
0009 #include <QCommandLineOption>
0010 #include <QApplication>
0011 #include <QDir>
0012 #include <QStringList>
0013 #include <QString>
0014 #include <QDebug>
0015 #include <QDataStream>
0016 #include <QBuffer>
0017 
0018 #include <KoResourcePaths.h>
0019 #include <klocalizedstring.h>
0020 #include <KisPart.h>
0021 #include <KisDocument.h>
0022 
0023 struct Q_DECL_HIDDEN KisApplicationArguments::Private
0024 {
0025     Private()
0026     {
0027     }
0028 
0029     QStringList filenames;
0030     int dpiX {72};
0031     int dpiY {72};
0032     bool doTemplate {false};
0033     bool exportAs {false};
0034     bool exportSequence {false};
0035     QString exportFileName;
0036     QString workspace;
0037     QString windowLayout;
0038     QString session;
0039     QString fileLayer;
0040     bool canvasOnly {false};
0041     bool noSplash {false};
0042     bool fullScreen {false};
0043 
0044     bool newImage {false};
0045     QString colorModel {"RGBA"};
0046     QString colorDepth {"U8"};
0047     int width {2000};
0048     int height {5000};
0049 
0050 };
0051 
0052 
0053 KisApplicationArguments::KisApplicationArguments()
0054     : d(new Private)
0055 {
0056 }
0057 
0058 
0059 KisApplicationArguments::~KisApplicationArguments()
0060 {
0061 }
0062 
0063 KisApplicationArguments::KisApplicationArguments(const QApplication &app)
0064     : d(new Private)
0065 {
0066     QCommandLineParser parser;
0067     parser.addVersionOption();
0068     parser.addHelpOption();
0069     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("template"), i18n("Open a new document with a template")));
0070     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("new-image"), i18n("Create a new image.\n"
0071                                                                                           "Possible colorspace values are:\n"
0072                                                                                           "    * RGBA\n"
0073                                                                                           "    * XYZA\n"
0074                                                                                           "    * LABA\n"
0075                                                                                           "    * CMYKA\n"
0076                                                                                           "    * GRAY\n"
0077                                                                                           "    * YCbCrA\n"
0078                                                                                           "Possible channel depth arguments are\n"
0079                                                                                           "    * U8 (8 bits integer)\n"
0080                                                                                           "    * U16 (16 bits integer)\n"
0081                                                                                           "    * F16 (16 bits floating point)\n"
0082                                                                                           "    * F32 (32 bits floating point)\n"),
0083                                         QLatin1String("colorspace,depth,width,height")));
0084     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("workspace"), i18n("The name of the workspace to open Krita with"), QLatin1String("workspace")));
0085     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("windowlayout"), i18n("The name of the window layout to open Krita with"), QLatin1String("windowlayout")));
0086     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("load-session"), i18n("The name of the session to open Krita with"), QLatin1String("load-session"))); // NB: the argument "session" is already used by QGuiApplication
0087     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("canvasonly"), i18n("Start Krita in canvas-only mode")));
0088     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("nosplash"), i18n("Do not show the splash screen")));
0089     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("fullscreen"), i18n("Start Krita in full-screen mode")));
0090     {
0091         QCommandLineOption opt(QStringList() << QLatin1String("dpi"), i18n("Override display DPI"), QLatin1String("dpiX,dpiY"));
0092         opt.setFlags(QCommandLineOption::HiddenFromHelp);
0093         parser.addOption(opt);
0094     }
0095     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("export"), i18n("Export to the given filename and exit")));
0096     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("export-sequence"), i18n("Export animation to the given filename and exit")));
0097     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("export-filename"), i18n("Filename for export"), QLatin1String("filename")));
0098     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("file-layer"), i18n("File layer to be added to existing or new file"), QLatin1String("file-layer")));
0099     parser.addOption(QCommandLineOption(QStringList() << QLatin1String("resource-location"), i18n("A location that overrides the configured location for Krita's resources"), QLatin1String("file-layer")));
0100     parser.addPositionalArgument(QLatin1String("[file(s)]"), i18n("File(s) or URL(s) to open"));
0101 
0102     QStringList filteredArgs;
0103     {
0104         auto checkIsIgnoreEpic = [](const QString &arg) {
0105             // List according to https://dev.epicgames.com/docs/services/en-US/Interfaces/Auth/index.html#epicgameslauncher
0106             static const QStringList epicIgnoreArgsStart = {
0107                 QStringLiteral("AUTH_PASSWORD="),
0108                 QStringLiteral("AUTH_LOGIN="),
0109                 QStringLiteral("AUTH_TYPE="),
0110                 QStringLiteral("epicapp="),
0111                 QStringLiteral("epicenv="),
0112                 QStringLiteral("epicusername="),
0113                 QStringLiteral("epicuserid="),
0114                 QStringLiteral("epiclocale="),
0115                 QStringLiteral("epicsandboxid="),
0116             };
0117             static const QStringList epicIgnoreArgsExact = {
0118                 QStringLiteral("EpicPortal"),
0119             };
0120             QStringRef argDashless(&arg);
0121             // Strip leading dashes.
0122             while (argDashless.startsWith('-')) {
0123                 argDashless = argDashless.mid(1);
0124             }
0125             Q_FOREACH(const auto &argToIgnore, epicIgnoreArgsStart) {
0126                 if (argDashless.startsWith(argToIgnore, Qt::CaseInsensitive)) {
0127                     return true;
0128                 }
0129             }
0130             Q_FOREACH(const auto &argToIgnore, epicIgnoreArgsExact) {
0131                 if (argDashless.compare(argToIgnore, Qt::CaseInsensitive) == 0) {
0132                     return true;
0133                 }
0134             }
0135             return false;
0136         };
0137 
0138         QStringListIterator iter(app.arguments());
0139         if (iter.hasNext()) {
0140             // First argument is application name.
0141             filteredArgs.append(iter.next());
0142 
0143             bool isAfterDoubleDash = false;
0144             while (iter.hasNext()) {
0145                 QString arg = iter.next();
0146                 if (arg == QLatin1String("--")) {
0147                     isAfterDoubleDash = true;
0148                 }
0149                 if (isAfterDoubleDash || !checkIsIgnoreEpic(arg)) {
0150                     filteredArgs.append(arg);
0151                 }
0152             }
0153         }
0154     }
0155 
0156     parser.process(filteredArgs);
0157 
0158     QString dpiValues = parser.value("dpi");
0159     if (!dpiValues.isEmpty()) {
0160         qWarning() << "The `dpi` argument does nothing!";
0161     }
0162 
0163     QString newImageValues = parser.value("new-image");
0164     d->newImage = !newImageValues.isEmpty();
0165     if (d->newImage) {
0166         QStringList v = newImageValues.split(",");
0167         if (v.size() != 4) {
0168             d->newImage = false;
0169             qWarning() << "Cannot create a new image: please specify colormodel, depth, width and height.";
0170         }
0171         d->colorModel = v[0].toUpper();
0172         d->colorDepth = v[1].toUpper();
0173         d->width = v[2].toInt();
0174         d->height = v[3].toInt();
0175     }
0176 
0177     d->fileLayer = parser.value("file-layer");
0178     d->exportFileName = parser.value("export-filename");
0179     d->workspace = parser.value("workspace");
0180     d->windowLayout = parser.value("windowlayout");
0181     d->session = parser.value("load-session");
0182     d->doTemplate = parser.isSet("template");
0183     d->exportAs = parser.isSet("export");
0184     d->exportSequence = parser.isSet("export-sequence");
0185     d->canvasOnly = parser.isSet("canvasonly");
0186     d->noSplash = parser.isSet("nosplash");
0187     d->fullScreen = parser.isSet("fullscreen");
0188 
0189     KoResourcePaths::s_overrideAppDataLocation = parser.value("resource-location");
0190 
0191     const QDir currentDir = QDir::current();
0192     Q_FOREACH (const QString &filename, parser.positionalArguments()) {
0193         d->filenames << currentDir.absoluteFilePath(filename);
0194     }
0195 }
0196 
0197 KisApplicationArguments::KisApplicationArguments(const KisApplicationArguments &rhs)
0198     : d(new Private)
0199 {
0200     d->filenames = rhs.filenames();
0201     d->dpiX = rhs.d->dpiX;
0202     d->dpiY = rhs.d->dpiY;
0203     d->doTemplate = rhs.doTemplate();
0204     d->exportAs = rhs.exportAs();
0205     d->exportFileName = rhs.exportFileName();
0206     d->canvasOnly = rhs.canvasOnly();
0207     d->workspace = rhs.workspace();
0208     d->windowLayout = rhs.windowLayout();
0209     d->session = rhs.session();
0210     d->noSplash = rhs.noSplash();
0211     d->fullScreen = rhs.fullScreen();
0212 
0213 }
0214 
0215 void KisApplicationArguments::operator=(const KisApplicationArguments &rhs)
0216 {
0217     d->filenames = rhs.filenames();
0218     d->dpiX = rhs.d->dpiX;
0219     d->dpiY = rhs.d->dpiY;
0220     d->doTemplate = rhs.doTemplate();
0221     d->exportAs = rhs.exportAs();
0222     d->exportFileName = rhs.exportFileName();
0223     d->canvasOnly = rhs.canvasOnly();
0224     d->workspace = rhs.workspace();
0225     d->windowLayout = rhs.windowLayout();
0226     d->session = rhs.session();
0227     d->noSplash = rhs.noSplash();
0228     d->fullScreen = rhs.fullScreen();
0229 }
0230 
0231 QByteArray KisApplicationArguments::serialize()
0232 {
0233     QBuffer buf;
0234     buf.open(QIODevice::WriteOnly);
0235     QDataStream ds(&buf);
0236     ds.setVersion(QDataStream::Qt_5_0);
0237     ds << d->filenames.count();
0238     Q_FOREACH (const QString &filename, d->filenames) {
0239         ds << filename;
0240     }
0241     ds << d->dpiX;
0242     ds << d->dpiY;
0243     ds << d->doTemplate;
0244     ds << d->exportAs;
0245     ds << d->exportFileName;
0246     ds << d->workspace;
0247     ds << d->windowLayout;
0248     ds << d->session;
0249     ds << d->canvasOnly;
0250     ds << d->noSplash;
0251     ds << d->fullScreen;
0252     ds << d->newImage;
0253     ds << d->height;
0254     ds << d->width;
0255     ds << d->height;
0256     ds << d->colorModel;
0257     ds << d->colorDepth;
0258     ds << d->fileLayer;
0259 
0260     buf.close();
0261 
0262     return buf.data();
0263 }
0264 
0265 KisApplicationArguments KisApplicationArguments::deserialize(QByteArray &serialized)
0266 {
0267     KisApplicationArguments args;
0268 
0269     QBuffer buf(&serialized);
0270     buf.open(QIODevice::ReadOnly);
0271     QDataStream ds(&buf);
0272     ds.setVersion(QDataStream::Qt_5_0);
0273     int count;
0274     ds >> count;
0275     for(int i = 0; i < count; ++i) {
0276         QString s;
0277         ds >> s;
0278         args.d->filenames << s;
0279     }
0280     ds >> args.d->dpiX;
0281     ds >> args.d->dpiY;
0282     ds >> args.d->doTemplate;
0283     ds >> args.d->exportAs;
0284     ds >> args.d->exportFileName;
0285     ds >> args.d->workspace;
0286     ds >> args.d->windowLayout;
0287     ds >> args.d->session;
0288     ds >> args.d->canvasOnly;
0289     ds >> args.d->noSplash;
0290     ds >> args.d->fullScreen;
0291     ds >> args.d->newImage;
0292     ds >> args.d->height;
0293     ds >> args.d->width;
0294     ds >> args.d->height;
0295     ds >> args.d->colorModel;
0296     ds >> args.d->colorDepth;
0297     ds >> args.d->fileLayer;
0298 
0299     buf.close();
0300 
0301     return args;
0302 }
0303 
0304 QStringList KisApplicationArguments::filenames() const
0305 {
0306     return d->filenames;
0307 }
0308 
0309 bool KisApplicationArguments::doTemplate() const
0310 {
0311     return d->doTemplate;
0312 }
0313 
0314 bool KisApplicationArguments::exportAs() const
0315 {
0316     return d->exportAs;
0317 }
0318 
0319 bool KisApplicationArguments::exportSequence() const
0320 {
0321     return d->exportSequence;
0322 }
0323 
0324 QString KisApplicationArguments::exportFileName() const
0325 {
0326     return d->exportFileName;
0327 }
0328 
0329 QString KisApplicationArguments::workspace() const
0330 {
0331     return d->workspace;
0332 }
0333 
0334 QString KisApplicationArguments::windowLayout() const
0335 {
0336     return d->windowLayout;
0337 }
0338 
0339 QString KisApplicationArguments::session() const
0340 {
0341     return d->session;
0342 }
0343 
0344 QString KisApplicationArguments::fileLayer() const
0345 {
0346     return d->fileLayer;
0347 }
0348 
0349 bool KisApplicationArguments::canvasOnly() const
0350 {
0351     return d->canvasOnly;
0352 }
0353 
0354 bool KisApplicationArguments::noSplash() const
0355 {
0356     return d->noSplash;
0357 }
0358 
0359 bool KisApplicationArguments::fullScreen() const
0360 {
0361     return d->fullScreen;
0362 }
0363 
0364 bool KisApplicationArguments::doNewImage() const
0365 {
0366     return d->newImage;
0367 }
0368 
0369 KisDocument *KisApplicationArguments::createDocumentFromArguments() const
0370 {
0371     KisDocument *doc = KisPart::instance()->createDocument();
0372     const KoColorSpace *cs = KoColorSpaceRegistry::instance()->colorSpace(d->colorModel, d->colorDepth, "");
0373     if (!cs) {
0374         qWarning() << "Could not create the colorspace for the new image. Check the colorspace and depth arguments.";
0375         return 0;
0376     }
0377 
0378     doc->newImage(i18n("Unnamed"), d->width, d->height, cs, KoColor(QColor(Qt::white), cs), KisConfig::CANVAS_COLOR, 1, "", 100.0);
0379     return doc;
0380 }