qmltaskmanager.cpp 7.74 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29

30
#include "qmltaskmanager.h"
31
#include "qmljseditorconstants.h"
32

33
#include <coreplugin/idocument.h>
hjk's avatar
hjk committed
34
#include <projectexplorer/projectexplorer.h>
dt's avatar
dt committed
35
#include <projectexplorer/taskhub.h>
36
#include <qmljs/qmljsmodelmanagerinterface.h>
37
#include <qmljs/qmljscontext.h>
38
39
40
41
#include <qmljs/qmljslink.h>
#include <qmljs/qmljscheck.h>
#include <qmljseditor/qmljseditor.h>
#include <qmljseditor/qmljseditoreditable.h>
42

43
44
#include <QDebug>
#include <QtConcurrentRun>
45
#include <utils/runextensions.h>
46
47

using namespace QmlJS;
48

49
namespace QmlJSEditor {
50
51
52
namespace Internal {

QmlTaskManager::QmlTaskManager(QObject *parent) :
53
54
55
    QObject(parent),
    m_taskHub(0),
    m_updatingSemantic(false)
56
{
hjk's avatar
hjk committed
57
    m_taskHub = ProjectExplorer::ProjectExplorerPlugin::taskHub();
58

59
60
61
62
63
64
    // displaying results incrementally leads to flickering
//    connect(&m_messageCollector, SIGNAL(resultsReadyAt(int,int)),
//            SLOT(displayResults(int,int)));
    connect(&m_messageCollector, SIGNAL(finished()),
            SLOT(displayAllResults()));

65
    m_updateDelay.setInterval(500);
66
67
68
69
70
    m_updateDelay.setSingleShot(true);
    connect(&m_updateDelay, SIGNAL(timeout()),
            SLOT(updateMessagesNow()));
}

71
static QList<ProjectExplorer::Task> convertToTasks(const QList<DiagnosticMessage> &messages, const Utils::FileName &fileName, const Core::Id &category)
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
{
    QList<ProjectExplorer::Task> result;
    foreach (const DiagnosticMessage &msg, messages) {
        ProjectExplorer::Task::TaskType type
                = msg.isError() ? ProjectExplorer::Task::Error
                                : ProjectExplorer::Task::Warning;

        ProjectExplorer::Task task(type, msg.message, fileName, msg.loc.startLine,
                                   category);

        result += task;
    }
    return result;
}

87
static QList<ProjectExplorer::Task> convertToTasks(const QList<StaticAnalysis::Message> &messages, const Utils::FileName &fileName, const Core::Id &category)
88
89
90
91
92
93
94
{
    QList<DiagnosticMessage> diagnostics;
    foreach (const StaticAnalysis::Message &msg, messages)
        diagnostics += msg.toDiagnosticMessage();
    return convertToTasks(diagnostics, fileName, category);
}

95
96
97
98
void QmlTaskManager::collectMessages(
        QFutureInterface<FileErrorMessages> &future,
        Snapshot snapshot, QList<ModelManagerInterface::ProjectInfo> projectInfos,
        QStringList importPaths, bool updateSemantic)
99
{
100
101
102
103
104
105
106
    foreach (const ModelManagerInterface::ProjectInfo &info, projectInfos) {
        QHash<QString, QList<DiagnosticMessage> > linkMessages;
        ContextPtr context;
        if (updateSemantic) {
            Link link(snapshot, importPaths, snapshot.libraryInfo(info.qtImportsPath));
            context = link(&linkMessages);
        }
107

108
109
110
111
        foreach (const QString &fileName, info.sourceFiles) {
            Document::Ptr document = snapshot.document(fileName);
            if (!document)
                continue;
112

113
114
            FileErrorMessages result;
            result.fileName = fileName;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
            if (Document::isFullySupportedLanguage(document->language())) {
                result.tasks = convertToTasks(document->diagnosticMessages(),
                                              Utils::FileName::fromString(fileName),
                                              Core::Id(Constants::TASK_CATEGORY_QML));

                if (updateSemantic) {
                    result.tasks += convertToTasks(linkMessages.value(fileName),
                                                   Utils::FileName::fromString(fileName),
                                                   Core::Id(Constants::TASK_CATEGORY_QML_ANALYSIS));

                    Check checker(document, context);
                    result.tasks += convertToTasks(checker(),
                                                   Utils::FileName::fromString(fileName),
                                                   Core::Id(Constants::TASK_CATEGORY_QML_ANALYSIS));
                }
130
            }
131

132
133
            if (!result.tasks.isEmpty())
                future.reportResult(result);
134
135
136
            if (future.isCanceled())
                break;
        }
137
    }
138
139
}

140
void QmlTaskManager::updateMessages()
141
{
142
143
    m_updateDelay.start();
}
144

145
146
147
148
149
150
void QmlTaskManager::updateSemanticMessagesNow()
{
    updateMessagesNow(true);
}

void QmlTaskManager::updateMessagesNow(bool updateSemantic)
151
{
152
153
154
155
156
    // don't restart a small update if a big one is running
    if (!updateSemantic && m_updatingSemantic)
        return;
    m_updatingSemantic = updateSemantic;

157
158
    // abort any update that's going on already
    m_messageCollector.cancel();
159
    removeAllTasks(updateSemantic);
160

161
162
163
164
165
    ModelManagerInterface *modelManager = ModelManagerInterface::instance();

    // process them
    QFuture<FileErrorMessages> future =
            QtConcurrent::run<FileErrorMessages>(
166
                &collectMessages, modelManager->newestSnapshot(), modelManager->projectInfos(),
167
                modelManager->importPaths(), updateSemantic);
168
    m_messageCollector.setFuture(future);
169
170
171
172
173
174
175
176
}

void QmlTaskManager::documentsRemoved(const QStringList path)
{
    foreach (const QString &item, path)
        removeTasksForFile(item);
}

177
void QmlTaskManager::displayResults(int begin, int end)
178
{
179
180
    for (int i = begin; i < end; ++i) {
        FileErrorMessages result = m_messageCollector.resultAt(i);
181
        foreach (const ProjectExplorer::Task &task, result.tasks) {
182
183
184
185
186
187
188
189
            insertTask(task);
        }
    }
}

void QmlTaskManager::displayAllResults()
{
    displayResults(0, m_messageCollector.future().resultCount());
190
    m_updatingSemantic = false;
191
192
193
194
}

void QmlTaskManager::insertTask(const ProjectExplorer::Task &task)
{
195
    QList<ProjectExplorer::Task> tasks = m_docsWithTasks.value(task.file.toString());
196
    tasks.append(task);
197
    m_docsWithTasks.insert(task.file.toString(), tasks);
dt's avatar
dt committed
198
    m_taskHub->addTask(task);
199
200
201
202
203
204
205
}

void QmlTaskManager::removeTasksForFile(const QString &fileName)
{
    if (m_docsWithTasks.contains(fileName)) {
        const QList<ProjectExplorer::Task> tasks = m_docsWithTasks.value(fileName);
        foreach (const ProjectExplorer::Task &task, tasks)
dt's avatar
dt committed
206
            m_taskHub->removeTask(task);
207
        m_docsWithTasks.remove(fileName);
208
209
210
    }
}

211
void QmlTaskManager::removeAllTasks(bool clearSemantic)
212
{
213
214
215
    m_taskHub->clearTasks(Constants::TASK_CATEGORY_QML);
    if (clearSemantic)
        m_taskHub->clearTasks(Constants::TASK_CATEGORY_QML_ANALYSIS);
216
217
218
    m_docsWithTasks.clear();
}

219
} // Internal
Kai Koehne's avatar
Kai Koehne committed
220
} // QmlProjectManager