6#include "NewstuffModel.h" 
    8#include "MarbleDebug.h" 
   10#include "MarbleZipReader.h" 
   13#include <QDomDocument> 
   15#include <QFutureWatcher> 
   18#include <QMutexLocker> 
   19#include <QNetworkAccessManager> 
   20#include <QNetworkReply> 
   22#include <QProcessEnvironment> 
   23#include <QTemporaryFile> 
   25#include <QtConcurrentRun> 
   39    QString m_releaseDate;
 
   43    QDomNode m_registryNode;
 
   45    qint64 m_downloadedSize;
 
   49    QString installedVersion() 
const;
 
   50    QString installedReleaseDate() 
const;
 
   51    bool isUpgradable() 
const;
 
   52    QStringList installedFiles() 
const;
 
   54    static bool deeperThan(
const QString &one, 
const QString &two);
 
   59class NewstuffModelPrivate
 
   72    using Action = QPair<int, UserAction>;
 
   74    NewstuffModel *m_parent;
 
   76    QList<NewstuffItem> m_items;
 
   78    QNetworkAccessManager m_networkAccessManager;
 
   82    QMap<QNetworkReply *, FetchPreviewJob *> m_networkJobs;
 
   84    QNetworkReply *m_currentReply;
 
   86    QTemporaryFile *m_currentFile;
 
   88    QString m_targetDirectory;
 
   90    QString m_registryFile;
 
   92    NewstuffModel::IdTag m_idTag;
 
   94    QDomDocument m_registryDocument;
 
   98    Action m_currentAction;
 
  100    QProcess *m_unpackProcess;
 
  104    QList<Action> m_actionQueue;
 
  106    QHash<int, QByteArray> m_roleNames;
 
  108    explicit NewstuffModelPrivate(NewstuffModel *parent);
 
  110    QIcon preview(
int index);
 
  111    void setPreview(
int index, 
const QIcon &previewIcon);
 
  113    void handleProviderData(QNetworkReply *reply);
 
  115    static bool canExecute(
const QString &executable);
 
  123    void uninstall(
int index);
 
  125    static void changeNode(QDomNode &node, QDomDocument &domDocument, 
const QString &key, 
const QString &value, NodeAction action);
 
  127    void readInstalledFiles(QStringList *target, 
const QDomNode &node);
 
  131    static NewstuffItem importNode(
const QDomNode &node);
 
  133    bool isTransitioning(
int index) 
const;
 
  137    void updateRegistry(
const QStringList &files);
 
  140    static void readValue(
const QDomNode &node, 
const QString &key, T *target);
 
  146    FetchPreviewJob(NewstuffModelPrivate *modelPrivate, 
int index);
 
  148    void run(
const QByteArray &data);
 
  151    NewstuffModelPrivate *
const m_modelPrivate;
 
  155NewstuffItem::NewstuffItem()
 
  157    , m_downloadedSize(0)
 
  162QString NewstuffItem::installedVersion()
 const 
  164    QDomNodeList const nodes = m_registryNode.toElement().elementsByTagName(
"version");
 
  165    if (nodes.
size() == 1) {
 
  172QString NewstuffItem::installedReleaseDate()
 const 
  174    QDomNodeList const nodes = m_registryNode.toElement().elementsByTagName(
"releasedate");
 
  175    if (nodes.
size() == 1) {
 
  182bool NewstuffItem::isUpgradable()
 const 
  184    bool installedOk, remoteOk;
 
  185    double const installed = installedVersion().toDouble(&installedOk);
 
  186    double const remote = m_version.toDouble(&remoteOk);
 
  187    return installedOk && remoteOk && remote > installed;
 
  193    QDomNodeList const nodes = m_registryNode.toElement().elementsByTagName(
"installedfile");
 
  194    for (
int i = 0; i < nodes.
count(); ++i) {
 
  200bool NewstuffItem::deeperThan(
const QString &one, 
const QString &two)
 
  205FetchPreviewJob::FetchPreviewJob(NewstuffModelPrivate *modelPrivate, 
int index)
 
  206    : m_modelPrivate(modelPrivate)
 
  211void FetchPreviewJob::run(
const QByteArray &data)
 
  219    const QIcon previewIcon(pixmap);
 
  220    m_modelPrivate->setPreview(m_index, previewIcon);
 
  223NewstuffModelPrivate::NewstuffModelPrivate(NewstuffModel *parent)
 
  225    , m_networkAccessManager(nullptr)
 
  226    , m_currentReply(nullptr)
 
  227    , m_currentFile(nullptr)
 
  228    , m_idTag(NewstuffModel::PayloadTag)
 
  229    , m_currentAction(-1, Install)
 
  230    , m_unpackProcess(nullptr)
 
  235QIcon NewstuffModelPrivate::preview(
int index)
 
  237    if (m_items.at(index).m_preview.isNull()) {
 
  240        setPreview(index, 
QIcon(dummyPixmap));
 
  242        m_networkJobs.insert(reply, 
new FetchPreviewJob(
this, index));
 
  245    Q_ASSERT(!m_items.at(index).m_preview.isNull());
 
  247    return m_items.at(index).m_preview;
 
  250void NewstuffModelPrivate::setPreview(
int index, 
const QIcon &previewIcon)
 
  252    NewstuffItem &item = m_items[index];
 
  253    item.m_preview = previewIcon;
 
  254    const QModelIndex affected = m_parent->index(index);
 
  255    Q_EMIT m_parent->dataChanged(affected, affected);
 
  258void NewstuffModelPrivate::handleProviderData(
QNetworkReply *reply)
 
  262        if (!redirectionAttribute.
isNull()) {
 
  263            for (
int i = 0; i < m_items.size(); ++i) {
 
  264                NewstuffItem &item = m_items[i];
 
  265                if (item.m_payloadUrl == reply->
url()) {
 
  266                    item.m_payloadUrl = redirectionAttribute.
toUrl();
 
  275            auto length = size.
value<qint64>();
 
  276            for (
int i = 0; i < m_items.size(); ++i) {
 
  277                NewstuffItem &item = m_items[i];
 
  278                if (item.m_payloadUrl == reply->
url()) {
 
  279                    item.m_payloadSize = length;
 
  281                    Q_EMIT m_parent->dataChanged(affected, affected);
 
  288    FetchPreviewJob *
const job = m_networkJobs.take(reply);
 
  292    if (!redirectionAttribute.
isNull()) {
 
  295            m_networkJobs.insert(redirectReply, job);
 
  308        mDebug() << 
"Cannot parse newstuff xml data ";
 
  316    for (
int i = 0; i < items.
length(); ++i) {
 
  317        m_items << importNode(items.
item(i));
 
  323bool NewstuffModelPrivate::canExecute(
const QString &executable)
 
  328        if (application.exists()) {
 
  336void NewstuffModelPrivate::installMap()
 
  338    if (m_unpackProcess) {
 
  339        m_unpackProcess->close();
 
  340        delete m_unpackProcess;
 
  341        m_unpackProcess = 
nullptr;
 
  344    } 
else if (m_currentFile->fileName().endsWith(
QLatin1StringView(
"tar.gz")) && canExecute(
"tar")) {
 
  346        QObject::connect(m_unpackProcess, SIGNAL(finished(
int)), m_parent, SLOT(contentsListed(
int)));
 
  349                                              << 
"-f" << m_currentFile->fileName();
 
  350        m_unpackProcess->setWorkingDirectory(m_targetDirectory);
 
  351        m_unpackProcess->start(
"tar", arguments);
 
  354            mDebug() << 
"Can only handle tar.gz files";
 
  356            mDebug() << 
"Cannot extract archive: tar executable not found in PATH.";
 
  361void NewstuffModelPrivate::unzip()
 
  363    MarbleZipReader zipReader(m_currentFile->fileName());
 
  365    for (
const MarbleZipReader::FileInfo &fileInfo : zipReader.fileInfoList()) {
 
  366        files << fileInfo.filePath;
 
  368    updateRegistry(files);
 
  369    zipReader.extractAll(m_targetDirectory);
 
  370    m_parent->mapInstalled(0);
 
  373void NewstuffModelPrivate::updateModel()
 
  376    for (
int i = 0; i < items.
length(); ++i) {
 
  377        QString const key = m_idTag == NewstuffModel::PayloadTag ? 
"payload" : 
"name";
 
  379        if (matches.
size() == 1) {
 
  382            for (
int j = 0; j < m_items.size() && !found; ++j) {
 
  383                NewstuffItem &item = m_items[j];
 
  384                if (m_idTag == NewstuffModel::PayloadTag && item.m_payloadUrl.toString() == value) {
 
  385                    item.m_registryNode = items.
item(i);
 
  388                if (m_idTag == NewstuffModel::NameTag && item.m_name == value) {
 
  389                    item.m_registryNode = items.
item(i);
 
  396                NewstuffItem item = importNode(items.
item(i));
 
  397                if (m_idTag == NewstuffModel::PayloadTag) {
 
  398                    item.m_registryNode = items.
item(i);
 
  399                } 
else if (m_idTag == NewstuffModel::NameTag) {
 
  400                    item.m_registryNode = items.
item(i);
 
  407    m_parent->beginResetModel();
 
  408    m_parent->endResetModel();
 
  411void NewstuffModelPrivate::saveRegistry()
 
  413    QFile output(m_registryFile);
 
  415        mDebug() << 
"Cannot open " << m_registryFile << 
" for writing";
 
  418        outStream << m_registryDocument.toString(2);
 
  424void NewstuffModelPrivate::uninstall(
int index)
 
  429    QStringList const files = m_items[index].installedFiles();
 
  430    for (
const QString &file : files) {
 
  438    std::sort(directories.
begin(), directories.
end(), NewstuffItem::deeperThan);
 
  439    for (
const QString &dir : directories) {
 
  443    m_items[index].m_registryNode.parentNode().removeChild(m_items[index].m_registryNode);
 
  444    m_items[index].m_registryNode.clear();
 
  450    if (action == Append) {
 
  463void NewstuffModelPrivate::readValue(
const QDomNode &node, 
const QString &key, T *target)
 
  466    if (matches.
size() == 1) {
 
  469        for (
int i = 0; i < matches.
size(); ++i) {
 
  479NewstuffModel::NewstuffModel(
QObject *parent)
 
  481    , d(new NewstuffModelPrivate(this))
 
  490    roles[Name] = 
"name";
 
  493    roles[Summary] = 
"summary";
 
  494    roles[Version] = 
"version";
 
  495    roles[ReleaseDate] = 
"releasedate";
 
  496    roles[Preview] = 
"preview";
 
  498    roles[InstalledVersion] = 
"installedversion";
 
  499    roles[InstalledReleaseDate] = 
"installedreleasedate";
 
  500    roles[InstalledFiles] = 
"installedfiles";
 
  501    roles[IsInstalled] = 
"installed";
 
  502    roles[IsUpgradable] = 
"upgradable";
 
  504    roles[IsTransitioning] = 
"transitioning";
 
  505    roles[PayloadSize] = 
"size";
 
  506    roles[DownloadedSize] = 
"downloaded";
 
  507    d->m_roleNames = roles;
 
  510NewstuffModel::~NewstuffModel()
 
  515int NewstuffModel::rowCount(
const QModelIndex &parent)
 const 
  518        return d->m_items.size();
 
  526    if (index.
isValid() && index.
row() >= 0 && index.
row() < d->m_items.size()) {
 
  529            return d->m_items.at(index.
row()).m_name;
 
  531            return d->preview(index.
row());
 
  533            return d->m_items.at(index.
row()).m_name;
 
  535            return d->m_items.at(index.
row()).m_author;
 
  537            return d->m_items.at(index.
row()).m_license;
 
  539            return d->m_items.at(index.
row()).m_summary;
 
  541            return d->m_items.at(index.
row()).m_version;
 
  543            return d->m_items.at(index.
row()).m_releaseDate;
 
  545            return d->m_items.at(index.
row()).m_previewUrl;
 
  547            return d->m_items.at(index.
row()).m_payloadUrl;
 
  548        case InstalledVersion:
 
  549            return d->m_items.at(index.
row()).installedVersion();
 
  550        case InstalledReleaseDate:
 
  551            return d->m_items.at(index.
row()).installedReleaseDate();
 
  553            return d->m_items.at(index.
row()).installedFiles();
 
  555            return !d->m_items.at(index.
row()).m_registryNode.isNull();
 
  557            return d->m_items.at(index.
row()).isUpgradable();
 
  559            return d->m_items.at(index.
row()).m_category;
 
  560        case IsTransitioning:
 
  561            return d->isTransitioning(index.
row());
 
  563            qint64 
const size = d->m_items.at(index.
row()).m_payloadSize;
 
  564            QUrl const url = d->m_items.at(index.
row()).m_payloadUrl;
 
  565            if (size < -1 && !url.
isEmpty()) {
 
  566                d->m_items[index.
row()].m_payloadSize = -1; 
 
  570            return qMax<qint64>(-1, size);
 
  573            return d->m_items.at(index.
row()).m_downloadedSize;
 
  582    return d->m_roleNames;
 
  585int NewstuffModel::count()
 const 
  590void NewstuffModel::setProvider(
const QString &downloadUrl)
 
  592    if (downloadUrl == d->m_provider) {
 
  596    d->m_provider = downloadUrl;
 
  597    Q_EMIT providerChanged();
 
  601QString NewstuffModel::provider()
 const 
  603    return d->m_provider;
 
  606void NewstuffModel::setTargetDirectory(
const QString &targetDirectory)
 
  608    if (targetDirectory != d->m_targetDirectory) {
 
  610        if (!targetDir.exists()) {
 
  612                qDebug() << 
"Failed to create directory " << targetDirectory << 
", newstuff installation might fail.";
 
  616        d->m_targetDirectory = targetDirectory;
 
  617        Q_EMIT targetDirectoryChanged();
 
  621QString NewstuffModel::targetDirectory()
 const 
  623    return d->m_targetDirectory;
 
  626void NewstuffModel::setRegistryFile(
const QString &filename, IdTag idTag)
 
  628    QString registryFile = filename;
 
  633    if (d->m_registryFile != registryFile) {
 
  634        d->m_registryFile = registryFile;
 
  636        Q_EMIT registryFileChanged();
 
  639        if (!inputFile.exists()) {
 
  642            QDomProcessingInstruction header = d->m_registryDocument.createProcessingInstruction(
"xml", R
"(version="1.0" encoding="utf-8")"); 
  644            d->m_root = d->m_registryDocument.createElement("hotnewstuffregistry");
 
  647            QFile input(registryFile);
 
  649                mDebug() << 
"Cannot open newstuff registry " << registryFile;
 
  653            if (!d->m_registryDocument.setContent(&input)) {
 
  654                mDebug() << 
"Cannot parse newstuff registry " << registryFile;
 
  658            d->m_root = d->m_registryDocument.documentElement();
 
  665QString NewstuffModel::registryFile()
 const 
  667    return d->m_registryFile;
 
  670void NewstuffModel::install(
int index)
 
  672    if (index < 0 || index >= d->m_items.size()) {
 
  676    NewstuffModelPrivate::Action action(index, NewstuffModelPrivate::Install);
 
  679        if (d->m_actionQueue.contains(action)) {
 
  682        d->m_actionQueue << action;
 
  688void NewstuffModel::uninstall(
int idx)
 
  690    if (idx < 0 || idx >= d->m_items.size()) {
 
  694    if (d->m_items[idx].m_registryNode.isNull()) {
 
  695        Q_EMIT uninstallationFinished(idx);
 
  698    NewstuffModelPrivate::Action action(idx, NewstuffModelPrivate::Uninstall);
 
  701        if (d->m_actionQueue.contains(action)) {
 
  704        d->m_actionQueue << action;
 
  710void NewstuffModel::cancel(
int index)
 
  712    if (!d->isTransitioning(index)) {
 
  718        if (d->m_currentAction.first == index) {
 
  719            if (d->m_currentAction.second == NewstuffModelPrivate::Install) {
 
  720                if (d->m_currentReply) {
 
  721                    d->m_currentReply->abort();
 
  722                    d->m_currentReply->deleteLater();
 
  723                    d->m_currentReply = 
nullptr;
 
  726                if (d->m_unpackProcess) {
 
  727                    d->m_unpackProcess->terminate();
 
  728                    d->m_unpackProcess->deleteLater();
 
  729                    d->m_unpackProcess = 
nullptr;
 
  732                if (d->m_currentFile) {
 
  733                    d->m_currentFile->deleteLater();
 
  734                    d->m_currentFile = 
nullptr;
 
  737                d->m_items[d->m_currentAction.first].m_downloadedSize = 0;
 
  739                Q_EMIT installationFailed(d->m_currentAction.first, tr(
"Installation aborted by user."));
 
  740                d->m_currentAction = NewstuffModelPrivate::Action(-1, NewstuffModelPrivate::Install);
 
  745            if (d->m_currentAction.second == NewstuffModelPrivate::Install) {
 
  746                NewstuffModelPrivate::Action install(index, NewstuffModelPrivate::Install);
 
  747                d->m_actionQueue.removeAll(install);
 
  748                Q_EMIT installationFailed(index, tr(
"Installation aborted by user."));
 
  750                NewstuffModelPrivate::Action uninstall(index, NewstuffModelPrivate::Uninstall);
 
  751                d->m_actionQueue.removeAll(uninstall);
 
  752                Q_EMIT uninstallationFinished(index); 
 
  760void NewstuffModel::updateProgress(qint64 bytesReceived, qint64 bytesTotal)
 
  762    qreal 
const progress = qBound<qreal>(0.0, 0.9 * bytesReceived / qreal(bytesTotal), 1.0);
 
  763    Q_EMIT installationProgressed(d->m_currentAction.first, progress);
 
  764    NewstuffItem &item = d->m_items[d->m_currentAction.first];
 
  765    item.m_payloadSize = bytesTotal;
 
  766    if (qreal(bytesReceived - item.m_downloadedSize) / bytesTotal >= 0.01 || progress >= 0.9) {
 
  768        item.m_downloadedSize = bytesReceived;
 
  769        QModelIndex const affected = index(d->m_currentAction.first);
 
  770        Q_EMIT dataChanged(affected, affected);
 
  774void NewstuffModel::retrieveData()
 
  776    if (d->m_currentReply && d->m_currentReply->isReadable()) {
 
  779        if (!redirectionAttribute.
isNull()) {
 
  780            d->m_currentReply = d->m_networkAccessManager.get(
QNetworkRequest(redirectionAttribute.
toUrl()));
 
  781            QObject::connect(d->m_currentReply, SIGNAL(readyRead()), 
this, SLOT(retrieveData()));
 
  782            QObject::connect(d->m_currentReply, SIGNAL(readChannelFinished()), 
this, SLOT(retrieveData()));
 
  783            QObject::connect(d->m_currentReply, SIGNAL(downloadProgress(qint64, qint64)), 
this, SLOT(updateProgress(qint64, qint64)));
 
  785            d->m_currentFile->write(d->m_currentReply->readAll());
 
  786            if (d->m_currentReply->isFinished()) {
 
  787                d->m_currentReply->deleteLater();
 
  788                d->m_currentReply = 
nullptr;
 
  789                d->m_currentFile->flush();
 
  796void NewstuffModel::mapInstalled(
int exitStatus)
 
  798    if (d->m_unpackProcess) {
 
  799        d->m_unpackProcess->deleteLater();
 
  800        d->m_unpackProcess = 
nullptr;
 
  803    if (d->m_currentFile) {
 
  804        d->m_currentFile->deleteLater();
 
  805        d->m_currentFile = 
nullptr;
 
  808    Q_EMIT installationProgressed(d->m_currentAction.first, 1.0);
 
  809    d->m_items[d->m_currentAction.first].m_downloadedSize = 0;
 
  810    if (exitStatus == 0) {
 
  811        Q_EMIT installationFinished(d->m_currentAction.first);
 
  813        mDebug() << 
"Process exit status " << exitStatus << 
" indicates an error.";
 
  814        Q_EMIT installationFailed(d->m_currentAction.first, QStringLiteral(
"Unable to unpack file. Process exited with status code %1.").arg(exitStatus));
 
  816    QModelIndex const affected = index(d->m_currentAction.first);
 
  820        d->m_currentAction = NewstuffModelPrivate::Action(-1, NewstuffModelPrivate::Install);
 
  822    Q_EMIT dataChanged(affected, affected);
 
  826void NewstuffModel::mapUninstalled()
 
  828    QModelIndex const affected = index(d->m_currentAction.first);
 
  829    Q_EMIT uninstallationFinished(d->m_currentAction.first);
 
  833        d->m_currentAction = NewstuffModelPrivate::Action(-1, NewstuffModelPrivate::Install);
 
  835    Q_EMIT dataChanged(affected, affected);
 
  839void NewstuffModel::contentsListed(
int exitStatus)
 
  841    if (exitStatus == 0) {
 
  843        d->updateRegistry(files);
 
  845        QObject::disconnect(d->m_unpackProcess, SIGNAL(finished(
int)), 
this, SLOT(contentsListed(
int)));
 
  846        QObject::connect(d->m_unpackProcess, SIGNAL(finished(
int)), 
this, SLOT(mapInstalled(
int)));
 
  849                                              << 
"-f" << d->m_currentFile->fileName();
 
  850        d->m_unpackProcess->start(
"tar", arguments);
 
  852        mDebug() << 
"Process exit status " << exitStatus << 
" indicates an error.";
 
  853        Q_EMIT installationFailed(d->m_currentAction.first,
 
  854                                  QStringLiteral(
"Unable to list file contents. Process exited with status code %1.").arg(exitStatus));
 
  858            d->m_currentAction = NewstuffModelPrivate::Action(-1, NewstuffModelPrivate::Install);
 
  864void NewstuffModelPrivate::updateRegistry(
const QStringList &files)
 
  866    Q_EMIT m_parent->installationProgressed(m_currentAction.first, 0.92);
 
  867    if (!m_registryFile.isEmpty()) {
 
  868        NewstuffItem &item = m_items[m_currentAction.first];
 
  869        QDomNode node = item.m_registryNode;
 
  870        NewstuffModelPrivate::NodeAction action = node.
isNull() ? NewstuffModelPrivate::Append : NewstuffModelPrivate::Replace;
 
  872            node = m_root.
appendChild(m_registryDocument.createElement(
"stuff"));
 
  876        changeNode(node, m_registryDocument, 
"name", item.m_name, action);
 
  877        changeNode(node, m_registryDocument, 
"providerid", m_provider, action);
 
  878        changeNode(node, m_registryDocument, 
"author", item.m_author, action);
 
  879        changeNode(node, m_registryDocument, 
"homepage", 
QString(), action);
 
  880        changeNode(node, m_registryDocument, 
"licence", item.m_license, action);
 
  881        changeNode(node, m_registryDocument, 
"version", item.m_version, action);
 
  882        QString const itemId = m_idTag == NewstuffModel::PayloadTag ? item.m_payloadUrl.toString() : item.m_name;
 
  883        changeNode(node, m_registryDocument, 
"id", itemId, action);
 
  884        changeNode(node, m_registryDocument, 
"releasedate", item.m_releaseDate, action);
 
  885        changeNode(node, m_registryDocument, 
"summary", item.m_summary, action);
 
  886        changeNode(node, m_registryDocument, 
"changelog", 
QString(), action);
 
  887        changeNode(node, m_registryDocument, 
"preview", item.m_previewUrl.toString(), action);
 
  888        changeNode(node, m_registryDocument, 
"previewBig", item.m_previewUrl.toString(), action);
 
  889        changeNode(node, m_registryDocument, 
"payload", item.m_payloadUrl.toString(), action);
 
  890        changeNode(node, m_registryDocument, 
"status", 
"installed", action);
 
  891        m_items[m_currentAction.first].m_registryNode = node;
 
  893        bool hasChildren = 
true;
 
  894        while (hasChildren) {
 
  897            hasChildren = !fileList.
isEmpty();
 
  898            for (
int i = 0; i < fileList.
count(); ++i) {
 
  903        for (
const QString &file : files) {
 
  912void NewstuffModelPrivate::processQueue()
 
  914    if (m_actionQueue.empty() || m_currentAction.first >= 0) {
 
  920        m_currentAction = m_actionQueue.takeFirst();
 
  922    if (m_currentAction.second == Install) {
 
  923        if (!m_currentFile) {
 
  924            QFileInfo const file = 
QFileInfo(m_items.at(m_currentAction.first).m_payloadUrl.path());
 
  928        if (m_currentFile->open()) {
 
  929            QUrl const payload = m_items.at(m_currentAction.first).m_payloadUrl;
 
  931            QObject::connect(m_currentReply, SIGNAL(readyRead()), m_parent, SLOT(retrieveData()));
 
  932            QObject::connect(m_currentReply, SIGNAL(readChannelFinished()), m_parent, SLOT(retrieveData()));
 
  933            QObject::connect(m_currentReply, SIGNAL(downloadProgress(qint64, qint64)), m_parent, SLOT(updateProgress(qint64, qint64)));
 
  936            mDebug() << 
"Failed to write to " << m_currentFile->fileName();
 
  941        QObject::connect(watcher, SIGNAL(finished()), m_parent, SLOT(mapUninstalled()));
 
  942        QObject::connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
 
  945        watcher->setFuture(future);
 
  949NewstuffItem NewstuffModelPrivate::importNode(
const QDomNode &node)
 
  953    readValue<QString>(node, 
"name", &item.m_name);
 
  954    readValue<QString>(node, 
"author", &item.m_author);
 
  955    readValue<QString>(node, 
"licence", &item.m_license);
 
  956    readValue<QString>(node, 
"summary", &item.m_summary);
 
  957    readValue<QString>(node, 
"version", &item.m_version);
 
  958    readValue<QString>(node, 
"releasedate", &item.m_releaseDate);
 
  959    readValue<QUrl>(node, 
"preview", &item.m_previewUrl);
 
  960    readValue<QUrl>(node, 
"payload", &item.m_payloadUrl);
 
  964bool NewstuffModelPrivate::isTransitioning(
int index)
 const 
  966    if (m_currentAction.first == index) {
 
  970    for (
const Action &action : m_actionQueue) {
 
  971        if (action.first == index) {
 
  981#include "moc_NewstuffModel.cpp" 
KIOCORE_EXPORT MkpathJob * mkpath(const QUrl &url, const QUrl &baseUrl=QUrl(), JobFlags flags=DefaultFlags)
 
QString path(const QString &relativePath)
 
Binds a QML item to a specific geodetic location in screen coordinates.
 
bool mkpath(const QString &dirPath) const const
 
bool rmdir(const QString &dirName) const const
 
QString value() const const
 
QDomElement createElement(const QString &tagName)
 
QDomText createTextNode(const QString &value)
 
QDomElement documentElement() const const
 
ParseResult setContent(QAnyStringView text, ParseOptions options)
 
QDomNodeList elementsByTagName(const QString &tagname) const const
 
void setAttribute(const QString &name, const QString &value)
 
QString text() const const
 
bool contains(const QString &name) const const
 
QDomNode namedItem(const QString &name) const const
 
QDomNode appendChild(const QDomNode &newChild)
 
QDomNamedNodeMap attributes() const const
 
QDomNode firstChild() const const
 
bool isNull() const const
 
QDomNode namedItem(const QString &name) const const
 
QDomNode removeChild(const QDomNode &oldChild)
 
QDomAttr toAttr() const const
 
QDomElement toElement() const const
 
QDomNode at(int index) const const
 
bool isEmpty() const const
 
QDomNode item(int index) const const
 
QString fileName() const const
 
QImage fromData(QByteArrayView data, const char *format)
 
bool isNull() const const
 
bool isValid() const const
 
QVariant attribute(QNetworkRequest::Attribute code) const const
 
QNetworkAccessManager::Operation operation() const const
 
RedirectionTargetAttribute
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
bool disconnect(const QMetaObject::Connection &connection)
 
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
 
QProcessEnvironment systemEnvironment()
 
QString value(const QString &name, const QString &defaultValue) const const
 
qsizetype length() const const
 
QString mid(qsizetype position, qsizetype n) const const
 
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
 
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
 
QFuture< T > run(Function function,...)
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
 
bool isEmpty() const const
 
bool isNull() const const
 
bool isValid() const const