qtoptionspage.cpp 25.8 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Tobias Hunger's avatar
Tobias Hunger committed
2
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
Tobias Hunger's avatar
Tobias Hunger committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
Tobias Hunger's avatar
Tobias Hunger committed
7
**
hjk's avatar
hjk committed
8 9 10 11
** 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
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
Tobias Hunger's avatar
Tobias Hunger committed
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
con's avatar
con committed
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
Tobias Hunger's avatar
Tobias Hunger committed
25

26
#include "qtoptionspage.h"
27
#include "qtconfigwidget.h"
28 29
#include "ui_showbuildlog.h"
#include "ui_qtversionmanager.h"
30
#include "ui_qtversioninfo.h"
31
#include "qtsupportconstants.h"
32
#include "qtversionmanager.h"
dt's avatar
dt committed
33
#include "qtversionfactory.h"
34 35

#include <coreplugin/progressmanager/progressmanager.h>
36
#include <coreplugin/coreconstants.h>
37
#include <coreplugin/coreicons.h>
hjk's avatar
hjk committed
38
#include <coreplugin/variablechooser.h>
39
#include <projectexplorer/toolchain.h>
40
#include <projectexplorer/toolchainmanager.h>
41
#include <projectexplorer/projectexplorerconstants.h>
42
#include <utils/buildablehelperlibrary.h>
43
#include <utils/hostosinfo.h>
hjk's avatar
hjk committed
44 45
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
46
#include <utils/runextensions.h>
47
#include <utils/algorithm.h>
48
#include <utils/treemodel.h>
49

50 51 52
#include <QDir>
#include <QMessageBox>
#include <QFileDialog>
53 54
#include <QTextBrowser>
#include <QDesktopServices>
55 56 57
#include <QSortFilterProxyModel>

#include <utility>
58

hjk's avatar
hjk committed
59
using namespace ProjectExplorer;
60
using namespace Utils;
61

hjk's avatar
hjk committed
62 63 64
namespace QtSupport {
namespace Internal {

65 66 67
class QtVersionItem : public TreeItem
{
public:
hjk's avatar
hjk committed
68 69
    explicit QtVersionItem(BaseQtVersion *version)
        : m_version(version)
70 71 72 73
    {}

    ~QtVersionItem()
    {
Daniel Teske's avatar
Daniel Teske committed
74
        delete m_version;
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    }

    void setVersion(BaseQtVersion *version)
    {
        m_version = version;
        update();
    }

    int uniqueId() const
    {
        return m_version ? m_version->uniqueId() : -1;
    }

    BaseQtVersion *version() const
    {
        return m_version;
    }

    QVariant data(int column, int role) const
    {
        if (!m_version)
            return TreeItem::data(column, role);

        if (role == Qt::DisplayRole) {
            if (column == 0)
                return m_version->displayName();
            if (column == 1)
                return m_version->qmakeCommand().toUserOutput();
        }

        if (role == Qt::DecorationRole && column == 0)
            return m_icon;

        return QVariant();
    }

    void setIcon(const QIcon &icon)
    {
        m_icon = icon;
        update();
    }

    QString buildLog() const
    {
        return m_buildLog;
    }

    void setBuildLog(const QString &buildLog)
    {
        m_buildLog = buildLog;
    }

    QByteArray toolChainId() const
    {
        return m_toolChainId;
    }

    void setToolChainId(const QByteArray &id)
    {
        m_toolChainId = id;
    }

private:
Daniel Teske's avatar
Daniel Teske committed
138
    BaseQtVersion *m_version = 0;
139 140 141 142
    QIcon m_icon;
    QString m_buildLog;
    QByteArray m_toolChainId;
};
hjk's avatar
hjk committed
143

144 145 146 147 148
///
// QtOptionsPage
///

QtOptionsPage::QtOptionsPage()
dt's avatar
dt committed
149
    : m_widget(0)
150
{
hjk's avatar
hjk committed
151
    setId(Constants::QTVERSION_SETTINGS_PAGE_ID);
152
    setDisplayName(QCoreApplication::translate("QtSupport", Constants::QTVERSION_SETTINGS_PAGE_NAME));
hjk's avatar
hjk committed
153
    setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
154 155 156
    setDisplayCategory(QCoreApplication::translate("ProjectExplorer",
        ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY));
    setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON));
157 158
}

159
QWidget *QtOptionsPage::widget()
160
{
161 162
    if (!m_widget)
        m_widget = new QtOptionsPageWidget;
163 164 165 166 167
    return m_widget;
}

void QtOptionsPage::apply()
{
168 169
    if (!m_widget) // page was never shown
        return;
170
    m_widget->apply();
171 172
}

173
void QtOptionsPage::finish()
174
{
175
    delete m_widget;
176 177
}

178
//-----------------------------------------------------
179 180


181
QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent)
182 183
    : QWidget(parent)
    , m_specifyNameString(tr("<specify a name>"))
184
    , m_ui(new Internal::Ui::QtVersionManager())
185
    , m_versionUi(new Internal::Ui::QtVersionInfo())
186
    , m_infoBrowser(new QTextBrowser)
187 188
    , m_invalidVersionIcon(Core::Icons::ERROR.icon())
    , m_warningVersionIcon(Core::Icons::WARNING.icon())
dt's avatar
dt committed
189
    , m_configurationWidget(0)
190 191
    , m_autoItem(0)
    , m_manualItem(0)
192
{
193 194
    QWidget *versionInfoWidget = new QWidget();
    m_versionUi->setupUi(versionInfoWidget);
195
    m_versionUi->editPathPushButton->setText(PathChooser::browseButtonLabel());
196

197
    m_ui->setupUi(this);
198

199 200
    m_infoBrowser->setOpenLinks(false);
    m_infoBrowser->setTextInteractionFlags(Qt::TextBrowserInteraction);
201 202
    connect(m_infoBrowser, &QTextBrowser::anchorClicked,
            this, &QtOptionsPageWidget::infoAnchorClicked);
203
    m_ui->infoWidget->setWidget(m_infoBrowser);
204 205
    connect(m_ui->infoWidget, &DetailsWidget::expanded,
            this, &QtOptionsPageWidget::setInfoWidgetVisibility);
206

207
    m_ui->versionInfoWidget->setWidget(versionInfoWidget);
hjk's avatar
hjk committed
208
    m_ui->versionInfoWidget->setState(DetailsWidget::NoSummary);
209

hjk's avatar
hjk committed
210
    m_model = new TreeModel;
211 212
    m_model->setHeader({tr("Name"), tr("qmake Location"), tr("Type")});

hjk's avatar
hjk committed
213 214 215 216 217
    m_autoItem = new StaticTreeItem({ tr("Auto-detected") });
    m_model->rootItem()->appendChild(m_autoItem);
    m_manualItem = new StaticTreeItem({ tr("Manual") });
    m_model->rootItem()->appendChild(m_manualItem);

218 219 220 221 222 223 224 225 226 227
    m_filterModel = new QSortFilterProxyModel(this);
    m_filterModel->setSourceModel(m_model);
    m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);

    m_ui->qtdirList->setModel(m_filterModel);
    m_ui->qtdirList->setSortingEnabled(true);

    m_ui->qtdirList->setFirstColumnSpanned(0, QModelIndex(), true);
    m_ui->qtdirList->setFirstColumnSpanned(1, QModelIndex(), true);

dt_'s avatar
dt_ committed
228
    m_ui->qtdirList->header()->setStretchLastSection(false);
229 230
    m_ui->qtdirList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
    m_ui->qtdirList->header()->setSectionResizeMode(1, QHeaderView::Stretch);
dt_'s avatar
dt_ committed
231
    m_ui->qtdirList->setTextElideMode(Qt::ElideNone);
232
    m_ui->qtdirList->sortByColumn(0, Qt::AscendingOrder);
233

234
    QList<int> additions = transform(QtVersionManager::versions(), &BaseQtVersion::uniqueId);
235 236

    updateQtVersions(additions, QList<int>(), QList<int>());
237 238

    m_ui->qtdirList->expandAll();
239

240 241
    connect(m_versionUi->nameEdit, &QLineEdit::textEdited,
            this, &QtOptionsPageWidget::updateCurrentQtName);
242

243 244
    connect(m_versionUi->editPathPushButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::editPath);
dt_'s avatar
dt_ committed
245

246 247 248 249
    connect(m_ui->addButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::addQtDir);
    connect(m_ui->delButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::removeQtDir);
250

251
    connect(m_ui->qtdirList->selectionModel(), &QItemSelectionModel::currentChanged,
252
            this, &QtOptionsPageWidget::versionChanged);
253

254 255
    connect(m_ui->cleanUpButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::cleanUpQtVersions);
dt's avatar
dt committed
256 257
    userChangedCurrentVersion();
    updateCleanUpButton();
258

259 260
    connect(QtVersionManager::instance(), &QtVersionManager::dumpUpdatedFor,
            this, &QtOptionsPageWidget::qtVersionsDumpUpdated);
261

262 263
    connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
264

265 266
    connect(ProjectExplorer::ToolChainManager::instance(), &ToolChainManager::toolChainsChanged,
            this, &QtOptionsPageWidget::toolChainsUpdated);
hjk's avatar
hjk committed
267 268

    auto chooser = new Core::VariableChooser(this);
269
    chooser->addSupportedWidget(m_versionUi->nameEdit, "Qt:Name");
hjk's avatar
hjk committed
270 271 272 273 274
    chooser->addMacroExpanderProvider(
        [this]() -> Utils::MacroExpander * {
            BaseQtVersion *version = currentVersion();
            return version ? version->macroExpander() : 0;
        });
275 276
}

dt's avatar
dt committed
277
BaseQtVersion *QtOptionsPageWidget::currentVersion() const
278
{
279 280 281 282
    QtVersionItem *item = currentItem();
    if (!item)
        return 0;
    return item->version();
283
}
284

285
QtVersionItem *QtOptionsPageWidget::currentItem() const
286
{
287 288
    QModelIndex idx = m_ui->qtdirList->selectionModel()->currentIndex();
    QModelIndex sourceIdx = m_filterModel->mapToSource(idx);
hjk's avatar
hjk committed
289 290
    TreeItem *item = m_model->itemForIndex(sourceIdx);
    return item->level() == 2 ? static_cast<QtVersionItem *>(item) : 0;
291
}
292

293 294
void QtOptionsPageWidget::cleanUpQtVersions()
{
295 296 297 298 299 300 301 302 303 304 305
    QVector<QtVersionItem *> toRemove;
    QString text;

    foreach (Utils::TreeItem *child, m_manualItem->children()) {
        auto item = static_cast<QtVersionItem *>(child);
        if (item->version() && !item->version()->isValid()) {
            toRemove.append(item);
            if (!text.isEmpty())
                text.append(QLatin1String("</li><li>"));
            text.append(item->version()->displayName());
        }
306 307 308 309 310
    }

    if (toRemove.isEmpty())
        return;

311

Friedemann Kleint's avatar
Friedemann Kleint committed
312
    if (QMessageBox::warning(0, tr("Remove Invalid Qt Versions"),
313 314
                             tr("Do you want to remove all invalid Qt Versions?<br>"
                                "<ul><li>%1</li></ul><br>"
315
                                "will be removed.").arg(text),
316 317 318
                             QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
        return;

319 320 321
    foreach (QtVersionItem *item, toRemove) {
        m_model->takeItem(item);
        delete item;
322
    }
323

dt's avatar
dt committed
324
    updateCleanUpButton();
325 326
}

327 328
void QtOptionsPageWidget::toolChainsUpdated()
{
329 330 331 332 333 334 335
    auto update = [this](Utils::TreeItem *parent) {
        foreach (Utils::TreeItem *child, parent->children()) {
            if (child == currentItem()) {
                updateDescriptionLabel();
            } else {
                updateVersionItem(static_cast<QtVersionItem *>(child));
            }
336
        }
337 338 339 340
    };

    update(m_autoItem);
    update(m_manualItem);
341 342
}

hjk's avatar
hjk committed
343
void QtOptionsPageWidget::qtVersionsDumpUpdated(const FileName &qmakeCommand)
344
{
345 346 347 348 349 350 351 352 353 354 355
    auto recheck = [qmakeCommand](Utils::TreeItem *parent) {
        foreach (Utils::TreeItem *child, parent->children()) {
            auto item = static_cast<QtVersionItem *>(child);
            if (item->version()->qmakeCommand() == qmakeCommand)
                item->version()->recheckDumper();
        }
    };

    recheck(m_autoItem);
    recheck(m_manualItem);

356 357
    if (currentVersion()
            && currentVersion()->qmakeCommand() == qmakeCommand) {
358 359 360 361 362
        updateWidgets();
        updateDescriptionLabel();
    }
}

363
void QtOptionsPageWidget::setInfoWidgetVisibility()
364
{
365 366
    m_ui->versionInfoWidget->setVisible(m_ui->infoWidget->state() == DetailsWidget::Collapsed);
    m_ui->infoWidget->setVisible(true);
367 368
}

369 370 371 372 373
void QtOptionsPageWidget::infoAnchorClicked(const QUrl &url)
{
    QDesktopServices::openUrl(url);
}

374 375 376 377 378 379 380 381
QtOptionsPageWidget::ValidityInfo QtOptionsPageWidget::validInformation(const BaseQtVersion *version)
{
    ValidityInfo info;
    info.icon = m_validVersionIcon;

    if (!version)
        return info;

382
    info.description = tr("Qt version %1 for %2").arg(version->qtVersionString(), version->description());
383 384 385 386 387 388 389 390 391
    if (!version->isValid()) {
        info.icon = m_invalidVersionIcon;
        info.message = version->invalidReason();
        return info;
    }

    // Do we have tool chain issues?
    QStringList missingToolChains;
    int abiCount = 0;
hjk's avatar
hjk committed
392 393 394
    foreach (const Abi &abi, version->qtAbis()) {
        if (ToolChainManager::findToolChains(abi).isEmpty())
            missingToolChains.append(abi.toString());
395 396 397
        ++abiCount;
    }

398
    bool useable = true;
399
    QStringList warnings;
400 401 402
    if (!isNameUnique(version))
        warnings << tr("Display Name is not unique.");

403 404 405
    if (!missingToolChains.isEmpty()) {
        if (missingToolChains.count() == abiCount) {
            // Yes, this Qt version can't be used at all!
406
            info.message = tr("No compiler can produce code for this Qt version. Please define one or more compilers.");
407 408 409 410
            info.icon = m_invalidVersionIcon;
            useable = false;
        } else {
            // Yes, some ABIs are unsupported
411
            warnings << tr("Not all possible target environments can be supported due to missing compilers.");
412 413 414 415
            info.toolTip = tr("The following ABIs are currently not supported:<ul><li>%1</li></ul>")
                    .arg(missingToolChains.join(QLatin1String("</li><li>")));
            info.icon = m_warningVersionIcon;
        }
416
    }
417 418

    if (useable) {
419 420
        warnings += version->warningReason();
        if (!warnings.isEmpty()) {
hjk's avatar
hjk committed
421
            info.message = warnings.join(QLatin1Char('\n'));
422 423 424 425
            info.icon = m_warningVersionIcon;
        }
    }

426 427 428
    return info;
}

hjk's avatar
hjk committed
429
QList<ToolChain*> QtOptionsPageWidget::toolChains(const BaseQtVersion *version)
430
{
431
    QList<ToolChain*> toolChains;
432
    if (!version)
433 434
        return toolChains;

435
    QSet<QByteArray> ids;
436 437 438 439 440 441 442 443
    foreach (const Abi &a, version->qtAbis()) {
        foreach (ToolChain *tc, ToolChainManager::findToolChains(a)) {
            if (ids.contains(tc->id()))
                continue;
            ids.insert(tc->id());
            toolChains.append(tc);
        }
    }
444

445
    return toolChains;
446 447
}

448
QByteArray QtOptionsPageWidget::defaultToolChainId(const BaseQtVersion *version)
449
{
hjk's avatar
hjk committed
450
    QList<ToolChain*> possibleToolChains = toolChains(version);
451 452
    if (!possibleToolChains.isEmpty())
        return possibleToolChains.first()->id();
453
    return QByteArray();
454 455
}

456 457 458
bool QtOptionsPageWidget::isNameUnique(const BaseQtVersion *version)
{
    const QString name = version->displayName().trimmed();
459 460 461 462 463 464 465 466 467 468 469 470 471

    auto isUnique = [name, version](Utils::TreeItem *parent) {
        foreach (Utils::TreeItem *child, parent->children()) {
            auto item = static_cast<QtVersionItem *>(child);
            if (item->version() == version)
                continue;
            if (item->version()->displayName().trimmed() == name)
                return false;
        }
        return true;
    };

    return isUnique(m_manualItem) && isUnique(m_autoItem);
472 473
}

474
void QtOptionsPageWidget::updateVersionItem(QtVersionItem *item)
475
{
476 477 478 479 480 481 482 483
    if (!item)
        return;
    if (!item->version())
        return;

    const ValidityInfo info = validInformation(item->version());
    item->update();
    item->setIcon(info.icon);
484 485
}

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
// 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)
503
{
504 505 506 507
    m_ui.log->setPlainText(text); // Show and scroll to bottom
    m_ui.log->moveCursor(QTextCursor::End);
    m_ui.log->ensureCursorVisible();
}
508

509
void QtOptionsPageWidget::showDebuggingBuildLog(const QtVersionItem *item)
510
{
511 512
    BaseQtVersion *version = item->version();
    if (!version)
513
        return;
514
    BuildLogDialog *dialog = new BuildLogDialog(this->window());
515 516
    dialog->setWindowTitle(tr("Debugging Helper Build Log for \"%1\"").arg(version->displayName()));
    dialog->setText(item->buildLog());
517
    dialog->show();
518 519
}

520 521 522
void QtOptionsPageWidget::updateQtVersions(const QList<int> &additions, const QList<int> &removals,
                                           const QList<int> &changes)
{
523
    QList<QtVersionItem *> toRemove;
524 525 526
    QList<int> toAdd = additions;

    // Generate list of all existing items:
527
    QList<QtVersionItem *> itemList;
528
    for (int i = 0; i < m_autoItem->childCount(); ++i)
529
        itemList.append(static_cast<QtVersionItem *>(m_autoItem->child(i)));
530
    for (int i = 0; i < m_manualItem->childCount(); ++i)
531
        itemList.append(static_cast<QtVersionItem *>(m_manualItem->child(i)));
532 533

    // Find existing items to remove/change:
534 535
    foreach (QtVersionItem *item, itemList) {
        int id = item->uniqueId();
536 537 538 539 540 541 542 543 544 545 546 547 548
        if (removals.contains(id)) {
            toRemove.append(item);
            continue;
        }

        if (changes.contains(id)) {
            toAdd.append(id);
            toRemove.append(item);
            continue;
        }
    }

    // Remove changed/removed items:
549 550
    foreach (QtVersionItem *item, toRemove) {
        m_model->takeItem(item);
551 552 553 554 555
        delete item;
    }

    // Add changed/added items:
    foreach (int a, toAdd) {
hjk's avatar
hjk committed
556
        BaseQtVersion *version = QtVersionManager::version(a)->clone();
557
        auto *item = new QtVersionItem(version);
558

559
        item->setToolChainId(defaultToolChainId(version));
560 561

        // Insert in the right place:
562 563
        Utils::TreeItem *parent = version->isAutodetected()? m_autoItem : m_manualItem;
        parent->appendChild(item);
564
    }
565

566 567 568 569 570 571 572
    auto update = [this](Utils::TreeItem *parent) {
        foreach (Utils::TreeItem *child, parent->children())
            updateVersionItem(static_cast<QtVersionItem *>(child));
    };

    update(m_autoItem);
    update(m_manualItem);
573 574
}

575
QtOptionsPageWidget::~QtOptionsPageWidget()
576 577
{
    delete m_ui;
dt's avatar
dt committed
578
    delete m_versionUi;
dt's avatar
dt committed
579
    delete m_configurationWidget;
580 581
}

dt_'s avatar
dt_ committed
582 583
void QtOptionsPageWidget::addQtDir()
{
hjk's avatar
hjk committed
584
    FileName qtVersion = FileName::fromString(
Tobias Hunger's avatar
Tobias Hunger committed
585
                QFileDialog::getOpenFileName(this,
Friedemann Kleint's avatar
Friedemann Kleint committed
586
                                             tr("Select a qmake Executable"),
Tobias Hunger's avatar
Tobias Hunger committed
587
                                             QString(),
588
                                             BuildableHelperLibrary::filterForQmakeFileDialog(),
Tobias Hunger's avatar
Tobias Hunger committed
589 590
                                             0,
                                             QFileDialog::DontResolveSymlinks));
dt's avatar
dt committed
591 592
    if (qtVersion.isNull())
        return;
593

594
    QFileInfo fi = qtVersion.toFileInfo();
595 596
    // should add all qt versions here ?
    if (BuildableHelperLibrary::isQtChooser(fi))
hjk's avatar
hjk committed
597
        qtVersion = FileName::fromString(BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget()));
598

599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
    auto checkAlreadyExists = [qtVersion](Utils::TreeItem *parent) {
        for (int i = 0; i < parent->childCount(); ++i) {
            auto item = static_cast<QtVersionItem *>(parent->childAt(i));
            if (item->version()->qmakeCommand() == qtVersion) {
                return std::make_pair(true, item->version()->displayName());
            }
        }
        return std::make_pair(false, QString());
    };

    bool alreadyExists;
    QString otherName;
    std::tie(alreadyExists, otherName) = checkAlreadyExists(m_autoItem);
    if (!alreadyExists)
        std::tie(alreadyExists, otherName) = checkAlreadyExists(m_manualItem);

    if (alreadyExists) {
dt's avatar
dt committed
616
        // Already exist
Friedemann Kleint's avatar
Friedemann Kleint committed
617
        QMessageBox::warning(this, tr("Qt Version Already Known"),
618
                             tr("This Qt version was already registered as \"%1\".")
619
                             .arg(otherName));
620
        return;
dt's avatar
dt committed
621
    }
622

623
    QString error;
624
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion, false, QString(), &error);
dt's avatar
dt committed
625
    if (version) {
626 627 628 629 630 631 632
        auto item = new QtVersionItem(version);
        item->setIcon(version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
        m_manualItem->appendChild(item);
        item->setToolChainId(defaultToolChainId(version));

        QModelIndex source = m_model->indexForItem(item);
        m_ui->qtdirList->setCurrentIndex(m_filterModel->mapFromSource(source)); // should update the rest of the ui
dt's avatar
dt committed
633 634
        m_versionUi->nameEdit->setFocus();
        m_versionUi->nameEdit->selectAll();
635
    } else {
636
        QMessageBox::warning(this, tr("Qmake Not Executable"),
Friedemann Kleint's avatar
Friedemann Kleint committed
637
                             tr("The qmake executable %1 could not be added: %2").arg(qtVersion.toUserOutput()).arg(error));
638
        return;
dt's avatar
dt committed
639 640
    }
    updateCleanUpButton();
641 642
}

643
void QtOptionsPageWidget::removeQtDir()
644
{
645 646
    QtVersionItem *item = currentItem();
    if (!item)
647 648
        return;

649
    m_model->takeItem(item);
650 651
    delete item;

dt's avatar
dt committed
652
    updateCleanUpButton();
653 654
}

dt_'s avatar
dt_ committed
655 656
void QtOptionsPageWidget::editPath()
{
657
    BaseQtVersion *current = currentVersion();
658
    QString dir = currentVersion()->qmakeCommand().toFileInfo().absolutePath();
hjk's avatar
hjk committed
659
    FileName qtVersion = FileName::fromString(
660
                QFileDialog::getOpenFileName(this,
Robert Loehning's avatar
Robert Loehning committed
661
                                             tr("Select a qmake Executable"),
662
                                             dir,
663
                                             BuildableHelperLibrary::filterForQmakeFileDialog(),
664 665
                                             0,
                                             QFileDialog::DontResolveSymlinks));
dt_'s avatar
dt_ committed
666 667 668
    if (qtVersion.isNull())
        return;
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
Daniel Teske's avatar
Daniel Teske committed
669 670
    if (!version)
        return;
dt_'s avatar
dt_ committed
671 672 673
    // Same type? then replace!
    if (current->type() != version->type()) {
        // not the same type, error out
Friedemann Kleint's avatar
Friedemann Kleint committed
674
        QMessageBox::critical(this, tr("Incompatible Qt Versions"),
Friedemann Kleint's avatar
Friedemann Kleint committed
675
                              tr("The Qt version selected must match the device type."),
dt_'s avatar
dt_ committed
676 677 678 679 680 681
                              QMessageBox::Ok);
        delete version;
        return;
    }
    // same type, replace
    version->setId(current->uniqueId());
682 683
    if (current->unexpandedDisplayName() != current->defaultUnexpandedDisplayName(current->qmakeCommand()))
        version->setUnexpandedDisplayName(current->displayName());
dt_'s avatar
dt_ committed
684 685

    // Update ui
686 687 688 689
    QtVersionItem *item = currentItem();
    item->setVersion(version);
    item->setToolChainId(defaultToolChainId(version));
    item->setIcon(version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
690 691 692
    userChangedCurrentVersion();

    delete current;
dt_'s avatar
dt_ committed
693 694
}

Friedemann Kleint's avatar
Friedemann Kleint committed
695
// To be called if a Qt version was removed or added
dt's avatar
dt committed
696
void QtOptionsPageWidget::updateCleanUpButton()
697
{
698
    bool hasInvalidVersion = false;
699 700 701
    foreach (Utils::TreeItem *child, m_manualItem->children()) {
        auto item = static_cast<QtVersionItem *>(child);
        if (item->version() && !item->version()->isValid()) {
702
            hasInvalidVersion = true;
dt's avatar
dt committed
703
            break;
704 705
        }
    }
706

707
    m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
708
}
709

dt's avatar
dt committed
710
void QtOptionsPageWidget::userChangedCurrentVersion()
con's avatar
con committed
711
{
dt's avatar
dt committed
712 713
    updateWidgets();
    updateDescriptionLabel();
714 715
}

dt's avatar
dt committed
716
void QtOptionsPageWidget::qtVersionChanged()
717
{
718 719 720 721 722
    updateDescriptionLabel();
}

void QtOptionsPageWidget::updateDescriptionLabel()
{
723
    QtVersionItem *item = currentItem();
hjk's avatar
hjk committed
724 725 726
    if (!item)
        return;

727
    const BaseQtVersion *version = item->version();
728 729 730 731 732 733 734 735 736
    const ValidityInfo info = validInformation(version);
    if (info.message.isEmpty()) {
        m_versionUi->errorLabel->setVisible(false);
    } else {
        m_versionUi->errorLabel->setVisible(true);
        m_versionUi->errorLabel->setText(info.message);
        m_versionUi->errorLabel->setToolTip(info.toolTip);
    }
    m_ui->infoWidget->setSummaryText(info.description);
hjk's avatar
hjk committed
737
    item->setIcon(info.icon);
738 739 740

    if (version) {
        m_infoBrowser->setHtml(version->toHtml(true));
741
        setInfoWidgetVisibility();
742
    } else {
743
        m_infoBrowser->clear();
744
        m_ui->versionInfoWidget->setVisible(false);
745 746
        m_ui->infoWidget->setVisible(false);
    }
747 748
}

749
void QtOptionsPageWidget::versionChanged(const QModelIndex &current, const QModelIndex &previous)
750
{
751 752
    Q_UNUSED(current);
    Q_UNUSED(previous);
dt's avatar
dt committed
753 754 755 756 757 758 759 760 761
    userChangedCurrentVersion();
}

void QtOptionsPageWidget::updateWidgets()
{
    delete m_configurationWidget;
    m_configurationWidget = 0;
    BaseQtVersion *version = currentVersion();
    if (version) {
762
        m_versionUi->nameEdit->setText(version->unexpandedDisplayName());
763
        m_versionUi->qmakePath->setText(version->qmakeCommand().toUserOutput());
dt's avatar
dt committed
764 765 766
        m_configurationWidget = version->createConfigurationWidget();
        if (m_configurationWidget) {
            m_versionUi->formLayout->addRow(m_configurationWidget);
dt's avatar
dt committed
767
            m_configurationWidget->setEnabled(!version->isAutodetected());
768 769
            connect(m_configurationWidget, &QtConfigWidget::changed,
                    this, &QtOptionsPageWidget::qtVersionChanged);
dt's avatar
dt committed
770
        }
771
    } else {
772
        m_versionUi->nameEdit->clear();
773
        m_versionUi->qmakePath->clear();
774 775
    }

dt's avatar
dt committed
776 777 778
    const bool enabled = version != 0;
    const bool isAutodetected = enabled && version->isAutodetected();
    m_ui->delButton->setEnabled(enabled && !isAutodetected);
779
    m_versionUi->nameEdit->setEnabled(enabled);
dt_'s avatar
dt_ committed
780
    m_versionUi->editPathPushButton->setEnabled(enabled && !isAutodetected);
781 782
}

783
void QtOptionsPageWidget::updateCurrentQtName()
784
{
785 786
    QtVersionItem *item = currentItem();
    if (!item || !item->version())
787
        return;
788

789 790
    item->version()->setUnexpandedDisplayName(m_versionUi->nameEdit->text());

791
    updateDescriptionLabel();
792

793 794 795 796 797 798 799
    auto update = [this](Utils::TreeItem *parent) {
        foreach (Utils::TreeItem *child, parent->children())
            updateVersionItem(static_cast<QtVersionItem *>(child));
    };

    update(m_autoItem);
    update(m_manualItem);
800 801
}

802 803
void QtOptionsPageWidget::apply()
{
804 805
    disconnect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
806

hjk's avatar
hjk committed
807
    QtVersionManager::setNewQtVersions(versions());
808

809 810
    connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
811 812
}

dt's avatar
dt committed
813
QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
814
{
dt's avatar
dt committed
815
    QList<BaseQtVersion *> result;
816 817 818
    auto gather = [&result](TreeItem *parent) {
        result.reserve(result.size() + parent->childCount());
        for (int i = 0; i < parent->childCount(); ++i)
Daniel Teske's avatar
Daniel Teske committed
819
            result.append(static_cast<QtVersionItem *>(parent->childAt(i))->version()->clone());
820 821 822 823 824
    };

    gather(m_autoItem);
    gather(m_manualItem);

825
    return result;
826 827
}

hjk's avatar
hjk committed
828 829
} // namespace Internal
} // namespace QtSupport