aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp
blob: 993bd3ac81fd6394636842bb349dc4327ab1c829 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "filepathmodel.h"

#include "exportnotification.h"

#include "projectexplorer/project.h"
#include "projectexplorer/projectnodes.h"
#include "utils/runextensions.h"

#include <QLoggingCategory>
#include <QTimer>

using namespace ProjectExplorer;

namespace  {
Q_LOGGING_CATEGORY(loggerError, "qtc.designer.assetExportPlugin.filePathModel", QtCriticalMsg)
Q_LOGGING_CATEGORY(loggerInfo, "qtc.designer.assetExportPlugin.filePathModel", QtInfoMsg)

void findQmlFiles(QFutureInterface<Utils::FilePath> &f, const Project *project)
{
    if (!project || f.isCanceled())
        return;

    int index = 0;
    project->files([&f, &index](const Node* node) ->bool {
        if (f.isCanceled())
            return false;
        Utils::FilePath path = node->filePath();
        bool isComponent = !path.fileName().isEmpty() && path.fileName().front().isUpper();
        if (isComponent && node->filePath().endsWith(".ui.qml"))
            f.reportResult(path, index++);
        return true;
    });
}
}

namespace QmlDesigner {

FilePathModel::FilePathModel(ProjectExplorer::Project *project, QObject *parent)
    : QAbstractListModel(parent),
      m_project(project)
{
    QTimer::singleShot(0, this, &FilePathModel::processProject);
}

FilePathModel::~FilePathModel()
{
    if (m_preprocessWatcher && !m_preprocessWatcher->isCanceled() &&
            !m_preprocessWatcher->isFinished()) {
        ExportNotification::addInfo(tr("Canceling file preparation."));
        m_preprocessWatcher->cancel();
        m_preprocessWatcher->waitForFinished();
        qCDebug(loggerInfo) << "Canceled file preparation.";
    }
}

Qt::ItemFlags FilePathModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags itemFlags = QAbstractListModel::flags(index);
    if (index.isValid())
        itemFlags |= Qt::ItemIsUserCheckable;
    return itemFlags;
}

int FilePathModel::rowCount(const QModelIndex &parent) const
{
    if (!parent.isValid())
        return m_files.count();
    return 0;
}

QVariant FilePathModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return {};

    switch (role) {
    case Qt::DisplayRole:
        return m_files[index.row()].toUserOutput();
    case Qt::CheckStateRole:
        return m_skipped.count(m_files[index.row()]) ? Qt::Unchecked : Qt::Checked;
    default:
        break;
    }

    return {};
}

bool FilePathModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() || role != Qt::CheckStateRole)
        return false;

    const Utils::FilePath path = m_files[index.row()];
    if (value == Qt::Checked)
        m_skipped.erase(path);
    else
        m_skipped.insert(path);

    emit dataChanged(index, index);
    return true;
}

Utils::FilePaths FilePathModel::files() const
{
    Utils::FilePaths selectedPaths;
    std::copy_if(m_files.begin(), m_files.end(), std::back_inserter(selectedPaths),
                 [this](const Utils::FilePath &path) {
        return !m_skipped.count(path);
    });
    return selectedPaths;
}

void FilePathModel::processProject()
{
    if (m_preprocessWatcher && !m_preprocessWatcher->isCanceled() &&
            !m_preprocessWatcher->isFinished()) {
        qCDebug(loggerError) << "Previous model load not finished.";
        return;
    }

    beginResetModel();
    m_preprocessWatcher.reset(new QFutureWatcher<Utils::FilePath>(this));
    connect(m_preprocessWatcher.get(), &QFutureWatcher<Utils::FilePath>::resultReadyAt, this,
            [this](int resultIndex) {
        beginInsertRows(index(0, 0) , m_files.count(), m_files.count());
        m_files.append(m_preprocessWatcher->resultAt(resultIndex));
        endInsertRows();
    });

    connect(m_preprocessWatcher.get(), &QFutureWatcher<Utils::FilePath>::finished,
            this, &FilePathModel::endResetModel);

    QFuture<Utils::FilePath> f = Utils::runAsync(&findQmlFiles, m_project);
    m_preprocessWatcher->setFuture(f);
}


}