cmakebuildstep.cpp 21.6 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
dt's avatar
dt committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
dt's avatar
dt committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
dt's avatar
dt committed
7
**
hjk's avatar
hjk committed
8
9
10
11
** 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
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
dt's avatar
dt committed
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
30

31
#include "cmakebuildstep.h"
32

33
34
#include "cmakebuildconfiguration.h"
#include "cmakeparser.h"
dt's avatar
dt committed
35
36
#include "cmakeprojectconstants.h"
#include "cmakeproject.h"
37
#include "cmakerunconfiguration.h"
dt's avatar
dt committed
38

Tobias Hunger's avatar
Tobias Hunger committed
39
#include <projectexplorer/buildsteplist.h>
Tobias Hunger's avatar
Tobias Hunger committed
40
#include <projectexplorer/deployconfiguration.h>
Tobias Hunger's avatar
Tobias Hunger committed
41
#include <projectexplorer/kitinformation.h>
42
#include <projectexplorer/projectexplorerconstants.h>
43
#include <projectexplorer/projectexplorer.h>
Tobias Hunger's avatar
Tobias Hunger committed
44
45
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
46

47
48
49
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtparser.h>

50
51
#include <coreplugin/find/itemviewfind.h>

52
#include <utils/algorithm.h>
53
#include <utils/qtcprocess.h>
54
#include <utils/pathchooser.h>
55

56
57
58
59
60
#include <QFormLayout>
#include <QGroupBox>
#include <QCheckBox>
#include <QLineEdit>
#include <QListWidget>
hjk's avatar
hjk committed
61

dt's avatar
dt committed
62
63
using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;
64
using namespace ProjectExplorer;
dt's avatar
dt committed
65

66
namespace {
67
const char MS_ID[] = "CMakeProjectManager.MakeStep";
Tobias Hunger's avatar
Tobias Hunger committed
68
const char CLEAN_KEY[] = "CMakeProjectManager.MakeStep.Clean"; // Obsolete since QtC 3.7
69
70
const char BUILD_TARGETS_KEY[] = "CMakeProjectManager.MakeStep.BuildTargets";
const char ADDITIONAL_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.AdditionalArguments";
71
const char ADD_RUNCONFIGURATION_ARGUMENT_KEY[] = "CMakeProjectManager.MakeStep.AddRunConfigurationArgument";
72
const char MAKE_COMMAND_KEY[] = "CMakeProjectManager.MakeStep.MakeCommand";
73
const char ADD_RUNCONFIGURATION_TEXT[] = "Current executable";
74
75
}

76
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl) :
Tobias Hunger's avatar
Tobias Hunger committed
77
    AbstractProcessStep(bsl, Core::Id(MS_ID)), m_addRunConfigurationArgument(false)
dt's avatar
dt committed
78
{
79
80
81
    ctor();
}

82
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Core::Id id) :
Tobias Hunger's avatar
Tobias Hunger committed
83
    AbstractProcessStep(bsl, id), m_addRunConfigurationArgument(false)
84
85
{
    ctor();
dt's avatar
dt committed
86
87
}

88
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, CMakeBuildStep *bs) :
Tobias Hunger's avatar
Tobias Hunger committed
89
    AbstractProcessStep(bsl, bs),
90
    m_buildTargets(bs->m_buildTargets),
91
    m_additionalArguments(bs->m_additionalArguments),
92
    m_addRunConfigurationArgument(bs->m_addRunConfigurationArgument),
93
    m_makeCmd(bs->m_makeCmd)
94
{
95
96
    ctor();
}
97

98
void CMakeBuildStep::ctor()
99
{
100
101
    m_percentProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)%\\]"));
    m_ninjaProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)/\\s*(\\d*)"));
102
    m_ninjaProgressString = QLatin1String("[%f/%t "); // ninja: [33/100
103
104
    //: Default display name for the cmake make step.
    setDefaultDisplayName(tr("Make"));
Peter Kümmel's avatar
Peter Kümmel committed
105

106
    CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
Peter Kümmel's avatar
Peter Kümmel committed
107
108
    if (bc) {
        m_activeConfiguration = 0;
109
        connect(bc, &CMakeBuildConfiguration::useNinjaChanged, this, &CMakeBuildStep::makeCommandChanged);
Peter Kümmel's avatar
Peter Kümmel committed
110
111
112
113
    } else {
        // That means the step is in the deploylist, so we listen to the active build config
        // changed signal and react to the activeBuildConfigurationChanged() signal of the buildconfiguration
        m_activeConfiguration = targetsActiveBuildConfiguration();
114
        connect(target(), &Target::activeBuildConfigurationChanged, this, &CMakeBuildStep::activeBuildConfigurationChanged);
Peter Kümmel's avatar
Peter Kümmel committed
115
116
        activeBuildConfigurationChanged();
    }
117

118
    connect(static_cast<CMakeProject *>(project()), &CMakeProject::buildTargetsChanged,
119
            this, &CMakeBuildStep::buildTargetsChanged);
120
121
}

122
CMakeBuildConfiguration *CMakeBuildStep::cmakeBuildConfiguration() const
dt's avatar
dt committed
123
124
125
126
{
    return static_cast<CMakeBuildConfiguration *>(buildConfiguration());
}

127
CMakeBuildConfiguration *CMakeBuildStep::targetsActiveBuildConfiguration() const
Peter Kümmel's avatar
Peter Kümmel committed
128
129
130
131
{
    return static_cast<CMakeBuildConfiguration *>(target()->activeBuildConfiguration());
}

132
CMakeRunConfiguration *CMakeBuildStep::targetsActiveRunConfiguration() const
133
134
135
136
{
    return qobject_cast<CMakeRunConfiguration *>(target()->activeRunConfiguration());
}

137
void CMakeBuildStep::activeBuildConfigurationChanged()
Peter Kümmel's avatar
Peter Kümmel committed
138
139
{
    if (m_activeConfiguration)
140
        disconnect(m_activeConfiguration, &CMakeBuildConfiguration::useNinjaChanged, this, &CMakeBuildStep::makeCommandChanged);
Peter Kümmel's avatar
Peter Kümmel committed
141
142
143

    m_activeConfiguration = targetsActiveBuildConfiguration();

144
    if (m_activeConfiguration)
145
        connect(m_activeConfiguration, &CMakeBuildConfiguration::useNinjaChanged, this, &CMakeBuildStep::makeCommandChanged);
146
147

    emit makeCommandChanged();
Peter Kümmel's avatar
Peter Kümmel committed
148
149
}

150
void CMakeBuildStep::buildTargetsChanged()
151
{
152
153
154
    const QStringList filteredTargets
            = Utils::filtered(static_cast<CMakeProject *>(project())->buildTargetTitles(),
                              [this](const QString &s) { return m_buildTargets.contains(s); });
155
156
157
    setBuildTargets(filteredTargets);
}

158
QVariantMap CMakeBuildStep::toMap() const
159
{
160
161
162
    QVariantMap map(AbstractProcessStep::toMap());
    map.insert(QLatin1String(BUILD_TARGETS_KEY), m_buildTargets);
    map.insert(QLatin1String(ADDITIONAL_ARGUMENTS_KEY), m_additionalArguments);
163
    map.insert(QLatin1String(ADD_RUNCONFIGURATION_ARGUMENT_KEY), m_addRunConfigurationArgument);
164
    map.insert(QLatin1String(MAKE_COMMAND_KEY), m_makeCmd);
165
    return map;
166
167
}

168
bool CMakeBuildStep::fromMap(const QVariantMap &map)
169
{
Tobias Hunger's avatar
Tobias Hunger committed
170
    if (map.value(QLatin1String(CLEAN_KEY), false).toBool()) {
171
        m_buildTargets = QStringList({ CMakeBuildStep::cleanTarget() });
Tobias Hunger's avatar
Tobias Hunger committed
172
173
174
175
    } else {
        m_buildTargets = map.value(QLatin1String(BUILD_TARGETS_KEY)).toStringList();
        m_additionalArguments = map.value(QLatin1String(ADDITIONAL_ARGUMENTS_KEY)).toString();
    }
176
    m_addRunConfigurationArgument = map.value(QLatin1String(ADD_RUNCONFIGURATION_ARGUMENT_KEY), false).toBool();
177
    m_makeCmd = map.value(QLatin1String(MAKE_COMMAND_KEY)).toString();
178

179
    return BuildStep::fromMap(map);
180
181
}

182

183
bool CMakeBuildStep::init(QList<const BuildStep *> &earlierSteps)
dt's avatar
dt committed
184
{
dt's avatar
dt committed
185
    CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
186
    if (!bc)
187
188
        bc = targetsActiveBuildConfiguration();

189
190
    if (!bc)
        emit addTask(Task::buildConfigurationMissingTask());
191

192
    ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit());
193
194
    if (!tc)
        emit addTask(Task::compilerMissingTask());
195
196

    if (!bc || !tc) {
197
        emitFaultyConfigurationMessage();
Daniel Teske's avatar
Daniel Teske committed
198
        return false;
199
200
    }

201
202
    m_useNinja = bc->useNinja();

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
    QString arguments;
    if (m_addRunConfigurationArgument) {
        CMakeRunConfiguration* rc = targetsActiveRunConfiguration();
        if (!rc) {
            emit addTask(Task(Task::Error,
                              QCoreApplication::translate("ProjectExplorer::Task",
                                        "You asked to build the current Run Configurations build target only, "
                                        "but the current Run Configuration is not associated with a build target. "
                                        "Please update the Make Step in your build settings."),
                            Utils::FileName(), -1,
                            ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
            emitFaultyConfigurationMessage();
            return false;
        }
        if (!rc->title().isEmpty())
            Utils::QtcProcess::addArg(&arguments, rc->title());
    }
    Utils::QtcProcess::addArgs(&arguments, m_buildTargets);
221
    Utils::QtcProcess::addArgs(&arguments, additionalArguments());
222

223
    setIgnoreReturnValue(m_buildTargets.contains(CMakeBuildStep::cleanTarget()));
224

225
226
    ProcessParameters *pp = processParameters();
    pp->setMacroExpander(bc->macroExpander());
227
228
229
230
231
232
233
    Utils::Environment env = bc->environment();
    // Force output to english for the parsers. Do this here and not in the toolchain's
    // addToEnvironment() to not screw up the users run environment.
    env.set(QLatin1String("LC_ALL"), QLatin1String("C"));
    if (m_useNinja && !env.value(QLatin1String("NINJA_STATUS")).startsWith(m_ninjaProgressString))
        env.set(QLatin1String("NINJA_STATUS"), m_ninjaProgressString + QLatin1String("%o/sec] "));
    pp->setEnvironment(env);
234
    pp->setWorkingDirectory(bc->buildDirectory().toString());
Peter Kümmel's avatar
Peter Kümmel committed
235
    pp->setCommand(makeCommand(tc, bc->environment()));
236
    pp->setArguments(arguments);
237
    pp->resolveAll();
238

239
    setOutputParser(new CMakeParser());
240
241
242
    IOutputParser *parser = target()->kit()->createOutputParser();
    if (parser)
        appendOutputParser(parser);
243
    outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
Tobias Hunger's avatar
Tobias Hunger committed
244

245
    return AbstractProcessStep::init(earlierSteps);
dt's avatar
dt committed
246
247
}

248
void CMakeBuildStep::run(QFutureInterface<bool> &fi)
dt's avatar
dt committed
249
{
Tobias Hunger's avatar
Tobias Hunger committed
250
    AbstractProcessStep::run(fi);
dt's avatar
dt committed
251
252
}

253
BuildStepConfigWidget *CMakeBuildStep::createConfigWidget()
dt's avatar
dt committed
254
{
255
    return new CMakeBuildStepConfigWidget(this);
dt's avatar
dt committed
256
257
}

258
bool CMakeBuildStep::immutable() const
dt's avatar
dt committed
259
{
260
    return false;
dt's avatar
dt committed
261
262
}

263
void CMakeBuildStep::stdOutput(const QString &line)
264
{
265
266
    if (m_percentProgress.indexIn(line) != -1) {
        bool ok = false;
Nikolai Kosjar's avatar
Nikolai Kosjar committed
267
        int percent = m_percentProgress.cap(1).toInt(&ok);
268
        if (ok)
269
            futureInterface()->setProgressValue(percent);
Peter Kümmel's avatar
Peter Kümmel committed
270
271
272
273
274
275
276
    } else if (m_ninjaProgress.indexIn(line) != -1) {
        bool ok = false;
        int done = m_ninjaProgress.cap(1).toInt(&ok);
        if (ok) {
            int all = m_ninjaProgress.cap(2).toInt(&ok);
            if (ok && all != 0) {
                int percent = 100.0 * done/all;
277
                futureInterface()->setProgressValue(percent);
Peter Kümmel's avatar
Peter Kümmel committed
278
279
            }
        }
280
    }
Peter Kümmel's avatar
Peter Kümmel committed
281
282
283
284
    if (m_useNinja)
        AbstractProcessStep::stdError(line);
    else
        AbstractProcessStep::stdOutput(line);
285
286
}

287
QStringList CMakeBuildStep::buildTargets() const
288
289
290
291
{
    return m_buildTargets;
}

292
bool CMakeBuildStep::buildsBuildTarget(const QString &target) const
293
{
294
295
296
297
    if (target == tr(ADD_RUNCONFIGURATION_TEXT))
        return addRunConfigurationArgument();
    else
        return m_buildTargets.contains(target);
298
299
}

300
void CMakeBuildStep::setBuildTarget(const QString &buildTarget, bool on)
301
{
302
303
304
305
306
307
308
309
310
311
    if (buildTarget == tr(ADD_RUNCONFIGURATION_TEXT)) {
        setAddRunConfigurationArgument(on);
    } else {
        QStringList old = m_buildTargets;
        if (on && !old.contains(buildTarget))
            old << buildTarget;
        else if (!on && old.contains(buildTarget))
            old.removeOne(buildTarget);
        setBuildTargets(old);
    }
312
313
}

314
void CMakeBuildStep::setBuildTargets(const QStringList &targets)
315
{
316
317
318
319
    if (targets != m_buildTargets) {
        m_buildTargets = targets;
        emit targetsToBuildChanged();
    }
320
321
}

322
void CMakeBuildStep::clearBuildTargets()
323
324
325
326
{
    m_buildTargets.clear();
}

327
QString CMakeBuildStep::additionalArguments() const
328
{
329
    return m_additionalArguments;
330
331
}

332
void CMakeBuildStep::setAdditionalArguments(const QString &list)
333
{
334
    m_additionalArguments = list;
335
336
}

337
bool CMakeBuildStep::addRunConfigurationArgument() const
338
339
340
341
{
    return m_addRunConfigurationArgument;
}

342
void CMakeBuildStep::setAddRunConfigurationArgument(bool add)
343
344
345
346
{
    m_addRunConfigurationArgument = add;
}

347
QString CMakeBuildStep::makeCommand(ToolChain *tc, const Utils::Environment &env) const
Peter Kümmel's avatar
Peter Kümmel committed
348
{
349
350
    if (!m_makeCmd.isEmpty())
        return m_makeCmd;
351
352
353
354
    CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
    if (!bc)
        bc = targetsActiveBuildConfiguration();
    if (bc && bc->useNinja())
Peter Kümmel's avatar
Peter Kümmel committed
355
        return QLatin1String("ninja");
356

Peter Kümmel's avatar
Peter Kümmel committed
357
358
359
360
361
362
    if (tc)
        return tc->makeCommand(env);

    return QLatin1String("make");
}

363
void CMakeBuildStep::setUserMakeCommand(const QString &make)
364
365
366
367
{
    m_makeCmd = make;
}

368
QString CMakeBuildStep::userMakeCommand() const
369
370
371
372
{
    return m_makeCmd;
}

373
QString CMakeBuildStep::cleanTarget()
Tobias Hunger's avatar
Tobias Hunger committed
374
375
376
377
{
    return QLatin1String("clean");
}

dt's avatar
dt committed
378
//
379
// CMakeBuildStepConfigWidget
dt's avatar
dt committed
380
//
381

382
383
CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep)
    : m_buildStep(buildStep)
384
385
{
    QFormLayout *fl = new QFormLayout(this);
386
387
    fl->setMargin(0);
    fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
388
389
    setLayout(fl);

390
391
392
393
    m_makePathChooser = new Utils::PathChooser(this);
    m_makePathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
    m_makePathChooser->setBaseDirectory(Utils::PathChooser::homePath());
    m_makePathChooser->setHistoryCompleter(QLatin1String("PE.MakeCommand.History"));
394
    m_makePathChooser->setPath(m_buildStep->userMakeCommand());
395
396
397

    fl->addRow(tr("Override command:"), m_makePathChooser);

398
    m_additionalArguments = new QLineEdit(this);
399
    fl->addRow(tr("Additional arguments:"), m_additionalArguments);
400
    m_additionalArguments->setText(m_buildStep->additionalArguments());
401

402
    m_buildTargetsList = new QListWidget;
403
    m_buildTargetsList->setFrameStyle(QFrame::NoFrame);
404
    m_buildTargetsList->setMinimumHeight(200);
405
406
407
408
409

    QFrame *frame = new QFrame(this);
    frame->setFrameStyle(QFrame::StyledPanel);
    QVBoxLayout *frameLayout = new QVBoxLayout(frame);
    frameLayout->setMargin(0);
410
411
    frameLayout->addWidget(Core::ItemViewFind::createSearchableWrapper(m_buildTargetsList,
                                                                       Core::ItemViewFind::LightColored));
412
413

    fl->addRow(tr("Targets:"), frame);
414

415
416
    auto itemAddRunConfigurationArgument = new QListWidgetItem(tr(ADD_RUNCONFIGURATION_TEXT), m_buildTargetsList);
    itemAddRunConfigurationArgument->setFlags(itemAddRunConfigurationArgument->flags() | Qt::ItemIsUserCheckable);
417
    itemAddRunConfigurationArgument->setCheckState(m_buildStep->addRunConfigurationArgument() ? Qt::Checked : Qt::Unchecked);
418
419
420
421
    QFont f;
    f.setItalic(true);
    itemAddRunConfigurationArgument->setFont(f);

422
    CMakeProject *pro = static_cast<CMakeProject *>(m_buildStep->project());
423
    QStringList targetList = pro->buildTargetTitles();
Aurindam Jana's avatar
Aurindam Jana committed
424
    targetList.sort();
425
    foreach (const QString &buildTarget, targetList) {
426
        QListWidgetItem *item = new QListWidgetItem(buildTarget, m_buildTargetsList);
427
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
428
        item->setCheckState(m_buildStep->buildsBuildTarget(item->text()) ? Qt::Checked : Qt::Unchecked);
429
    }
430

dt_'s avatar
dt_ committed
431
432
    updateDetails();

433
434
435
436
437
    connect(m_makePathChooser, &Utils::PathChooser::rawPathChanged, this, &CMakeBuildStepConfigWidget::makeEdited);
    connect(m_additionalArguments, &QLineEdit::textEdited, this, &CMakeBuildStepConfigWidget::additionalArgumentsEdited);
    connect(m_buildTargetsList, &QListWidget::itemChanged, this, &CMakeBuildStepConfigWidget::itemChanged);
    connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
            this, &CMakeBuildStepConfigWidget::updateDetails);
dt_'s avatar
dt_ committed
438

439
440
441
442
    connect(pro, &CMakeProject::buildTargetsChanged, this, &CMakeBuildStepConfigWidget::buildTargetsChanged);
    connect(m_buildStep, &CMakeBuildStep::targetsToBuildChanged, this, &CMakeBuildStepConfigWidget::selectedBuildTargetsChanged);
    connect(pro, &CMakeProject::environmentChanged, this, &CMakeBuildStepConfigWidget::updateDetails);
    connect(m_buildStep, &CMakeBuildStep::makeCommandChanged, this, &CMakeBuildStepConfigWidget::updateDetails);
443
444
}

445
void CMakeBuildStepConfigWidget::makeEdited()
446
{
447
    m_buildStep->setUserMakeCommand(m_makePathChooser->rawPath());
448
449
450
    updateDetails();
}

451
void CMakeBuildStepConfigWidget::additionalArgumentsEdited()
452
{
453
    m_buildStep->setAdditionalArguments(m_additionalArguments->text());
454
    updateDetails();
455
456
}

457
void CMakeBuildStepConfigWidget::itemChanged(QListWidgetItem *item)
458
{
459
    m_buildStep->setBuildTarget(item->text(), item->checkState() & Qt::Checked);
460
    updateDetails();
461
}
dt's avatar
dt committed
462

463
QString CMakeBuildStepConfigWidget::displayName() const
dt's avatar
dt committed
464
{
465
    return tr("Make", "CMakeProjectManager::CMakeBuildStepConfigWidget display name.");
dt's avatar
dt committed
466
467
}

468
void CMakeBuildStepConfigWidget::buildTargetsChanged()
469
{
470
    disconnect(m_buildTargetsList, &QListWidget::itemChanged, this, &CMakeBuildStepConfigWidget::itemChanged);
471
472

    auto *addRunConfigurationArgumentItem = m_buildTargetsList->takeItem(0);
473
    m_buildTargetsList->clear();
474
475
    m_buildTargetsList->insertItem(0, addRunConfigurationArgumentItem);

476
    CMakeProject *pro = static_cast<CMakeProject *>(m_buildStep->target()->project());
tomdeblauwe's avatar
tomdeblauwe committed
477
    foreach (const QString& buildTarget, pro->buildTargetTitles()) {
478
        QListWidgetItem *item = new QListWidgetItem(buildTarget, m_buildTargetsList);
479
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
480
        item->setCheckState(m_buildStep->buildsBuildTarget(item->text()) ? Qt::Checked : Qt::Unchecked);
481
    }
482
    connect(m_buildTargetsList, &QListWidget::itemChanged, this, &CMakeBuildStepConfigWidget::itemChanged);
483
    updateSummary();
484
485
}

486
void CMakeBuildStepConfigWidget::selectedBuildTargetsChanged()
487
{
488
    disconnect(m_buildTargetsList, &QListWidget::itemChanged, this, &CMakeBuildStepConfigWidget::itemChanged);
489
    for (int y = 0; y < m_buildTargetsList->count(); ++y) {
490
        QListWidgetItem *item = m_buildTargetsList->item(y);
491
        item->setCheckState(m_buildStep->buildsBuildTarget(item->text()) ? Qt::Checked : Qt::Unchecked);
492
    }
493
    connect(m_buildTargetsList, &QListWidget::itemChanged, this, &CMakeBuildStepConfigWidget::itemChanged);
494
495
496
    updateSummary();
}

497
void CMakeBuildStepConfigWidget::updateDetails()
498
{
499
    BuildConfiguration *bc = m_buildStep->buildConfiguration();
500
    if (!bc)
501
        bc = m_buildStep->target()->activeBuildConfiguration();
Tobias Hunger's avatar
Tobias Hunger committed
502
    if (!bc) {
503
        m_summaryText = tr("<b>No build configuration found on this kit.</b>");
Tobias Hunger's avatar
Tobias Hunger committed
504
505
506
507
        updateSummary();
        return;
    }

508
    ToolChain *tc = ToolChainKitInformation::toolChain(m_buildStep->target()->kit());
509
    if (tc) {
510
        QString arguments;
511
        if (m_buildStep->addRunConfigurationArgument())
512
513
            arguments = QLatin1String("<i>&lt;") + tr(ADD_RUNCONFIGURATION_TEXT) + QLatin1String("&gt;</i>");

514
515
        Utils::QtcProcess::addArgs(&arguments, Utils::QtcProcess::joinArgs(m_buildStep->buildTargets()));
        Utils::QtcProcess::addArgs(&arguments, m_buildStep->additionalArguments());
516
517
518
519

        ProcessParameters param;
        param.setMacroExpander(bc->macroExpander());
        param.setEnvironment(bc->environment());
520
        param.setWorkingDirectory(bc->buildDirectory().toString());
521
        param.setCommand(m_buildStep->makeCommand(tc, bc->environment()));
522
523
524
        param.setArguments(arguments);
        m_summaryText = param.summary(displayName());
    } else {
525
        m_summaryText = QLatin1String("<b>") + ToolChainKitInformation::msgNoToolChainInTarget() + QLatin1String("</b>");
526
    }
527
    emit updateSummary();
dt's avatar
dt committed
528
529
}

530
QString CMakeBuildStepConfigWidget::summaryText() const
dt's avatar
dt committed
531
{
532
    return m_summaryText;
dt's avatar
dt committed
533
534
}

dt's avatar
dt committed
535
//
536
// CMakeBuildStepFactory
dt's avatar
dt committed
537
538
//

539
CMakeBuildStepFactory::CMakeBuildStepFactory(QObject *parent) : IBuildStepFactory(parent)
dt's avatar
dt committed
540
541
542
{
}

543
CMakeBuildStepFactory::~CMakeBuildStepFactory()
dt's avatar
dt committed
544
{
545
546
}

547
bool CMakeBuildStepFactory::canCreate(BuildStepList *parent, Core::Id id) const
548
{
549
550
551
    if (parent->target()->project()->id() == Constants::CMAKEPROJECT_ID)
        return id == MS_ID;
    return false;
dt's avatar
dt committed
552
553
}

554
BuildStep *CMakeBuildStepFactory::create(BuildStepList *parent, Core::Id id)
dt's avatar
dt committed
555
{
Tobias Hunger's avatar
Tobias Hunger committed
556
    if (!canCreate(parent, id))
557
        return 0;
558
    CMakeBuildStep *step = new CMakeBuildStep(parent);
Tobias Hunger's avatar
Tobias Hunger committed
559
    if (parent->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN)
560
        step->setBuildTarget(CMakeBuildStep::cleanTarget(), true);
561
    return step;
dt's avatar
dt committed
562
563
}

564
bool CMakeBuildStepFactory::canClone(BuildStepList *parent, BuildStep *source) const
565
{
Tobias Hunger's avatar
Tobias Hunger committed
566
    return canCreate(parent, source->id());
567
568
}

569
BuildStep *CMakeBuildStepFactory::clone(BuildStepList *parent, BuildStep *source)
570
{
Tobias Hunger's avatar
Tobias Hunger committed
571
    if (!canClone(parent, source))
572
        return 0;
573
    return new CMakeBuildStep(parent, static_cast<CMakeBuildStep *>(source));
574
575
}

576
bool CMakeBuildStepFactory::canRestore(BuildStepList *parent, const QVariantMap &map) const
dt's avatar
dt committed
577
{
578
    return canCreate(parent, idFromMap(map));
dt's avatar
dt committed
579
580
}

581
BuildStep *CMakeBuildStepFactory::restore(BuildStepList *parent, const QVariantMap &map)
582
{
Tobias Hunger's avatar
Tobias Hunger committed
583
    if (!canRestore(parent, map))
584
        return 0;
585
    CMakeBuildStep *bs(new CMakeBuildStep(parent));
586
587
588
589
590
591
    if (bs->fromMap(map))
        return bs;
    delete bs;
    return 0;
}

592
QList<Core::Id> CMakeBuildStepFactory::availableCreationIds(BuildStepList *parent) const
593
{
594
    if (parent->target()->project()->id() == Constants::CMAKEPROJECT_ID)
595
596
        return QList<Core::Id>() << Core::Id(MS_ID);
    return QList<Core::Id>();
597
598
}

599
QString CMakeBuildStepFactory::displayNameForId(Core::Id id) const
600
{
601
    if (id == MS_ID)
602
        return tr("Make", "Display name for CMakeProjectManager::CMakeBuildStep id.");
603
604
    return QString();
}
605

606
void CMakeBuildStep::processStarted()
607
608
609
610
611
{
    futureInterface()->setProgressRange(0, 100);
    AbstractProcessStep::processStarted();
}

612
void CMakeBuildStep::processFinished(int exitCode, QProcess::ExitStatus status)
613
{
614
    AbstractProcessStep::processFinished(exitCode, status);
615
616
    futureInterface()->setProgressValue(100);
}