buildmanager.cpp 22.8 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
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
****************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
#include "buildmanager.h"
hjk's avatar
hjk committed
31
32

#include "buildprogress.h"
Tobias Hunger's avatar
Tobias Hunger committed
33
#include "buildsteplist.h"
con's avatar
con committed
34
#include "compileoutputwindow.h"
35
#include "project.h"
36
#include "projectexplorer.h"
37
#include "projectexplorersettings.h"
Tobias Hunger's avatar
Tobias Hunger committed
38
#include "target.h"
hjk's avatar
hjk committed
39
#include "taskwindow.h"
dt's avatar
dt committed
40
#include "taskhub.h"
con's avatar
con committed
41

42
#include <coreplugin/icore.h>
43
#include <coreplugin/progressmanager/progressmanager.h>
con's avatar
con committed
44
#include <coreplugin/progressmanager/futureprogress.h>
45
#include <projectexplorer/session.h>
hjk's avatar
hjk committed
46
#include <extensionsystem/pluginmanager.h>
con's avatar
con committed
47

48
#include <QPointer>
49
50
51
52
53
#include <QTime>
#include <QTimer>
#include <QList>
#include <QHash>
#include <QFutureWatcher>
54
#include <QElapsedTimer>
55

56
#include <utils/QtConcurrentTools>
57

58
#include <QApplication>
con's avatar
con committed
59

60
61
62
63
64
using namespace Core;

namespace ProjectExplorer {

static QString msgProgress(int progress, int total)
Friedemann Kleint's avatar
Friedemann Kleint committed
65
{
66
    return BuildManager::tr("Finished %1 of %n steps", 0, total).arg(progress);
67
68
}

69
70
struct BuildManagerPrivate
{
71
72
73
74
75
76
77
    BuildManagerPrivate();

    Internal::CompileOutputWindow *m_outputWindow;
    TaskHub *m_taskHub;
    Internal::TaskWindow *m_taskWindow;

    QList<BuildStep *> m_buildQueue;
Daniel Teske's avatar
Daniel Teske committed
78
    QList<bool> m_enabledState;
79
    QStringList m_stepNames;
80
81
    bool m_running;
    QFutureWatcher<bool> m_watcher;
82
    QFutureInterface<bool> m_futureInterfaceForAysnc;
83
84
85
86
    BuildStep *m_currentBuildStep;
    QString m_currentConfiguration;
    // used to decide if we are building a project to decide when to emit buildStateChanged(Project *)
    QHash<Project *, int>  m_activeBuildSteps;
Daniel Teske's avatar
Daniel Teske committed
87
88
    QHash<Target *, int> m_activeBuildStepsPerTarget;
    QHash<ProjectConfiguration *, int> m_activeBuildStepsPerProjectConfiguration;
89
90
    Project *m_previousBuildStepProject;
    // is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling
Daniel Teske's avatar
Daniel Teske committed
91
    bool m_skipDisabled;
92
93
94
95
96
97
98
    bool m_canceling;

    // Progress reporting to the progress manager
    int m_progress;
    int m_maxProgress;
    QFutureInterface<void> *m_progressFutureInterface;
    QFutureWatcher<void> m_progressWatcher;
99
    QPointer<FutureProgress> m_futureProgress;
100
101

    QElapsedTimer m_elapsed;
102
103
104
105
106
};

BuildManagerPrivate::BuildManagerPrivate() :
    m_running(false)
  , m_previousBuildStepProject(0)
Daniel Teske's avatar
Daniel Teske committed
107
  , m_skipDisabled(false)
108
109
110
111
  , m_canceling(false)
  , m_maxProgress(0)
  , m_progressFutureInterface(0)
{
Friedemann Kleint's avatar
Friedemann Kleint committed
112
113
}

hjk's avatar
hjk committed
114
115
116
static BuildManagerPrivate *d = 0;
static BuildManager *m_instance = 0;

hjk's avatar
hjk committed
117
BuildManager::BuildManager(QObject *parent, QAction *cancelBuildAction)
hjk's avatar
hjk committed
118
    : QObject(parent)
con's avatar
con committed
119
{
hjk's avatar
hjk committed
120
121
122
    m_instance = this;
    d = new BuildManagerPrivate;

123
    connect(&d->m_watcher, SIGNAL(finished()),
con's avatar
con committed
124
125
            this, SLOT(nextBuildQueue()));

126
    connect(&d->m_watcher, SIGNAL(progressValueChanged(int)),
127
            this, SLOT(progressChanged()));
128
129
    connect(&d->m_watcher, SIGNAL(progressTextChanged(QString)),
            this, SLOT(progressTextChanged()));
Robert Loehning's avatar
Robert Loehning committed
130
    connect(&d->m_watcher, SIGNAL(progressRangeChanged(int,int)),
131
132
            this, SLOT(progressChanged()));

hjk's avatar
hjk committed
133
    connect(SessionManager::instance(), SIGNAL(aboutToRemoveProject(ProjectExplorer::Project*)),
Robert Loehning's avatar
Robert Loehning committed
134
            this, SLOT(aboutToRemoveProject(ProjectExplorer::Project*)));
135

136
    d->m_outputWindow = new Internal::CompileOutputWindow(cancelBuildAction);
137
    ExtensionSystem::PluginManager::addObject(d->m_outputWindow);
con's avatar
con committed
138

139
    d->m_taskWindow = new Internal::TaskWindow;
140
    ExtensionSystem::PluginManager::addObject(d->m_taskWindow);
con's avatar
con committed
141

142
    qRegisterMetaType<ProjectExplorer::BuildStep::OutputFormat>();
143
    qRegisterMetaType<ProjectExplorer::BuildStep::OutputNewlineSetting>();
144

145
    connect(d->m_taskWindow, SIGNAL(tasksChanged()),
146
            this, SLOT(updateTaskCount()));
con's avatar
con committed
147

148
    connect(d->m_taskWindow, SIGNAL(tasksCleared()),
dt's avatar
dt committed
149
150
            this,SIGNAL(tasksCleared()));

151
    connect(&d->m_progressWatcher, SIGNAL(canceled()),
con's avatar
con committed
152
            this, SLOT(cancel()));
153
    connect(&d->m_progressWatcher, SIGNAL(finished()),
154
            this, SLOT(finish()));
con's avatar
con committed
155
156
}

hjk's avatar
hjk committed
157
158
159
160
161
QObject *BuildManager::instance()
{
    return m_instance;
}

dt's avatar
dt committed
162
163
void BuildManager::extensionsInitialized()
{
164
    TaskHub::addCategory(Constants::TASK_CATEGORY_COMPILE,
165
                         tr("Compile", "Category for compiler issues listed under 'Issues'"));
166
    TaskHub::addCategory(Constants::TASK_CATEGORY_BUILDSYSTEM,
167
                         tr("Build System", "Category for build system issues listed under 'Issues'"));
168
169
    TaskHub::addCategory(Constants::TASK_CATEGORY_DEPLOYMENT,
                         tr("Deployment", "Category for deployment issues listed under 'Issues'"));
dt's avatar
dt committed
170
171
}

con's avatar
con committed
172
173
174
BuildManager::~BuildManager()
{
    cancel();
hjk's avatar
hjk committed
175
    m_instance = 0;
176
    ExtensionSystem::PluginManager::removeObject(d->m_taskWindow);
177
    delete d->m_taskWindow;
con's avatar
con committed
178

179
    ExtensionSystem::PluginManager::removeObject(d->m_outputWindow);
180
    delete d->m_outputWindow;
hjk's avatar
hjk committed
181
182

    delete d;
con's avatar
con committed
183
184
}

hjk's avatar
hjk committed
185
void BuildManager::aboutToRemoveProject(Project *p)
186
{
187
188
    QHash<Project *, int>::iterator it = d->m_activeBuildSteps.find(p);
    QHash<Project *, int>::iterator end = d->m_activeBuildSteps.end();
189
190
191
192
193
194
195
196
    if (it != end && *it > 0) {
        // We are building the project that's about to be removed.
        // We cancel the whole queue, which isn't the nicest thing to do
        // but a safe thing.
        cancel();
    }
}

hjk's avatar
hjk committed
197
bool BuildManager::isBuilding()
con's avatar
con committed
198
199
{
    // we are building even if we are not running yet
200
    return !d->m_buildQueue.isEmpty() || d->m_running;
con's avatar
con committed
201
202
}

hjk's avatar
hjk committed
203
int BuildManager::getErrorTaskCount()
204
205
{
    const int errors =
206
207
208
            d->m_taskWindow->errorTaskCount(Constants::TASK_CATEGORY_BUILDSYSTEM)
            + d->m_taskWindow->errorTaskCount(Constants::TASK_CATEGORY_COMPILE)
            + d->m_taskWindow->errorTaskCount(Constants::TASK_CATEGORY_DEPLOYMENT);
209
210
211
    return errors;
}

con's avatar
con committed
212
213
void BuildManager::cancel()
{
214
    if (d->m_running) {
215
216
        if (d->m_canceling)
            return;
217
218
        d->m_canceling = true;
        d->m_watcher.cancel();
219
        if (d->m_currentBuildStep->runInGuiThread()) {
220
            d->m_currentBuildStep->cancel();
221
222
223
224
225
            while (d->m_canceling)
                QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
        } else {
            d->m_watcher.waitForFinished();
        }
con's avatar
con committed
226
227
228
    }
}

229
230
void BuildManager::updateTaskCount()
{
231
    const int errors = getErrorTaskCount();
232
    ProgressManager::setApplicationLabel(errors > 0 ? QString::number(errors) : QString());
hjk's avatar
hjk committed
233
    emit m_instance->tasksChanged();
234
235
236
237
}

void BuildManager::finish()
{
238
239
240
241
242
    const QTime format = QTime(0, 0, 0, 0).addMSecs(d->m_elapsed.elapsed() + 500);
    QString time = format.toString(QLatin1String("h:mm:ss"));
    if (time.startsWith(QLatin1String("0:")))
        time.remove(0, 2); // Don't display zero hours
    addToOutputWindow(tr("Elapsed time: %1.") .arg(time), BuildStep::MessageOutput);
243

244
    QApplication::alert(ICore::mainWindow(), 3000);
245
246
}

con's avatar
con committed
247
248
void BuildManager::emitCancelMessage()
{
249
    addToOutputWindow(tr("Canceled build/deployment."), BuildStep::ErrorMessageOutput);
con's avatar
con committed
250
251
252
253
}

void BuildManager::clearBuildQueue()
{
254
    foreach (BuildStep *bs, d->m_buildQueue) {
Daniel Teske's avatar
Daniel Teske committed
255
        decrementActiveBuildSteps(bs);
256
        disconnectOutput(bs);
257
    }
con's avatar
con committed
258

259
    d->m_stepNames.clear();
260
    d->m_buildQueue.clear();
Daniel Teske's avatar
Daniel Teske committed
261
    d->m_enabledState.clear();
262
263
264
    d->m_running = false;
    d->m_previousBuildStepProject = 0;
    d->m_currentBuildStep = 0;
con's avatar
con committed
265

266
267
268
269
270
    d->m_progressFutureInterface->reportCanceled();
    d->m_progressFutureInterface->reportFinished();
    d->m_progressWatcher.setFuture(QFuture<void>());
    delete d->m_progressFutureInterface;
    d->m_progressFutureInterface = 0;
271
    d->m_futureProgress = 0;
272
    d->m_maxProgress = 0;
con's avatar
con committed
273

hjk's avatar
hjk committed
274
    emit m_instance->buildQueueFinished(false);
con's avatar
con committed
275
276
277
278
279
}


void BuildManager::toggleOutputWindow()
{
280
    d->m_outputWindow->toggle(IOutputPane::ModeSwitch);
con's avatar
con committed
281
282
283
284
}

void BuildManager::showTaskWindow()
{
285
    d->m_taskWindow->popup(IOutputPane::NoModeSwitch);
con's avatar
con committed
286
287
288
289
}

void BuildManager::toggleTaskWindow()
{
290
    d->m_taskWindow->toggle(IOutputPane::ModeSwitch);
con's avatar
con committed
291
292
}

hjk's avatar
hjk committed
293
bool BuildManager::tasksAvailable()
con's avatar
con committed
294
{
295
    const int count =
296
297
298
            d->m_taskWindow->taskCount(Constants::TASK_CATEGORY_BUILDSYSTEM)
            + d->m_taskWindow->taskCount(Constants::TASK_CATEGORY_COMPILE)
            + d->m_taskWindow->taskCount(Constants::TASK_CATEGORY_DEPLOYMENT);
299
    return count > 0;
con's avatar
con committed
300
301
}

302
void BuildManager::startBuildQueue(const QStringList &preambleMessage)
con's avatar
con committed
303
{
304
    if (d->m_buildQueue.isEmpty()) {
hjk's avatar
hjk committed
305
        emit m_instance->buildQueueFinished(true);
306
        return;
307
    }
308
    if (!d->m_running) {
309
        d->m_elapsed.start();
con's avatar
con committed
310
        // Progress Reporting
311
312
        d->m_progressFutureInterface = new QFutureInterface<void>;
        d->m_progressWatcher.setFuture(d->m_progressFutureInterface->future());
313
314
        foreach (const QString &str, preambleMessage)
            addToOutputWindow(str, BuildStep::MessageOutput, BuildStep::DontAppendNewline);
315
316
317
        TaskHub::clearTasks(Constants::TASK_CATEGORY_COMPILE);
        TaskHub::clearTasks(Constants::TASK_CATEGORY_BUILDSYSTEM);
        TaskHub::clearTasks(Constants::TASK_CATEGORY_DEPLOYMENT);
318
319
        ProgressManager::setApplicationLabel(QString());
        d->m_futureProgress = ProgressManager::addTask(d->m_progressFutureInterface->future(),
320
              QString(), "ProjectExplorer.Task.Build",
321
              ProgressManager::KeepOnFinish | ProgressManager::ShowInApplicationIcon);
hjk's avatar
hjk committed
322
        connect(d->m_futureProgress.data(), SIGNAL(clicked()), m_instance, SLOT(showBuildResults()));
323
        d->m_futureProgress.data()->setWidget(new Internal::BuildProgress(d->m_taskWindow));
324
325
        d->m_futureProgress.data()->setStatusBarWidget(new Internal::BuildProgress(d->m_taskWindow,
                                                                                   Qt::Horizontal));
326
327
        d->m_progress = 0;
        d->m_progressFutureInterface->setProgressRange(0, d->m_maxProgress * 100);
con's avatar
con committed
328

329
330
        d->m_running = true;
        d->m_progressFutureInterface->reportStarted();
con's avatar
con committed
331
332
333
        nextStep();
    } else {
        // Already running
334
335
        d->m_progressFutureInterface->setProgressRange(0, d->m_maxProgress * 100);
        d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, msgProgress(d->m_progress, d->m_maxProgress));
con's avatar
con committed
336
337
338
339
340
    }
}

void BuildManager::showBuildResults()
{
341
    if (tasksAvailable())
con's avatar
con committed
342
343
344
345
346
347
        toggleTaskWindow();
    else
        toggleOutputWindow();
    //toggleTaskWindow();
}

348
void BuildManager::addToTaskWindow(const ProjectExplorer::Task &task)
con's avatar
con committed
349
{
350
    d->m_outputWindow->registerPositionOf(task);
dt's avatar
dt committed
351
    // Distribute to all others
352
    TaskHub::addTask(task);
con's avatar
con committed
353
354
}

355
356
void BuildManager::addToOutputWindow(const QString &string, BuildStep::OutputFormat format,
    BuildStep::OutputNewlineSetting newLineSetting)
con's avatar
con committed
357
{
358
359
360
361
362
363
    QString stringToWrite;
    if (format == BuildStep::MessageOutput || format == BuildStep::ErrorMessageOutput) {
        stringToWrite = QTime::currentTime().toString();
        stringToWrite += QLatin1String(": ");
    }
    stringToWrite += string;
364
365
366
    if (newLineSetting == BuildStep::DoAppendNewline)
        stringToWrite += QLatin1Char('\n');
    d->m_outputWindow->appendText(stringToWrite, format);
con's avatar
con committed
367
368
}

369
370
371
void BuildManager::buildStepFinishedAsync()
{
    disconnect(d->m_currentBuildStep, SIGNAL(finished()),
hjk's avatar
hjk committed
372
               m_instance, SLOT(buildStepFinishedAsync()));
373
    d->m_futureInterfaceForAysnc = QFutureInterface<bool>();
374
    nextBuildQueue();
375
376
}

con's avatar
con committed
377
378
void BuildManager::nextBuildQueue()
{
379
    d->m_outputWindow->flush();
380
381
    if (d->m_canceling) {
        d->m_canceling = false;
hjk's avatar
hjk committed
382
        QTimer::singleShot(0, m_instance, SLOT(emitCancelMessage()));
383
384
385
386
387
388
389
390

        disconnectOutput(d->m_currentBuildStep);
        decrementActiveBuildSteps(d->m_currentBuildStep);

        //TODO NBS fix in qtconcurrent
        d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100,
                                                              tr("Build/Deployment canceled"));
        clearBuildQueue();
con's avatar
con committed
391
        return;
392
    }
con's avatar
con committed
393

394
    disconnectOutput(d->m_currentBuildStep);
395
396
    if (!d->m_skipDisabled)
        ++d->m_progress;
397
    d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, msgProgress(d->m_progress, d->m_maxProgress));
Daniel Teske's avatar
Daniel Teske committed
398
    decrementActiveBuildSteps(d->m_currentBuildStep);
con's avatar
con committed
399

Daniel Teske's avatar
Daniel Teske committed
400
    bool result = d->m_skipDisabled || d->m_watcher.result();
con's avatar
con committed
401
402
    if (!result) {
        // Build Failure
403
404
        const QString projectName = d->m_currentBuildStep->project()->displayName();
        const QString targetName = d->m_currentBuildStep->target()->displayName();
405
        addToOutputWindow(tr("Error while building/deploying project %1 (kit: %2)").arg(projectName, targetName), BuildStep::ErrorOutput);
406
        addToOutputWindow(tr("When executing step '%1'").arg(d->m_currentBuildStep->displayName()), BuildStep::ErrorOutput);
con's avatar
con committed
407
        // NBS TODO fix in qtconcurrent
408
        d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, tr("Error while building/deploying project %1 (kit: %2)").arg(projectName, targetName));
con's avatar
con committed
409
410
411
412
413
414
415
416
    }

    if (result)
        nextStep();
    else
        clearBuildQueue();
}

417
418
void BuildManager::progressChanged()
{
419
    if (!d->m_progressFutureInterface)
420
        return;
421
    int range = d->m_watcher.progressMaximum() - d->m_watcher.progressMinimum();
422
    if (range != 0) {
423
        int percent = (d->m_watcher.progressValue() - d->m_watcher.progressMinimum()) * 100 / range;
424
425
        d->m_progressFutureInterface->setProgressValueAndText(d->m_progress * 100 + percent, msgProgress(d->m_progress, d->m_maxProgress)
                                                              + QLatin1Char('\n') + d->m_watcher.progressText());
426
427
428
    }
}

429
430
431
432
433
434
void BuildManager::progressTextChanged()
{
    int range = d->m_watcher.progressMaximum() - d->m_watcher.progressMinimum();
    int percent = 0;
    if (range != 0)
        percent = (d->m_watcher.progressValue() - d->m_watcher.progressMinimum()) * 100 / range;
435
436
    d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100 + percent, msgProgress(d->m_progress, d->m_maxProgress) +
                                                          QLatin1Char('\n') + d->m_watcher.progressText());
437
438
}

con's avatar
con committed
439
440
void BuildManager::nextStep()
{
441
442
443
    if (!d->m_buildQueue.empty()) {
        d->m_currentBuildStep = d->m_buildQueue.front();
        d->m_buildQueue.pop_front();
444
        QString name = d->m_stepNames.takeFirst();
Daniel Teske's avatar
Daniel Teske committed
445
        d->m_skipDisabled = !d->m_enabledState.takeFirst();
446
447
        if (d->m_futureProgress)
            d->m_futureProgress.data()->setTitle(name);
con's avatar
con committed
448

449
450
        if (d->m_currentBuildStep->project() != d->m_previousBuildStepProject) {
            const QString projectName = d->m_currentBuildStep->project()->displayName();
451
            addToOutputWindow(tr("Running steps for project %1...")
452
                              .arg(projectName), BuildStep::MessageOutput);
453
            d->m_previousBuildStepProject = d->m_currentBuildStep->project();
con's avatar
con committed
454
        }
Daniel Teske's avatar
Daniel Teske committed
455
456
457
458
459
460
461
462

        if (d->m_skipDisabled) {
            addToOutputWindow(tr("Skipping disabled step %1.")
                              .arg(d->m_currentBuildStep->displayName()), BuildStep::MessageOutput);
            nextBuildQueue();
            return;
        }

463
464
        if (d->m_currentBuildStep->runInGuiThread()) {
            connect (d->m_currentBuildStep, SIGNAL(finished()),
hjk's avatar
hjk committed
465
                     m_instance, SLOT(buildStepFinishedAsync()));
466
467
468
469
470
            d->m_watcher.setFuture(d->m_futureInterfaceForAysnc.future());
            d->m_currentBuildStep->run(d->m_futureInterfaceForAysnc);
        } else {
            d->m_watcher.setFuture(QtConcurrent::run(&BuildStep::run, d->m_currentBuildStep));
        }
con's avatar
con committed
471
    } else {
472
473
474
475
476
477
478
479
        d->m_running = false;
        d->m_previousBuildStepProject = 0;
        d->m_progressFutureInterface->reportFinished();
        d->m_progressWatcher.setFuture(QFuture<void>());
        d->m_currentBuildStep = 0;
        delete d->m_progressFutureInterface;
        d->m_progressFutureInterface = 0;
        d->m_maxProgress = 0;
hjk's avatar
hjk committed
480
        emit m_instance->buildQueueFinished(true);
con's avatar
con committed
481
482
483
    }
}

Daniel Teske's avatar
Daniel Teske committed
484
bool BuildManager::buildQueueAppend(QList<BuildStep *> steps, QStringList names)
con's avatar
con committed
485
{
486
    d->m_outputWindow->clearContents();
dt's avatar
dt committed
487
488
489
490
491
    int count = steps.size();
    bool init = true;
    int i = 0;
    for (; i < count; ++i) {
        BuildStep *bs = steps.at(i);
492
        connect(bs, SIGNAL(addTask(ProjectExplorer::Task)),
hjk's avatar
hjk committed
493
                m_instance, SLOT(addToTaskWindow(ProjectExplorer::Task)));
Robert Loehning's avatar
Robert Loehning committed
494
        connect(bs, SIGNAL(addOutput(QString,ProjectExplorer::BuildStep::OutputFormat,ProjectExplorer::BuildStep::OutputNewlineSetting)),
hjk's avatar
hjk committed
495
                m_instance, SLOT(addToOutputWindow(QString,ProjectExplorer::BuildStep::OutputFormat,ProjectExplorer::BuildStep::OutputNewlineSetting)));
Daniel Teske's avatar
Daniel Teske committed
496
497
498
499
500
        if (bs->enabled()) {
            init = bs->init();
            if (!init)
                break;
        }
dt's avatar
dt committed
501
    }
502
    if (!init) {
dt's avatar
dt committed
503
504
505
506
        BuildStep *bs = steps.at(i);

        // cleaning up
        // print something for the user
507
        const QString projectName = bs->project()->displayName();
Tobias Hunger's avatar
Tobias Hunger committed
508
        const QString targetName = bs->target()->displayName();
509
        addToOutputWindow(tr("Error while building/deploying project %1 (kit: %2)").arg(projectName, targetName), BuildStep::ErrorOutput);
510
        addToOutputWindow(tr("When executing step '%1'").arg(bs->displayName()), BuildStep::ErrorOutput);
dt's avatar
dt committed
511
512

        // disconnect the buildsteps again
513
514
        for (int j = 0; j <= i; ++j)
            disconnectOutput(steps.at(j));
515
516
517
        return false;
    }

dt's avatar
dt committed
518
519
    // Everthing init() well
    for (i = 0; i < count; ++i) {
520
        d->m_buildQueue.append(steps.at(i));
521
        d->m_stepNames.append(names.at(i));
522
523
524
525
        bool enabled = steps.at(i)->enabled();
        d->m_enabledState.append(enabled);
        if (enabled)
            ++d->m_maxProgress;
Daniel Teske's avatar
Daniel Teske committed
526
        incrementActiveBuildSteps(steps.at(i));
dt's avatar
dt committed
527
    }
528
    return true;
con's avatar
con committed
529
530
}

531
bool BuildManager::buildList(BuildStepList *bsl, const QString &stepListName)
con's avatar
con committed
532
{
533
    return buildLists(QList<BuildStepList *>() << bsl, QStringList() << stepListName);
con's avatar
con committed
534
535
}

536
bool BuildManager::buildLists(QList<BuildStepList *> bsls, const QStringList &stepListNames, const QStringList &preambelMessage)
con's avatar
con committed
537
{
dt's avatar
dt committed
538
    QList<BuildStep *> steps;
539
    foreach (BuildStepList *list, bsls)
Tobias Hunger's avatar
Tobias Hunger committed
540
        steps.append(list->steps());
dt's avatar
dt committed
541

542
543
544
545
546
547
548
549
550
    QStringList names;
    names.reserve(steps.size());
    for (int i = 0; i < bsls.size(); ++i) {
        for (int j = 0; j < bsls.at(i)->steps().size(); ++j) {
            names.append(stepListNames.at(i));
        }
    }

    bool success = buildQueueAppend(steps, names);
dt's avatar
dt committed
551
    if (!success) {
552
        d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
553
        return false;
con's avatar
con committed
554
    }
dt's avatar
dt committed
555

556
    if (ProjectExplorerPlugin::projectExplorerSettings().showCompilerOutput)
557
        d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
558
    startBuildQueue(preambelMessage);
559
    return true;
con's avatar
con committed
560
561
}

562
void BuildManager::appendStep(BuildStep *step, const QString &name)
con's avatar
con committed
563
{
564
    bool success = buildQueueAppend(QList<BuildStep *>() << step, QStringList() << name);
dt's avatar
dt committed
565
    if (!success) {
566
        d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
dt's avatar
dt committed
567
568
        return;
    }
569
    if (ProjectExplorerPlugin::projectExplorerSettings().showCompilerOutput)
570
        d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
con's avatar
con committed
571
572
573
    startBuildQueue();
}

Daniel Teske's avatar
Daniel Teske committed
574
575
576
577
578
579
580
581
582
583
template <class T>
int count(const QHash<T *, int> &hash, T *key)
{
    typename QHash<T *, int>::const_iterator it = hash.find(key);
    typename QHash<T *, int>::const_iterator end = hash.end();
    if (it != end)
        return *it;
    return 0;
}

con's avatar
con committed
584
585
bool BuildManager::isBuilding(Project *pro)
{
Daniel Teske's avatar
Daniel Teske committed
586
587
588
589
590
591
592
593
594
595
596
    return count(d->m_activeBuildSteps, pro) > 0;
}

bool BuildManager::isBuilding(Target *t)
{
    return count(d->m_activeBuildStepsPerTarget, t) > 0;
}

bool BuildManager::isBuilding(ProjectConfiguration *p)
{
    return count(d->m_activeBuildStepsPerProjectConfiguration, p) > 0;
con's avatar
con committed
597
598
}

599
600
bool BuildManager::isBuilding(BuildStep *step)
{
601
    return (d->m_currentBuildStep == step) || d->m_buildQueue.contains(step);
602
603
}

Daniel Teske's avatar
Daniel Teske committed
604
template <class T> bool increment(QHash<T *, int> &hash, T *key)
con's avatar
con committed
605
{
Daniel Teske's avatar
Daniel Teske committed
606
607
    typename QHash<T *, int>::iterator it = hash.find(key);
    typename QHash<T *, int>::iterator end = hash.end();
con's avatar
con committed
608
    if (it == end) {
Daniel Teske's avatar
Daniel Teske committed
609
610
        hash.insert(key, 1);
        return true;
con's avatar
con committed
611
612
    } else if (*it == 0) {
        ++*it;
Daniel Teske's avatar
Daniel Teske committed
613
        return true;
con's avatar
con committed
614
615
616
    } else {
        ++*it;
    }
Daniel Teske's avatar
Daniel Teske committed
617
    return false;
con's avatar
con committed
618
619
}

Daniel Teske's avatar
Daniel Teske committed
620
template <class T> bool decrement(QHash<T *, int> &hash, T *key)
con's avatar
con committed
621
{
Daniel Teske's avatar
Daniel Teske committed
622
623
    typename QHash<T *, int>::iterator it = hash.find(key);
    typename QHash<T *, int>::iterator end = hash.end();
con's avatar
con committed
624
    if (it == end) {
Daniel Teske's avatar
Daniel Teske committed
625
        // Can't happen
con's avatar
con committed
626
627
    } else if (*it == 1) {
        --*it;
Daniel Teske's avatar
Daniel Teske committed
628
        return true;
con's avatar
con committed
629
630
631
    } else {
        --*it;
    }
Daniel Teske's avatar
Daniel Teske committed
632
633
634
635
636
637
638
639
    return false;
}

void BuildManager::incrementActiveBuildSteps(BuildStep *bs)
{
    increment<ProjectConfiguration>(d->m_activeBuildStepsPerProjectConfiguration, bs->projectConfiguration());
    increment<Target>(d->m_activeBuildStepsPerTarget, bs->target());
    if (increment<Project>(d->m_activeBuildSteps, bs->project()))
hjk's avatar
hjk committed
640
        emit m_instance->buildStateChanged(bs->project());
Daniel Teske's avatar
Daniel Teske committed
641
642
643
644
645
646
647
}

void BuildManager::decrementActiveBuildSteps(BuildStep *bs)
{
    decrement<ProjectConfiguration>(d->m_activeBuildStepsPerProjectConfiguration, bs->projectConfiguration());
    decrement<Target>(d->m_activeBuildStepsPerTarget, bs->target());
    if (decrement<Project>(d->m_activeBuildSteps, bs->project()))
hjk's avatar
hjk committed
648
        emit m_instance->buildStateChanged(bs->project());
con's avatar
con committed
649
}
650

651
652
653
void BuildManager::disconnectOutput(BuildStep *bs)
{
    disconnect(bs, SIGNAL(addTask(ProjectExplorer::Task)),
hjk's avatar
hjk committed
654
               m_instance, SLOT(addToTaskWindow(ProjectExplorer::Task)));
655
656
    disconnect(bs, SIGNAL(addOutput(QString, ProjectExplorer::BuildStep::OutputFormat,
        ProjectExplorer::BuildStep::OutputNewlineSetting)),
hjk's avatar
hjk committed
657
        m_instance, SLOT(addToOutputWindow(QString, ProjectExplorer::BuildStep::OutputFormat,
658
659
660
            ProjectExplorer::BuildStep::OutputNewlineSetting)));
}

661
} // namespace ProjectExplorer