cmakeopenprojectwizard.cpp 21.1 KB
Newer Older
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
30 31 32
**
**************************************************************************/

33 34 35 36 37 38 39 40 41

/// TODO
/// To check
/// a) with an old cmake
/// => should not show combobox always use mingw generator
/// b) with an new cmake
/// always show combo box, defaulting if there's already a existing build


qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
42 43 44 45
#include "cmakeopenprojectwizard.h"
#include "cmakeprojectmanager.h"

#include <utils/pathchooser.h>
46
#include <projectexplorer/toolchainmanager.h>
47 48
#include <projectexplorer/toolchain.h>
#include <projectexplorer/abi.h>
49
#include <texteditor/fontsettings.h>
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
50 51 52 53 54 55 56

#include <QtGui/QVBoxLayout>
#include <QtGui/QFormLayout>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QPlainTextEdit>
#include <QtCore/QDateTime>
dt's avatar
dt committed
57
#include <QtCore/QStringList>
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;

///////
//  Page Flow:
//   Start (No .user file)
//    |
//    |---> In Source Build --> Page: Tell the user about that
//                               |--> Already existing cbp file (and new enough) --> Page: Ready to load the project
//                               |--> Page: Ask for cmd options, run generator
//    |---> No in source Build --> Page: Ask the user for the build directory
//                                   |--> Already existing cbp file (and new enough) --> Page: Ready to load the project
//                                   |--> Page: Ask for cmd options, run generator

73
CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const Utils::Environment &env)
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
74
    : m_cmakeManager(cmakeManager),
dt's avatar
dt committed
75
      m_sourceDirectory(sourceDirectory),
76
      m_creatingCbpFiles(false),
77 78
      m_environment(env),
      m_toolChain(0)
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
79 80 81 82 83 84 85
{
    int startid;
    if (hasInSourceBuild()) {
        startid = InSourcePageId;
        m_buildDirectory = m_sourceDirectory;
    } else {
        startid = ShadowBuildPageId;
dt's avatar
dt committed
86 87 88
        QDir dir(m_sourceDirectory);
        dir.cdUp();
        m_buildDirectory = dir.absolutePath() + "/qtcreator-build";
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
89 90 91 92 93 94
    }

    setPage(InSourcePageId, new InSourceBuildPage(this));
    setPage(ShadowBuildPageId, new ShadowBuildPage(this));
    setPage(CMakeRunPageId, new CMakeRunPage(this));

95 96 97 98 99 100 101
    Utils::WizardProgress *wp = wizardProgress();
    Utils::WizardProgressItem *inSourceItem = wp->item(InSourcePageId);
    Utils::WizardProgressItem *shadowBuildItem = wp->item(ShadowBuildPageId);
    Utils::WizardProgressItem *cmakeRunItem = wp->item(CMakeRunPageId);
    inSourceItem->setNextItems(QList<Utils::WizardProgressItem *>() << cmakeRunItem);
    shadowBuildItem->setNextItems(QList<Utils::WizardProgressItem *>() << cmakeRunItem);

qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
102
    setStartId(startid);
dt's avatar
dt committed
103
    init();
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
104 105
}

dt's avatar
dt committed
106
CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory,
107
                                               const QString &buildDirectory, CMakeOpenProjectWizard::Mode mode,
108
                                               const Utils::Environment &env)
dt's avatar
dt committed
109 110
    : m_cmakeManager(cmakeManager),
      m_sourceDirectory(sourceDirectory),
111
      m_creatingCbpFiles(true),
112 113
      m_environment(env),
      m_toolChain(0)
dt's avatar
dt committed
114
{
115 116

    CMakeRunPage::Mode rmode;
117
    if (mode == CMakeOpenProjectWizard::NeedToCreate)
118 119 120
        rmode = CMakeRunPage::Recreate;
    else if (mode == CMakeOpenProjectWizard::WantToUpdate)
        rmode = CMakeRunPage::WantToUpdate;
121
    else
122 123
        rmode = CMakeRunPage::NeedToUpdate;
    addPage(new CMakeRunPage(this, rmode, buildDirectory));
dt's avatar
dt committed
124
    init();
dt's avatar
dt committed
125 126
}

127
CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory,
128
                                               const QString &oldBuildDirectory,
129
                                               const Utils::Environment &env)
130 131
    : m_cmakeManager(cmakeManager),
      m_sourceDirectory(sourceDirectory),
132
      m_creatingCbpFiles(true),
133 134
      m_environment(env),
      m_toolChain(0)
135 136 137
{
    m_buildDirectory = oldBuildDirectory;
    addPage(new ShadowBuildPage(this, true));
138
    addPage(new CMakeRunPage(this, CMakeRunPage::ChangeDirectory));
dt's avatar
dt committed
139 140 141 142 143
    init();
}

void CMakeOpenProjectWizard::init()
{
144
    setOption(QWizard::NoBackButtonOnStartPage);
dt's avatar
dt committed
145
    setWindowTitle(tr("CMake Wizard"));
146 147
}

qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
148 149 150 151 152 153 154
CMakeManager *CMakeOpenProjectWizard::cmakeManager() const
{
    return m_cmakeManager;
}

int CMakeOpenProjectWizard::nextId() const
{
dt's avatar
dt committed
155 156
    if (m_creatingCbpFiles)
        return QWizard::nextId();
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
157 158
    int cid = currentId();
    if (cid == InSourcePageId) {
159
        return CMakeRunPageId;
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
160
    } else if (cid == ShadowBuildPageId) {
161
        return CMakeRunPageId;
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
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
    }
    return -1;
}


bool CMakeOpenProjectWizard::hasInSourceBuild() const
{
    QFileInfo fi(m_sourceDirectory + "/CMakeCache.txt");
    if (fi.exists())
        return true;
    return false;
}

bool CMakeOpenProjectWizard::existsUpToDateXmlFile() const
{
    QString cbpFile = CMakeManager::findCbpFile(QDir(buildDirectory()));
    if (!cbpFile.isEmpty()) {
        // We already have a cbp file
        QFileInfo cbpFileInfo(cbpFile);
        QFileInfo cmakeListsFileInfo(sourceDirectory() + "/CMakeLists.txt");

        if (cbpFileInfo.lastModified() > cmakeListsFileInfo.lastModified())
            return true;
    }
    return false;
}

QString CMakeOpenProjectWizard::buildDirectory() const
{
    return m_buildDirectory;
}

QString CMakeOpenProjectWizard::sourceDirectory() const
{
    return m_sourceDirectory;
}

void CMakeOpenProjectWizard::setBuildDirectory(const QString &directory)
{
    m_buildDirectory = directory;
}

204
QString CMakeOpenProjectWizard::arguments() const
dt's avatar
dt committed
205
{
206
    return m_arguments;
dt's avatar
dt committed
207 208
}

209
void CMakeOpenProjectWizard::setArguments(const QString &args)
dt's avatar
dt committed
210
{
211
    m_arguments = args;
dt's avatar
dt committed
212 213
}

214
ProjectExplorer::ToolChain *CMakeOpenProjectWizard::toolChain() const
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
215
{
216
    return m_toolChain;
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
217 218
}

219
void CMakeOpenProjectWizard::setToolChain(ProjectExplorer::ToolChain *tc)
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
220
{
221
    m_toolChain = tc;
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
222 223
}

224

225
Utils::Environment CMakeOpenProjectWizard::environment() const
226 227 228 229
{
    return m_environment;
}

qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
230 231 232 233 234 235 236

InSourceBuildPage::InSourceBuildPage(CMakeOpenProjectWizard *cmakeWizard)
    : QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard)
{
    setLayout(new QVBoxLayout);
    QLabel *label = new QLabel(this);
    label->setWordWrap(true);
237
    label->setText(tr("Qt Creator has detected an <b>in-source-build in %1</b> "
Friedemann Kleint's avatar
Friedemann Kleint committed
238
                   "which prevents shadow builds. Qt Creator will not allow you to change the build directory. "
239 240
                   "If you want a shadow build, clean your source directory and re-open the project.")
                   .arg(m_cmakeWizard->buildDirectory()));
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
241
    layout()->addWidget(label);
242
    setTitle(tr("Build Location"));
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
243 244
}

245
ShadowBuildPage::ShadowBuildPage(CMakeOpenProjectWizard *cmakeWizard, bool change)
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
246 247 248 249 250 251 252
    : QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard)
{
    QFormLayout *fl = new QFormLayout;
    this->setLayout(fl);

    QLabel *label = new QLabel(this);
    label->setWordWrap(true);
253 254 255 256 257 258 259
    if (change)
        label->setText(tr("Please enter the directory in which you want to build your project. "));
    else
        label->setText(tr("Please enter the directory in which you want to build your project. "
                          "Qt Creator recommends to not use the source directory for building. "
                          "This ensures that the source directory remains clean and enables multiple builds "
                          "with different settings."));
con's avatar
con committed
260
    fl->addRow(label);
261
    m_pc = new Utils::PathChooser(this);
262
    m_pc->setBaseDirectory(m_cmakeWizard->sourceDirectory());
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
263
    m_pc->setPath(m_cmakeWizard->buildDirectory());
con's avatar
con committed
264
    connect(m_pc, SIGNAL(changed(QString)), this, SLOT(buildDirectoryChanged()));
265
    fl->addRow(tr("Build directory:"), m_pc);
266
    setTitle(tr("Build Location"));
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
267 268 269 270 271 272 273
}

void ShadowBuildPage::buildDirectoryChanged()
{
    m_cmakeWizard->setBuildDirectory(m_pc->path());
}

274
CMakeRunPage::CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard, Mode mode, const QString &buildDirectory)
dt's avatar
dt committed
275 276 277
    : QWizardPage(cmakeWizard),
      m_cmakeWizard(cmakeWizard),
      m_complete(false),
278 279
      m_mode(mode),
      m_buildDirectory(buildDirectory)
dt's avatar
dt committed
280 281 282 283 284
{
    initWidgets();
}

void CMakeRunPage::initWidgets()
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
285 286
{
    QFormLayout *fl = new QFormLayout;
con's avatar
con committed
287
    fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
288
    setLayout(fl);
289
    // Description Label
dt's avatar
dt committed
290 291 292 293
    m_descriptionLabel = new QLabel(this);
    m_descriptionLabel->setWordWrap(true);

    fl->addRow(m_descriptionLabel);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
294

295 296 297
    if (m_cmakeWizard->cmakeManager()->isCMakeExecutableValid()) {
        m_cmakeExecutable = 0;
    } else {
Jarek Kobus's avatar
Jarek Kobus committed
298
        QString text = tr("Please specify the path to the cmake executable. No cmake executable was found in the path.");
299 300 301 302
        QString cmakeExecutable = m_cmakeWizard->cmakeManager()->cmakeExecutable();
        if (!cmakeExecutable.isEmpty()) {
            QFileInfo fi(cmakeExecutable);
            if (!fi.exists())
Jarek Kobus's avatar
Jarek Kobus committed
303
                text += tr(" The cmake executable (%1) does not exist.").arg(cmakeExecutable);
304 305 306
            else if (!fi.isExecutable())
                text += tr(" The path %1 is not a executable.").arg(cmakeExecutable);
            else
Jarek Kobus's avatar
Jarek Kobus committed
307
                text += tr(" The path %1 is not a valid cmake.").arg(cmakeExecutable);
308 309
        }

con's avatar
con committed
310 311 312
        QLabel *cmakeLabel = new QLabel(text);
        cmakeLabel->setWordWrap(true);
        fl->addRow(cmakeLabel);
313
        // Show a field for the user to enter
314
        m_cmakeExecutable = new Utils::PathChooser(this);
315
        m_cmakeExecutable->setExpectedKind(Utils::PathChooser::ExistingCommand);
con's avatar
con committed
316
        fl->addRow("cmake Executable:", m_cmakeExecutable);
317 318 319
    }

    // Run CMake Line (with arguments)
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
320
    m_argumentsLineEdit = new QLineEdit(this);
321
    connect(m_argumentsLineEdit,SIGNAL(returnPressed()), this, SLOT(runCMake()));
con's avatar
con committed
322
    fl->addRow(tr("Arguments:"), m_argumentsLineEdit);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
323

324
    m_generatorComboBox = new QComboBox(this);
con's avatar
con committed
325
    fl->addRow(tr("Generator:"), m_generatorComboBox);
dt's avatar
dt committed
326

qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
327
    m_runCMake = new QPushButton(this);
328
    m_runCMake->setText(tr("Run CMake"));
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
329
    connect(m_runCMake, SIGNAL(clicked()), this, SLOT(runCMake()));
330

con's avatar
con committed
331 332 333 334
    QHBoxLayout *hbox2 = new QHBoxLayout;
    hbox2->addStretch(10);
    hbox2->addWidget(m_runCMake);
    fl->addRow(hbox2);
335

336
    // Bottom output window
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
337
    m_output = new QPlainTextEdit(this);
338
    m_output->setReadOnly(true);
con's avatar
con committed
339 340 341
    // set smaller minimum size to avoid vanishing descriptions if all of the
    // above is shown and the dialog not vertically resizing to fit stuff in (Mac)
    m_output->setMinimumHeight(15);
342
    QFont f(TextEditor::FontSettings::defaultFixedFontFamily());
343 344
    f.setStyleHint(QFont::TypeWriter);
    m_output->setFont(f);
345 346 347
    QSizePolicy pl = m_output->sizePolicy();
    pl.setVerticalStretch(1);
    m_output->setSizePolicy(pl);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
348
    fl->addRow(m_output);
349 350 351 352 353

    m_exitCodeLabel = new QLabel(this);
    m_exitCodeLabel->setVisible(false);
    fl->addRow(m_exitCodeLabel);

354
    setTitle(tr("Run CMake"));
355
    setMinimumSize(600, 400);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
356 357
}

358 359
void CMakeRunPage::initializePage()
{
360
    if (m_mode == Initial) {
361
        m_complete = m_cmakeWizard->existsUpToDateXmlFile();
362
        m_buildDirectory = m_cmakeWizard->buildDirectory();
363 364 365

        if (m_cmakeWizard->existsUpToDateXmlFile()) {
            m_descriptionLabel->setText(
366
                    tr("The directory %1 already contains a cbp file, which is recent enough. "
367
                       "You can pass special arguments or change the used tool chain here and rerun CMake. "
368
                       "Or simply finish the wizard directly.").arg(m_buildDirectory));
369 370
        } else {
            m_descriptionLabel->setText(
371 372
                    tr("The directory %1 does not contain a cbp file. Qt Creator needs to create this file by running CMake. "
                       "Some projects require command line arguments to the initial CMake call.").arg(m_buildDirectory));
373
        }
374
    } else if (m_mode == CMakeRunPage::NeedToUpdate) {
375
        m_descriptionLabel->setText(tr("The directory %1 contains an outdated .cbp file. Qt "
376
                                       "Creator needs to update this file by running CMake. "
377
                                       "If you want to add additional command line arguments, "
378
                                       "add them below. Note that CMake remembers command "
Friedemann Kleint's avatar
Friedemann Kleint committed
379
                                       "line arguments from the previous runs.").arg(m_buildDirectory));
380
    } else if(m_mode == CMakeRunPage::Recreate) {
Friedemann Kleint's avatar
Friedemann Kleint committed
381
        m_descriptionLabel->setText(tr("The directory %1 specified in a build-configuration, "
382
                                       "does not contain a cbp file. Qt Creator needs to "
383
                                       "recreate this file, by running CMake. "
384
                                       "Some projects require command line arguments to "
385
                                       "the initial CMake call. Note that CMake remembers command "
Friedemann Kleint's avatar
Friedemann Kleint committed
386
                                       "line arguments from the previous runs.").arg(m_buildDirectory));
387
    } else if(m_mode == CMakeRunPage::ChangeDirectory) {
388
        m_buildDirectory = m_cmakeWizard->buildDirectory();
389
        m_descriptionLabel->setText(tr("Qt Creator needs to run CMake in the new build directory. "
390
                                       "Some projects require command line arguments to the "
391
                                       "initial CMake call."));
392 393
    } else if (m_mode == CMakeRunPage::WantToUpdate) {
        m_descriptionLabel->setText(tr("Refreshing cbp file in %1.").arg(m_buildDirectory));
394
    }
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414


    // Try figuring out generator and toolchain from CMakeCache.txt
    QString cachedGenerator;
    QString cmakeCxxCompiler;
    QFile fi(m_buildDirectory + "/CMakeCache.txt");
    if (fi.exists()) {
        // Cache exists, then read it...
        if (fi.open(QIODevice::ReadOnly | QIODevice::Text)) {
            while (!fi.atEnd()) {
                QString line = fi.readLine();
                if (line.startsWith("CMAKE_GENERATOR:INTERNAL=")) {
                    int splitpos = line.indexOf('=');
                    if (splitpos != -1)
                        cachedGenerator = line.mid(splitpos + 1).trimmed();
                }
                if (line.startsWith("CMAKE_CXX_COMPILER:FILEPATH=")) {
                    int splitpos = line.indexOf("=");
                    if (splitpos != -1)
                        cmakeCxxCompiler = line.mid(splitpos +1).trimmed();
415
                }
416 417
                if (!cachedGenerator.isEmpty() && !cmakeCxxCompiler.isEmpty())
                    break;
418
            }
419
        }
420
    }
dt's avatar
dt committed
421

422 423 424 425 426 427 428
    // Build the list of generators/toolchains we want to offer
    // todo restrict toolchains based on CMAKE_CXX_COMPILER ?
    Q_UNUSED(cmakeCxxCompiler);
    m_generatorComboBox->clear();
    bool hasCodeBlocksGenerator = m_cmakeWizard->cmakeManager()->hasCodeBlocksMsvcGenerator();
    ProjectExplorer::Abi abi = ProjectExplorer::Abi::hostAbi();
    abi = ProjectExplorer::Abi(abi.architecture(), abi.os(), ProjectExplorer::Abi::UnknownFlavor,
429
                               abi.binaryFormat(), 0);
430 431 432 433 434 435 436 437 438 439 440
    QList<ProjectExplorer::ToolChain *> tcs =
            ProjectExplorer::ToolChainManager::instance()->findToolChains(abi);

    foreach (ProjectExplorer::ToolChain *tc, tcs) {
        ProjectExplorer::Abi targetAbi = tc->targetAbi();
        QVariant tcVariant = qVariantFromValue(static_cast<void *>(tc));
        if (targetAbi.os() == ProjectExplorer::Abi::WindowsOS) {
            if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2005Flavor
                    || targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2008Flavor
                    || targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2010Flavor) {
                if (hasCodeBlocksGenerator && (cachedGenerator.isEmpty() || cachedGenerator == "NMake Makefiles"))
441
                    m_generatorComboBox->addItem(tr("NMake Generator (%1)").arg(tc->displayName()), tcVariant);
442 443
             } else if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
                if (cachedGenerator.isEmpty() || cachedGenerator == "MinGW Makefiles")
444 445
                    m_generatorComboBox->addItem(tr("MinGW Generator (%1)").arg(tc->displayName()), tcVariant);
            }
446 447 448 449
        } else {
            // Non windows
            if (cachedGenerator.isEmpty() || cachedGenerator == "Unix Makefiles")
                m_generatorComboBox->addItem(tr("Unix Generator (%1)").arg(tc->displayName()), tcVariant);
450
        }
451
    }
452 453
}

qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
454 455
void CMakeRunPage::runCMake()
{
456 457 458 459 460
    if (m_cmakeExecutable) {
        // We asked the user for the cmake executable
        m_cmakeWizard->cmakeManager()->setCMakeExecutable(m_cmakeExecutable->path());
    }

461 462 463
    int index = m_generatorComboBox->currentIndex();

    ProjectExplorer::ToolChain *tc = 0;
464
    if (index >= 0)
465
        tc = static_cast<ProjectExplorer::ToolChain *>(m_generatorComboBox->itemData(index).value<void *>());
466 467 468 469
    if (!tc) {
        m_output->appendPlainText(tr("No generator selected."));
        return;
    }
470 471

    m_cmakeWizard->setToolChain(tc);
472

qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
473 474
    m_runCMake->setEnabled(false);
    m_argumentsLineEdit->setEnabled(false);
475
    m_generatorComboBox->setEnabled(false);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
476
    CMakeManager *cmakeManager = m_cmakeWizard->cmakeManager();
477

dt's avatar
dt committed
478
    QString generator = QLatin1String("-GCodeBlocks - Unix Makefiles");
hjk's avatar
hjk committed
479
    if (tc->targetAbi().os() == ProjectExplorer::Abi::WindowsOS) {
480
        if (tc->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor)
481
            generator = QLatin1String("-GCodeBlocks - MinGW Makefiles");
482 483
        else
            generator = QLatin1String("-GCodeBlocks - NMake Makefiles");
dt's avatar
dt committed
484 485
    }

486 487 488 489

    Utils::Environment env = m_cmakeWizard->environment();
    tc->addToEnvironment(env);

490

491 492 493 494

    m_output->clear();

    if (m_cmakeWizard->cmakeManager()->isCMakeExecutableValid()) {
495
        m_cmakeProcess = new Utils::QtcProcess();
496 497
        connect(m_cmakeProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(cmakeReadyReadStandardOutput()));
        connect(m_cmakeProcess, SIGNAL(readyReadStandardError()), this, SLOT(cmakeReadyReadStandardError()));
498
        connect(m_cmakeProcess, SIGNAL(finished(int)), this, SLOT(cmakeFinished()));
499
        cmakeManager->createXmlFile(m_cmakeProcess, m_argumentsLineEdit->text(), m_cmakeWizard->sourceDirectory(), m_buildDirectory, env, generator);
500 501 502
    } else {
        m_runCMake->setEnabled(true);
        m_argumentsLineEdit->setEnabled(true);
503
        m_generatorComboBox->setEnabled(true);
Jarek Kobus's avatar
Jarek Kobus committed
504
        m_output->appendPlainText(tr("No valid cmake executable specified."));
505
    }
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
506 507
}

508 509 510 511 512 513 514 515 516
static QColor mix_colors(QColor a, QColor b)
{
    return QColor((a.red() + 2 * b.red()) / 3, (a.green() + 2 * b.green()) / 3,
                  (a.blue() + 2* b.blue()) / 3, (a.alpha() + 2 * b.alpha()) / 3);
}

void CMakeRunPage::cmakeReadyReadStandardOutput()
{
    QTextCursor cursor(m_output->document());
dt_'s avatar
dt_ committed
517
    cursor.movePosition(QTextCursor::End);
518 519 520 521 522 523 524 525 526 527
    QTextCharFormat tf;

    QFont font = m_output->font();
    tf.setFont(font);
    tf.setForeground(m_output->palette().color(QPalette::Text));

    cursor.insertText(m_cmakeProcess->readAllStandardOutput(), tf);
}

void CMakeRunPage::cmakeReadyReadStandardError()
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
528
{
529 530 531 532 533 534 535 536 537 538
    QTextCursor cursor(m_output->document());
    QTextCharFormat tf;

    QFont font = m_output->font();
    QFont boldFont = font;
    boldFont.setBold(true);
    tf.setFont(boldFont);
    tf.setForeground(mix_colors(m_output->palette().color(QPalette::Text), QColor(Qt::red)));

    cursor.insertText(m_cmakeProcess->readAllStandardError(), tf);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
539 540 541 542 543 544
}

void CMakeRunPage::cmakeFinished()
{
    m_runCMake->setEnabled(true);
    m_argumentsLineEdit->setEnabled(true);
545 546
    m_generatorComboBox->setEnabled(true);

547 548
    if (m_cmakeProcess->exitCode() != 0) {
        m_exitCodeLabel->setVisible(true);
Jarek Kobus's avatar
Jarek Kobus committed
549
        m_exitCodeLabel->setText(tr("CMake exited with errors. Please check CMake output."));
550 551 552 553 554
        m_complete = false;
    } else {
        m_exitCodeLabel->setVisible(false);
        m_complete = true;
    }
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
555 556
    m_cmakeProcess->deleteLater();
    m_cmakeProcess = 0;
557
    m_cmakeWizard->setArguments(m_argumentsLineEdit->text());
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
558 559 560 561 562 563 564 565
    //TODO Actually test that running cmake was finished, for setting this bool
    emit completeChanged();
}

void CMakeRunPage::cleanupPage()
{
    m_output->clear();
    m_complete = false;
566
    m_exitCodeLabel->setVisible(false);
qtc-committer@nokia.com's avatar
qtc-committer@nokia.com committed
567 568 569 570 571 572 573
    emit completeChanged();
}

bool CMakeRunPage::isComplete() const
{
    return m_complete;
}