DiscoverObject.cpp 18.2 KB
Newer Older
1
/*
2
 *   SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3
 *
4
 *   SPDX-License-Identifier: LGPL-2.0-or-later
5 6
 */

7
#include "DiscoverObject.h"
8
#include "PaginateModel.h"
9
#include "UnityLauncher.h"
10
#include "FeaturedModel.h"
11
#include "CachedNetworkAccessManager.h"
12
#include "DiscoverDeclarativePlugin.h"
13
#include "DiscoverBackendsFactory.h"
14 15

// Qt includes
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
16
#include <QAction>
Laurent Montel's avatar
Laurent Montel committed
17
#include "discover_debug.h"
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
18
#include <QDesktopServices>
Laurent Montel's avatar
Laurent Montel committed
19 20 21
#include <QQmlEngine>
#include <QQmlContext>
#include <QQmlApplicationEngine>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
22 23
#include <QtQuick/QQuickItem>
#include <qqml.h>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
24
#include <QPointer>
25
#include <QGuiApplication>
26
#include <QSortFilterProxyModel>
27
#include <QTimer>
28
#include <QSessionManager>
29
#include <QClipboard>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
30
#include <QDBusConnection>
31
#include <QDBusMessage>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
32
#include <QDBusPendingCall>
33 34

// KDE includes
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
35
#include <KAboutApplicationDialog>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
36
#include <KAuthorized>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
37
#include <KBugReport>
38
#include <KLocalizedString>
39
#include <KLocalizedContext>
40
#include <KAboutData>
41
#include <KConcatenateRowsProxyModel>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
42 43
#include <KSharedConfig>
#include <KConfigGroup>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
44
#include <KStandardAction>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
45
#include <KCrash>
46
#include <kcoreaddons_version.h>
47
// #include <KSwitchLanguageDialog>
48

49
// DiscoverCommon includes
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
50
#include <resources/AbstractResource.h>
51
#include <resources/ResourcesModel.h>
52
#include <resources/ResourcesProxyModel.h>
53
#include <Category/Category.h>
54
#include <Category/CategoryModel.h>
55

56
#include <functional>
57
#include <cmath>
58
#include <unistd.h>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
59
#include <resources/StoredResultsStream.h>
60
#include <utils.h>
61
#include <QMimeDatabase>
62

63
#ifdef WITH_FEEDBACK
64
#include "plasmauserfeedback.h"
65
#endif
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
66 67
#include "discoversettings.h"

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
68 69 70 71 72 73 74
class CachedNetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
{
    virtual QNetworkAccessManager * create(QObject *parent) override {
        return new CachedNetworkAccessManager(QStringLiteral("images"), parent);
    }
};

75 76 77 78 79 80 81 82 83 84 85 86
class OurSortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus
{
    Q_OBJECT
    Q_INTERFACES(QQmlParserStatus)
public:
    void classBegin() override {}
    void componentComplete() override {
        if (dynamicSortFilter())
            sort(0);
    }
};

87
DiscoverObject::DiscoverObject(CompactMode mode, const QVariantMap &initialProperties)
88 89
    : QObject()
    , m_engine(new QQmlApplicationEngine)
90
    , m_mode(mode)
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
91
    , m_networkAccessManagerFactory(new CachedNetworkAccessManagerFactory)
92
{
93
    setObjectName(QStringLiteral("DiscoverMain"));
94 95 96 97
    m_engine->rootContext()->setContextObject(new KLocalizedContext(m_engine));
    auto factory = m_engine->networkAccessManagerFactory();
    m_engine->setNetworkAccessManagerFactory(nullptr);
    delete factory;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
98
    m_engine->setNetworkAccessManagerFactory(m_networkAccessManagerFactory.data());
99

100
    qmlRegisterType<UnityLauncher>("org.kde.discover.app", 1, 0, "UnityLauncher");
101
    qmlRegisterType<PaginateModel>("org.kde.discover.app", 1, 0, "PaginateModel");
102
    qmlRegisterType<KConcatenateRowsProxyModel>("org.kde.discover.app", 1, 0, "KConcatenateRowsProxyModel");
103
    qmlRegisterType<FeaturedModel>("org.kde.discover.app", 1, 0, "FeaturedModel");
104
    qmlRegisterType<OurSortFilterProxyModel>("org.kde.discover.app", 1, 0, "QSortFilterProxyModel");
105
#ifdef WITH_FEEDBACK
106
    qmlRegisterSingletonType<PlasmaUserFeedback>("org.kde.discover.app", 1, 0, "UserFeedbackSettings", [](QQmlEngine*, QJSEngine*) -> QObject* { return new PlasmaUserFeedback(KSharedConfig::openConfig(QStringLiteral("PlasmaUserFeedback"), KConfig::NoGlobals)); });
107
#endif
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
108 109 110 111 112 113
    qmlRegisterSingletonType<DiscoverSettings>("org.kde.discover.app", 1, 0, "DiscoverSettings", [](QQmlEngine*, QJSEngine*) -> QObject* {
            auto r = new DiscoverSettings;
            connect(r, &DiscoverSettings::installedPageSortingChanged, r, &DiscoverSettings::save);
            connect(r, &DiscoverSettings::appsListPageSortingChanged, r, &DiscoverSettings::save);
            return r;
        });
114 115 116 117 118 119 120 121
    qmlRegisterAnonymousType<QQuickView>("org.kde.discover.app", 1);
    qmlRegisterAnonymousType<QActionGroup>("org.kde.discover.app", 1);
    qmlRegisterAnonymousType<QAction>("org.kde.discover.app", 1);

    qmlRegisterAnonymousType<KAboutData>("org.kde.discover.app", 1);
    qmlRegisterAnonymousType<KAboutLicense>("org.kde.discover.app", 1);
    qmlRegisterAnonymousType<KAboutPerson>("org.kde.discover.app", 1);

122
    qmlRegisterUncreatableType<DiscoverObject>("org.kde.discover.app", 1, 0, "DiscoverMainWindow", QStringLiteral("don't do that"));
123
    setupActions();
124

125 126 127 128 129 130
    auto uri = "org.kde.discover";
    DiscoverDeclarativePlugin* plugin = new DiscoverDeclarativePlugin;
    plugin->setParent(this);
    plugin->initializeEngine(m_engine, uri);
    plugin->registerTypes(uri);

131
    m_engine->setInitialProperties(initialProperties);
132
    m_engine->rootContext()->setContextProperty(QStringLiteral("app"), this);
133
    m_engine->rootContext()->setContextProperty(QStringLiteral("discoverAboutData"), QVariant::fromValue(KAboutData::applicationData()));
134

135
    connect(m_engine, &QQmlApplicationEngine::objectCreated, this, &DiscoverObject::integrateObject);
136
    m_engine->load(QUrl(QStringLiteral("qrc:/qml/DiscoverWindow.qml")));
137 138 139 140 141 142

    connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, [this](){
        const auto objs = m_engine->rootObjects();
        for(auto o: objs)
            delete o;
    });
143 144
    auto action = new OneTimeAction(
        [this]() {
145
            bool found = DiscoverBackendsFactory::hasRequestedBackends();
146 147
            const auto backends = ResourcesModel::global()->backends();
            for (auto b : backends)
148 149 150 151
                found |= b->hasApplications();

            if (!found)
                Q_EMIT openErrorPage(i18n("No application back-ends found, please report to your distribution."));
152 153 154 155 156 157 158 159
        }
        , this);

    if (ResourcesModel::global()->backends().isEmpty()) {
        connect(ResourcesModel::global(), &ResourcesModel::allInitialized, action, &OneTimeAction::trigger);
    } else {
        action->trigger();
    }
160 161
}

162
DiscoverObject::~DiscoverObject()
163
{
164
    delete m_engine;
165 166
}

167
bool DiscoverObject::isRoot()
168 169 170 171
{
    return ::getuid() == 0;
}

172
QStringList DiscoverObject::modes() const
173
{
174
    QStringList ret;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
175
    QObject* obj = rootObject();
176 177
    for(int i = obj->metaObject()->propertyOffset(); i<obj->metaObject()->propertyCount(); i++) {
        QMetaProperty p = obj->metaObject()->property(i);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
178
        QByteArray compName = p.name();
Laurent Montel's avatar
Laurent Montel committed
179
        if(compName.startsWith("top") && compName.endsWith("Comp")) {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
180
            ret += QString::fromLatin1(compName.mid(3, compName.length()-7));
181 182 183 184 185
        }
    }
    return ret;
}

186
void DiscoverObject::openMode(const QString& _mode)
187
{
188 189
    QObject* obj = rootObject();
    if (!obj) {
Laurent Montel's avatar
Laurent Montel committed
190
        qCWarning(DISCOVER_LOG) << "could not get the main object";
191 192 193
        return;
    }

194
    if(!modes().contains(_mode, Qt::CaseInsensitive))
Laurent Montel's avatar
Laurent Montel committed
195
        qCWarning(DISCOVER_LOG) << "unknown mode" << _mode << modes();
196

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
197
    QString mode = _mode;
198
    mode[0] = mode[0].toUpper();
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
199

200 201 202
    const QByteArray propertyName = "top"+mode.toLatin1()+"Comp";
    const QVariant modeComp = obj->property(propertyName.constData());
    if (!modeComp.isValid())
Laurent Montel's avatar
Laurent Montel committed
203
        qCWarning(DISCOVER_LOG) << "couldn't open mode" << _mode;
204 205
    else
        obj->setProperty("currentTopLevel", modeComp);
206 207
}

208
void DiscoverObject::openMimeType(const QString& mime)
209
{
210
    emit listMimeInternal(mime);
211 212
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
213 214 215 216 217 218 219 220 221 222 223
void DiscoverObject::showLoadingPage()
{
    QObject* obj = rootObject();
    if (!obj) {
        qCWarning(DISCOVER_LOG) << "could not get the main object";
        return;
    }

    obj->setProperty("currentTopLevel", QStringLiteral("qrc:/qml/LoadingPage.qml"));
}

224
void DiscoverObject::openCategory(const QString& category)
225
{
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
226
    showLoadingPage();
227 228 229
    auto action = new OneTimeAction(
        [this, category]() {
            Category* cat = CategoryModel::global()->findCategoryByName(category);
230 231 232
            if (cat) {
                emit listCategoryInternal(cat);
            } else {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
233
                openMode(QStringLiteral("Browsing"));
234 235 236 237
                showPassiveNotification(i18n("Could not find category '%1'", category));
            }
        }
        , this);
238

239 240
    if (CategoryModel::global()->rootCategories().isEmpty()) {
        connect(CategoryModel::global(), &CategoryModel::rootCategoriesChanged, action, &OneTimeAction::trigger);
241 242
    } else {
        action->trigger();
243
    }
244
}
245

246
void DiscoverObject::openLocalPackage(const QUrl& localfile)
247
{
248 249
    if (!QFile::exists(localfile.toLocalFile())) {
//         showPassiveNotification(i18n("Trying to open unexisting file '%1'", localfile.toString()));
Laurent Montel's avatar
Laurent Montel committed
250
        qCWarning(DISCOVER_LOG) << "Trying to open unexisting file" << localfile;
251 252
        return;
    }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
253
    showLoadingPage();
254 255
    auto action = new OneTimeAction(
        [this, localfile]() {
256 257 258
            AbstractResourcesBackend::Filters f;
            f.resourceUrl = localfile;
            auto stream = new StoredResultsStream({ResourcesModel::global()->search(f)});
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
259
            connect(stream, &StoredResultsStream::finishedResources, this, [this, localfile](const QVector<AbstractResource*> &res) {
260 261
                if (res.count() == 1) {
                    emit openApplicationInternal(res.first());
262
                } else {
263 264 265 266
                    QMimeDatabase db;
                    auto mime = db.mimeTypeForUrl(localfile);
                    auto fIsFlatpakBackend = [](AbstractResourcesBackend* backend) { return backend->metaObject()->className() == QByteArray("FlatpakBackend"); };
                    if (mime.name().startsWith(QLatin1String("application/vnd.flatpak")) && !kContains(ResourcesModel::global()->backends(), fIsFlatpakBackend)) {
Laurent Montel's avatar
Laurent Montel committed
267
                        openApplication(QUrl(QStringLiteral("appstream://org.kde.discover.flatpak")));
268 269
                        showPassiveNotification(i18n("Cannot interact with flatpak resources without the flatpak backend %1. Please install it first.", localfile.toDisplayString()));
                    } else {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
270
                        openMode(QStringLiteral("Browsing"));
271 272
                        showPassiveNotification(i18n("Couldn't open %1", localfile.toDisplayString()));
                    }
273
                }
274
            });
275 276 277 278
        }
        , this);

    if (ResourcesModel::global()->backends().isEmpty()) {
279
        connect(ResourcesModel::global(), &ResourcesModel::backendsChanged, action, &OneTimeAction::trigger);
280 281 282 283 284
    } else {
        action->trigger();
    }
}

285
void DiscoverObject::openApplication(const QUrl& url)
286
{
287
    Q_ASSERT(!url.isEmpty());
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
288
    showLoadingPage();
289 290 291 292 293
    auto action = new OneTimeAction(
        [this, url]() {
            AbstractResourcesBackend::Filters f;
            f.resourceUrl = url;
            auto stream = new StoredResultsStream({ResourcesModel::global()->search(f)});
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
294
            connect(stream, &StoredResultsStream::finishedResources, this, [this, url](const QVector<AbstractResource*> &res) {
295
                if (res.count() >= 1) {
296
                    emit openApplicationInternal(res.first());
297 298 299
                } else if (url.scheme() == QLatin1String("snap")) {
                    openApplication(QUrl(QStringLiteral("appstream://org.kde.discover.snap")));
                    showPassiveNotification(i18n("Please make sure snap support is installed %1", url.toDisplayString()));
300
                } else {
301
                    Q_EMIT openErrorPage(i18n("Couldn't open %1", url.toDisplayString()));
302 303 304 305 306 307
                }
            });
        }
        , this);

    if (ResourcesModel::global()->backends().isEmpty()) {
308
        connect(ResourcesModel::global(), &ResourcesModel::backendsChanged, action, &OneTimeAction::trigger);
309 310 311
    } else {
        action->trigger();
    }
312
}
313

314
void DiscoverObject::integrateObject(QObject* object)
315
{
316
    if (!object) {
Laurent Montel's avatar
Laurent Montel committed
317
        qCWarning(DISCOVER_LOG) << "Errors when loading the GUI";
318 319 320 321 322 323
        QTimer::singleShot(0, QCoreApplication::instance(), [](){
            QCoreApplication::instance()->exit(1);
        });
        return;
    }

324 325
    Q_ASSERT(object == rootObject());

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
326 327 328
    KConfigGroup window(KSharedConfig::openConfig(), "Window");
    if (window.hasKey("geometry"))
        rootObject()->setGeometry(window.readEntry("geometry", QRect()));
329 330 331 332
    if (window.hasKey("visibility")) {
        QWindow::Visibility visibility(QWindow::Visibility(window.readEntry<int>("visibility", QWindow::Windowed)));
        rootObject()->setVisibility(qMax(visibility, QQuickView::AutomaticVisibility));
    }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
333 334 335 336
    connect(rootObject(), &QQuickView::sceneGraphError, this, [] (QQuickWindow::SceneGraphError /*error*/, const QString &message) {
        KCrash::setErrorMessage(message);
        qFatal("%s", qPrintable(message));
    });
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
337

338
    object->installEventFilter(this);
339
    connect(object, &QObject::destroyed, qGuiApp, &QCoreApplication::quit);
340

341
    object->setParent(m_engine);
342 343 344 345 346 347
    connect(qGuiApp, &QGuiApplication::commitDataRequest, this, [this](QSessionManager &sessionManager) {
        if (ResourcesModel::global()->isBusy()) {
            Q_EMIT preventedClose();
            sessionManager.cancel();
        }
    });
348 349
}

350
bool DiscoverObject::eventFilter(QObject * object, QEvent * event)
351 352 353 354 355 356
{
    if (object!=rootObject())
        return false;

    if (event->type() == QEvent::Close) {
        if (ResourcesModel::global()->isBusy()) {
Laurent Montel's avatar
Laurent Montel committed
357
            qCWarning(DISCOVER_LOG) << "not closing because there's still pending tasks";
358 359 360
            Q_EMIT preventedClose();
            return true;
        }
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
361 362 363

        KConfigGroup window(KSharedConfig::openConfig(), "Window");
        window.writeEntry("geometry", rootObject()->geometry());
364
        window.writeEntry<int>("visibility", rootObject()->visibility());
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
365
//     } else if (event->type() == QEvent::ShortcutOverride) {
Laurent Montel's avatar
Laurent Montel committed
366
//         qCWarning(DISCOVER_LOG) << "Action conflict" << event;
367
    }
368
    return false;
369 370
}

371
void DiscoverObject::setupActions()
372
{
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
373
    if (KAuthorized::authorizeAction(QStringLiteral("help_report_bug")) && !KAboutData::applicationData().bugAddress().isEmpty()) {
374
        auto mReportBugAction = KStandardAction::reportBug(this, &DiscoverObject::reportBug, this);
375
        m_collection[mReportBugAction->objectName()] = mReportBugAction;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
376 377
    }

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
378
    if (KAuthorized::authorizeAction(QStringLiteral("help_about_app"))) {
379
        auto mAboutAppAction = KStandardAction::aboutApp(this, &DiscoverObject::aboutApplication, this);
380
        m_collection[mAboutAppAction->objectName()] = mAboutAppAction;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
381
    }
382
}
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
383

384
QAction * DiscoverObject::action(const QString& name) const
385
{
386
    return m_collection.value(name);
387 388
}

389
QString DiscoverObject::iconName(const QIcon& icon)
390
{
391
    return icon.name();
392
}
393

394
void DiscoverObject::aboutApplication()
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
395 396 397 398 399 400 401 402 403
{
    static QPointer<QDialog> dialog;
    if (!dialog) {
        dialog = new KAboutApplicationDialog(KAboutData::applicationData(), nullptr);
        dialog->setAttribute(Qt::WA_DeleteOnClose);
    }
    dialog->show();
}

404
void DiscoverObject::reportBug()
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
405 406 407 408 409 410 411 412 413
{
    static QPointer<QDialog> dialog;
    if (!dialog) {
        dialog = new KBugReport(KAboutData::applicationData(), nullptr);
        dialog->setAttribute(Qt::WA_DeleteOnClose);
    }
    dialog->show();
}

414
void DiscoverObject::switchApplicationLanguage()
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
415 416 417 418 419 420
{
//     auto langDialog = new KSwitchLanguageDialog(nullptr);
//     connect(langDialog, SIGNAL(finished(int)), this, SLOT(dialogFinished()));
//     langDialog->show();
}

421
void DiscoverObject::setCompactMode(DiscoverObject::CompactMode mode)
422
{
423 424 425 426
    if (m_mode != mode) {
        m_mode = mode;
        Q_EMIT compactModeChanged(m_mode);
    }
427
}
428

429
class DiscoverTestExecutor : public QObject
430
{
431 432 433 434 435 436 437 438 439 440
public:
    DiscoverTestExecutor(QObject* rootObject, QQmlEngine* engine, const QUrl &url)
        : QObject(engine)
    {
        connect(engine, &QQmlEngine::quit, this, &DiscoverTestExecutor::finish, Qt::QueuedConnection);

        QQmlComponent* component = new QQmlComponent(engine, url, engine);
        m_testObject = component->create(engine->rootContext());

        if (!m_testObject) {
Laurent Montel's avatar
Laurent Montel committed
441
            qCWarning(DISCOVER_LOG) << "error loading test" << url << m_testObject << component->errors();
442 443
            Q_ASSERT(false);
        }
444

445 446
        m_testObject->setProperty("appRoot", QVariant::fromValue<QObject*>(rootObject));
        connect(engine, &QQmlEngine::warnings, this, &DiscoverTestExecutor::processWarnings);
447 448
    }

449
    void processWarnings(const QList<QQmlError> &warnings) {
450 451
        foreach(const QQmlError &warning, warnings) {
            if (warning.url().path().endsWith(QLatin1String("DiscoverTest.qml"))) {
Laurent Montel's avatar
Laurent Montel committed
452
                qCWarning(DISCOVER_LOG) << "Test failed!" << warnings;
453 454 455
                qGuiApp->exit(1);
            }
        }
456 457 458 459
        m_warnings << warnings;
    }

    void finish() {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
460
        //The CI doesn't seem to have icons, remove when it's not an issue anymore
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
461
        m_warnings.erase(std::remove_if(m_warnings.begin(), m_warnings.end(), [](const QQmlError& err) -> bool {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
462
            return err.description().contains(QLatin1String("QML Image: Failed to get image from provider: image://icon/"));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
463
        }));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
464

465
        if (m_warnings.isEmpty())
Laurent Montel's avatar
Laurent Montel committed
466
            qCDebug(DISCOVER_LOG) << "cool no warnings!";
467
        else
468
            qCDebug(DISCOVER_LOG) << "test finished successfully despite" << m_warnings;
469 470 471 472 473 474 475 476
        qGuiApp->exit(m_warnings.count());
    }

private:
    QObject* m_testObject;
    QList<QQmlError> m_warnings;
};

477
void DiscoverObject::loadTest(const QUrl& url)
478 479
{
    new DiscoverTestExecutor(rootObject(), engine(), url);
480
}
481

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
482
QQuickWindow* DiscoverObject::rootObject() const
483
{
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
484
    return qobject_cast<QQuickWindow*>(m_engine->rootObjects().at(0));
485
}
486

487
void DiscoverObject::showPassiveNotification(const QString& msg)
488 489 490 491 492
{
    QTimer::singleShot(100, this, [this, msg](){
        QMetaObject::invokeMethod(rootObject(), "showPassiveNotification", Qt::QueuedConnection, Q_ARG(QVariant, msg), Q_ARG(QVariant, {}), Q_ARG(QVariant, {}), Q_ARG(QVariant, {}));
    });
}
493

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
494 495
void DiscoverObject::reboot()
{
496 497 498 499 500 501
    QDBusConnection::sessionBus().asyncCall(
        QDBusMessage::createMethodCall(QStringLiteral("org.kde.LogoutPrompt"),
                                       QStringLiteral("/LogoutPrompt"),
                                       QStringLiteral("org.kde.LogoutPrompt"),
                                       QStringLiteral("promptReboot"))
    );
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
502
}
503

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
504 505 506 507 508 509
QRect DiscoverObject::initialGeometry() const
{
    KConfigGroup window(KSharedConfig::openConfig(), "Window");
    return window.readEntry("geometry", QRect());
}

510 511 512 513 514
QString DiscoverObject::describeSources() const
{
    return rootObject()->property("describeSources").toString();
}

515
#include "DiscoverObject.moc"