desktopqmakerunconfiguration.cpp 26.2 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** 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
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

30
#include "desktopqmakerunconfiguration.h"
hjk's avatar
hjk committed
31

32 33 34
#include "qmakenodes.h"
#include "qmakeproject.h"
#include "qmakebuildconfiguration.h"
con's avatar
con committed
35

36
#include <coreplugin/coreconstants.h>
37
#include <projectexplorer/localenvironmentaspect.h>
Tobias Hunger's avatar
Tobias Hunger committed
38
#include <projectexplorer/target.h>
39
#include <qtsupport/qtkitinformation.h>
40
#include <qtsupport/qtoutputformatter.h>
Tobias Hunger's avatar
Tobias Hunger committed
41
#include <qtsupport/qtsupportconstants.h>
42
#include <utils/detailswidget.h>
43
#include <utils/hostosinfo.h>
44 45 46 47
#include <utils/pathchooser.h>
#include <utils/persistentsettings.h>
#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
con's avatar
con committed
48

49 50 51 52
#include <QCheckBox>
#include <QComboBox>
#include <QDir>
#include <QFileInfo>
53 54 55 56
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include <QToolButton>
con's avatar
con committed
57

58 59
using namespace ProjectExplorer;
using namespace Utils;
con's avatar
con committed
60

61 62
namespace QmakeProjectManager {
namespace Internal {
63

64
const char QMAKE_RC_PREFIX[] = "Qt4ProjectManager.Qt4RunConfiguration:";
hjk's avatar
hjk committed
65 66 67 68 69
const char COMMAND_LINE_ARGUMENTS_KEY[] = "Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments";
const char PRO_FILE_KEY[] = "Qt4ProjectManager.Qt4RunConfiguration.ProFile";
const char USE_TERMINAL_KEY[] = "Qt4ProjectManager.Qt4RunConfiguration.UseTerminal";
const char USE_DYLD_IMAGE_SUFFIX_KEY[] = "Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix";
const char USER_WORKING_DIRECTORY_KEY[] = "Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory";
70

71
static QString pathFromId(Core::Id id)
con's avatar
con committed
72
{
73
    return id.suffixAfter(QMAKE_RC_PREFIX);
74
}
75

76
//
77
// QmakeRunConfiguration
78 79
//

80
DesktopQmakeRunConfiguration::DesktopQmakeRunConfiguration(Target *parent, Core::Id id) :
Tobias Hunger's avatar
Tobias Hunger committed
81 82
    LocalApplicationRunConfiguration(parent, id),
    m_proFilePath(pathFromId(id)),
83
    m_runMode(ApplicationLauncher::Gui),
84
    m_isUsingDyldImageSuffix(false)
85
{
86 87
    addExtraAspect(new ProjectExplorer::LocalEnvironmentAspect(this));

88
    QmakeProject *project = static_cast<QmakeProject *>(parent->project());
Tobias Hunger's avatar
Tobias Hunger committed
89 90 91
    m_parseSuccess = project->validParse(m_proFilePath);
    m_parseInProgress = project->parseInProgress(m_proFilePath);

92
    ctor();
con's avatar
con committed
93 94
}

95
DesktopQmakeRunConfiguration::DesktopQmakeRunConfiguration(Target *parent, DesktopQmakeRunConfiguration *source) :
96 97 98 99
    LocalApplicationRunConfiguration(parent, source),
    m_commandLineArguments(source->m_commandLineArguments),
    m_proFilePath(source->m_proFilePath),
    m_runMode(source->m_runMode),
100
    m_forcedGuiMode(source->m_forcedGuiMode),
101 102
    m_isUsingDyldImageSuffix(source->m_isUsingDyldImageSuffix),
    m_userWorkingDirectory(source->m_userWorkingDirectory),
103 104
    m_parseSuccess(source->m_parseSuccess),
    m_parseInProgress(source->m_parseInProgress)
con's avatar
con committed
105
{
106
    ctor();
con's avatar
con committed
107 108
}

109
DesktopQmakeRunConfiguration::~DesktopQmakeRunConfiguration()
dt's avatar
dt committed
110 111 112
{
}

113
bool DesktopQmakeRunConfiguration::isEnabled() const
114
{
115
    return m_parseSuccess && !m_parseInProgress;
116
}
117

118
QString DesktopQmakeRunConfiguration::disabledReason() const
dt_'s avatar
dt_ committed
119
{
120
    if (m_parseInProgress)
121
        return tr("The .pro file \"%1\" is currently being parsed.")
122 123
                .arg(QFileInfo(m_proFilePath).fileName());

dt_'s avatar
dt_ committed
124
    if (!m_parseSuccess)
125
        return static_cast<QmakeProject *>(target()->project())->disabledReasonForRunConfiguration(m_proFilePath);
dt_'s avatar
dt_ committed
126 127 128
    return QString();
}

129
void DesktopQmakeRunConfiguration::proFileUpdated(QmakeProFileNode *pro, bool success, bool parseInProgress)
130
{
131
    LocalEnvironmentAspect *aspect = extraAspect<LocalEnvironmentAspect>();
132 133
    QTC_ASSERT(aspect, return);

134 135 136 137
    if (m_proFilePath != pro->path()) {
        if (!parseInProgress) {
            // We depend on all .pro files for the LD_LIBRARY_PATH so we emit a signal for all .pro files
            // This can be optimized by checking whether LD_LIBRARY_PATH changed
138
            aspect->buildEnvironmentHasChanged();
139
        }
140
        return;
141
    }
142

143
    bool enabled = isEnabled();
144
    QString reason = disabledReason();
145
    m_parseSuccess = success;
146
    m_parseInProgress = parseInProgress;
147
    if (enabled != isEnabled() || reason != disabledReason())
148
        emit enabledChanged();
149

150 151
    if (!parseInProgress) {
        emit effectiveTargetInformationChanged();
152
        aspect->buildEnvironmentHasChanged();
153
    }
154 155
}

156
void DesktopQmakeRunConfiguration::ctor()
157
{
158
    setDefaultDisplayName(defaultDisplayName());
159

Tobias Hunger's avatar
Tobias Hunger committed
160
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
161
    m_forcedGuiMode = (version && version->type() == QLatin1String(QtSupport::Constants::SIMULATORQT));
Tobias Hunger's avatar
Tobias Hunger committed
162

163 164 165 166 167
    QmakeProject *project = static_cast<QmakeProject *>(target()->project());
    connect(project, &QmakeProject::proFileUpdated,
            this, &DesktopQmakeRunConfiguration::proFileUpdated);
    connect(target(), &Target::kitChanged,
            this, &DesktopQmakeRunConfiguration::kitChanged);
Tobias Hunger's avatar
Tobias Hunger committed
168 169
}

170
void DesktopQmakeRunConfiguration::kitChanged()
Tobias Hunger's avatar
Tobias Hunger committed
171
{
Tobias Hunger's avatar
Tobias Hunger committed
172
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
173
    m_forcedGuiMode = (version && version->type() == QLatin1String(QtSupport::Constants::SIMULATORQT));
Tobias Hunger's avatar
Tobias Hunger committed
174
    emit runModeChanged(runMode()); // Always emit
175 176
}

177
//////
178
/// DesktopQmakeRunConfigurationWidget
179 180
/////

181
DesktopQmakeRunConfigurationWidget::DesktopQmakeRunConfigurationWidget(DesktopQmakeRunConfiguration *qmakeRunConfiguration, QWidget *parent)
182
    : QWidget(parent),
183
    m_qmakeRunConfiguration(qmakeRunConfiguration),
184
    m_ignoreChange(false),
mae's avatar
mae committed
185 186
    m_usingDyldImageSuffix(0),
    m_isShown(false)
con's avatar
con committed
187
{
dt's avatar
dt committed
188 189 190
    QVBoxLayout *vboxTopLayout = new QVBoxLayout(this);
    vboxTopLayout->setMargin(0);

191 192 193
    QHBoxLayout *hl = new QHBoxLayout();
    hl->addStretch();
    m_disabledIcon = new QLabel(this);
194
    m_disabledIcon->setPixmap(QPixmap(QLatin1String(Core::Constants::ICON_WARNING)));
195 196 197 198 199 200 201
    hl->addWidget(m_disabledIcon);
    m_disabledReason = new QLabel(this);
    m_disabledReason->setVisible(false);
    hl->addWidget(m_disabledReason);
    hl->addStretch();
    vboxTopLayout->addLayout(hl);

202 203
    m_detailsContainer = new DetailsWidget(this);
    m_detailsContainer->setState(DetailsWidget::NoSummary);
dt's avatar
dt committed
204 205 206 207
    vboxTopLayout->addWidget(m_detailsContainer);
    QWidget *detailsWidget = new QWidget(m_detailsContainer);
    m_detailsContainer->setWidget(detailsWidget);
    QFormLayout *toplayout = new QFormLayout(detailsWidget);
con's avatar
con committed
208
    toplayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
con's avatar
con committed
209 210
    toplayout->setMargin(0);

211
    m_executableLineEdit = new QLineEdit(m_qmakeRunConfiguration->executable(), this);
212 213
    m_executableLineEdit->setEnabled(false);
    toplayout->addRow(tr("Executable:"), m_executableLineEdit);
con's avatar
con committed
214

Tobias Hunger's avatar
Tobias Hunger committed
215
    QLabel *argumentsLabel = new QLabel(tr("Arguments:"), this);
216
    m_argumentsLineEdit = new QLineEdit(qmakeRunConfiguration->rawCommandLineArguments(), this);
217 218 219
    argumentsLabel->setBuddy(m_argumentsLineEdit);
    toplayout->addRow(argumentsLabel, m_argumentsLineEdit);

220 221
    m_workingDirectoryEdit = new PathChooser(this);
    m_workingDirectoryEdit->setExpectedKind(PathChooser::Directory);
222
    m_workingDirectoryEdit->setHistoryCompleter(QLatin1String("Qmake.WorkingDir.History"));
223
    m_workingDirectoryEdit->setPath(m_qmakeRunConfiguration->baseWorkingDirectory());
224
    m_workingDirectoryEdit->setBaseFileName(m_qmakeRunConfiguration->target()->project()->projectDirectory());
225
    EnvironmentAspect *aspect = qmakeRunConfiguration->extraAspect<EnvironmentAspect>();
226
    if (aspect) {
Tobias Hunger's avatar
Tobias Hunger committed
227
        connect(aspect, SIGNAL(environmentChanged()), this, SLOT(environmentWasChanged()));
228 229
        environmentWasChanged();
    }
230
    m_workingDirectoryEdit->setPromptDialogTitle(tr("Select Working Directory"));
231

Tobias Hunger's avatar
Tobias Hunger committed
232
    QToolButton *resetButton = new QToolButton(this);
233
    resetButton->setToolTip(tr("Reset to default"));
234
    resetButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_RESET)));
235 236

    QHBoxLayout *boxlayout = new QHBoxLayout();
237
    boxlayout->setMargin(0);
238 239
    boxlayout->addWidget(m_workingDirectoryEdit);
    boxlayout->addWidget(resetButton);
240
    toplayout->addRow(tr("Working directory:"), boxlayout);
con's avatar
con committed
241

hjk's avatar
hjk committed
242
    QHBoxLayout *innerBox = new QHBoxLayout();
243
    m_useTerminalCheck = new QCheckBox(tr("Run in terminal"), this);
244
    m_useTerminalCheck->setChecked(m_qmakeRunConfiguration->runMode() == ApplicationLauncher::Console);
245
    m_useTerminalCheck->setVisible(!m_qmakeRunConfiguration->forcedGuiMode());
hjk's avatar
hjk committed
246 247 248 249
    innerBox->addWidget(m_useTerminalCheck);

    m_useQvfbCheck = new QCheckBox(tr("Run on QVFb"), this);
    m_useQvfbCheck->setToolTip(tr("Check this option to run the application on a Qt Virtual Framebuffer."));
250
    m_useQvfbCheck->setChecked(m_qmakeRunConfiguration->runMode() == ApplicationLauncher::Console);
hjk's avatar
hjk committed
251 252 253 254
    m_useQvfbCheck->setVisible(false);
    innerBox->addWidget(m_useQvfbCheck);
    innerBox->addStretch();
    toplayout->addRow(QString(), innerBox);
255

256
    if (HostOsInfo::isMacHost()) {
257
        m_usingDyldImageSuffix = new QCheckBox(tr("Use debug version of frameworks (DYLD_IMAGE_SUFFIX=_debug)"), this);
258
        m_usingDyldImageSuffix->setChecked(m_qmakeRunConfiguration->isUsingDyldImageSuffix());
259 260 261 262
        toplayout->addRow(QString(), m_usingDyldImageSuffix);
        connect(m_usingDyldImageSuffix, SIGNAL(toggled(bool)),
                this, SLOT(usingDyldImageSuffixToggled(bool)));
    }
263

264
    runConfigurationEnabledChange();
265

con's avatar
con committed
266
    connect(m_workingDirectoryEdit, SIGNAL(changed(QString)),
267
            this, SLOT(workDirectoryEdited()));
268 269

    connect(resetButton, SIGNAL(clicked()),
270
            this, SLOT(workingDirectoryReseted()));
271

272
    connect(m_argumentsLineEdit, SIGNAL(textEdited(QString)),
273
            this, SLOT(argumentsEdited(QString)));
274 275
    connect(m_useTerminalCheck, SIGNAL(toggled(bool)),
            this, SLOT(termToggled(bool)));
hjk's avatar
hjk committed
276 277
    connect(m_useQvfbCheck, SIGNAL(toggled(bool)),
            this, SLOT(qvfbToggled(bool)));
278

279
    connect(qmakeRunConfiguration, SIGNAL(baseWorkingDirectoryChanged(QString)),
280 281
            this, SLOT(workingDirectoryChanged(QString)));

282
    connect(qmakeRunConfiguration, SIGNAL(commandLineArgumentsChanged(QString)),
283
            this, SLOT(commandLineArgumentsChanged(QString)));
284 285
    connect(qmakeRunConfiguration, SIGNAL(runModeChanged(ProjectExplorer::ApplicationLauncher::Mode)),
            this, SLOT(runModeChanged(ProjectExplorer::ApplicationLauncher::Mode)));
286
    connect(qmakeRunConfiguration, SIGNAL(usingDyldImageSuffixChanged(bool)),
287
            this, SLOT(usingDyldImageSuffixChanged(bool)));
288
    connect(qmakeRunConfiguration, SIGNAL(effectiveTargetInformationChanged()),
289
            this, SLOT(effectiveTargetInformationChanged()), Qt::QueuedConnection);
290

291
    connect(qmakeRunConfiguration, SIGNAL(enabledChanged()),
292
            this, SLOT(runConfigurationEnabledChange()));
293 294
}

295
DesktopQmakeRunConfigurationWidget::~DesktopQmakeRunConfigurationWidget()
Tobias Hunger's avatar
Tobias Hunger committed
296 297 298
{
}

299
void DesktopQmakeRunConfigurationWidget::environmentWasChanged()
300
{
301
    EnvironmentAspect *aspect = m_qmakeRunConfiguration->extraAspect<EnvironmentAspect>();
302 303 304 305
    QTC_ASSERT(aspect, return);
    m_workingDirectoryEdit->setEnvironment(aspect->environment());
}

306
void DesktopQmakeRunConfigurationWidget::runConfigurationEnabledChange()
307
{
308
    bool enabled = m_qmakeRunConfiguration->isEnabled();
309 310
    m_disabledIcon->setVisible(!enabled);
    m_disabledReason->setVisible(!enabled);
311
    m_disabledReason->setText(m_qmakeRunConfiguration->disabledReason());
312 313
}

314
void DesktopQmakeRunConfigurationWidget::workDirectoryEdited()
315 316 317 318
{
    if (m_ignoreChange)
        return;
    m_ignoreChange = true;
319
    m_qmakeRunConfiguration->setBaseWorkingDirectory(m_workingDirectoryEdit->rawPath());
320 321 322
    m_ignoreChange = false;
}

323
void DesktopQmakeRunConfigurationWidget::workingDirectoryReseted()
324 325 326
{
    // This emits a signal connected to workingDirectoryChanged()
    // that sets the m_workingDirectoryEdit
327
    m_qmakeRunConfiguration->setBaseWorkingDirectory(QString());
328 329
}

330
void DesktopQmakeRunConfigurationWidget::argumentsEdited(const QString &args)
331 332
{
    m_ignoreChange = true;
333
    m_qmakeRunConfiguration->setCommandLineArguments(args);
334 335 336
    m_ignoreChange = false;
}

337
void DesktopQmakeRunConfigurationWidget::termToggled(bool on)
338 339
{
    m_ignoreChange = true;
340 341
    m_qmakeRunConfiguration->setRunMode(on ? ApplicationLauncher::Console
                                           : ApplicationLauncher::Gui);
342 343 344
    m_ignoreChange = false;
}

345
void DesktopQmakeRunConfigurationWidget::qvfbToggled(bool on)
hjk's avatar
hjk committed
346
{
347
    Q_UNUSED(on);
hjk's avatar
hjk committed
348 349 350 351
    m_ignoreChange = true;
    m_ignoreChange = false;
}

352
void DesktopQmakeRunConfigurationWidget::usingDyldImageSuffixToggled(bool state)
353 354
{
    m_ignoreChange = true;
355
    m_qmakeRunConfiguration->setUsingDyldImageSuffix(state);
356 357 358
    m_ignoreChange = false;
}

359
void DesktopQmakeRunConfigurationWidget::workingDirectoryChanged(const QString &workingDirectory)
360 361 362 363 364
{
    if (!m_ignoreChange)
        m_workingDirectoryEdit->setPath(workingDirectory);
}

365
void DesktopQmakeRunConfigurationWidget::commandLineArgumentsChanged(const QString &args)
366
{
dt's avatar
dt committed
367 368 369
    if (m_ignoreChange)
        return;
    m_argumentsLineEdit->setText(args);
370 371
}

372
void DesktopQmakeRunConfigurationWidget::runModeChanged(ApplicationLauncher::Mode runMode)
373
{
Tobias Hunger's avatar
Tobias Hunger committed
374
    if (!m_ignoreChange) {
375
        m_useTerminalCheck->setVisible(!m_qmakeRunConfiguration->forcedGuiMode());
376
        m_useTerminalCheck->setChecked(runMode == ApplicationLauncher::Console);
Tobias Hunger's avatar
Tobias Hunger committed
377
    }
378 379
}

380
void DesktopQmakeRunConfigurationWidget::usingDyldImageSuffixChanged(bool state)
381 382 383 384 385
{
    if (!m_ignoreChange && m_usingDyldImageSuffix)
        m_usingDyldImageSuffix->setChecked(state);
}

386
void DesktopQmakeRunConfigurationWidget::effectiveTargetInformationChanged()
387
{
388
    if (m_isShown) {
389
        m_executableLineEdit->setText(QDir::toNativeSeparators(m_qmakeRunConfiguration->executable()));
390
        m_ignoreChange = true;
391
        m_workingDirectoryEdit->setPath(QDir::toNativeSeparators(m_qmakeRunConfiguration->baseWorkingDirectory()));
392
        m_ignoreChange = false;
393
    }
394 395
}

396
void DesktopQmakeRunConfigurationWidget::showEvent(QShowEvent *event)
397
{
398 399 400
    m_isShown = true;
    effectiveTargetInformationChanged();
    QWidget::showEvent(event);
401 402
}

403
void DesktopQmakeRunConfigurationWidget::hideEvent(QHideEvent *event)
404 405 406 407
{
    m_isShown = false;
    QWidget::hideEvent(event);
}
408

409
QWidget *DesktopQmakeRunConfiguration::createConfigurationWidget()
410
{
411
    return new DesktopQmakeRunConfigurationWidget(this, 0);
con's avatar
con committed
412 413
}

414
QVariantMap DesktopQmakeRunConfiguration::toMap() const
con's avatar
con committed
415
{
416
    const QDir projectDir = QDir(target()->project()->projectDirectory().toString());
417 418 419
    QVariantMap map(LocalApplicationRunConfiguration::toMap());
    map.insert(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY), m_commandLineArguments);
    map.insert(QLatin1String(PRO_FILE_KEY), projectDir.relativeFilePath(m_proFilePath));
420
    map.insert(QLatin1String(USE_TERMINAL_KEY), m_runMode == ApplicationLauncher::Console);
421 422 423
    map.insert(QLatin1String(USE_DYLD_IMAGE_SUFFIX_KEY), m_isUsingDyldImageSuffix);
    map.insert(QLatin1String(USER_WORKING_DIRECTORY_KEY), m_userWorkingDirectory);
    return map;
con's avatar
con committed
424 425
}

426
bool DesktopQmakeRunConfiguration::fromMap(const QVariantMap &map)
427
{
428
    const QDir projectDir = QDir(target()->project()->projectDirectory().toString());
429
    m_commandLineArguments = map.value(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY)).toString();
430
    m_proFilePath = QDir::cleanPath(projectDir.filePath(map.value(QLatin1String(PRO_FILE_KEY)).toString()));
431 432
    m_runMode = map.value(QLatin1String(USE_TERMINAL_KEY), false).toBool()
            ? ApplicationLauncher::Console : ApplicationLauncher::Gui;
433 434 435 436
    m_isUsingDyldImageSuffix = map.value(QLatin1String(USE_DYLD_IMAGE_SUFFIX_KEY), false).toBool();

    m_userWorkingDirectory = map.value(QLatin1String(USER_WORKING_DIRECTORY_KEY)).toString();

437 438
    m_parseSuccess = static_cast<QmakeProject *>(target()->project())->validParse(m_proFilePath);
    m_parseInProgress = static_cast<QmakeProject *>(target()->project())->parseInProgress(m_proFilePath);
439

440
    return LocalApplicationRunConfiguration::fromMap(map);
con's avatar
con committed
441 442
}

443
QString DesktopQmakeRunConfiguration::executable() const
con's avatar
con committed
444
{
445 446
    QmakeProject *pro = static_cast<QmakeProject *>(target()->project());
    const QmakeProFileNode *node = pro->rootQmakeProjectNode()->findProFileFor(m_proFilePath);
447
    return extractWorkingDirAndExecutable(node).second;
con's avatar
con committed
448 449
}

450
ApplicationLauncher::Mode DesktopQmakeRunConfiguration::runMode() const
con's avatar
con committed
451
{
Tobias Hunger's avatar
Tobias Hunger committed
452
    if (m_forcedGuiMode)
453
        return ProjectExplorer::ApplicationLauncher::Gui;
con's avatar
con committed
454 455 456
    return m_runMode;
}

457
bool DesktopQmakeRunConfiguration::forcedGuiMode() const
Tobias Hunger's avatar
Tobias Hunger committed
458 459 460 461
{
    return m_forcedGuiMode;
}

462
bool DesktopQmakeRunConfiguration::isUsingDyldImageSuffix() const
463 464 465 466
{
    return m_isUsingDyldImageSuffix;
}

467
void DesktopQmakeRunConfiguration::setUsingDyldImageSuffix(bool state)
468 469 470 471 472
{
    m_isUsingDyldImageSuffix = state;
    emit usingDyldImageSuffixChanged(state);
}

473
QString DesktopQmakeRunConfiguration::workingDirectory() const
474
{
475
    EnvironmentAspect *aspect = extraAspect<EnvironmentAspect>();
476
    QTC_ASSERT(aspect, return baseWorkingDirectory());
477
    return QDir::cleanPath(aspect->environment().expandVariables(
478
                Utils::expandMacros(baseWorkingDirectory(), macroExpander())));
479 480
}

481
QString DesktopQmakeRunConfiguration::baseWorkingDirectory() const
con's avatar
con committed
482
{
483
    // if the user overrode us, then return his working directory
484
    if (!m_userWorkingDirectory.isEmpty())
485 486 487
        return m_userWorkingDirectory;

    // else what the pro file reader tells us
488 489
    QmakeProject *pro = static_cast<QmakeProject *>(target()->project());
    const QmakeProFileNode *node = pro->rootQmakeProjectNode()->findProFileFor(m_proFilePath);
490
    return extractWorkingDirAndExecutable(node).first;
con's avatar
con committed
491 492
}

493
QString DesktopQmakeRunConfiguration::commandLineArguments() const
494
{
495
    return QtcProcess::expandMacros(m_commandLineArguments, macroExpander());
496 497
}

498
QString DesktopQmakeRunConfiguration::rawCommandLineArguments() const
con's avatar
con committed
499 500 501 502
{
    return m_commandLineArguments;
}

503
void DesktopQmakeRunConfiguration::setBaseWorkingDirectory(const QString &wd)
504
{
505 506 507 508 509 510 511
    const QString &oldWorkingDirectory = workingDirectory();

    m_userWorkingDirectory = wd;

    const QString &newWorkingDirectory = workingDirectory();
    if (oldWorkingDirectory != newWorkingDirectory)
        emit baseWorkingDirectoryChanged(newWorkingDirectory);
512 513
}

514
void DesktopQmakeRunConfiguration::setCommandLineArguments(const QString &argumentsString)
con's avatar
con committed
515
{
516 517
    m_commandLineArguments = argumentsString;
    emit commandLineArgumentsChanged(argumentsString);
con's avatar
con committed
518 519
}

520
void DesktopQmakeRunConfiguration::setRunMode(ApplicationLauncher::Mode runMode)
521 522 523 524 525
{
    m_runMode = runMode;
    emit runModeChanged(runMode);
}

526
void DesktopQmakeRunConfiguration::addToBaseEnvironment(Environment &env) const
527 528 529 530 531 532 533
{
    if (m_isUsingDyldImageSuffix)
        env.set(QLatin1String("DYLD_IMAGE_SUFFIX"), QLatin1String("_debug"));

    // The user could be linking to a library found via a -L/some/dir switch
    // to find those libraries while actually running we explicitly prepend those
    // dirs to the library search path
534
    const QmakeProFileNode *node = static_cast<QmakeProject *>(target()->project())->rootQmakeProjectNode()->findProFileFor(m_proFilePath);
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
    if (node) {
        const QStringList libDirectories = node->variableValue(LibDirectoriesVar);
        if (!libDirectories.isEmpty()) {
            const QString proDirectory = node->buildDir();
            foreach (QString dir, libDirectories) {
                // Fix up relative entries like "LIBS+=-L.."
                const QFileInfo fi(dir);
                if (!fi.isAbsolute())
                    dir = QDir::cleanPath(proDirectory + QLatin1Char('/') + dir);
                env.prependOrSetLibrarySearchPath(dir);
            } // foreach
        } // libDirectories
    } // node

    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(target()->kit());
    if (qtVersion)
        env.prependOrSetLibrarySearchPath(qtVersion->qmakeProperty("QT_INSTALL_LIBS"));
}

554
QString DesktopQmakeRunConfiguration::proFilePath() const
con's avatar
con committed
555 556 557 558
{
    return m_proFilePath;
}

559
QString DesktopQmakeRunConfiguration::defaultDisplayName()
560
{
561
    QString defaultName;
562
    if (!m_proFilePath.isEmpty())
563
        defaultName = QFileInfo(m_proFilePath).completeBaseName();
564
    else
Caroline Chao's avatar
Caroline Chao committed
565
        defaultName = tr("Qt Run Configuration");
566
    return defaultName;
567 568
}

569
OutputFormatter *DesktopQmakeRunConfiguration::createOutputFormatter() const
dt's avatar
dt committed
570
{
Tobias Hunger's avatar
Tobias Hunger committed
571
    return new QtSupport::QtOutputFormatter(target()->project());
dt's avatar
dt committed
572 573
}

574
QPair<QString, QString> DesktopQmakeRunConfiguration::extractWorkingDirAndExecutable(const QmakeProFileNode *node) const
575 576 577 578 579 580 581 582 583 584 585 586 587
{
    if (!node)
        return qMakePair(QString(), QString());
    TargetInformation ti = node->targetInformation();
    if (!ti.valid)
        return qMakePair(QString(), QString());

    const QStringList &config = node->variableValue(ConfigVar);

    QString destDir = ti.destDir;
    QString workingDir;
    if (!destDir.isEmpty()) {
        bool workingDirIsBaseDir = false;
Orgad Shaneh's avatar
Orgad Shaneh committed
588
        if (destDir == ti.buildTarget)
589 590 591 592 593 594 595 596 597 598 599 600 601
            workingDirIsBaseDir = true;
        if (QDir::isRelativePath(destDir))
            destDir = QDir::cleanPath(ti.buildDir + QLatin1Char('/') + destDir);

        if (workingDirIsBaseDir)
            workingDir = ti.buildDir;
        else
            workingDir = destDir;
    } else {
        destDir = ti.buildDir;
        workingDir = ti.buildDir;
    }

602
    if (HostOsInfo::isMacHost() && config.contains(QLatin1String("app_bundle"))) {
603 604 605 606 607 608 609
        const QString infix = QLatin1Char('/') + ti.target
                + QLatin1String(".app/Contents/MacOS");
        workingDir += infix;
        destDir += infix;
    }

    QString executable = QDir::cleanPath(destDir + QLatin1Char('/') + ti.target);
610 611
    executable = HostOsInfo::withExecutableSuffix(executable);
    //qDebug() << "##### QmakeRunConfiguration::extractWorkingDirAndExecutable:" workingDir << executable;
612 613 614
    return qMakePair(workingDir, executable);
}

con's avatar
con committed
615
///
616
/// DesktopQmakeRunConfigurationFactory
con's avatar
con committed
617 618 619
/// This class is used to restore run settings (saved in .user files)
///

620
DesktopQmakeRunConfigurationFactory::DesktopQmakeRunConfigurationFactory(QObject *parent) :
Tobias Hunger's avatar
Tobias Hunger committed
621
    QmakeRunConfigurationFactory(parent)
622
{ setObjectName(QLatin1String("DesktopQmakeRunConfigurationFactory")); }
con's avatar
con committed
623

624
DesktopQmakeRunConfigurationFactory::~DesktopQmakeRunConfigurationFactory()
Tobias Hunger's avatar
Tobias Hunger committed
625
{ }
con's avatar
con committed
626

627
bool DesktopQmakeRunConfigurationFactory::canCreate(Target *parent, Core::Id id) const
con's avatar
con committed
628
{
Tobias Hunger's avatar
Tobias Hunger committed
629
    if (!canHandle(parent))
Tobias Hunger's avatar
Tobias Hunger committed
630
        return false;
631
    QmakeProject *project = static_cast<QmakeProject *>(parent->project());
Tobias Hunger's avatar
Tobias Hunger committed
632
    return project->hasApplicationProFile(pathFromId(id));
con's avatar
con committed
633 634
}

635
RunConfiguration *DesktopQmakeRunConfigurationFactory::doCreate(Target *parent, Core::Id id)
con's avatar
con committed
636
{
637
    DesktopQmakeRunConfiguration *rc = new DesktopQmakeRunConfiguration(parent, id);
638
    const QmakeProFileNode *node = static_cast<QmakeProject *>(parent->project())->rootQmakeProjectNode()->findProFileFor(rc->proFilePath());
639
    if (node) // should always be found
Tobias Hunger's avatar
Tobias Hunger committed
640
        rc->setRunMode(node->variableValue(ConfigVar).contains(QLatin1String("console"))
641
                       && !node->variableValue(QtVar).contains(QLatin1String("testlib"))
642
                       ? ApplicationLauncher::Console : ApplicationLauncher::Gui);
Tobias Hunger's avatar
Tobias Hunger committed
643
    return rc;
644 645
}

646
bool DesktopQmakeRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
647
{
Tobias Hunger's avatar
Tobias Hunger committed
648
    if (!canHandle(parent))
649
        return false;
650
    return idFromMap(map).toString().startsWith(QLatin1String(QMAKE_RC_PREFIX));
651 652
}

653
RunConfiguration *DesktopQmakeRunConfigurationFactory::doRestore(Target *parent, const QVariantMap &map)
654
{
655
    return new DesktopQmakeRunConfiguration(parent, idFromMap(map));
656 657
}

658
bool DesktopQmakeRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const
659
{
Tobias Hunger's avatar
Tobias Hunger committed
660
    return canCreate(parent, source->id());
661 662
}

663
RunConfiguration *DesktopQmakeRunConfigurationFactory::clone(Target *parent, RunConfiguration *source)
664 665 666
{
    if (!canClone(parent, source))
        return 0;
667 668
    DesktopQmakeRunConfiguration *old = static_cast<DesktopQmakeRunConfiguration *>(source);
    return new DesktopQmakeRunConfiguration(parent, old);
con's avatar
con committed
669 670
}

671
QList<Core::Id> DesktopQmakeRunConfigurationFactory::availableCreationIds(Target *parent, CreationMode mode) const
con's avatar
con committed
672
{
Tobias Hunger's avatar
Tobias Hunger committed
673
    if (!canHandle(parent))
674
        return QList<Core::Id>();
Tobias Hunger's avatar
Tobias Hunger committed
675

676
    QmakeProject *project = static_cast<QmakeProject *>(parent->project());
677
    QList<QmakeProFileNode *> nodes = project->applicationProFiles();
678 679
    if (mode == AutoCreate)
        nodes = QmakeProject::nodesWithQtcRunnable(nodes);
680
    return QmakeProject::idsForNodes(Core::Id(QMAKE_RC_PREFIX), nodes);
con's avatar
con committed
681 682
}

683
QString DesktopQmakeRunConfigurationFactory::displayNameForId(Core::Id id) const
con's avatar
con committed
684
{
685
    return QFileInfo(pathFromId(id)).completeBaseName();
con's avatar
con committed
686
}
Tobias Hunger's avatar
Tobias Hunger committed
687

688
bool DesktopQmakeRunConfigurationFactory::canHandle(Target *t) const
Tobias Hunger's avatar
Tobias Hunger committed
689
{
Tobias Hunger's avatar
Tobias Hunger committed
690
    if (!t->project()->supportsKit(t->kit()))
Tobias Hunger's avatar
Tobias Hunger committed
691
        return false;
692
    if (!qobject_cast<QmakeProject *>(t->project()))
Tobias Hunger's avatar
Tobias Hunger committed
693
        return false;
694 695
    Core::Id devType = DeviceTypeKitInformation::deviceTypeId(t->kit());
    return devType == Constants::DESKTOP_DEVICE_TYPE;
Tobias Hunger's avatar
Tobias Hunger committed
696 697
}

698
QList<RunConfiguration *> DesktopQmakeRunConfigurationFactory::runConfigurationsForNode(Target *t, const Node *n)
Tobias Hunger's avatar
Tobias Hunger committed
699
{
700 701
    QList<RunConfiguration *> result;
    foreach (RunConfiguration *rc, t->runConfigurations())
702
        if (DesktopQmakeRunConfiguration *qt4c = qobject_cast<DesktopQmakeRunConfiguration *>(rc))
Tobias Hunger's avatar
Tobias Hunger committed
703 704 705 706
            if (qt4c->proFilePath() == n->path())
                result << rc;
    return result;
}
707 708 709

} // namespace Internal
} // namespace QmakeProjectManager