Skip to content
Snippets Groups Projects
tdialogloaderobject.cpp 15.4 KiB
Newer Older
/***************************************************************************
 *   Copyright (C) 2017-2021 by Tomasz Bojczuk                             *
 *   seelook@gmail.com                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *  You should have received a copy of the GNU General Public License      *
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/

#include "tdialogloaderobject.h"
#include "main/texamexecutor.h"
#include "main/texamsummary.h"
#include "main/texamview.h"
#include "main/tnootkacertificate.h"
#include "main/tpiechartitem.h"
#include "main/tstartexamitem.h"
#include "main/ttiphandler.h"
#include "tlevelpreviewitem.h"
#include "tlevelselector.h"
#include "tmelgenitem.h"
#include "tmelodyimportitem.h"
#include "tmelodywrapper.h"
#include "ttunerdialogitem.h"
#include "updater/tupdateitem.h"
#if !defined(Q_OS_ANDROID)
#include "charts/tbarchartdelegate.h"
#include "charts/tchartitem.h"
#include "charts/tcharttipitem.h"
#include "charts/tlinchartdelegate.h"
#include "updater/tupdatechecker.h"
#include <qtr.h>
#include <tpath.h>
#include <QtCore/qdebug.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qsettings.h>
#include <QtCore/qversionnumber.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpalette.h>
#include <QtWidgets/qdialogbuttonbox.h>
bool TdialogLoaderObject::m_firstTime = true;
TdialogLoaderObject::TdialogLoaderObject(QObject *parent)
    : QObject(parent)
    if (m_firstTime) {
        qmlRegisterType<TlevelCreatorItem>("Nootka.Dialogs", 1, 0, "TlevelCreatorItem");
        qmlRegisterType<TlevelPreviewItem>("Nootka.Dialogs", 1, 0, "TlevelPreviewItem");
        qmlRegisterType<TlevelSelector>("Nootka.Dialogs", 1, 0, "TlevelsSelector");
        qmlRegisterType<TmelodyListView>("Nootka.Dialogs", 1, 0, "TmelodyListView");
        qmlRegisterType<TmelodyWrapper>("Nootka.Dialogs", 1, 0, "TmelodyWrapper");
        qmlRegisterType<TtunerDialogItem>("Nootka.Dialogs", 1, 0, "TtunerDialogItem");
        qmlRegisterType<TrtmSelectorItem>("Nootka.Dialogs", 1, 0, "TrtmSelectorItem");
        qmlRegisterType<TmelGenItem>("Nootka.Dialogs", 1, 0, "TmelGenItem");
        qmlRegisterType<TmelodyImportItem>("Nootka.Dialogs", 1, 0, "TmelodyImportItem");

        qmlRegisterType<TexamExecutor>("Nootka.Exam", 1, 0, "Texecutor");
        qmlRegisterType<TexamView>("Nootka.Exam", 1, 0, "Tresults");
        qmlRegisterUncreatableType<TtipHandler>("Nootka.Exam", 1, 0, "TipHandler", QStringLiteral("You cannot create an instance of the TipHandler."));
        qmlRegisterType<TexamSummary>("Nootka.Exam", 1, 0, "TexamSummary");
        qmlRegisterType<TstartExamItem>("Nootka.Exam", 1, 0, "TstartExamItem");
        qmlRegisterType<TnootkaCertificate>("Nootka.Exam", 1, 0, "CertificateItem");
        qmlRegisterType<TpieChartItem>("Nootka.Exam", 1, 0, "TpieChartItem");

        qmlRegisterType<TupdateItem>("Nootka.Update", 1, 0, "TupdateItem");

        qRegisterMetaType<Tlevel *>("Tlevel*");
        qRegisterMetaType<Texam *>("Texam*");
        qRegisterMetaType<Tmelody *>("Tmelody*");

#if !defined(Q_OS_ANDROID)
        qmlRegisterType<TchartItem>("Nootka.Charts", 1, 0, "TchartItem");
        qmlRegisterType<TchartTipItem>("Nootka.Charts", 1, 0, "TchartTipItem");
        qmlRegisterType<TlinChartDelegate>("Nootka.Charts", 1, 0, "TlinChartDelegate");
        qmlRegisterType<TbarChartDelegate>("Nootka.Charts", 1, 0, "TbarChartDelegate");
        m_firstTime = false;
    }
TdialogLoaderObject::~TdialogLoaderObject()
{
QString TdialogLoaderObject::stdButtonText(int role)
{
    switch (role) {
    case 33554432:
        return qTR("QPlatformTheme", "Apply");
    case 4194304:
        return qTR("QPlatformTheme", "Cancel");
    case 134217728:
        return qTR("QPlatformTheme", "Restore Defaults");
    case 16777216:
        return qTR("QPlatformTheme", "Help");
    case 2097152:
        return qTR("QPlatformTheme", "Close");
    case 1024:
        return qTR("QPlatformTheme", "OK");
    default:
        return QString();
    }
QString TdialogLoaderObject::stdButtonIcon(int role)
{
    switch (role) {
    case 33554432:
        return QStringLiteral("check"); // Apply
    case 4194304:
        return QStringLiteral("stopExam"); // Cancel
    case 134217728:
        return QStringLiteral("restore-defaults"); // Restore defaults
    case 16777216:
        return QStringLiteral("help"); // Help
    case 2097152:
        return QStringLiteral("exit"); // Close
    case 1024:
        return QStringLiteral("check"); // OK
    default:
        return QString();
    }
QString TdialogLoaderObject::buttonRoleIcon(int role) const
{
    switch (static_cast<QDialogButtonBox::ButtonRole>(role)) {
    case QDialogButtonBox::ApplyRole:
        return QStringLiteral("check"); // Apply
    case QDialogButtonBox::ResetRole:
        return QStringLiteral("restore-defaults"); // Restore defaults
    case QDialogButtonBox::HelpRole:
        return QStringLiteral("help"); // Help
    case QDialogButtonBox::AcceptRole:
        return QStringLiteral("check"); // OK
    default:
        return QStringLiteral("exit");
    }
QColor TdialogLoaderObject::buttinRoleColor(int role) const
{
    switch (static_cast<QDialogButtonBox::ButtonRole>(role)) {
    case QDialogButtonBox::ApplyRole:
        return Qt::green; // Apply
    case QDialogButtonBox::ResetRole:
        return QColor(0, 128, 128); // Restore defaults
    case QDialogButtonBox::HelpRole:
        return QColor(250, 140, 0); // Help
    case QDialogButtonBox::AcceptRole:
        return Qt::green; // OK
    default:
        return Qt::red;
    }
void TdialogLoaderObject::openFile(const QString &fileName)
{
    QFile file(fileName);
    quint32 hdr = 0;
    if (file.open(QIODevice::ReadOnly)) {
        QDataStream in(&file);
        in >> hdr; // check what file type
        auto fullPath = QDir(file.fileName()).absolutePath();
        file.close();
        if (Texam::couldBeExam(hdr)) {
            if (Texam::isExamVersion(hdr))
                emit continueExam(fullPath);
            else
                GLOB->warnAboutNewerVersion(fileName);
        } else if (Tlevel::couldBeLevel(hdr)) {
            if (Tlevel::isLevelVersion(hdr))
                emit openLevel(fullPath);
            else
                GLOB->warnAboutNewerVersion(fileName);
        } else
            qDebug() << "[TdialogLoaderObject] file" << fileName << "is not supported by Nootka";
    }
QString TdialogLoaderObject::aboutQt() const
{
    return "<h1 align=\"center\">"
        + qTR("QMessageBox", "<h3>About Qt</h3><p>This program uses Qt version %1.</p>")
              .arg(qVersion())
              .replace(QLatin1String("<p>"), QString())
              .replace(QLatin1String("</p>"), QString())
        + "</h1><br>"
        + qTR("QMessageBox",
              "<p>Qt is a C++ toolkit for cross-platform application "
              "development.</p>"
              "<p>Qt provides single-source portability across all major desktop "
              "operating systems. It is also available for embedded Linux and other "
              "embedded and mobile operating systems.</p>"
              "<p>Qt is available under three different licensing options designed "
              "to accommodate the needs of our various users.</p>"
              "<p>Qt licensed under our commercial license agreement is appropriate "
              "for development of proprietary/commercial software where you do not "
              "want to share any source code with third parties or otherwise cannot "
              "comply with the terms of the GNU LGPL version 3 or GNU LGPL version 2.1.</p>"
              "<p>Qt licensed under the GNU LGPL version 3 is appropriate for the "
              "development of Qt&nbsp;applications provided you can comply with the terms "
              "and conditions of the GNU LGPL version 3.</p>"
              "<p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the "
              "development of Qt&nbsp;applications provided you can comply with the terms "
              "and conditions of the GNU LGPL version 2.1.</p>"
              "<p>Please see <a href=\"http://%2/\">%2</a> "
              "for an overview of Qt licensing.</p>"
              "<p>Copyright (C) %1 The Qt Company Ltd and other "
              "contributors.</p>"
              "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
              "<p>Qt is The Qt Company Ltd product developed as an open source "
              "project. See <a href=\"http://%3/\">%3</a> for more information.</p>")
              .arg(QStringLiteral("2021"), QStringLiteral("qt.io/licensing"), QStringLiteral("qt.io"));
QString TdialogLoaderObject::mainHelp() const
{
    return TmainHelp::mainHelp();
}
QStringList TdialogLoaderObject::getChanges() const
{
    QFile file(Tpath::main + QLatin1String("changes"));
    QStringList chLog;
    QTextStream in;
    if (file.open(QFile::ReadOnly | QFile::Text)) {
        QTextStream in(&file);
SeeLook's avatar
SeeLook committed
        in.setEncoding(QStringConverter::Utf8);
        QStringList htmlText = in.readAll().replace(QLatin1String("  "), QLatin1String("&nbsp;&nbsp;")).split(QLatin1String("\n"));
        chLog << QLatin1String("<h1>Nootka TWO</h1>");
        for (int i = 0; i < htmlText.size(); i++) {
            if (htmlText[i].startsWith(QLatin1String("0.")) || htmlText[i].startsWith(QLatin1String("1.")) || htmlText[i].startsWith(QLatin1String("2."))) {
                htmlText[i] = QString("<font size=\"6\" color=\"%1\"><b>&nbsp;").arg(qApp->palette().highlight().color().name()) + htmlText[i]
                    + QLatin1String("</b></font>");
                chLog << htmlText[i] + QLatin1String("<br>");
            } else if (htmlText[i].contains(QLatin1String("======"))) {
                htmlText[i] = QStringLiteral("<h1>Nootka ONE</h1>");
                chLog << htmlText[i] + QLatin1String("<br>");
            } else if (htmlText[i].length() > 7) {
                if (htmlText[i].contains(QLatin1String("BUG")))
                    htmlText[i] = QStringLiteral("&nbsp;&nbsp;<u>BUG FIXES</u>");
                else if (htmlText[i].contains(QLatin1String("Under the hood")))
                    htmlText[i] = QStringLiteral("&nbsp;&nbsp;<u>Under the hood</u>");
                else if (!htmlText[i].contains(QLatin1String("&nbsp;&nbsp; - ")))
                    htmlText[i] = QLatin1String("<b>") + htmlText[i] + QLatin1String("</b>");
                chLog.last().append(htmlText[i] + QLatin1String("<br>"));
            }
        }
    file.close();
    return chLog;
QString TdialogLoaderObject::getLicense()
{
    QFile file(Tpath::main + QLatin1String("gpl"));
    QString license;
    QTextStream in;
    if (!file.exists()) { // Debian based
        QDir d(Tpath::main);
        d.cdUp();
        file.setFileName(d.path() + QLatin1String("/doc/nootka/copyright"));
    }
    if (file.open(QFile::ReadOnly | QFile::Text)) {
        QTextStream in(&file);
SeeLook's avatar
SeeLook committed
        in.setEncoding(QStringConverter::Utf8);
        license = in.readAll();
    }
    file.close();
    return license;
void TdialogLoaderObject::updateCheckInBackground()
{
    auto updater = new TupdateChecker(qApp);
    connect(updater, &TupdateChecker::updateMessage, [=](QString m) {
        if (m.isEmpty() || m.contains(QLatin1String("error")) || m.contains(QLatin1String("No need")))
            updater->deleteLater();
    });
    updater->check(true); // do not display update window when no updates found
/**
 * This method is invoked by user from GlobalPage,
 * so it handles @p TupdateChecker::updateSummary and @p updateMessage signals.
 */
void TdialogLoaderObject::checkForUpdates()
{
    auto updater = new TupdateChecker(qApp);
    connect(updater, &TupdateChecker::updateSummary, this, [=](const QString &v, const QString &c, TupdateRules *r) {
        // This method is called by GlobalPage and creates Popup with updates
        // so update item content just once, when TupdateItem doesn't exist yet
        bool updateItem = TupdateItem::instance() == nullptr;
        emit updateSummary(v, c, *r);
        if (TupdateItem::instance() && updateItem) {
            TupdateItem::instance()->setUpdateRules(r, v);
            TupdateItem::instance()->setChanges(c);
        }
    });
    connect(updater, &TupdateChecker::updateMessage, this, [=](QString m) {
        m_updateMessage = m;
        emit updateMessageChanged();
        if (m.isEmpty() || m.contains(QLatin1String("error")))
            updater->deleteLater();
    });
    updater->check(false); // Anyway show update window
bool TdialogLoaderObject::checkVersion(QObject *nootWin)
{
    // Do not show changelog page until user wants to see any 'Got It' info.
    if ((!GLOB->isSingleNote() && GLOB->gotIt(QLatin1String("noteSelected"), true)) || GLOB->gotIt(QLatin1String("soundInfo"), true)
#if defined(Q_OS_ANDROID)
        || GLOB->gotIt(QLatin1String("howToScore"), true)
    )
        return false;

    QString configVersion = GLOB->config->value(QLatin1String("version"), QString()).toString();
    auto confVerNr = QVersionNumber::fromString(configVersion);
    auto currVerNr = QVersionNumber::fromString(GLOB->version);
    if (currVerNr > confVerNr) {
        QTimer::singleShot(1500, [=] {
            if (nootWin && QString(nootWin->metaObject()->className()).contains("MainWindow_QMLTYPE")) {
                QMetaObject::invokeMethod(nootWin, "showDialog", Q_ARG(QVariant, 2));
                auto dialogLoader = qvariant_cast<QObject *>(nootWin->property("dialogLoader"));
                if (dialogLoader) {
                    auto aboutContent = qvariant_cast<QObject *>(dialogLoader->property("currentDialog"));
                    QMetaObject::invokeMethod(aboutContent, "showPage", Q_ARG(QVariant, 6));
                }
                GLOB->config->setValue(QLatin1String("version"), GLOB->version);
            }
        });
        return true;
    }
bool TdialogLoaderObject::checkForSupport(QObject *nootWin)
{
    if (nootWin && QString(nootWin->metaObject()->className()).contains("MainWindow_QMLTYPE")) {
        int supportDaysPass = GLOB->config->value("General/supportDate", QDate(2012, 12, 31)).toDate().daysTo(QDate::currentDate());
        if (supportDaysPass > 7) { // display support dialog every seven days
            QTimer::singleShot(1500, [=] {
                QMetaObject::invokeMethod(nootWin, "askForSupport");
            });
            GLOB->config->setValue("General/supportDate", QDate::currentDate());
            return true;
        }