qtoptionspage.cpp 24.6 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
    }

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

105 106 107 108 109 110
        if (role == Qt::FontRole && m_changed) {
            QFont font;
            font.setBold(true);
            return font;
         }

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 138 139 140 141 142
        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;
    }

143 144 145 146 147 148 149 150
    void setChanged(bool changed)
    {
        if (changed == m_changed)
            return;
        m_changed = changed;
        update();
    }

151
private:
Daniel Teske's avatar
Daniel Teske committed
152
    BaseQtVersion *m_version = 0;
153 154 155
    QIcon m_icon;
    QString m_buildLog;
    QByteArray m_toolChainId;
156
    bool m_changed = false;
157
};
hjk's avatar
hjk committed
158

159 160 161 162 163
///
// QtOptionsPage
///

QtOptionsPage::QtOptionsPage()
dt's avatar
dt committed
164
    : m_widget(0)
165
{
hjk's avatar
hjk committed
166
    setId(Constants::QTVERSION_SETTINGS_PAGE_ID);
167
    setDisplayName(QCoreApplication::translate("QtSupport", Constants::QTVERSION_SETTINGS_PAGE_NAME));
hjk's avatar
hjk committed
168
    setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
169 170 171
    setDisplayCategory(QCoreApplication::translate("ProjectExplorer",
        ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY));
    setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON));
172 173
}

174
QWidget *QtOptionsPage::widget()
175
{
176 177
    if (!m_widget)
        m_widget = new QtOptionsPageWidget;
178 179 180 181 182
    return m_widget;
}

void QtOptionsPage::apply()
{
183 184
    if (!m_widget) // page was never shown
        return;
185
    m_widget->apply();
186 187
}

188
void QtOptionsPage::finish()
189
{
190
    delete m_widget;
191 192
}

193
//-----------------------------------------------------
194 195


196
QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent)
197 198
    : QWidget(parent)
    , m_specifyNameString(tr("<specify a name>"))
199
    , m_ui(new Internal::Ui::QtVersionManager())
200
    , m_versionUi(new Internal::Ui::QtVersionInfo())
201
    , m_infoBrowser(new QTextBrowser)
202 203
    , m_invalidVersionIcon(Core::Icons::ERROR.icon())
    , m_warningVersionIcon(Core::Icons::WARNING.icon())
dt's avatar
dt committed
204
    , m_configurationWidget(0)
205
{
206 207
    QWidget *versionInfoWidget = new QWidget();
    m_versionUi->setupUi(versionInfoWidget);
208
    m_versionUi->editPathPushButton->setText(PathChooser::browseButtonLabel());
209

210
    m_ui->setupUi(this);
211

212 213
    m_infoBrowser->setOpenLinks(false);
    m_infoBrowser->setTextInteractionFlags(Qt::TextBrowserInteraction);
214 215
    connect(m_infoBrowser, &QTextBrowser::anchorClicked,
            this, &QtOptionsPageWidget::infoAnchorClicked);
216
    m_ui->infoWidget->setWidget(m_infoBrowser);
217 218
    connect(m_ui->infoWidget, &DetailsWidget::expanded,
            this, &QtOptionsPageWidget::setInfoWidgetVisibility);
219

220
    m_ui->versionInfoWidget->setWidget(versionInfoWidget);
hjk's avatar
hjk committed
221
    m_ui->versionInfoWidget->setState(DetailsWidget::NoSummary);
222

223 224
    m_autoItem = new StaticTreeItem(QStringList(tr("Auto-detected")));
    m_manualItem = new StaticTreeItem(QStringList(tr("Manual" )));
225 226 227

    m_model = new LeveledTreeModel<Utils::TreeItem, QtVersionItem>();
    m_model->setHeader({tr("Name"), tr("qmake Location"), tr("Type")});
hjk's avatar
hjk committed
228 229 230
    m_model->rootItem()->appendChild(m_autoItem);
    m_model->rootItem()->appendChild(m_manualItem);

231 232 233 234 235 236 237 238 239 240
    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
241
    m_ui->qtdirList->header()->setStretchLastSection(false);
242 243
    m_ui->qtdirList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
    m_ui->qtdirList->header()->setSectionResizeMode(1, QHeaderView::Stretch);
244
    m_ui->qtdirList->setTextElideMode(Qt::ElideMiddle);
245
    m_ui->qtdirList->sortByColumn(0, Qt::AscendingOrder);
246

247
    QList<int> additions = transform(QtVersionManager::versions(), &BaseQtVersion::uniqueId);
248 249

    updateQtVersions(additions, QList<int>(), QList<int>());
250 251

    m_ui->qtdirList->expandAll();
252

253 254
    connect(m_versionUi->nameEdit, &QLineEdit::textEdited,
            this, &QtOptionsPageWidget::updateCurrentQtName);
255

256 257
    connect(m_versionUi->editPathPushButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::editPath);
dt_'s avatar
dt_ committed
258

259 260 261 262
    connect(m_ui->addButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::addQtDir);
    connect(m_ui->delButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::removeQtDir);
263

264
    connect(m_ui->qtdirList->selectionModel(), &QItemSelectionModel::currentChanged,
265
            this, &QtOptionsPageWidget::versionChanged);
266

267 268
    connect(m_ui->cleanUpButton, &QAbstractButton::clicked,
            this, &QtOptionsPageWidget::cleanUpQtVersions);
dt's avatar
dt committed
269 270
    userChangedCurrentVersion();
    updateCleanUpButton();
271

272 273
    connect(QtVersionManager::instance(), &QtVersionManager::dumpUpdatedFor,
            this, &QtOptionsPageWidget::qtVersionsDumpUpdated);
274

275 276
    connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
277

278 279
    connect(ProjectExplorer::ToolChainManager::instance(), &ToolChainManager::toolChainsChanged,
            this, &QtOptionsPageWidget::toolChainsUpdated);
hjk's avatar
hjk committed
280 281

    auto chooser = new Core::VariableChooser(this);
282
    chooser->addSupportedWidget(m_versionUi->nameEdit, "Qt:Name");
hjk's avatar
hjk committed
283 284 285 286 287
    chooser->addMacroExpanderProvider(
        [this]() -> Utils::MacroExpander * {
            BaseQtVersion *version = currentVersion();
            return version ? version->macroExpander() : 0;
        });
288 289
}

dt's avatar
dt committed
290
BaseQtVersion *QtOptionsPageWidget::currentVersion() const
291
{
292 293 294 295
    QtVersionItem *item = currentItem();
    if (!item)
        return 0;
    return item->version();
296
}
297

298
QtVersionItem *QtOptionsPageWidget::currentItem() const
299
{
300 301
    QModelIndex idx = m_ui->qtdirList->selectionModel()->currentIndex();
    QModelIndex sourceIdx = m_filterModel->mapToSource(idx);
302
    return m_model->secondLevelItemForIndex(sourceIdx);
303
}
304

305 306
void QtOptionsPageWidget::cleanUpQtVersions()
{
307 308 309 310 311 312 313 314 315 316 317
    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());
        }
318 319 320 321 322
    }

    if (toRemove.isEmpty())
        return;

323

Friedemann Kleint's avatar
Friedemann Kleint committed
324
    if (QMessageBox::warning(0, tr("Remove Invalid Qt Versions"),
325 326
                             tr("Do you want to remove all invalid Qt Versions?<br>"
                                "<ul><li>%1</li></ul><br>"
327
                                "will be removed.").arg(text),
328 329 330
                             QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
        return;

331 332 333
    foreach (QtVersionItem *item, toRemove) {
        m_model->takeItem(item);
        delete item;
334
    }
335

dt's avatar
dt committed
336
    updateCleanUpButton();
337 338
}

339 340
void QtOptionsPageWidget::toolChainsUpdated()
{
341 342 343 344 345 346
    m_model->forSecondLevelItems([this](QtVersionItem *item) {
        if (item == currentItem())
            updateDescriptionLabel();
        else
            updateVersionItem(item);
    });
347 348
}

hjk's avatar
hjk committed
349
void QtOptionsPageWidget::qtVersionsDumpUpdated(const FileName &qmakeCommand)
350
{
351 352 353 354
    m_model->forSecondLevelItems([this, qmakeCommand](QtVersionItem *item) {
        if (item->version()->qmakeCommand() == qmakeCommand)
            item->version()->recheckDumper();
    });
355

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

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

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

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

    if (!version)
        return info;

381
    info.description = tr("Qt version %1 for %2").arg(version->qtVersionString(), version->description());
382 383 384 385 386 387 388 389 390
    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
391 392 393
    foreach (const Abi &abi, version->qtAbis()) {
        if (ToolChainManager::findToolChains(abi).isEmpty())
            missingToolChains.append(abi.toString());
394 395 396
        ++abiCount;
    }

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

402 403 404
    if (!missingToolChains.isEmpty()) {
        if (missingToolChains.count() == abiCount) {
            // Yes, this Qt version can't be used at all!
405
            info.message = tr("No compiler can produce code for this Qt version. Please define one or more compilers.");
406 407 408 409
            info.icon = m_invalidVersionIcon;
            useable = false;
        } else {
            // Yes, some ABIs are unsupported
410
            warnings << tr("Not all possible target environments can be supported due to missing compilers.");
411 412 413 414
            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;
        }
415
    }
416 417

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

425 426 427
    return info;
}

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

434
    QSet<QByteArray> ids;
435 436 437 438 439 440 441 442
    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);
        }
    }
443

444
    return toolChains;
445 446
}

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

455 456 457
bool QtOptionsPageWidget::isNameUnique(const BaseQtVersion *version)
{
    const QString name = version->displayName().trimmed();
458

459 460 461 462
    return !m_model->findSecondLevelItem([name, version](QtVersionItem *item) {
        BaseQtVersion *v = item->version();
        return v != version && v->displayName().trimmed() == name;
    });
463 464
}

465
void QtOptionsPageWidget::updateVersionItem(QtVersionItem *item)
466
{
467 468 469 470 471 472 473 474
    if (!item)
        return;
    if (!item->version())
        return;

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

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
// 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)
494
{
495 496 497 498
    m_ui.log->setPlainText(text); // Show and scroll to bottom
    m_ui.log->moveCursor(QTextCursor::End);
    m_ui.log->ensureCursorVisible();
}
499

500
void QtOptionsPageWidget::showDebuggingBuildLog(const QtVersionItem *item)
501
{
502 503
    BaseQtVersion *version = item->version();
    if (!version)
504
        return;
505
    BuildLogDialog *dialog = new BuildLogDialog(this->window());
506 507
    dialog->setWindowTitle(tr("Debugging Helper Build Log for \"%1\"").arg(version->displayName()));
    dialog->setText(item->buildLog());
508
    dialog->show();
509 510
}

511 512 513
void QtOptionsPageWidget::updateQtVersions(const QList<int> &additions, const QList<int> &removals,
                                           const QList<int> &changes)
{
514
    QList<QtVersionItem *> toRemove;
515 516 517
    QList<int> toAdd = additions;

    // Find existing items to remove/change:
518
    m_model->forSecondLevelItems([&](QtVersionItem *item) {
519
        int id = item->uniqueId();
520 521
        if (removals.contains(id)) {
            toRemove.append(item);
522
        } else if (changes.contains(id)) {
523 524 525
            toAdd.append(id);
            toRemove.append(item);
        }
526
    });
527 528

    // Remove changed/removed items:
529 530
    foreach (QtVersionItem *item, toRemove) {
        m_model->takeItem(item);
531 532 533 534 535
        delete item;
    }

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

539
        item->setToolChainId(defaultToolChainId(version));
540 541

        // Insert in the right place:
542 543
        Utils::TreeItem *parent = version->isAutodetected()? m_autoItem : m_manualItem;
        parent->appendChild(item);
544
    }
545

546
    m_model->forSecondLevelItems([this](QtVersionItem *item) { updateVersionItem(item); });
547 548
}

549
QtOptionsPageWidget::~QtOptionsPageWidget()
550 551
{
    delete m_ui;
dt's avatar
dt committed
552
    delete m_versionUi;
dt's avatar
dt committed
553
    delete m_configurationWidget;
554 555
}

dt_'s avatar
dt_ committed
556 557
void QtOptionsPageWidget::addQtDir()
{
hjk's avatar
hjk committed
558
    FileName qtVersion = FileName::fromString(
Tobias Hunger's avatar
Tobias Hunger committed
559
                QFileDialog::getOpenFileName(this,
Friedemann Kleint's avatar
Friedemann Kleint committed
560
                                             tr("Select a qmake Executable"),
Tobias Hunger's avatar
Tobias Hunger committed
561
                                             QString(),
562
                                             BuildableHelperLibrary::filterForQmakeFileDialog(),
Tobias Hunger's avatar
Tobias Hunger committed
563 564
                                             0,
                                             QFileDialog::DontResolveSymlinks));
dt's avatar
dt committed
565 566
    if (qtVersion.isNull())
        return;
567

568
    QFileInfo fi = qtVersion.toFileInfo();
569 570
    // should add all qt versions here ?
    if (BuildableHelperLibrary::isQtChooser(fi))
hjk's avatar
hjk committed
571
        qtVersion = FileName::fromString(BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget()));
572

573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
    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
590
        // Already exist
Friedemann Kleint's avatar
Friedemann Kleint committed
591
        QMessageBox::warning(this, tr("Qt Version Already Known"),
592
                             tr("This Qt version was already registered as \"%1\".")
593
                             .arg(otherName));
594
        return;
dt's avatar
dt committed
595
    }
596

597
    QString error;
598
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion, false, QString(), &error);
dt's avatar
dt committed
599
    if (version) {
600 601 602 603 604 605 606
        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
607 608
        m_versionUi->nameEdit->setFocus();
        m_versionUi->nameEdit->selectAll();
609
    } else {
610
        QMessageBox::warning(this, tr("Qmake Not Executable"),
Friedemann Kleint's avatar
Friedemann Kleint committed
611
                             tr("The qmake executable %1 could not be added: %2").arg(qtVersion.toUserOutput()).arg(error));
612
        return;
dt's avatar
dt committed
613 614
    }
    updateCleanUpButton();
615 616
}

617
void QtOptionsPageWidget::removeQtDir()
618
{
619 620
    QtVersionItem *item = currentItem();
    if (!item)
621 622
        return;

623
    m_model->takeItem(item);
624 625
    delete item;

dt's avatar
dt committed
626
    updateCleanUpButton();
627 628
}

dt_'s avatar
dt_ committed
629 630
void QtOptionsPageWidget::editPath()
{
631
    BaseQtVersion *current = currentVersion();
632
    QString dir = currentVersion()->qmakeCommand().toFileInfo().absolutePath();
hjk's avatar
hjk committed
633
    FileName qtVersion = FileName::fromString(
634
                QFileDialog::getOpenFileName(this,
Robert Loehning's avatar
Robert Loehning committed
635
                                             tr("Select a qmake Executable"),
636
                                             dir,
637
                                             BuildableHelperLibrary::filterForQmakeFileDialog(),
638 639
                                             0,
                                             QFileDialog::DontResolveSymlinks));
dt_'s avatar
dt_ committed
640 641 642
    if (qtVersion.isNull())
        return;
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
Daniel Teske's avatar
Daniel Teske committed
643 644
    if (!version)
        return;
dt_'s avatar
dt_ committed
645 646 647
    // Same type? then replace!
    if (current->type() != version->type()) {
        // not the same type, error out
Friedemann Kleint's avatar
Friedemann Kleint committed
648
        QMessageBox::critical(this, tr("Incompatible Qt Versions"),
Friedemann Kleint's avatar
Friedemann Kleint committed
649
                              tr("The Qt version selected must match the device type."),
dt_'s avatar
dt_ committed
650 651 652 653 654 655
                              QMessageBox::Ok);
        delete version;
        return;
    }
    // same type, replace
    version->setId(current->uniqueId());
656 657
    if (current->unexpandedDisplayName() != current->defaultUnexpandedDisplayName(current->qmakeCommand()))
        version->setUnexpandedDisplayName(current->displayName());
dt_'s avatar
dt_ committed
658 659

    // Update ui
660 661 662 663 664
    if (QtVersionItem *item = currentItem()) {
        item->setVersion(version);
        item->setToolChainId(defaultToolChainId(version));
        item->setIcon(version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
    }
665 666 667
    userChangedCurrentVersion();

    delete current;
dt_'s avatar
dt_ committed
668 669
}

Friedemann Kleint's avatar
Friedemann Kleint committed
670
// To be called if a Qt version was removed or added
dt's avatar
dt committed
671
void QtOptionsPageWidget::updateCleanUpButton()
672
{
673
    bool hasInvalidVersion = false;
674 675 676
    foreach (Utils::TreeItem *child, m_manualItem->children()) {
        auto item = static_cast<QtVersionItem *>(child);
        if (item->version() && !item->version()->isValid()) {
677
            hasInvalidVersion = true;
dt's avatar
dt committed
678
            break;
679 680
        }
    }
681

682
    m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
683
}
684

dt's avatar
dt committed
685
void QtOptionsPageWidget::userChangedCurrentVersion()
con's avatar
con committed
686
{
dt's avatar
dt committed
687 688
    updateWidgets();
    updateDescriptionLabel();
689 690
}

dt's avatar
dt committed
691
void QtOptionsPageWidget::qtVersionChanged()
692
{
693 694 695 696 697
    updateDescriptionLabel();
}

void QtOptionsPageWidget::updateDescriptionLabel()
{
698
    QtVersionItem *item = currentItem();
699
    const BaseQtVersion *version = item ? item->version() : 0;
700 701 702 703 704 705 706 707 708
    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);
709 710
    if (item)
        item->setIcon(info.icon);
711 712 713

    if (version) {
        m_infoBrowser->setHtml(version->toHtml(true));
714
        setInfoWidgetVisibility();
715
    } else {
716
        m_infoBrowser->clear();
717
        m_ui->versionInfoWidget->setVisible(false);
718 719
        m_ui->infoWidget->setVisible(false);
    }
720 721
}

722
void QtOptionsPageWidget::versionChanged(const QModelIndex &current, const QModelIndex &previous)
723
{
724 725
    Q_UNUSED(current);
    Q_UNUSED(previous);
dt's avatar
dt committed
726 727 728 729 730 731 732 733 734
    userChangedCurrentVersion();
}

void QtOptionsPageWidget::updateWidgets()
{
    delete m_configurationWidget;
    m_configurationWidget = 0;
    BaseQtVersion *version = currentVersion();
    if (version) {
735
        m_versionUi->nameEdit->setText(version->unexpandedDisplayName());
736
        m_versionUi->qmakePath->setText(version->qmakeCommand().toUserOutput());
dt's avatar
dt committed
737 738 739
        m_configurationWidget = version->createConfigurationWidget();
        if (m_configurationWidget) {
            m_versionUi->formLayout->addRow(m_configurationWidget);
dt's avatar
dt committed
740
            m_configurationWidget->setEnabled(!version->isAutodetected());
741 742
            connect(m_configurationWidget, &QtConfigWidget::changed,
                    this, &QtOptionsPageWidget::qtVersionChanged);
dt's avatar
dt committed
743
        }
744
    } else {
745
        m_versionUi->nameEdit->clear();
746
        m_versionUi->qmakePath->clear();
747 748
    }

dt's avatar
dt committed
749 750 751
    const bool enabled = version != 0;
    const bool isAutodetected = enabled && version->isAutodetected();
    m_ui->delButton->setEnabled(enabled && !isAutodetected);
752
    m_versionUi->nameEdit->setEnabled(enabled);
dt_'s avatar
dt_ committed
753
    m_versionUi->editPathPushButton->setEnabled(enabled && !isAutodetected);
754 755
}

756
void QtOptionsPageWidget::updateCurrentQtName()
757
{
758 759
    QtVersionItem *item = currentItem();
    if (!item || !item->version())
760
        return;
761

762
    item->setChanged(true);
763 764
    item->version()->setUnexpandedDisplayName(m_versionUi->nameEdit->text());

765
    updateDescriptionLabel();
766
    m_model->forSecondLevelItems([this](QtVersionItem *item) { updateVersionItem(item); });
767 768
}

769 770
void QtOptionsPageWidget::apply()
{
771 772
    disconnect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
773

774
    QList<BaseQtVersion *> versions;
775

776 777 778 779
    m_model->forSecondLevelItems([this, &versions](QtVersionItem *item) {
        item->setChanged(false);
        versions.append(item->version()->clone());
    });
780

781
    QtVersionManager::setNewQtVersions(versions);
782 783


784 785
    connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
786 787
}

hjk's avatar
hjk committed
788 789
} // namespace Internal
} // namespace QtSupport