genericmakestep.cpp 9.91 KB
Newer Older
Roberto Raggi's avatar
Roberto Raggi committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** 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.
**
** GNU Lesser General Public License Usage
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

30
#include "genericmakestep.h"
Roberto Raggi's avatar
Roberto Raggi committed
31 32 33
#include "genericprojectconstants.h"
#include "genericproject.h"

34
#include <extensionsystem/pluginmanager.h>
35
#include <projectexplorer/toolchain.h>
Roberto Raggi's avatar
Roberto Raggi committed
36
#include <utils/qtcassert.h>
37

Roberto Raggi's avatar
Roberto Raggi committed
38 39 40 41 42 43 44 45 46 47 48 49 50
#include <QtGui/QFormLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QCheckBox>
#include <QtGui/QLineEdit>
#include <QtGui/QListWidget>

namespace {
bool debug = false;
}

using namespace GenericProjectManager;
using namespace GenericProjectManager::Internal;

51
GenericMakeStep::GenericMakeStep(GenericProject *pro)
Roberto Raggi's avatar
Roberto Raggi committed
52 53 54 55
    : AbstractProcessStep(pro), m_pro(pro), m_buildParser(0)
{
}

56
GenericMakeStep::~GenericMakeStep()
Roberto Raggi's avatar
Roberto Raggi committed
57 58 59 60 61
{
    delete m_buildParser;
    m_buildParser = 0;
}

62
bool GenericMakeStep::init(const QString &buildConfiguration)
Roberto Raggi's avatar
Roberto Raggi committed
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 93 94 95 96 97 98 99 100
{
    // TODO figure out the correct build parser
    delete m_buildParser;
    m_buildParser = 0;

    const QString buildParser = m_pro->buildParser(buildConfiguration);
    qDebug() << "*** build parser:" << buildParser;

    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));

    setEnabled(buildConfiguration, true);
    setWorkingDirectory(buildConfiguration, m_pro->buildDirectory(buildConfiguration));
101 102 103 104
    if (ProjectExplorer::ToolChain *toolChain = m_pro->toolChain())
        setCommand(buildConfiguration, toolChain->makeCommand());
    else
        setCommand(buildConfiguration, "make");
Roberto Raggi's avatar
Roberto Raggi committed
105 106 107 108 109
    setArguments(buildConfiguration, value(buildConfiguration, "buildTargets").toStringList()); // TODO
    setEnvironment(buildConfiguration, m_pro->environment(buildConfiguration));
    return AbstractProcessStep::init(buildConfiguration);
}

110
void GenericMakeStep::run(QFutureInterface<bool> &fi)
Roberto Raggi's avatar
Roberto Raggi committed
111 112 113 114
{
    AbstractProcessStep::run(fi);
}

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

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

125
ProjectExplorer::BuildStepConfigWidget *GenericMakeStep::createConfigWidget()
Roberto Raggi's avatar
Roberto Raggi committed
126
{
127
    return new GenericMakeStepConfigWidget(this);
Roberto Raggi's avatar
Roberto Raggi committed
128 129
}

130
bool GenericMakeStep::immutable() const
Roberto Raggi's avatar
Roberto Raggi committed
131 132 133 134
{
    return true;
}

135
void GenericMakeStep::stdOut(const QString &line)
Roberto Raggi's avatar
Roberto Raggi committed
136 137 138 139 140 141
{
    if (m_buildParser)
        m_buildParser->stdOutput(line);
    AbstractProcessStep::stdOut(line);
}

142
void GenericMakeStep::stdError(const QString &line)
Roberto Raggi's avatar
Roberto Raggi committed
143 144 145 146 147 148
{
    if (m_buildParser)
        m_buildParser->stdError(line);
    AbstractProcessStep::stdError(line);
}

149
void GenericMakeStep::slotAddToTaskWindow(const QString & fn, int type, int linenumber, const QString & description)
Roberto Raggi's avatar
Roberto Raggi committed
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
{
    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);
}

195
void GenericMakeStep::addDirectory(const QString &dir)
Roberto Raggi's avatar
Roberto Raggi committed
196 197 198 199 200
{
    if (!m_openDirectories.contains(dir))
        m_openDirectories.insert(dir);
}

201
void GenericMakeStep::removeDirectory(const QString &dir)
Roberto Raggi's avatar
Roberto Raggi committed
202 203 204 205 206 207
{
    if (m_openDirectories.contains(dir))
        m_openDirectories.remove(dir);
}


208
GenericProject *GenericMakeStep::project() const
Roberto Raggi's avatar
Roberto Raggi committed
209 210 211 212
{
    return m_pro;
}

213
bool GenericMakeStep::buildsTarget(const QString &buildConfiguration, const QString &target) const
Roberto Raggi's avatar
Roberto Raggi committed
214 215 216 217
{
    return value(buildConfiguration, "buildTargets").toStringList().contains(target);
}

218
void GenericMakeStep::setBuildTarget(const QString &buildConfiguration, const QString &target, bool on)
Roberto Raggi's avatar
Roberto Raggi committed
219 220 221 222 223 224 225 226 227
{
    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));
}

//
228
// GenericMakeStepConfigWidget
Roberto Raggi's avatar
Roberto Raggi committed
229
//
230 231

GenericMakeStepConfigWidget::GenericMakeStepConfigWidget(GenericMakeStep *makeStep)
Roberto Raggi's avatar
Roberto Raggi committed
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
    : m_makeStep(makeStep)
{
    QFormLayout *fl = new QFormLayout(this);
    setLayout(fl);

    m_targetsList = new QListWidget;
    fl->addRow("Targets:", m_targetsList);

    // TODO update this list also on rescans of the GenericLists.txt
    GenericProject *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);
    }
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
}

250
void GenericMakeStepConfigWidget::itemChanged(QListWidgetItem *item)
Roberto Raggi's avatar
Roberto Raggi committed
251 252 253 254
{
    m_makeStep->setBuildTarget(m_buildConfiguration, item->text(), item->checkState() & Qt::Checked);
}

255
QString GenericMakeStepConfigWidget::displayName() const
Roberto Raggi's avatar
Roberto Raggi committed
256 257 258 259
{
    return "Make";
}

260
void GenericMakeStepConfigWidget::init(const QString &buildConfiguration)
Roberto Raggi's avatar
Roberto Raggi committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
{
    // TODO

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

//
277
// GenericMakeStepFactory
Roberto Raggi's avatar
Roberto Raggi committed
278 279
//

280
bool GenericMakeStepFactory::canCreate(const QString &name) const
Roberto Raggi's avatar
Roberto Raggi committed
281 282 283 284
{
    return (Constants::MAKESTEP == name);
}

285
ProjectExplorer::BuildStep *GenericMakeStepFactory::create(ProjectExplorer::Project *project, const QString &name) const
Roberto Raggi's avatar
Roberto Raggi committed
286 287 288 289
{
    Q_ASSERT(name == Constants::MAKESTEP);
    GenericProject *pro = qobject_cast<GenericProject *>(project);
    Q_ASSERT(pro);
290
    return new GenericMakeStep(pro);
Roberto Raggi's avatar
Roberto Raggi committed
291 292
}

293
QStringList GenericMakeStepFactory::canCreateForProject(ProjectExplorer::Project * /* pro */) const
Roberto Raggi's avatar
Roberto Raggi committed
294 295 296 297
{
    return QStringList();
}

298
QString GenericMakeStepFactory::displayNameForName(const QString & /* name */) const
Roberto Raggi's avatar
Roberto Raggi committed
299 300 301
{
    return "Make";
}