makestep.cpp 10.5 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 54 55 56
{
}

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

bool MakeStep::init(const QString &buildConfiguration)
{
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
    // TODO figure out the correct build parser
    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 101 102 103

    QStringList arguments = value(buildConfiguration, "buildTargets").toStringList();
    arguments << additionalArguments(buildConfiguration);
    setArguments(buildConfiguration, arguments); // TODO
dt's avatar
dt committed
104 105 106 107 108 109 110 111 112 113 114
    setEnvironment(buildConfiguration, m_pro->environment(buildConfiguration));
    return AbstractProcessStep::init(buildConfiguration);
}

void MakeStep::run(QFutureInterface<bool> &fi)
{
    AbstractProcessStep::run(fi);
}

QString MakeStep::name()
{
115
    return Constants::MAKESTEP;
dt's avatar
dt committed
116 117 118 119
}

QString MakeStep::displayName()
{
120
    return "Make";
dt's avatar
dt committed
121 122 123 124
}

ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
{
125
    return new MakeStepConfigWidget(this);
dt's avatar
dt committed
126 127 128 129 130 131 132
}

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

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 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
void MakeStep::stdOut(const QString &line)
{
    if (m_buildParser)
        m_buildParser->stdOutput(line);
    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);
}


206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
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));
}

225 226 227 228 229 230 231 232 233 234
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
235
//
236
// MakeStepConfigWidget
dt's avatar
dt committed
237
//
238

239
MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
240 241 242 243 244
    : m_makeStep(makeStep)
{
    QFormLayout *fl = new QFormLayout(this);
    setLayout(fl);

245 246 247 248 249
    m_additionalArguments = new QLineEdit(this);
    fl->addRow("Additional arguments:", m_additionalArguments);

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

250 251 252 253 254 255 256 257 258 259
    m_targetsList = new QListWidget;
    fl->addRow("Targets:", m_targetsList);

    // 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);
    }
260

261 262 263
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
}

264
void MakeStepConfigWidget::additionalArgumentsEdited()
265 266 267 268
{
    m_makeStep->setAdditionalArguments(m_buildConfiguration, ProjectExplorer::Environment::parseCombinedArgString(m_additionalArguments->text()));
}

269
void MakeStepConfigWidget::itemChanged(QListWidgetItem *item)
270 271 272
{
    m_makeStep->setBuildTarget(m_buildConfiguration, item->text(), item->checkState() & Qt::Checked);
}
dt's avatar
dt committed
273

274
QString MakeStepConfigWidget::displayName() const
dt's avatar
dt committed
275 276 277 278
{
    return "Make";
}

279
void MakeStepConfigWidget::init(const QString &buildConfiguration)
dt's avatar
dt committed
280
{
281 282 283 284 285 286 287 288 289 290
    // 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*)));
291 292

    m_additionalArguments->setText(ProjectExplorer::Environment::joinArgumentList(m_makeStep->additionalArguments(m_buildConfiguration)));
dt's avatar
dt committed
293 294 295
}

//
296
// MakeStepFactory
dt's avatar
dt committed
297 298
//

299
bool MakeStepFactory::canCreate(const QString &name) const
dt's avatar
dt committed
300 301 302 303
{
    return (Constants::MAKESTEP == name);
}

304
ProjectExplorer::BuildStep *MakeStepFactory::create(ProjectExplorer::Project *project, const QString &name) const
dt's avatar
dt committed
305
{
dt's avatar
dt committed
306
    Q_ASSERT(name == Constants::MAKESTEP);
dt's avatar
dt committed
307
    CMakeProject *pro = qobject_cast<CMakeProject *>(project);
dt's avatar
dt committed
308
    Q_ASSERT(pro);
dt's avatar
dt committed
309 310 311
    return new MakeStep(pro);
}

312
QStringList MakeStepFactory::canCreateForProject(ProjectExplorer::Project * /* pro */) const
dt's avatar
dt committed
313 314 315 316
{
    return QStringList();
}

317
QString MakeStepFactory::displayNameForName(const QString & /* name */) const
dt's avatar
dt committed
318 319 320 321
{
    return "Make";
}