makestep.cpp 11 KB
Newer Older
1
/**************************************************************************
dt's avatar
dt committed
2 3 4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
dt's avatar
dt committed
6 7 8
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
9
** Commercial Usage
dt's avatar
dt committed
10
**
11 12 13 14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
dt's avatar
dt committed
15
**
16
** GNU Lesser General Public License Usage
dt's avatar
dt committed
17
**
18 19 20 21 22 23
** 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.
dt's avatar
dt committed
24
**
25 26
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
dt's avatar
dt committed
27
**
28
**************************************************************************/
dt's avatar
dt committed
29 30 31 32 33

#include "makestep.h"
#include "cmakeprojectconstants.h"
#include "cmakeproject.h"

34
#include <extensionsystem/pluginmanager.h>
hjk's avatar
hjk committed
35
#include <utils/qtcassert.h>
36

37 38 39 40 41
#include <QtGui/QFormLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QCheckBox>
#include <QtGui/QLineEdit>
#include <QtGui/QListWidget>
hjk's avatar
hjk committed
42

43 44 45 46
namespace {
bool debug = false;
}

dt's avatar
dt committed
47 48 49 50
using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;

MakeStep::MakeStep(CMakeProject *pro)
51
    : AbstractProcessStep(pro), m_pro(pro), m_buildParser(0)
dt's avatar
dt committed
52
{
53
    m_percentProgress = QRegExp("^\\[\\s*(\\d*)%\\]");
dt's avatar
dt committed
54 55 56 57
}

MakeStep::~MakeStep()
{
58 59
    delete m_buildParser;
    m_buildParser = 0;
dt's avatar
dt committed
60 61 62 63
}

bool MakeStep::init(const QString &buildConfiguration)
{
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
    delete m_buildParser;
    m_buildParser = 0;
    QString buildParser = m_pro->buildParser(buildConfiguration);
    QList<ProjectExplorer::IBuildParserFactory *> buildParserFactories =
            ExtensionSystem::PluginManager::instance()->getObjects<ProjectExplorer::IBuildParserFactory>();

    foreach (ProjectExplorer::IBuildParserFactory * factory, buildParserFactories)
        if (factory->canCreate(buildParser)) {
            m_buildParser = factory->create(buildParser);
            break;
        }
    if (m_buildParser) {
        connect(m_buildParser, SIGNAL(addToOutputWindow(const QString &)),
                this, SIGNAL(addToOutputWindow(const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(addToTaskWindow(const QString &, int, int, const QString &)),
                this, SLOT(slotAddToTaskWindow(const QString &, int, int, const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(enterDirectory(const QString &)),
                this, SLOT(addDirectory(const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(leaveDirectory(const QString &)),
                this, SLOT(removeDirectory(const QString &)),
                Qt::DirectConnection);
    }

    m_openDirectories.clear();
    addDirectory(m_pro->buildDirectory(buildConfiguration));

dt's avatar
dt committed
93 94
    setEnabled(buildConfiguration, true);
    setWorkingDirectory(buildConfiguration, m_pro->buildDirectory(buildConfiguration));
95 96 97
#ifdef Q_OS_WIN
    setCommand(buildConfiguration, "mingw32-make");
#else // Q_OS_WIN
dt's avatar
dt committed
98
    setCommand(buildConfiguration, "make"); // TODO give full path here?
99
#endif // Q_OS_WIN
100

dt's avatar
dt committed
101 102 103 104 105 106 107 108
    if (value("clean").isValid() && value("clean").toBool())  {
       setArguments(buildConfiguration, QStringList() << "clean");
   } else {
        QStringList arguments = value(buildConfiguration, "buildTargets").toStringList();
        arguments << additionalArguments(buildConfiguration);
        setArguments(buildConfiguration, arguments); // TODO
        setEnvironment(buildConfiguration, m_pro->environment(buildConfiguration));
    }
dt's avatar
dt committed
109 110 111 112 113
    return AbstractProcessStep::init(buildConfiguration);
}

void MakeStep::run(QFutureInterface<bool> &fi)
{
114 115
    m_futureInterface = &fi;
    m_futureInterface->setProgressRange(0, 100);
dt's avatar
dt committed
116
    AbstractProcessStep::run(fi);
117
    m_futureInterface = 0;
dt's avatar
dt committed
118 119 120 121
}

QString MakeStep::name()
{
122
    return Constants::MAKESTEP;
dt's avatar
dt committed
123 124 125 126
}

QString MakeStep::displayName()
{
127
    return "Make";
dt's avatar
dt committed
128 129 130 131
}

ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
{
132
    return new MakeStepConfigWidget(this);
dt's avatar
dt committed
133 134 135 136 137 138 139
}

bool MakeStep::immutable() const
{
    return true;
}

140 141 142 143
void MakeStep::stdOut(const QString &line)
{
    if (m_buildParser)
        m_buildParser->stdOutput(line);
144 145 146 147 148 149
    if (m_percentProgress.indexIn(line) != -1) {
        bool ok = false;
        int percent = m_percentProgress.cap(1).toInt(&ok);;
        if (ok)
            m_futureInterface->setProgressValue(percent);
    }
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
    AbstractProcessStep::stdOut(line);
}

void MakeStep::stdError(const QString &line)
{
    if (m_buildParser)
        m_buildParser->stdError(line);
    AbstractProcessStep::stdError(line);
}

void MakeStep::slotAddToTaskWindow(const QString & fn, int type, int linenumber, const QString & description)
{
    QString filePath = fn;
    if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
        // We have no save way to decide which file in which subfolder
        // is meant. Therefore we apply following heuristics:
        // 1. Search for unique file in directories currently indicated as open by GNU make
        //    (Enter directory xxx, Leave directory xxx...) + current directory
        // 3. Check if file is unique in whole project
        // 4. Otherwise give up

        filePath = filePath.trimmed();

        QList<QFileInfo> possibleFiles;
        foreach (const QString &dir, m_openDirectories) {
            QFileInfo candidate(dir + QLatin1Char('/') + filePath);
            if (debug)
                qDebug() << "Checking path " << candidate.filePath();
            if (candidate.exists()
                    && !possibleFiles.contains(candidate)) {
                if (debug)
                    qDebug() << candidate.filePath() << "exists!";
                possibleFiles << candidate;
            }
        }
        if (possibleFiles.count() == 0) {
            if (debug)
                qDebug() << "No success. Trying all files in project ...";
            QString fileName = QFileInfo(filePath).fileName();
            foreach (const QString &file, project()->files(ProjectExplorer::Project::AllFiles)) {
                QFileInfo candidate(file);
                if (candidate.fileName() == fileName) {
                    if (debug)
                        qDebug() << "Found " << file;
                    possibleFiles << candidate;
                }
            }
        }
        if (possibleFiles.count() == 1)
            filePath = possibleFiles.first().filePath();
        else
            qWarning() << "Could not find absolute location of file " << filePath;
    }
    emit addToTaskWindow(filePath, type, linenumber, description);
}

void MakeStep::addDirectory(const QString &dir)
{
    if (!m_openDirectories.contains(dir))
        m_openDirectories.insert(dir);
}

void MakeStep::removeDirectory(const QString &dir)
{
    if (m_openDirectories.contains(dir))
        m_openDirectories.remove(dir);
}

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
CMakeProject *MakeStep::project() const
{
    return m_pro;
}

bool MakeStep::buildsTarget(const QString &buildConfiguration, const QString &target) const
{
    return value(buildConfiguration, "buildTargets").toStringList().contains(target);
}

void MakeStep::setBuildTarget(const QString &buildConfiguration, const QString &target, bool on)
{
    QStringList old = value(buildConfiguration, "buildTargets").toStringList();
    if (on && !old.contains(target))
        setValue(buildConfiguration, "buildTargets", old << target);
    else if(!on && old.contains(target))
        setValue(buildConfiguration, "buildTargets", old.removeOne(target));
}

237 238 239 240 241 242 243 244 245 246
QStringList MakeStep::additionalArguments(const QString &buildConfiguration) const
{
    return value(buildConfiguration, "additionalArguments").toStringList();
}

void MakeStep::setAdditionalArguments(const QString &buildConfiguration, const QStringList &list)
{
    setValue(buildConfiguration, "additionalArguments", list);
}

dt's avatar
dt committed
247
//
248
// MakeStepConfigWidget
dt's avatar
dt committed
249
//
250

251
MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
252 253 254 255 256
    : m_makeStep(makeStep)
{
    QFormLayout *fl = new QFormLayout(this);
    setLayout(fl);

257
    m_additionalArguments = new QLineEdit(this);
258
    fl->addRow(tr("Additional arguments:"), m_additionalArguments);
259 260 261

    connect(m_additionalArguments, SIGNAL(textEdited(const QString &)), this, SLOT(additionalArgumentsEdited()));

262
    m_targetsList = new QListWidget;
263
    fl->addRow(tr("Targets:"), m_targetsList);
264 265 266 267 268 269 270 271

    // TODO update this list also on rescans of the CMakeLists.txt
    CMakeProject *pro = m_makeStep->project();
    foreach(const QString& target, pro->targets()) {
        QListWidgetItem *item = new QListWidgetItem(target, m_targetsList);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
        item->setCheckState(Qt::Unchecked);
    }
272

273 274 275
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
}

276
void MakeStepConfigWidget::additionalArgumentsEdited()
277 278 279 280
{
    m_makeStep->setAdditionalArguments(m_buildConfiguration, ProjectExplorer::Environment::parseCombinedArgString(m_additionalArguments->text()));
}

281
void MakeStepConfigWidget::itemChanged(QListWidgetItem *item)
282 283 284
{
    m_makeStep->setBuildTarget(m_buildConfiguration, item->text(), item->checkState() & Qt::Checked);
}
dt's avatar
dt committed
285

286
QString MakeStepConfigWidget::displayName() const
dt's avatar
dt committed
287 288 289 290
{
    return "Make";
}

291
void MakeStepConfigWidget::init(const QString &buildConfiguration)
dt's avatar
dt committed
292
{
293 294 295 296 297 298 299 300 301 302
    // disconnect to make the changes to the items
    disconnect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
    m_buildConfiguration = buildConfiguration;
    int count = m_targetsList->count();
    for(int i = 0; i < count; ++i) {
        QListWidgetItem *item = m_targetsList->item(i);
        item->setCheckState(m_makeStep->buildsTarget(buildConfiguration, item->text()) ? Qt::Checked : Qt::Unchecked);
    }
    // and connect again
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
303 304

    m_additionalArguments->setText(ProjectExplorer::Environment::joinArgumentList(m_makeStep->additionalArguments(m_buildConfiguration)));
dt's avatar
dt committed
305 306 307
}

//
308
// MakeStepFactory
dt's avatar
dt committed
309 310
//

311
bool MakeStepFactory::canCreate(const QString &name) const
dt's avatar
dt committed
312 313 314 315
{
    return (Constants::MAKESTEP == name);
}

316
ProjectExplorer::BuildStep *MakeStepFactory::create(ProjectExplorer::Project *project, const QString &name) const
dt's avatar
dt committed
317
{
dt's avatar
dt committed
318
    Q_ASSERT(name == Constants::MAKESTEP);
dt's avatar
dt committed
319
    CMakeProject *pro = qobject_cast<CMakeProject *>(project);
dt's avatar
dt committed
320
    Q_ASSERT(pro);
dt's avatar
dt committed
321 322 323
    return new MakeStep(pro);
}

324
QStringList MakeStepFactory::canCreateForProject(ProjectExplorer::Project * /* pro */) const
dt's avatar
dt committed
325 326 327 328
{
    return QStringList();
}

329
QString MakeStepFactory::displayNameForName(const QString & /* name */) const
dt's avatar
dt committed
330 331 332 333
{
    return "Make";
}