File indexing completed on 2024-04-28 09:45:39

0001 //  SPDX-FileCopyrightText: 1998 Matthias Hoelzer <hoelzer@kde.org>
0002 //  SPDX-FileCopyrightText: 2002, 2016 David Faure <faure@kde.org>
0003 //  SPDX-FileCopyrightText: 2005 Brad Hards <bradh@frogmouth.net>
0004 //  SPDX-FileCopyrightText: 2008 Dmitry Suzdalev <dimsuz@gmail.com>
0005 //  SPDX-FileCopyrightText: 2011 Kai Uwe Broulik <kde@privat.broulik.de>
0006 //  SPDX-FileCopyrightText: 2020 Tristan Miller <psychonaut@nothingisreal.com>
0007 //
0008 //  SPDX-License-Identifier: GPL-2.0-or-later
0009 
0010 #include "config-kdialog.h"
0011 #include "widgets.h"
0012 #include "utils.h"
0013 #include "kdialog_version.h"
0014 
0015 // KF
0016 #include <KMessageBox>
0017 #include <KRecentDocument>
0018 #include <KAboutData>
0019 #include <KConfig>
0020 #include <KIconDialog>
0021 #include <KColorMimeData>
0022 #include <KWindowSystem>
0023 #include <KIconLoader>
0024 #include <KLocalizedString>
0025 
0026 
0027 // Qt
0028 #include <QApplication>
0029 #include <QDate>
0030 #include <QDateTime>
0031 #include <QCheckBox>
0032 #include <QClipboard>
0033 #include <QColorDialog>
0034 #include <QDBusServiceWatcher>
0035 #include <QDebug>
0036 #include <QFileDialog>
0037 #include <QUrl>
0038 #include <QProcess>
0039 #include <QRegularExpression>
0040 #include <QTimer>
0041 
0042 #include <iostream>
0043 #include <memory>
0044 
0045 #if defined HAVE_X11
0046 #include <X11/Xlib.h>
0047 #include <X11/Xutil.h>
0048 #endif
0049 
0050 #include <QDBusConnection>
0051 #include <QDBusConnectionInterface>
0052 
0053 #include <unistd.h>
0054 #include <QCommandLineParser>
0055 #include <QCommandLineOption>
0056 
0057 using namespace std;
0058 
0059 // this class hooks into the eventloop and outputs the id
0060 // of shown dialogs or makes the dialog transient for other winids.
0061 // Will destroy itself on app exit.
0062 class ForeignWindowAttacher : public QObject
0063 {
0064 public:
0065     ForeignWindowAttacher(bool printID, const QString &parentHandle)
0066         : QObject(qApp)
0067         , print(printID)
0068         , parentHandle(parentHandle)
0069     {
0070         if (qApp) {
0071             qApp->installEventFilter(this);
0072         }
0073     }
0074 
0075 protected:
0076     bool eventFilter(QObject *o, QEvent *e) override;
0077 private:
0078     bool print;
0079     QString parentHandle;
0080 };
0081 
0082 bool ForeignWindowAttacher::eventFilter(QObject *o, QEvent *e)
0083 {
0084     if (e->type() == QEvent::Show && o->isWidgetType()
0085         && o->inherits("QDialog")) {
0086         auto w = static_cast<QWidget *>(o);
0087         if (print) {
0088             cout << "winId: " << w->winId() << endl;
0089         }
0090         if (!parentHandle.isEmpty()) {
0091             w->setAttribute(Qt::WA_NativeWindow, true);
0092             KWindowSystem::setMainWindow(w->windowHandle(), parentHandle);
0093         }
0094         deleteLater(); // ForeignWindowAttacher is not needed anymore after the first dialog was shown
0095         return false;
0096     }
0097     return QObject::eventFilter(o, e);
0098 }
0099 
0100 /**
0101  * Display a passive notification popup using the D-Bus interface, if possible.
0102  * @return true if the notification was successfully sent, false otherwise.
0103  */
0104 static bool sendVisualNotification(const QString &text, const QString &title, const QString &icon, int timeout)
0105 {
0106     const QString dbusServiceName = QStringLiteral("org.freedesktop.Notifications");
0107     const QString dbusInterfaceName = QStringLiteral("org.freedesktop.Notifications");
0108     const QString dbusPath = QStringLiteral("/org/freedesktop/Notifications");
0109 
0110     // check if service already exists on plugin instantiation
0111     QDBusConnectionInterface *interface = QDBusConnection::sessionBus().interface();
0112 
0113     if (!interface || !interface->isServiceRegistered(dbusServiceName)) {
0114         //kDebug() << dbusServiceName << "D-Bus service not registered";
0115         return false;
0116     }
0117 
0118     if (timeout == 0) {
0119         timeout = 10 * 1000;
0120     }
0121 
0122     QDBusMessage m = QDBusMessage::createMethodCall(dbusServiceName, dbusPath, dbusInterfaceName, QStringLiteral("Notify"));
0123     QList<QVariant> args;
0124 
0125     args.append(QStringLiteral("kdialog")); // app_name
0126     args.append(0U); // replaces_id
0127     args.append(icon); // app_icon
0128     args.append(title); // summary
0129     args.append(text); // body
0130     args.append(QStringList()); // actions - unused for plain passive popups
0131     args.append(QVariantMap()); // hints - unused atm
0132     args.append(timeout); // expire timeout
0133 
0134     m.setArguments(args);
0135 
0136     QDBusMessage replyMsg = QDBusConnection::sessionBus().call(m);
0137     if (replyMsg.type() == QDBusMessage::ReplyMessage) {
0138         if (!replyMsg.arguments().isEmpty()) {
0139             return true;
0140         }
0141         // Not displaying any error messages as this is optional for kdialog
0142         // and KPassivePopup is a perfectly valid fallback.
0143         //else {
0144         //  kDebug() << "Error: received reply with no arguments.";
0145         //}
0146     } else if (replyMsg.type() == QDBusMessage::ErrorMessage) {
0147         //kDebug() << "Error: failed to send D-Bus message";
0148         //kDebug() << replyMsg;
0149     } else {
0150         //kDebug() << "Unexpected reply type";
0151     }
0152 
0153     return false;
0154 }
0155 
0156 static void outputStringList(const QStringList &list, bool separateOutput)
0157 {
0158     if (separateOutput) {
0159         for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) {
0160             cout << (*it).toLocal8Bit().data() << endl;
0161         }
0162     } else {
0163         for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) {
0164             cout << (*it).toLocal8Bit().data() << " ";
0165         }
0166         cout << endl;
0167     }
0168 }
0169 
0170 static void outputStringList(const QList<QUrl> &list, bool separateOutput)
0171 {
0172     if (separateOutput) {
0173         for (auto it = list.constBegin(); it != list.constEnd(); ++it) {
0174             cout << (*it).toDisplayString().toLocal8Bit().data() << endl;
0175         }
0176     } else {
0177         for (auto it = list.constBegin(); it != list.constEnd(); ++it) {
0178             cout << (*it).toDisplayString().toLocal8Bit().data() << " ";
0179         }
0180         cout << endl;
0181     }
0182 }
0183 
0184 static KGuiItem configuredYes(const QString &text)
0185 {
0186     return KGuiItem(text, QStringLiteral("dialog-ok"));
0187 }
0188 
0189 static KGuiItem configuredNo(const QString &text)
0190 {
0191     return KGuiItem(text, QStringLiteral("process-stop"));
0192 }
0193 
0194 static KGuiItem configuredCancel(const QString &text)
0195 {
0196     return KGuiItem(text, QStringLiteral("dialog-cancel"));
0197 }
0198 
0199 static KGuiItem configuredContinue(const QString &text)
0200 {
0201     return KGuiItem(text, QStringLiteral("arrow-right"));
0202 }
0203 
0204 static void setFileDialogFilter(QFileDialog &dlg, const QString &filter)
0205 {
0206     if (filter.contains(QLatin1String("*"))) {
0207         QString qtFilter = filter;
0208         dlg.setNameFilter(qtFilter.replace(QLatin1Char('|'), QLatin1Char('\n')));
0209     } else if (!filter.isEmpty()) {
0210         dlg.setMimeTypeFilters(filter.trimmed().split(QLatin1Char(' ')));
0211     }
0212 }
0213 
0214 // taken from qfiledialog.cp
0215 static QString initialSelection(const QUrl &url)
0216 {
0217     if (url.isEmpty()) {
0218         return QString();
0219     }
0220     if (url.isLocalFile()) {
0221         QFileInfo info(url.toLocalFile());
0222         if (!info.isDir()) {
0223             return info.fileName();
0224         } else {
0225             return QString();
0226         }
0227     }
0228     // With remote URLs we can only assume.
0229     return url.fileName();
0230 }
0231 
0232 static QUrl initialDirectory(const QUrl &url)
0233 {
0234     if (url.isLocalFile() && QFileInfo(url.toLocalFile()).isDir()) {
0235         return url;
0236     }
0237     return url.adjusted(QUrl::RemoveFilename);
0238 }
0239 
0240 int main(int argc, char *argv[])
0241 {
0242     // Bug 373677: Qt removes various arguments it treats internally (such as title and icon) from args
0243     // and applies them to the first Qt::Window, while here we only show dialogs
0244     // so we need to store them before we even create our QApplication
0245     QStringList rawArgs;
0246     for (int i = 0; i < argc; ++i) {
0247         rawArgs << QString::fromLocal8Bit(argv[i]);
0248     }
0249 
0250     QApplication app(argc, argv);
0251     KLocalizedString::setApplicationDomain(QByteArrayLiteral("kdialog"));
0252 
0253     KAboutData aboutData(QStringLiteral("kdialog"), QString(),
0254                          QStringLiteral(KDIALOG_VERSION_STRING), i18n("KDialog can be used to show nice dialog boxes from shell scripts"),
0255                          KAboutLicense::GPL,
0256                          i18n("(C) 2000, Nick Thompson"));
0257     aboutData.addAuthor(i18n("David Faure"), i18n("Current maintainer"), QStringLiteral("faure@kde.org"));
0258     aboutData.addAuthor(i18n("Brad Hards"), QString(), QStringLiteral("bradh@frogmouth.net"));
0259     aboutData.addAuthor(i18n("Nick Thompson"), QString(), QString() /*"nickthompson@lucent.com" bounces*/);
0260     aboutData.addAuthor(i18n("Matthias Hölzer"), QString(), QStringLiteral("hoelzer@kde.org"));
0261     aboutData.addAuthor(i18n("David Gümbel"), QString(), QStringLiteral("david.guembel@gmx.net"));
0262     aboutData.addAuthor(i18n("Richard Moore"), QString(), QStringLiteral("rich@kde.org"));
0263     aboutData.addAuthor(i18n("Dawit Alemayehu"), QString(), QStringLiteral("adawit@kde.org"));
0264     aboutData.addAuthor(i18n("Kai Uwe Broulik"), QString(), QStringLiteral("kde@privat.broulik.de"));
0265     KAboutData::setApplicationData(aboutData);
0266     QGuiApplication::setApplicationDisplayName(QString());
0267 
0268     QCommandLineParser parser;
0269     aboutData.setupCommandLine(&parser);
0270 
0271     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("yesno"), i18n("Question message box with yes/no buttons"), QStringLiteral("text")));
0272     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("yesnocancel"), i18n("Question message box with yes/no/cancel buttons"), QStringLiteral("text")));
0273     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("warningyesno"), i18n("Warning message box with yes/no buttons"), QStringLiteral("text")));
0274     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("warningcontinuecancel"), i18n("Warning message box with continue/cancel buttons"), QStringLiteral("text")));
0275     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("warningyesnocancel"), i18n("Warning message box with yes/no/cancel buttons"), QStringLiteral("text")));
0276 
0277     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("ok-label"), i18n("Use text as OK button label"), QStringLiteral("text")));
0278     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("yes-label"), i18n("Use text as Yes button label"), QStringLiteral("text")));
0279     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("no-label"), i18n("Use text as No button label"), QStringLiteral("text")));
0280     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("cancel-label"), i18n("Use text as Cancel button label"), QStringLiteral("text")));
0281     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("continue-label"), i18n("Use text as Continue button label"), QStringLiteral("text")));
0282     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("sorry"), i18n("'Sorry' message box"), QStringLiteral("text")));
0283     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("detailedsorry"), i18n("'Sorry' message box with expandable Details field"), QStringLiteral("text> <details")));
0284     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("error"), i18n("'Error' message box"), QStringLiteral("text")));
0285     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("detailederror"), i18n("'Error' message box with expandable Details field"), QStringLiteral("text> <details")));
0286     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("msgbox"), i18n("Message Box dialog"), QStringLiteral("text")));
0287     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("inputbox"), i18n("Input Box dialog"), QStringLiteral("text> <init")));
0288     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("imgbox"), i18n("Image Box dialog"), QStringLiteral("file")));
0289     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("imginputbox"), i18n("Image Box Input dialog"), QStringLiteral("file> <text")));
0290     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("password"), i18n("Password dialog"), QStringLiteral("text")));
0291     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("newpassword"), i18n("New Password dialog"), QStringLiteral("text")));
0292     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("textbox"), i18n("Text Box dialog"), QStringLiteral("file")));
0293     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("textinputbox"), i18n("Text Input Box dialog"), QStringLiteral("text> <init")));
0294     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("combobox"), i18n("ComboBox dialog"), QStringLiteral("text")));
0295     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("menu"), i18n("Menu dialog"), QStringLiteral("text")));
0296     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("checklist"), i18n("Check List dialog"), QStringLiteral("text")));
0297     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("radiolist"), i18n("Radio List dialog"), QStringLiteral("text")));
0298     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("passivepopup"), i18n("Passive Popup"), QStringLiteral("text> <timeout")));
0299     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("icon"), i18n("Popup icon"), QStringLiteral("icon")));
0300     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("getopenfilename"), i18n("File dialog to open an existing file (arguments [startDir] [filter])")));
0301     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("getsavefilename"), i18n("File dialog to save a file (arguments [startDir] [filter])")));
0302     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("getexistingdirectory"), i18n("File dialog to select an existing directory (arguments [startDir])")));
0303     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("getopenurl"), i18n("File dialog to open an existing URL (arguments [startDir] [filter])")));
0304     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("getsaveurl"), i18n("File dialog to save a URL (arguments [startDir] [filter])")));
0305     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("geticon"), i18n("Icon chooser dialog (arguments [group] [context])")));
0306     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("progressbar"), i18n("Progress bar dialog, returns a D-Bus reference for communication"), QStringLiteral("text")));
0307     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("getcolor"), i18n("Color dialog to select a color")));
0308     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("format"), i18n("Allow --getcolor to specify output format"), QStringLiteral("text")));
0309     // TODO gauge stuff, reading values from stdin
0310     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("title"), i18n("Dialog title"), QStringLiteral("text")));
0311     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("default"), i18n("Default entry to use for combobox, menu, color, and calendar"), QStringLiteral("text")));
0312     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("multiple"), i18n("Allows the --getopenurl and --getopenfilename options to return multiple files")));
0313     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("separate-output"), i18n("Return list items on separate lines (for checklist option and file open with --multiple)")));
0314     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("print-winid"), i18n("Outputs the winId of each dialog")));
0315     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("dontagain"), i18n("Config file and option name for saving the \"do-not-show/ask-again\" state"),
0316     QStringLiteral("file:entry")));
0317     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("slider"), i18n("Slider dialog box, returns selected value (arguments [text] [min] [max] [step])")));
0318     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("dateformat"), i18n("Date format for calendar result and/or default value (Qt-style); defaults to 'ddd MMM d yyyy'"), QStringLiteral("text")));
0319     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("calendar"), i18n("Calendar dialog box, returns selected date"), QStringLiteral("text")));
0320     /* kdialog originally used --embed for attaching the dialog box.  However this is misleading and so we changed to --attach.
0321      * For backwards compatibility, we silently map --embed to --attach */
0322     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("attach"), i18n("Makes the dialog transient for an X app specified by winid"), QStringLiteral("winid")));
0323     QCommandLineOption embedOption(QStringList() << QStringLiteral("embed"), i18n("A synonym for --attach"), QStringLiteral("winid"));
0324     embedOption.setFlags(QCommandLineOption::HiddenFromHelp);
0325     parser.addOption(embedOption);
0326     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("geometry"), i18n("Dialog geometry: [=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"), QStringLiteral("geometry")));
0327 
0328     parser.addPositionalArgument(QStringLiteral("[arg]"), i18n("Arguments - depending on main option"));
0329 
0330     parser.process(rawArgs);
0331     aboutData.processCommandLine(&parser);
0332 
0333     // execute kdialog command
0334 
0335     QApplication::setWindowIcon(QIcon::fromTheme(parser.value(QStringLiteral("icon")), QIcon::fromTheme(QStringLiteral("system-run"))));
0336 
0337     const QStringList args = parser.positionalArguments();
0338     QString title = parser.value(QStringLiteral("title"));
0339     if (title.isEmpty()) {
0340         title = i18n("KDialog");
0341     }
0342     const bool separateOutput = parser.isSet(QStringLiteral("separate-output"));
0343     const bool printWId = parser.isSet(QStringLiteral("print-winid"));
0344     QString defaultEntry;
0345     const QString geometry = parser.value(QStringLiteral("geometry"));
0346     Utils::setGeometry(geometry);
0347 
0348     QString parentHandle;
0349     bool attach = parser.isSet(QStringLiteral("attach"));
0350     if (attach) {
0351         parentHandle = parser.value(QStringLiteral("attach"));
0352     } else if (parser.isSet(QStringLiteral("embed"))) {
0353         /* KDialog originally used --embed for attaching the dialog box.  However this is misleading and so we changed to --attach.
0354          * For consistency, we silently map --embed to --attach */
0355         attach = true;
0356         parentHandle = parser.value(QStringLiteral("embed"));
0357     }
0358 
0359     if (printWId || attach) {
0360         (void)new ForeignWindowAttacher(printWId, parentHandle);
0361     }
0362 
0363     // button labels
0364     // Initialize with default labels
0365     KGuiItem okButton = KStandardGuiItem::ok();
0366     KGuiItem yesButton = configuredYes(i18nc("@action:button", "&Yes"));
0367     KGuiItem noButton = configuredNo(i18nc("@action:button", "&No"));
0368     KGuiItem cancelButton = KStandardGuiItem::cancel();
0369     KGuiItem continueButton = KStandardGuiItem::cont();
0370 
0371     // Customize the asked labels
0372     if (parser.isSet(QStringLiteral("ok-label"))) {
0373         okButton = configuredYes( parser.value(QStringLiteral("ok-label")) );
0374     }
0375     if (parser.isSet(QStringLiteral("yes-label"))) {
0376         yesButton = configuredYes(parser.value(QStringLiteral("yes-label")));
0377     }
0378     if (parser.isSet(QStringLiteral("no-label"))) {
0379         noButton = configuredNo(parser.value(QStringLiteral("no-label")));
0380     }
0381     if (parser.isSet(QStringLiteral("cancel-label"))) {
0382         cancelButton = configuredCancel(parser.value(QStringLiteral("cancel-label")));
0383     }
0384     if (parser.isSet(QStringLiteral("continue-label"))) {
0385         continueButton = configuredContinue(parser.value(QStringLiteral("continue-label")));
0386     }
0387 
0388     // --yesno and other message boxes
0389     auto type = static_cast<KMessageBox::DialogType>(0);
0390     QMessageBox::Icon icon = QMessageBox::Question;
0391     QByteArray option;
0392     if (parser.isSet(QStringLiteral("yesno"))) {
0393         option = "yesno";
0394         type = KMessageBox::QuestionTwoActions;
0395     } else if (parser.isSet(QStringLiteral("yesnocancel"))) {
0396         option = "yesnocancel";
0397         type = KMessageBox::QuestionTwoActionsCancel;
0398     } else if (parser.isSet(QStringLiteral("warningyesno"))) {
0399         option = "warningyesno";
0400         type = KMessageBox::WarningTwoActions;
0401         icon = QMessageBox::Warning;
0402     } else if (parser.isSet(QStringLiteral("warningcontinuecancel"))) {
0403         option = "warningcontinuecancel";
0404         type = KMessageBox::WarningContinueCancel;
0405         icon = QMessageBox::Warning;
0406     } else if (parser.isSet(QStringLiteral("warningyesnocancel"))) {
0407         option = "warningyesnocancel";
0408         type = KMessageBox::WarningTwoActionsCancel;
0409         icon = QMessageBox::Warning;
0410     } else if (parser.isSet(QStringLiteral("sorry"))) {
0411         option = "sorry";
0412         type = KMessageBox::Error;
0413         icon = QMessageBox::Warning;
0414     } else if (parser.isSet(QStringLiteral("detailedsorry"))) {
0415         option = "detailedsorry";
0416         type = KMessageBox::Error;
0417         icon = QMessageBox::Warning;
0418     } else if (parser.isSet(QStringLiteral("error"))) {
0419         option = "error";
0420         type = KMessageBox::Error;
0421         icon = QMessageBox::Critical;
0422     } else if (parser.isSet(QStringLiteral("detailederror"))) {
0423         option = "detailederror";
0424         type = KMessageBox::Error;
0425         icon = QMessageBox::Critical;
0426     } else if (parser.isSet(QStringLiteral("msgbox"))) {
0427         option = "msgbox";
0428         type = KMessageBox::Information;
0429         icon = QMessageBox::Information;
0430     }
0431 
0432     if (!option.isEmpty()) {
0433         std::unique_ptr<KConfig> dontagaincfg;
0434         // --dontagain
0435         QString dontagain; // QString()
0436         if (parser.isSet(QStringLiteral("dontagain"))) {
0437             QString value = parser.value(QStringLiteral("dontagain"));
0438             const QStringList values = value.split(QLatin1Char(':'), Qt::SkipEmptyParts);
0439             if (values.count() == 2) {
0440                 dontagaincfg.reset(new KConfig(values[0]));
0441                 KMessageBox::setDontShowAgainConfig(dontagaincfg.get());
0442                 dontagain = values[ 1 ];
0443 
0444                 if (type == KMessageBox::WarningContinueCancel) {
0445                     if (!KMessageBox::shouldBeShownContinue(dontagain)) {
0446                         return 0;
0447                     }
0448                 } else {
0449                     KMessageBox::ButtonCode code;
0450                     if (!KMessageBox::shouldBeShownTwoActions(dontagain, code)) {
0451                         return code == KMessageBox::PrimaryAction ? 0 : 1;
0452                     }
0453                 }
0454             } else {
0455                 qDebug("Incorrect --dontagain!");
0456             }
0457         }
0458 
0459         QString text = Utils::parseString(parser.value(QString::fromLatin1(option)));
0460 
0461         QString details;
0462         if (args.count() == 1) {
0463             details = Utils::parseString(args.at(0));
0464         }
0465 
0466         QDialog dialog;
0467         dialog.setWindowTitle(title);
0468         auto buttonBox = new QDialogButtonBox(&dialog);
0469         KMessageBox::Options options = KMessageBox::NoExec | KMessageBox::Notify;
0470 
0471         switch (type) {
0472         case KMessageBox::QuestionTwoActions:
0473         case KMessageBox::WarningTwoActions:
0474             buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
0475             KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), yesButton);
0476             KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), noButton);
0477             break;
0478         case KMessageBox::QuestionTwoActionsCancel:
0479         case KMessageBox::WarningTwoActionsCancel:
0480             buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
0481             KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), yesButton);
0482             KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), noButton);
0483             KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), cancelButton);
0484             break;
0485         case KMessageBox::WarningContinueCancel:
0486             buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
0487             KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), continueButton);
0488             KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), cancelButton);
0489             break;
0490         case KMessageBox::Error:
0491         case KMessageBox::Information:
0492             buttonBox->addButton(QDialogButtonBox::Ok);
0493             KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), okButton);
0494             buttonBox->button(QDialogButtonBox::Ok)->setFocus();
0495             break;
0496         }
0497         (void)KMessageBox::createKMessageBox(&dialog,           // dialog
0498                                              buttonBox,         // buttons
0499                                              icon,          // icon
0500                                              text,          // text
0501                                              {},            // strlist
0502                                              dontagain.isEmpty() ? QString() : i18n("Do not ask again"), // ask
0503                                              nullptr,           // checkboxReturn
0504                                              options,           // options
0505                                              details);          // details
0506         Utils::handleXGeometry(&dialog);
0507         const auto ret = QDialogButtonBox::StandardButton(dialog.exec());
0508         if (!dontagain.isEmpty()) {
0509             // We use NoExec in order to call handleXGeometry before exec
0510             // But that means we need to query the state of the dontShowAgain checkbox ourselves too...
0511             auto cb = dialog.findChild<QCheckBox *>();
0512             Q_ASSERT(cb);
0513             if (cb && cb->isChecked()) {
0514                 if (type == KMessageBox::WarningContinueCancel) {
0515                     if (ret == QDialogButtonBox::Yes) {
0516                         KMessageBox::saveDontShowAgainContinue(dontagain);
0517                     }
0518                 } else if (ret != QDialogButtonBox::Cancel) {
0519                     KMessageBox::saveDontShowAgainTwoActions(dontagain, ret == QDialogButtonBox::Yes ? KMessageBox::PrimaryAction : KMessageBox::SecondaryAction);
0520                 }
0521             }
0522         }
0523         // We want to return 0 for ok, yes and continue, 1 for no and 2 for cancel
0524         return (ret == QDialogButtonBox::Ok || ret == QDialogButtonBox::Yes) ? 0
0525                : (ret == QDialogButtonBox::No ? 1 : 2);
0526     }
0527 
0528     // --inputbox text [init]
0529     if (parser.isSet(QStringLiteral("inputbox"))) {
0530         QString result;
0531         QString init;
0532 
0533         if (args.count() > 0) {
0534             init = args.at(0);
0535         }
0536 
0537         const bool retcode = Widgets::inputBox(nullptr, title, Utils::parseString(parser.value(QStringLiteral("inputbox"))), init, result);
0538         cout << result.toLocal8Bit().data() << endl;
0539         return retcode ? 0 : 1;
0540     }
0541 
0542     // --password text
0543     if (parser.isSet(QStringLiteral("password"))) {
0544         QString result;
0545         // Note that KPasswordDialog (as of 5.73.0) word-wraps the prompt, so newlines will be converted to spaces
0546         const bool retcode = Widgets::passwordBox(nullptr, title, Utils::parseString(parser.value(QStringLiteral("password"))), result);
0547         cout << qPrintable(result) << endl;
0548         return retcode ? 0 : 1;
0549     }
0550 
0551     // --newpassword text
0552     if (parser.isSet(QStringLiteral("newpassword"))) {
0553         QString result;
0554         const bool retcode = Widgets::newPasswordBox(nullptr, title, Utils::parseString(parser.value(QStringLiteral("newpassword"))), result);
0555         cout << qPrintable(result) << endl;
0556         return retcode ? 0 : 1;
0557     }
0558 
0559     // --passivepopup
0560     if (parser.isSet(QStringLiteral("passivepopup"))) {
0561         int timeout = 0;
0562         if (args.count() > 0) {
0563             timeout = 1000 * args.at(0).toInt();
0564         }
0565 
0566         if (timeout < 0) {
0567             timeout = -1;
0568         }
0569 
0570         // Use --icon parameter for passivepopup as well
0571         QString iconArg;
0572         if (parser.isSet(QStringLiteral("icon"))) {
0573             iconArg = parser.value(QStringLiteral("icon"));
0574         } else {
0575             iconArg = QStringLiteral("dialog-information");      // Use generic (i)-icon if none specified
0576         }
0577 
0578         // try to use more stylish notifications
0579         const bool result = sendVisualNotification(Utils::parseString(parser.value(QStringLiteral("passivepopup"))), title, iconArg, timeout);
0580         if (result) {
0581             return 0;
0582         }
0583 
0584         qApp->exec();
0585         return 0;
0586     }
0587 
0588     // --textbox file [width] [height]
0589     if (parser.isSet(QStringLiteral("textbox"))) {
0590         int w = 0;
0591         int h = 0;
0592 
0593         if (args.count() == 2) {
0594             w = args.at(0).toInt();
0595             h = args.at(1).toInt();
0596         }
0597 
0598         return Widgets::textBox(nullptr, w, h, title, parser.value(QStringLiteral("textbox")));
0599     }
0600 
0601     // --imgbox <file>
0602     if (parser.isSet(QStringLiteral("imgbox"))) {
0603         return Widgets::imgBox(nullptr, title, parser.value(QStringLiteral("imgbox")));
0604     }
0605 
0606     // --imginputbox <file> [text]
0607     if (parser.isSet(QStringLiteral("imginputbox"))) {
0608         QString result;
0609         QString text;
0610 
0611         if (args.count() > 0) {
0612             text = args.at(0);
0613         }
0614 
0615         const bool retcode = Widgets::imgInputBox(nullptr, title, parser.value(QStringLiteral("imginputbox")), Utils::parseString(text), result);
0616         cout << result.toLocal8Bit().data() << endl;
0617         return retcode ? 0 : 1;
0618     }
0619 
0620     // --textinputbox file [width] [height]
0621     if (parser.isSet(QStringLiteral("textinputbox"))) {
0622         int w = 400;
0623         int h = 200;
0624 
0625         if (args.count() >= 3) {
0626             w = args.at(1).toInt();
0627             h = args.at(2).toInt();
0628         }
0629 
0630         QString init;
0631         if (args.count() >= 1) {
0632             init = Utils::parseString(args.at(0));
0633         }
0634 
0635         QString result;
0636         int ret = Widgets::textInputBox(nullptr, w, h, title, Utils::parseString(parser.value(QStringLiteral("textinputbox"))), init, result);
0637         cout << qPrintable(result) << endl;
0638         return ret;
0639     }
0640 
0641     // --combobox <text> item [item] ..."
0642     if (parser.isSet(QStringLiteral("combobox"))) {
0643         QStringList list;
0644         if (args.count() >= 1) {
0645             for (int i = 0; i < args.count(); i++) {
0646                 list.append(args.at(i));
0647             }
0648             const QString text = Utils::parseString(parser.value(QStringLiteral("combobox")));
0649             if (parser.isSet(QStringLiteral("default"))) {
0650                 defaultEntry = parser.value(QStringLiteral("default"));
0651             }
0652             QString result;
0653             const bool retcode = Widgets::comboBox(nullptr, title, text, list, defaultEntry, result);
0654             cout << result.toLocal8Bit().data() << endl;
0655             return retcode ? 0 : 1;
0656         }
0657         cerr << qPrintable(i18n("Syntax: --combobox <text> item [item] ...")) << endl;
0658         return -1;
0659     }
0660 
0661     // --menu text tag item [tag item] ...
0662     if (parser.isSet(QStringLiteral("menu"))) {
0663         QStringList list;
0664         if (args.count() >= 2) {
0665             for (int i = 0; i < args.count(); i++) {
0666                 list.append(args.at(i));
0667             }
0668             const QString text = Utils::parseString(parser.value(QStringLiteral("menu")));
0669             if (parser.isSet(QStringLiteral("default"))) {
0670                 defaultEntry = parser.value(QStringLiteral("default"));
0671             }
0672             QString result;
0673             const bool retcode = Widgets::listBox(nullptr, title, text, list, defaultEntry, result);
0674             if (1 == retcode) { // OK was selected
0675                 cout << result.toLocal8Bit().data() << endl;
0676             }
0677             return retcode ? 0 : 1;
0678         }
0679         cerr << qPrintable(i18n("Syntax: --menu text tag item [tag item] ...")) << endl;
0680         return -1;
0681     }
0682 
0683     // --checklist text tag item status [tag item status] ...
0684     if (parser.isSet(QStringLiteral("checklist"))) {
0685         QStringList list;
0686         if (args.count() >= 3) {
0687             for (int i = 0; i < args.count(); i++) {
0688                 list.append(args.at(i));
0689             }
0690 
0691             const QString text = Utils::parseString(parser.value(QStringLiteral("checklist")));
0692             QStringList result;
0693 
0694             const bool retcode = Widgets::checkList(nullptr, title, text, list, separateOutput, result);
0695 
0696             for (int i = 0; i < result.count(); i++) {
0697                 if (!result.at(i).isEmpty()) {
0698                     cout << result.at(i).toLocal8Bit().data() << endl;
0699                 }
0700             }
0701             return retcode ? 0 : 1;
0702         }
0703         cerr << qPrintable(i18n("Syntax: --checklist text tag item on/off [tag item on/off] ...")) << endl;
0704         return -1;
0705     }
0706 
0707     // --radiolist text tag item status [tag item status] ...
0708     if (parser.isSet(QStringLiteral("radiolist"))) {
0709         QStringList list;
0710         if (args.count() >= 3) {
0711             for (int i = 0; i < args.count(); i++) {
0712                 list.append(args.at(i));
0713             }
0714 
0715             const QString text = Utils::parseString(parser.value(QStringLiteral("radiolist")));
0716             QString result;
0717             const bool retcode = Widgets::radioBox(nullptr, title, text, list, result);
0718             cout << result.toLocal8Bit().data() << endl;
0719             return retcode ? 0 : 1;
0720         }
0721         cerr << qPrintable(i18n("Syntax: --radiolist text tag item on/off [tag item on/off] ...")) << endl;
0722         return -1;
0723     }
0724 
0725     // getopenfilename [startDir] [filter]
0726     // getopenurl [startDir] [filter]
0727     if (parser.isSet(QStringLiteral("getopenfilename")) || parser.isSet(QStringLiteral("getopenurl"))) {
0728         QString startDir = args.count() > 0 ? args.at(0) : QString();
0729         const QUrl startUrl = QUrl::fromUserInput(startDir);
0730         QString filter;
0731         if (args.count() > 1) {
0732             filter = Utils::parseString(args.at(1));
0733         }
0734         const bool multiple = parser.isSet(QStringLiteral("multiple"));
0735 
0736         QFileDialog dlg;
0737         dlg.setAcceptMode(QFileDialog::AcceptOpen);
0738         dlg.setDirectoryUrl(initialDirectory(startUrl));
0739         dlg.selectFile(initialSelection(startUrl));
0740 
0741         if (multiple) {
0742             dlg.setFileMode(QFileDialog::ExistingFiles);
0743         } else {
0744             dlg.setFileMode(QFileDialog::ExistingFile);
0745         }
0746         const bool openUrls = parser.isSet(QStringLiteral("getopenurl"));
0747         if (!openUrls) {
0748             dlg.setSupportedSchemes({QStringLiteral("file")});
0749         }
0750         setFileDialogFilter(dlg, filter);
0751         Utils::handleXGeometry(&dlg);
0752         dlg.setWindowTitle(title.isEmpty() ? i18nc("@title:window", "Open") : title);
0753         if (!dlg.exec()) {
0754             return 1; // canceled
0755         }
0756 
0757         if (openUrls) {
0758             const QList<QUrl> result = dlg.selectedUrls();
0759             if (!result.isEmpty()) {
0760                 if (multiple) {
0761                     outputStringList(result, separateOutput);
0762                     return 0;
0763                 } else {
0764                     cout << result.at(0).url().toLocal8Bit().data() << endl;
0765                     return 0;
0766                 }
0767             }
0768         } else {
0769             const QStringList result = dlg.selectedFiles();
0770             if (!result.isEmpty()) {
0771                 if (multiple) {
0772                     outputStringList(result, separateOutput);
0773                     return 0;
0774                 } else {
0775                     cout << result.at(0).toLocal8Bit().data() << endl;
0776                     return 0;
0777                 }
0778             }
0779         }
0780         return 1;
0781     }
0782 
0783     // getsaveurl [startDir] [filter]
0784     // getsavefilename [startDir] [filter]
0785     if ((parser.isSet(QStringLiteral("getsavefilename"))) || (parser.isSet(QStringLiteral("getsaveurl")))) {
0786         QString startDir = args.count() > 0 ? args.at(0) : QString();
0787         QString filter;
0788         const QUrl startUrl = QUrl::fromUserInput(startDir);
0789 
0790         if (args.count() > 1) {
0791             filter = Utils::parseString(args.at(1));
0792         }
0793         QFileDialog dlg;
0794         dlg.setAcceptMode(QFileDialog::AcceptSave);
0795         dlg.setFileMode(QFileDialog::AnyFile);
0796         dlg.setDirectoryUrl(initialDirectory(startUrl));
0797         dlg.selectFile(initialSelection(startUrl));
0798         setFileDialogFilter(dlg, filter);
0799         const bool saveUrls = parser.isSet(QStringLiteral("getsaveurl"));
0800         if (!saveUrls) {
0801             dlg.setSupportedSchemes({QStringLiteral("file")});
0802         }
0803         Utils::handleXGeometry(&dlg);
0804         dlg.setWindowTitle(title.isEmpty() ? i18nc("@title:window", "Save As") : title);
0805         if (!dlg.exec()) {
0806             return 1; // canceled
0807         }
0808 
0809         if (saveUrls) {
0810             const QList<QUrl> result = dlg.selectedUrls();
0811             if (!result.isEmpty()) {
0812                 cout << result.at(0).toString().toLocal8Bit().data() << endl;
0813                 return 0;
0814             }
0815         } else { // getsavefilename
0816             const QStringList result = dlg.selectedFiles();
0817             if (!result.isEmpty()) {
0818                 const QString file = result.at(0);
0819                 KRecentDocument::add(QUrl::fromLocalFile(file));
0820                 cout << file.toLocal8Bit().data() << endl;
0821                 return 0;
0822             }
0823         }
0824         return 1; // canceled
0825     }
0826 
0827     // getexistingdirectory [startDir]
0828     if (parser.isSet(QStringLiteral("getexistingdirectory"))) {
0829         QString startDir = args.count() > 0 ? args.at(0) : QString();
0830         const QUrl startUrl = QUrl::fromUserInput(startDir);
0831 
0832         QFileDialog dlg;
0833         dlg.setFileMode(QFileDialog::Directory);
0834         dlg.setOption(QFileDialog::ShowDirsOnly, true);
0835         dlg.setDirectoryUrl(initialDirectory(startUrl));
0836         dlg.selectFile(initialSelection(startUrl));
0837         Utils::handleXGeometry(&dlg);
0838         dlg.setWindowTitle(title.isEmpty() ? i18nc("@title:window", "Select Directory") : title);
0839         if (!dlg.exec()) {
0840             return 1; // canceled
0841         }
0842         const QList<QUrl> urls = dlg.selectedUrls();
0843         if (!urls.isEmpty()) {
0844             cout << qPrintable(urls.at(0).toDisplayString(QUrl::PreferLocalFile)) << endl;
0845             return 0;
0846         }
0847         return 1; // canceled
0848     }
0849 
0850     // geticon [group] [context]
0851     if (parser.isSet(QStringLiteral("geticon"))) {
0852         QString groupStr, contextStr;
0853         groupStr = parser.value(QStringLiteral("geticon"));
0854         if (args.count() >= 1) {
0855             contextStr = args.at(0);
0856         }
0857         const KIconLoader::Group group
0858             = (groupStr == QLatin1String("Desktop")) ? KIconLoader::Desktop
0859               : (groupStr == QLatin1String("Toolbar")) ? KIconLoader::Toolbar
0860               : (groupStr == QLatin1String("MainToolbar")) ? KIconLoader::MainToolbar
0861               : (groupStr == QLatin1String("Small")) ? KIconLoader::Small
0862               : (groupStr == QLatin1String("Dialog")) ? KIconLoader::Dialog
0863               : (groupStr == QLatin1String("User")) ? KIconLoader::User
0864               : /* else */ KIconLoader::NoGroup;
0865 
0866         const KIconLoader::Context context
0867             = (contextStr == QLatin1String("Action")) ? KIconLoader::Action
0868               : (contextStr == QLatin1String("Application")) ? KIconLoader::Application
0869               : (contextStr == QLatin1String("Device")) ? KIconLoader::Device
0870               : (contextStr == QLatin1String("FileSystem")) ? KIconLoader::Place
0871               : (contextStr == QLatin1String("MimeType")) ? KIconLoader::MimeType
0872               : (contextStr == QLatin1String("Animation")) ? KIconLoader::Animation
0873               : (contextStr == QLatin1String("Category")) ? KIconLoader::Category
0874               : (contextStr == QLatin1String("Emblem")) ? KIconLoader::Emblem
0875               : (contextStr == QLatin1String("Emote")) ? KIconLoader::Emote
0876               : (contextStr == QLatin1String("International")) ? KIconLoader::International
0877               : (contextStr == QLatin1String("Place")) ? KIconLoader::Place
0878               : (contextStr == QLatin1String("StatusIcon")) ? KIconLoader::StatusIcon
0879               : // begin: KDE3 compatibility (useful?)
0880               (contextStr == QLatin1String("Devices")) ? KIconLoader::Device
0881               : (contextStr == QLatin1String("MimeTypes")) ? KIconLoader::MimeType
0882               : (contextStr == QLatin1String("FileSystems")) ? KIconLoader::Place
0883               : (contextStr == QLatin1String("Applications")) ? KIconLoader::Application
0884               : (contextStr == QLatin1String("Actions")) ? KIconLoader::Action
0885               : // end: KDE3 compatibility
0886                 /* else */ KIconLoader::Any;
0887 
0888         KIconDialog dlg;
0889         dlg.setup(group, context);
0890         dlg.setIconSize(KIconLoader::SizeHuge);
0891 
0892         if (!title.isEmpty()) {
0893             dlg.setWindowTitle(title);
0894         }
0895 
0896         Utils::handleXGeometry(&dlg);
0897 
0898         const QString result = dlg.openDialog();
0899 
0900         if (!result.isEmpty()) {
0901             cout << result.toLocal8Bit().data() << endl;
0902             return 0;
0903         }
0904         return 1; // canceled
0905     }
0906 
0907     // --progressbar text totalsteps
0908     if (parser.isSet(QStringLiteral("progressbar"))) {
0909         const QString text = Utils::parseString(parser.value(QStringLiteral("progressbar")));
0910 
0911         QProcess process;
0912         QStringList arguments;
0913         arguments << QStringLiteral("--progressbar");
0914         arguments << text;
0915         arguments << QStringLiteral("--title");
0916         arguments << title;
0917         if (args.count() == 1) {
0918             arguments << args.at(0);
0919         }
0920         qint64 pid = 0;
0921         if (process.startDetached(QStandardPaths::findExecutable(QStringLiteral("kdialog_progress_helper")), arguments, QString(), &pid)) {
0922             QDBusConnection dbus = QDBusConnection::sessionBus();
0923             const QString serviceName = QStringLiteral("org.kde.kdialog-") + QString::number(pid);
0924             QDBusServiceWatcher watcher(serviceName, dbus, QDBusServiceWatcher::WatchForRegistration);
0925             QObject::connect(&watcher, &QDBusServiceWatcher::serviceRegistered, [serviceName](){
0926                 std::cout << serviceName.toLatin1().constData() << " /ProgressDialog" << std::endl << std::flush;
0927                 qApp->quit();
0928             });
0929             qApp->exec();
0930             return 0;
0931         }
0932         qWarning() << "Error starting kdialog_progress_helper";
0933         return 1;
0934     }
0935 
0936     // --getcolor
0937     if (parser.isSet(QStringLiteral("getcolor"))) {
0938         QColorDialog dlg;
0939 
0940         if (parser.isSet(QStringLiteral("default"))) {
0941             defaultEntry = parser.value(QStringLiteral("default"));
0942             dlg.setCurrentColor(defaultEntry);
0943         } else {
0944             QColor color = KColorMimeData::fromMimeData(QApplication::clipboard()->mimeData(QClipboard::Clipboard));
0945             if (color.isValid()) {
0946                 dlg.setCurrentColor(color);
0947             }
0948         }
0949 
0950         Utils::handleXGeometry(&dlg);
0951         dlg.setWindowTitle(title.isEmpty() ? i18nc("@title:window", "Choose Color") : title);
0952 
0953         if (dlg.exec()) {
0954             QString result;
0955             const QColor color = dlg.selectedColor();
0956             if (color.isValid() && parser.isSet(QStringLiteral("format"))) {
0957                 bool found = false;
0958                 QString format = parser.value(QStringLiteral("format"));
0959                 format.remove(QLatin1Char('*')); // stripped out * for safety
0960                 QList<QRegularExpression> pattern_pool;
0961                 pattern_pool << QRegularExpression(QStringLiteral("(%#?[-+]?\\d*\\.?\\d*(?:ll|hh|l|h)?[diouxX])"))
0962                              << QRegularExpression(QStringLiteral("(%#?[-+]?\\d*\\.?\\d*[l]?[efgEFG])"));
0963 
0964                 for (int i = 0; i < pattern_pool.size(); i++) {
0965                     QRegularExpressionMatchIterator itor = pattern_pool.at(i).globalMatch(format);
0966                     QRegularExpressionMatch match;
0967                     int match_count = 0;
0968                     while (itor.hasNext()) {
0969                         match = itor.next();
0970                         if (match.hasMatch()) {
0971                             match_count++;
0972                         }
0973                     }
0974                     // currently only handle RGB, when alpha is ready, should hit 4
0975                     if (3 == match_count) {
0976                         found = true;
0977                         if (match.captured(0).contains(QRegularExpression(QStringLiteral("[diouxX]")))) {
0978                             result = QString::asprintf(format.toUtf8().constData(), color.red(), color.green(), color.blue());
0979                         } else {
0980                             result = QString::asprintf(format.toUtf8().constData(), color.redF(), color.greenF(), color.blueF());
0981                         }
0982                         break;
0983                     }
0984                 }
0985                 if (false == found) {
0986                     cout << "Invalid format pattern";
0987                 }
0988             } else {
0989                 result = color.name();
0990             }
0991             cout << result.toLocal8Bit().data() << endl;
0992             return 0;
0993         }
0994         return 1; // canceled
0995     }
0996 
0997     if (parser.isSet(QStringLiteral("slider"))) {
0998         if (args.count() == 4) {
0999             QString text = Utils::parseString(args.at(0));
1000             int miniValue = args.at(1).toInt();
1001             int maxValue = args.at(2).toInt();
1002             int step = args.at(3).toInt();
1003 
1004             int result = 0;
1005 
1006             const bool returnCode = Widgets::slider(nullptr, title, text, miniValue, maxValue, step, result);
1007             if (returnCode) {
1008                 cout << result << endl;
1009             }
1010             return returnCode;
1011         } else {
1012             cerr << qPrintable(i18n("Syntax: --slider <text> <min> <max> <step>")) << endl;
1013             return -1;
1014         }
1015     }
1016 
1017     // --calendar text [--default default] [--dateformat format]
1018     if (parser.isSet(QStringLiteral("calendar"))) {
1019         // The default format is weird and non-standard. Sadly, it's too late to change this now.
1020         QString dateFormat = QStringLiteral("ddd MMM d yyyy");
1021         if (parser.isSet(QStringLiteral("dateformat"))) {
1022             dateFormat = parser.value(QStringLiteral("dateformat"));
1023         }
1024 
1025         QDate defaultDate = QDateTime::currentDateTime().date(); // today
1026         if (parser.isSet(QStringLiteral("default"))) {
1027             defaultEntry = parser.value(QStringLiteral("default"));
1028             defaultDate = QDate::fromString(defaultEntry, dateFormat);
1029         }
1030 
1031         const QString text = Utils::parseString(parser.value(QStringLiteral("calendar")));
1032         QDate result;
1033 
1034         const bool returnCode = Widgets::calendar(nullptr, title, text, result, defaultDate);
1035         if (returnCode) {
1036             cout << result.toString(dateFormat).toLocal8Bit().data() << endl;
1037         }
1038         return returnCode;
1039     }
1040 
1041     parser.showHelp();
1042     return -2; // NOTREACHED
1043 }