qtoptionspage.cpp 32.7 KB
Newer Older
Tobias Hunger's avatar
Tobias Hunger committed
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).
Tobias Hunger's avatar
Tobias Hunger committed
6
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
Tobias Hunger's avatar
Tobias Hunger committed
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.
Tobias Hunger's avatar
Tobias Hunger committed
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
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
Tobias Hunger's avatar
Tobias Hunger committed
30 31 32
**
**************************************************************************/

33 34 35
#include "qtoptionspage.h"
#include "ui_showbuildlog.h"
#include "ui_qtversionmanager.h"
36 37
#include "ui_qtversioninfo.h"
#include "ui_debugginghelper.h"
38
#include "qtsupportconstants.h"
39
#include "qtversionmanager.h"
dt's avatar
dt committed
40
#include "qtversionfactory.h"
41 42 43
#include "qmldumptool.h"
#include "qmldebugginglibrary.h"
#include "qmlobservertool.h"
44 45 46

#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
47
#include <utils/treewidgetcolumnstretcher.h>
48
#include <utils/qtcassert.h>
dt's avatar
dt committed
49
#include <utils/buildablehelperlibrary.h>
50
#include <qtconcurrent/runextensions.h>
51 52

#include <QtCore/QDir>
53
#include <QtGui/QToolTip>
54
#include <QtGui/QMessageBox>
dt's avatar
dt committed
55 56
#include <QtGui/QFileDialog>
#include <QtGui/QMainWindow>
57

58
enum ModelRoles { VersionIdRole = Qt::UserRole, BuildLogRole, BuildRunningRole};
59

60 61
using namespace QtSupport;
using namespace QtSupport::Internal;
62

63 64 65 66 67
///
// QtOptionsPage
///

QtOptionsPage::QtOptionsPage()
dt's avatar
dt committed
68
    : m_widget(0)
69 70 71 72 73
{
}

QString QtOptionsPage::id() const
{
74
    return QLatin1String(Constants::QTVERSION_SETTINGS_PAGE_ID);
75 76
}

77
QString QtOptionsPage::displayName() const
78
{
79
    return QCoreApplication::translate("Qt4ProjectManager", Constants::QTVERSION_SETTINGS_PAGE_NAME);
80 81 82 83
}

QString QtOptionsPage::category() const
{
84
    return QLatin1String(Constants::QT_SETTINGS_CATEGORY);
85 86
}

87
QString QtOptionsPage::displayCategory() const
88
{
89
    return QCoreApplication::translate("Qt4ProjectManager", Constants::QT_SETTINGS_TR_CATEGORY);
90 91
}

92 93 94 95 96
QIcon QtOptionsPage::categoryIcon() const
{
    return QIcon(QLatin1String(Constants::QT_SETTINGS_CATEGORY_ICON));
}

97 98 99
QWidget *QtOptionsPage::createPage(QWidget *parent)
{
    QtVersionManager *vm = QtVersionManager::instance();
Tobias Hunger's avatar
Tobias Hunger committed
100
    m_widget = new QtOptionsPageWidget(parent, vm->versions());
101 102
    if (m_searchKeywords.isEmpty())
        m_searchKeywords = m_widget->searchKeywords();
103 104 105 106 107
    return m_widget;
}

void QtOptionsPage::apply()
{
108 109
    if (!m_widget) // page was never shown
        return;
110 111 112
    m_widget->finish();

    QtVersionManager *vm = QtVersionManager::instance();
113
    vm->setNewQtVersions(m_widget->versions());
114 115
}

116 117 118 119 120
bool QtOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

121
//-----------------------------------------------------
122 123


dt's avatar
dt committed
124
QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent, QList<BaseQtVersion *> versions)
125 126
    : QWidget(parent)
    , m_specifyNameString(tr("<specify a name>"))
127
    , m_ui(new Internal::Ui::QtVersionManager())
128 129
    , m_versionUi(new Internal::Ui::QtVersionInfo())
    , m_debuggingHelperUi(new Internal::Ui::DebuggingHelper())
130
    , m_invalidVersionIcon(":/projectexplorer/images/compile_error.png")
dt's avatar
dt committed
131
    , m_configurationWidget(0)
132 133
{
    // Initialize m_versions
dt's avatar
dt committed
134
    foreach (BaseQtVersion *version, versions)
dt's avatar
dt committed
135
        m_versions.push_back(version->clone());
136

137 138
    QWidget *versionInfoWidget = new QWidget();
    m_versionUi->setupUi(versionInfoWidget);
139

140 141 142
    QWidget *debuggingHelperDetailsWidget = new QWidget();
    m_debuggingHelperUi->setupUi(debuggingHelperDetailsWidget);

143
    m_ui->setupUi(this);
144 145 146 147 148

    m_ui->versionInfoWidget->setWidget(versionInfoWidget);
    m_ui->versionInfoWidget->setState(Utils::DetailsWidget::NoSummary);

    m_ui->debuggingHelperWidget->setWidget(debuggingHelperDetailsWidget);
149

150 151
    // setup parent items for auto-detected and manual versions
    m_ui->qtdirList->header()->setResizeMode(QHeaderView::ResizeToContents);
dt_'s avatar
dt_ committed
152 153
    m_ui->qtdirList->header()->setStretchLastSection(false);
    m_ui->qtdirList->setTextElideMode(Qt::ElideNone);
154
    QTreeWidgetItem *autoItem = new QTreeWidgetItem(m_ui->qtdirList);
155
    m_ui->qtdirList->installEventFilter(this);
156 157
    autoItem->setText(0, tr("Auto-detected"));
    autoItem->setFirstColumnSpanned(true);
158
    autoItem->setFlags(Qt::ItemIsEnabled);
159 160 161
    QTreeWidgetItem *manualItem = new QTreeWidgetItem(m_ui->qtdirList);
    manualItem->setText(0, tr("Manual"));
    manualItem->setFirstColumnSpanned(true);
162
    manualItem->setFlags(Qt::ItemIsEnabled);
163

164
    for (int i = 0; i < m_versions.count(); ++i) {
dt's avatar
dt committed
165
        BaseQtVersion *version = m_versions.at(i);
166
        QTreeWidgetItem *item = new QTreeWidgetItem(version->isAutodetected()? autoItem : manualItem);
167
        item->setText(0, version->displayName());
168
        item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
169
        item->setData(0, VersionIdRole, version->uniqueId());
dt's avatar
dt committed
170
        item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
171
    }
172
    m_ui->qtdirList->expandAll();
173

174
    connect(m_versionUi->nameEdit, SIGNAL(textEdited(const QString &)),
175 176
            this, SLOT(updateCurrentQtName()));

dt_'s avatar
dt_ committed
177 178 179
    connect(m_versionUi->editPathPushButton, SIGNAL(clicked()),
            this, SLOT(editPath()));

180 181 182 183 184 185 186 187
    connect(m_ui->addButton, SIGNAL(clicked()),
            this, SLOT(addQtDir()));
    connect(m_ui->delButton, SIGNAL(clicked()),
            this, SLOT(removeQtDir()));

    connect(m_ui->qtdirList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
            this, SLOT(versionChanged(QTreeWidgetItem *, QTreeWidgetItem *)));

188
    connect(m_debuggingHelperUi->rebuildButton, SIGNAL(clicked()),
189
            this, SLOT(buildDebuggingHelper()));
190 191 192 193
    connect(m_debuggingHelperUi->gdbHelperBuildButton, SIGNAL(clicked()),
            this, SLOT(buildGdbHelper()));
    connect(m_debuggingHelperUi->qmlDumpBuildButton, SIGNAL(clicked()),
            this, SLOT(buildQmlDump()));
194 195
    connect(m_debuggingHelperUi->qmlDebuggingLibBuildButton, SIGNAL(clicked()),
            this, SLOT(buildQmlDebuggingLibrary()));
196 197 198 199
    connect(m_debuggingHelperUi->qmlObserverBuildButton, SIGNAL(clicked()),
            this, SLOT(buildQmlObserver()));

    connect(m_debuggingHelperUi->showLogButton, SIGNAL(clicked()),
200
            this, SLOT(slotShowDebuggingBuildLog()));
201

202
    connect(m_ui->cleanUpButton, SIGNAL(clicked()), this, SLOT(cleanUpQtVersions()));
dt's avatar
dt committed
203 204
    userChangedCurrentVersion();
    updateCleanUpButton();
205

206 207
    connect(QtVersionManager::instance(), SIGNAL(dumpUpdatedFor(QString)),
            this, SLOT(qtVersionsDumpUpdated(QString)));
208 209
}

210 211 212 213 214
bool QtOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
{
    // Set the items tooltip, which may cause costly initialization
    // of QtVersion and must be up-to-date
    if (o != m_ui->qtdirList || e->type() != QEvent::ToolTip)
215
        return false;
216 217 218 219 220 221 222 223
    QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
    const QPoint treePos = helpEvent->pos() - QPoint(0, m_ui->qtdirList->header()->height());
    QTreeWidgetItem *item = m_ui->qtdirList->itemAt(treePos);
    if (!item)
        return false;
    const int index = indexForTreeItem(item);
    if (index == -1)
        return false;
224
    const QString tooltip = m_versions.at(index)->toHtml(true);
225 226 227 228 229
    QToolTip::showText(helpEvent->globalPos(), tooltip, m_ui->qtdirList);
    helpEvent->accept();
    return true;
}

230
int QtOptionsPageWidget::currentIndex() const
231
{
232 233 234 235
    if (QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
        return indexForTreeItem(currentItem);
    return -1;
}
236

dt's avatar
dt committed
237
BaseQtVersion *QtOptionsPageWidget::currentVersion() const
238 239 240
{
    const int currentItemIndex = currentIndex();
    if (currentItemIndex >= 0 && currentItemIndex < m_versions.size())
241
        return m_versions.at(currentItemIndex);
242 243
    return 0;
}
244

dt's avatar
dt committed
245
static inline int findVersionById(const QList<BaseQtVersion *> &l, int id)
246 247 248
{
    const int size = l.size();
    for (int i = 0; i < size; i++)
249
        if (l.at(i)->uniqueId() == id)
250 251 252
            return i;
    return -1;
}
253

254
// Update with results of terminated helper build
255
void QtOptionsPageWidget::debuggingHelperBuildFinished(int qtVersionId, const QString &output, DebuggingHelperBuildTask::Tools tools)
256
{
257
    const int index = findVersionById(m_versions, qtVersionId);
258 259
    if (index == -1)
        return; // Oops, somebody managed to delete the version
260

dt's avatar
dt committed
261
    BaseQtVersion *version = m_versions.at(index);
262

263 264
    // Update item view
    QTreeWidgetItem *item = treeItemForIndex(index);
265 266 267 268 269
    QTC_ASSERT(item, return);
    DebuggingHelperBuildTask::Tools buildFlags
            = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
    buildFlags &= ~tools;
    item->setData(0, BuildRunningRole,  QVariant::fromValue(buildFlags));
270
    item->setData(0, BuildLogRole, output);
271

272 273
    bool success = true;
    if (tools & DebuggingHelperBuildTask::GdbDebugging)
dt's avatar
dt committed
274
        success &= version->hasGdbDebuggingHelper();
275
    if (tools & DebuggingHelperBuildTask::QmlDebugging)
dt's avatar
dt committed
276
        success &= version->hasQmlDebuggingLibrary();
277
    if (tools & DebuggingHelperBuildTask::QmlDump)
dt's avatar
dt committed
278
        success &= version->hasQmlDump();
279
    if (tools & DebuggingHelperBuildTask::QmlObserver)
dt's avatar
dt committed
280
        success &= version->hasQmlObserver();
281 282 283

    // Update bottom control if the selection is still the same
    if (index == currentIndex()) {
284
        updateDebuggingHelperUi();
285
    }
286

287 288
    if (!success)
        showDebuggingBuildLog(item);
289 290
}

291 292 293
void QtOptionsPageWidget::cleanUpQtVersions()
{
    QStringList toRemove;
dt's avatar
dt committed
294
    foreach (const BaseQtVersion *v, m_versions) {
295
        if (!v->isValid() && !v->isAutodetected())
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
            toRemove.append(v->displayName());
    }

    if (toRemove.isEmpty())
        return;

    if (QMessageBox::warning(0, tr("Remove invalid Qt Versions"),
                             tr("Do you want to remove all invalid Qt Versions?<br>"
                                "<ul><li>%1</li></ul><br>"
                                "will be removed.").arg(toRemove.join(QLatin1String("</li><li>"))),
                             QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
        return;

    for (int i = m_versions.count() - 1; i >= 0; --i) {
        if (!m_versions.at(i)->isValid()) {
            QTreeWidgetItem *item = treeItemForIndex(i);
            delete item;

            delete m_versions.at(i);
            m_versions.removeAt(i);
        }
    }
dt's avatar
dt committed
318
    updateCleanUpButton();
319 320
}

321
void QtOptionsPageWidget::qtVersionsDumpUpdated(const QString &qmakeCommand)
322 323 324 325 326
{
    foreach (BaseQtVersion *version, m_versions) {
        if (version->qmakeCommand() == qmakeCommand)
            version->recheckDumper();
    }
327 328
    if (currentVersion()
            && currentVersion()->qmakeCommand() == qmakeCommand) {
329 330 331 332 333 334
        updateWidgets();
        updateDescriptionLabel();
        updateDebuggingHelperUi();
    }
}

335
void QtOptionsPageWidget::buildDebuggingHelper(DebuggingHelperBuildTask::Tools tools)
336 337 338 339 340
{
    const int index = currentIndex();
    if (index < 0)
        return;

341 342
    QTreeWidgetItem *item = treeItemForIndex(index);
    QTC_ASSERT(item, return);
343

344 345 346 347
    DebuggingHelperBuildTask::Tools buildFlags
            = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
    buildFlags |= tools;
    item->setData(0, BuildRunningRole, QVariant::fromValue(buildFlags));
348

dt's avatar
dt committed
349
    BaseQtVersion *version = m_versions.at(index);
350 351 352
    if (!version)
        return;

353
    updateDebuggingHelperUi();
354

355
    // Run a debugging helper build task in the background.
356
    DebuggingHelperBuildTask *buildTask = new DebuggingHelperBuildTask(version, tools);
357 358
    // Don't open General Messages pane with errors
    buildTask->showOutputOnError(false);
359 360
    connect(buildTask, SIGNAL(finished(int,QString,DebuggingHelperBuildTask::Tools)),
            this, SLOT(debuggingHelperBuildFinished(int,QString,DebuggingHelperBuildTask::Tools)),
361
            Qt::QueuedConnection);
362
    QFuture<void> task = QtConcurrent::run(&DebuggingHelperBuildTask::run, buildTask);
363
    const QString taskName = tr("Building helpers");
364

365
    Core::ICore::instance()->progressManager()->addTask(task, taskName,
366
                                                        QLatin1String("Qt4ProjectManager::BuildHelpers"));
367
}
368 369 370 371 372 373 374 375 376 377
void QtOptionsPageWidget::buildGdbHelper()
{
    buildDebuggingHelper(DebuggingHelperBuildTask::GdbDebugging);
}

void QtOptionsPageWidget::buildQmlDump()
{
    buildDebuggingHelper(DebuggingHelperBuildTask::QmlDump);
}

378 379 380 381 382
void QtOptionsPageWidget::buildQmlDebuggingLibrary()
{
    buildDebuggingHelper(DebuggingHelperBuildTask::QmlDebugging);
}

383 384
void QtOptionsPageWidget::buildQmlObserver()
{
385
    DebuggingHelperBuildTask::Tools qmlDbgTools =
Kai Koehne's avatar
Kai Koehne committed
386 387
            DebuggingHelperBuildTask::QmlObserver;
    qmlDbgTools |= DebuggingHelperBuildTask::QmlDebugging;
388
    buildDebuggingHelper(qmlDbgTools);
389
}
390

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
// Non-modal dialog
class BuildLogDialog : public QDialog {
public:
    explicit BuildLogDialog(QWidget *parent = 0);
    void setText(const QString &text);

private:
    Ui_ShowBuildLog m_ui;
};

BuildLogDialog::BuildLogDialog(QWidget *parent) : QDialog(parent)
{
    m_ui.setupUi(this);
    setAttribute(Qt::WA_DeleteOnClose, true);
}

void BuildLogDialog::setText(const QString &text)
408
{
409 410 411 412
    m_ui.log->setPlainText(text); // Show and scroll to bottom
    m_ui.log->moveCursor(QTextCursor::End);
    m_ui.log->ensureCursorVisible();
}
413

414 415 416 417 418 419 420 421 422
void QtOptionsPageWidget::slotShowDebuggingBuildLog()
{
    if (const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
        showDebuggingBuildLog(currentItem);
}

void QtOptionsPageWidget::showDebuggingBuildLog(const QTreeWidgetItem *currentItem)
{
    const int currentItemIndex = indexForTreeItem(currentItem);
423 424
    if (currentItemIndex < 0)
        return;
425 426
    BuildLogDialog *dialog = new BuildLogDialog(this);
    dialog->setWindowTitle(tr("Debugging Helper Build Log for '%1'").arg(currentItem->text(0)));
427
    dialog->setText(currentItem->data(0, BuildLogRole).toString());
428
    dialog->show();
429 430
}

431
QtOptionsPageWidget::~QtOptionsPageWidget()
432 433
{
    delete m_ui;
dt's avatar
dt committed
434 435
    delete m_versionUi;
    delete m_debuggingHelperUi;
dt's avatar
dt committed
436
    delete m_configurationWidget;
437
    qDeleteAll(m_versions);
438 439
}

dt_'s avatar
dt_ committed
440
static QString filterForQmakeFileDialog()
441
{
dt's avatar
dt committed
442 443 444 445 446
    QString filter("qmake (");
    foreach (const QString &s, Utils::BuildableHelperLibrary::possibleQMakeCommands()) {
        filter += s + " ";
    }
    filter += ")";
dt_'s avatar
dt_ committed
447 448
    return filter;
}
449

dt_'s avatar
dt_ committed
450 451
void QtOptionsPageWidget::addQtDir()
{
dt's avatar
dt committed
452
    QString qtVersion = QFileDialog::getOpenFileName(this,
dt_'s avatar
dt_ committed
453 454
                                                     tr("Select a qmake executable"),
                                                     QString(), filterForQmakeFileDialog());
dt's avatar
dt committed
455 456 457 458 459
    if (qtVersion.isNull())
        return;
    if (QtVersionManager::instance()->qtVersionForQMakeBinary(qtVersion)) {
        // Already exist
    }
460

dt's avatar
dt committed
461 462 463
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
    if (version) {
        m_versions.append(version);
464

dt's avatar
dt committed
465 466 467 468 469 470 471 472 473 474
        QTreeWidgetItem *item = new QTreeWidgetItem(m_ui->qtdirList->topLevelItem(1));
        item->setText(0, version->displayName());
        item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
        item->setData(0, VersionIdRole, version->uniqueId());
        item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
        m_ui->qtdirList->setCurrentItem(item); // should update the rest of the ui
        m_versionUi->nameEdit->setFocus();
        m_versionUi->nameEdit->selectAll();
    }
    updateCleanUpButton();
475 476
}

477
void QtOptionsPageWidget::removeQtDir()
478 479
{
    QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
480
    int index = indexForTreeItem(item);
481 482 483 484 485
    if (index < 0)
        return;

    delete item;

dt's avatar
dt committed
486
    BaseQtVersion *version = m_versions.at(index);
487
    m_versions.removeAt(index);
488
    delete version;
dt's avatar
dt committed
489
    updateCleanUpButton();
490 491
}

dt_'s avatar
dt_ committed
492 493
void QtOptionsPageWidget::editPath()
{
494 495
    BaseQtVersion *current = currentVersion();
    QString dir = QFileInfo(currentVersion()->qmakeCommand()).absolutePath();
dt_'s avatar
dt_ committed
496 497
    QString qtVersion = QFileDialog::getOpenFileName(this,
                                                     tr("Select a qmake executable"),
498
                                                     dir, filterForQmakeFileDialog());
dt_'s avatar
dt_ committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512
    if (qtVersion.isNull())
        return;
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
    // Same type? then replace!
    if (current->type() != version->type()) {
        // not the same type, error out
        QMessageBox::critical(this, tr("Qt versions incompatible"),
                              tr("The qt version selected must be for the same target."),
                              QMessageBox::Ok);
        delete version;
        return;
    }
    // same type, replace
    version->setId(current->uniqueId());
dt_'s avatar
dt_ committed
513 514
    if (current->displayName() != current->defaultDisplayName(current->qtVersionString(), current->qmakeCommand()))
        version->setDisplayName(current->displayName());
dt_'s avatar
dt_ committed
515 516 517 518 519 520 521 522 523 524 525 526
    m_versions.replace(m_versions.indexOf(current), version);
    delete current;

    // Update ui
    userChangedCurrentVersion();
    QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
    item->setText(0, version->displayName());
    item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
    item->setData(0, VersionIdRole, version->uniqueId());
    item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
}

527
void QtOptionsPageWidget::updateDebuggingHelperUi()
528
{
dt's avatar
dt committed
529
    BaseQtVersion *version = currentVersion();
530
    const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
531

532
    if (!version || !version->isValid()) {
533
        m_ui->debuggingHelperWidget->setVisible(false);
534
    } else {
535 536 537 538 539
        const DebuggingHelperBuildTask::Tools availableTools = DebuggingHelperBuildTask::availableTools(version);
        const bool canBuildGdbHelper = availableTools & DebuggingHelperBuildTask::GdbDebugging;
        const bool canBuildQmlDumper = availableTools & DebuggingHelperBuildTask::QmlDump;
        const bool canBuildQmlDebuggingLib = availableTools & DebuggingHelperBuildTask::QmlDebugging;
        const bool canBuildQmlObserver = availableTools & DebuggingHelperBuildTask::QmlObserver;
540

541 542 543
        const bool hasGdbHelper = !version->gdbDebuggingHelperLibrary().isEmpty();
        const bool hasQmlDumper = version->hasQmlDump();
        const bool hasQmlDebuggingLib = version->hasQmlDebuggingLibrary();
544
        const bool needsQmlDebuggingLib = version->needsQmlDebuggingLibrary();
545
        const bool hasQmlObserver = !version->qmlObserverTool().isEmpty();
546

547 548
        bool isBuildingGdbHelper = false;
        bool isBuildingQmlDumper = false;
549
        bool isBuildingQmlDebuggingLib = false;
550 551 552 553 554 555 556
        bool isBuildingQmlObserver = false;

        if (currentItem) {
            DebuggingHelperBuildTask::Tools buildingTools
                    = currentItem->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
            isBuildingGdbHelper = buildingTools & DebuggingHelperBuildTask::GdbDebugging;
            isBuildingQmlDumper = buildingTools & DebuggingHelperBuildTask::QmlDump;
557
            isBuildingQmlDebuggingLib = buildingTools & DebuggingHelperBuildTask::QmlDebugging;
558 559 560
            isBuildingQmlObserver = buildingTools & DebuggingHelperBuildTask::QmlObserver;
        }

561 562 563 564 565 566
        // get names of tools from labels
        QStringList helperNames;
        if (hasGdbHelper)
            helperNames << m_debuggingHelperUi->gdbHelperLabel->text().remove(':');
        if (hasQmlDumper)
            helperNames << m_debuggingHelperUi->qmlDumpLabel->text().remove(':');
567 568
        if (hasQmlDebuggingLib)
            helperNames << m_debuggingHelperUi->qmlDebuggingLibLabel->text().remove(':');
569 570 571 572 573
        if (hasQmlObserver)
            helperNames << m_debuggingHelperUi->qmlObserverLabel->text().remove(':');

        QString status;
        if (helperNames.isEmpty()) {
574
            status = tr("Helpers: None available");
575
        } else {
Friedemann Kleint's avatar
Friedemann Kleint committed
576
            //: %1 is list of tool names.
577
            status = tr("Helpers: %1.").arg(helperNames.join(QLatin1String(", ")));
578 579 580 581
        }

        m_ui->debuggingHelperWidget->setSummaryText(status);

582 583
        QString gdbHelperText;
        Qt::TextInteractionFlags gdbHelperTextFlags = Qt::NoTextInteraction;
584
        if (hasGdbHelper) {
585
            gdbHelperText = QDir::toNativeSeparators(version->gdbDebuggingHelperLibrary());
586
            gdbHelperTextFlags = Qt::TextSelectableByMouse;
587
        } else {
588 589 590 591 592
            if (canBuildGdbHelper) {
                gdbHelperText =  tr("<i>Not yet built.</i>");
            } else {
                gdbHelperText =  tr("<i>Not needed.</i>");
            }
593
        }
594 595
        m_debuggingHelperUi->gdbHelperStatus->setText(gdbHelperText);
        m_debuggingHelperUi->gdbHelperStatus->setTextInteractionFlags(gdbHelperTextFlags);
596
        m_debuggingHelperUi->gdbHelperBuildButton->setEnabled(canBuildGdbHelper && !isBuildingGdbHelper);
597

598
        QString qmlDumpStatusText, qmlDumpStatusToolTip;
599
        Qt::TextInteractionFlags qmlDumpStatusTextFlags = Qt::NoTextInteraction;
600
        if (hasQmlDumper) {
601 602
            qmlDumpStatusText = QDir::toNativeSeparators(version->qmlDumpTool(false));
            const QString debugQmlDumpPath = QDir::toNativeSeparators(version->qmlDumpTool(true));
603
            if (qmlDumpStatusText != debugQmlDumpPath) {
604 605
                if (!qmlDumpStatusText.isEmpty()
                        && !debugQmlDumpPath.isEmpty())
606 607 608
                    qmlDumpStatusText += QLatin1String("\n");
                qmlDumpStatusText += debugQmlDumpPath;
            }
609
            qmlDumpStatusTextFlags = Qt::TextSelectableByMouse;
610
        } else {
611 612 613 614
            if (canBuildQmlDumper) {
                qmlDumpStatusText = tr("<i>Not yet built.</i>");
            } else {
                qmlDumpStatusText = tr("<i>Cannot be compiled.</i>");
615
                QmlDumpTool::canBuild(version, &qmlDumpStatusToolTip);
616
            }
617
        }
618
        m_debuggingHelperUi->qmlDumpStatus->setText(qmlDumpStatusText);
619
        m_debuggingHelperUi->qmlDumpStatus->setTextInteractionFlags(qmlDumpStatusTextFlags);
620
        m_debuggingHelperUi->qmlDumpStatus->setToolTip(qmlDumpStatusToolTip);
621
        m_debuggingHelperUi->qmlDumpBuildButton->setEnabled(canBuildQmlDumper & !isBuildingQmlDumper);
622

623
        QString qmlDebuggingLibStatusText, qmlDebuggingLibToolTip;
624 625 626 627 628 629 630 631 632 633
        Qt::TextInteractionFlags qmlDebuggingLibStatusTextFlags = Qt::NoTextInteraction;
        if (hasQmlDebuggingLib) {
            qmlDebuggingLibStatusText = QDir::toNativeSeparators(
                        version->qmlDebuggingHelperLibrary(false));
            const QString debugPath = QDir::toNativeSeparators(
                        version->qmlDebuggingHelperLibrary(true));

            if (qmlDebuggingLibStatusText != debugPath) {
                if (!qmlDebuggingLibStatusText.isEmpty()
                        && !debugPath.isEmpty()) {
634
                    qmlDebuggingLibStatusText += QLatin1Char('\n');
635 636 637 638
                }
                qmlDebuggingLibStatusText += debugPath;
            }
            qmlDebuggingLibStatusTextFlags = Qt::TextSelectableByMouse;
639 640 641 642
        } else {
            if (!needsQmlDebuggingLib) {
                qmlDebuggingLibStatusText = tr("<i>Not needed.</i>");
            } else if (canBuildQmlDebuggingLib) {
643 644 645
                qmlDebuggingLibStatusText = tr("<i>Not yet built.</i>");
            } else {
                qmlDebuggingLibStatusText = tr("<i>Cannot be compiled.</i>");
646
                QmlDebuggingLibrary::canBuild(version, &qmlDebuggingLibToolTip);
647 648 649 650
            }
        }
        m_debuggingHelperUi->qmlDebuggingLibStatus->setText(qmlDebuggingLibStatusText);
        m_debuggingHelperUi->qmlDebuggingLibStatus->setTextInteractionFlags(qmlDebuggingLibStatusTextFlags);
651
        m_debuggingHelperUi->qmlDebuggingLibStatus->setToolTip(qmlDebuggingLibToolTip);
652 653
        m_debuggingHelperUi->qmlDebuggingLibBuildButton->setEnabled(needsQmlDebuggingLib
                                                                    && canBuildQmlDebuggingLib
654 655
                                                                    && !isBuildingQmlDebuggingLib);

656
        QString qmlObserverStatusText, qmlObserverToolTip;
657
        Qt::TextInteractionFlags qmlObserverStatusTextFlags = Qt::NoTextInteraction;
658
        if (hasQmlObserver) {
659
            qmlObserverStatusText = QDir::toNativeSeparators(version->qmlObserverTool());
660
            qmlObserverStatusTextFlags = Qt::TextSelectableByMouse;
661
        }  else {
662 663 664
            if (!needsQmlDebuggingLib) {
                qmlObserverStatusText = tr("<i>Not needed.</i>");
            } else if (canBuildQmlObserver) {
665 666 667
                qmlObserverStatusText = tr("<i>Not yet built.</i>");
            } else {
                qmlObserverStatusText = tr("<i>Cannot be compiled.</i>");
668
                QmlObserverTool::canBuild(version, &qmlObserverToolTip);
669
            }
670
        }
671
        m_debuggingHelperUi->qmlObserverStatus->setText(qmlObserverStatusText);
672
        m_debuggingHelperUi->qmlObserverStatus->setTextInteractionFlags(qmlObserverStatusTextFlags);
673
        m_debuggingHelperUi->qmlObserverStatus->setToolTip(qmlObserverToolTip);
674 675
        m_debuggingHelperUi->qmlObserverBuildButton->setEnabled(canBuildQmlObserver
                                                                & !isBuildingQmlObserver);
676 677 678 679

        const bool hasLog = currentItem && !currentItem->data(0, BuildLogRole).toString().isEmpty();
        m_debuggingHelperUi->showLogButton->setEnabled(hasLog);

680 681 682 683 684 685
        m_debuggingHelperUi->rebuildButton->setEnabled((!isBuildingGdbHelper
                                                        && !isBuildingQmlDumper
                                                        && !isBuildingQmlDebuggingLib
                                                        && !isBuildingQmlObserver)
                                                       && (canBuildGdbHelper
                                                           || canBuildQmlDumper
686
                                                           || (canBuildQmlDebuggingLib && needsQmlDebuggingLib)
687
                                                           || canBuildQmlObserver));
688

689
        m_ui->debuggingHelperWidget->setVisible(true);
690 691 692
    }
}

dt's avatar
dt committed
693 694
// To be called if a qt version was removed or added
void QtOptionsPageWidget::updateCleanUpButton()
695
{
696
    bool hasInvalidVersion = false;
697 698
    for (int i = 0; i < m_versions.count(); ++i) {
        if (!m_versions.at(i)->isValid()) {
699
            hasInvalidVersion = true;
dt's avatar
dt committed
700
            break;
701 702
        }
    }
703
    m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
704
}
705

dt's avatar
dt committed
706
void QtOptionsPageWidget::userChangedCurrentVersion()
con's avatar
con committed
707
{
dt's avatar
dt committed
708 709 710
    updateWidgets();
    updateDescriptionLabel();
    updateDebuggingHelperUi();
711 712
}

dt's avatar
dt committed
713
void QtOptionsPageWidget::qtVersionChanged()
714
{
715
    updateDescriptionLabel();
dt's avatar
dt committed
716
    updateDebuggingHelperUi();
717 718 719 720
}

void QtOptionsPageWidget::updateDescriptionLabel()
{
721 722 723 724 725
    QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
    const BaseQtVersion *version = currentVersion();
    if (!version) {
        m_versionUi->errorLabel->setText(QString());
    } else if (version->isValid()) {
dt's avatar
dt committed
726 727
        m_versionUi->errorLabel->setText( tr("Qt version %1 for %2").arg(version->qtVersionString(),
                                                                         version->description()));
728 729
        item->setIcon(0, m_validVersionIcon);
    } else {
730
        m_versionUi->errorLabel->setText(version->invalidReason());
731 732
        item->setIcon(0, m_invalidVersionIcon);
    }
733 734
}

735
int QtOptionsPageWidget::indexForTreeItem(const QTreeWidgetItem *item) const
736 737 738
{
    if (!item || !item->parent())
        return -1;
739
    const int uniqueId = item->data(0, VersionIdRole).toInt();
740 741 742 743 744 745 746
    for (int index = 0; index < m_versions.size(); ++index) {
        if (m_versions.at(index)->uniqueId() == uniqueId)
            return index;
    }
    return -1;
}

747 748
QTreeWidgetItem *QtOptionsPageWidget::treeItemForIndex(int index) const
{
749
    const int uniqueId = m_versions.at(index)->uniqueId();
750 751 752 753
    for (int i = 0; i < m_ui->qtdirList->topLevelItemCount(); ++i) {
        QTreeWidgetItem *toplevelItem = m_ui->qtdirList->topLevelItem(i);
        for (int j = 0; j < toplevelItem->childCount(); ++j) {
            QTreeWidgetItem *item = toplevelItem->child(j);
754
            if (item->data(0, VersionIdRole).toInt() == uniqueId) {
755 756 757 758 759 760 761
                return item;
            }
        }
    }
    return 0;
}

dt's avatar
dt committed
762
void QtOptionsPageWidget::versionChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *old)
763
{
dt's avatar
dt committed
764 765
    Q_UNUSED(newItem)
    if (old)
766
        fixQtVersionName(indexForTreeItem(old));
dt's avatar
dt committed
767 768 769 770 771 772 773 774 775 776 777 778 779 780
    userChangedCurrentVersion();
}

void QtOptionsPageWidget::updateWidgets()
{
    delete m_configurationWidget;
    m_configurationWidget = 0;
    BaseQtVersion *version = currentVersion();
    if (version) {
        m_versionUi->nameEdit->setText(version->displayName());
        m_versionUi->qmakePath->setText(QDir::toNativeSeparators(version->qmakeCommand()));
        m_configurationWidget = version->createConfigurationWidget();
        if (m_configurationWidget) {
            m_versionUi->formLayout->addRow(m_configurationWidget);
dt's avatar
dt committed
781
            m_configurationWidget->setEnabled(!version->isAutodetected());
dt's avatar
dt committed
782 783 784
            connect(m_configurationWidget, SIGNAL(changed()),
                    this, SLOT(qtVersionChanged()));
        }
785
    } else {
786
        m_versionUi->nameEdit->clear();
dt's avatar
dt committed
787
        m_versionUi->qmakePath->setText(QString()); // clear()
788 789
    }

dt's avatar
dt committed
790 791 792 793
    const bool enabled = version != 0;
    const bool isAutodetected = enabled && version->isAutodetected();
    m_ui->delButton->setEnabled(enabled && !isAutodetected);
    m_versionUi->nameEdit->setEnabled(enabled && !isAutodetected);
dt_'s avatar
dt_ committed
794
    m_versionUi->editPathPushButton->setEnabled(enabled && !isAutodetected);
795 796
}

797
void QtOptionsPageWidget::updateCurrentQtName()
798 799 800
{
    QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
    Q_ASSERT(currentItem);
801 802 803
    int currentItemIndex = indexForTreeItem(currentItem);
    if (currentItemIndex < 0)
        return;
804
    m_versions[currentItemIndex]->setDisplayName(m_versionUi->nameEdit->text());
805
    currentItem->setText(0, m_versions[currentItemIndex]->displayName());
806
    updateDescriptionLabel();
807 808 809
}


810
void QtOptionsPageWidget::finish()
811 812
{
    if (QTreeWidgetItem *item = m_ui->qtdirList->currentItem())
813
        fixQtVersionName(indexForTreeItem(item));
814 815 816 817 818 819
}

/* Checks that the qt version name is unique
 * and otherwise changes the name
 *
 */
820
void QtOptionsPageWidget::fixQtVersionName(int index)
821
{
822 823
    if (index < 0)
        return;
824
    int count = m_versions.count();
825
    QString name = m_versions.at(index)->displayName();
dt_'s avatar
dt_ committed
826 827
    if (name.isEmpty())
        return;
828 829
    for (int i = 0; i < count; ++i) {
        if (i != index) {
830
            if (m_versions.at(i)->displayName() == m_versions.at(index)->displayName()) {
831 832 833
                // Same name, find new name
                QRegExp regexp("^(.*)\\((\\d)\\)$");
                if (regexp.exactMatch(name)) {
Tobias Hunger's avatar
Tobias Hunger committed
834
                    // Already in Name (#) format
835 836 837 838
                    name = regexp.cap(1);
                    name += QLatin1Char('(');
                    name += QString::number(regexp.cap(2).toInt() + 1);
                    name += QLatin1Char(')');
839
                } else {
840
                    name +=  QLatin1String(" (2)");
841 842
                }
                // set new name
843
                m_versions[index]->setDisplayName(name);
844
                treeItemForIndex(index)->setText(0, name);
845 846 847 848 849 850 851 852

                // Now check again...
                fixQtVersionName(index);
            }
        }
    }
}

dt's avatar
dt committed
853
QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
854
{
dt's avatar
dt committed
855
    QList<BaseQtVersion *> result;
856
    for (int i = 0; i < m_versions.count(); ++i)
dt's avatar
dt committed
857
        result.append(m_versions.at(i)->clone());
858
    return result;
859 860
}

861 862