qtoptionspage.cpp 24.3 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 192
    QWidget *versionInfoWidget = new QWidget();
    m_versionUi->setupUi(versionInfoWidget);
193
    m_versionUi->editPathPushButton->setText(PathChooser::browseButtonLabel());
194

195
    m_ui->setupUi(this);
196

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

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

hjk's avatar
hjk committed
208
    m_autoItem = new StaticTreeItem({ tr("Auto-detected") });
209 210 211 212
    m_manualItem = new StaticTreeItem({ tr("Manual" )});

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

216 217 218 219 220 221 222 223 224 225
    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
226
    m_ui->qtdirList->header()->setStretchLastSection(false);
227 228
    m_ui->qtdirList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
    m_ui->qtdirList->header()->setSectionResizeMode(1, QHeaderView::Stretch);
dt_'s avatar
dt_ committed
229
    m_ui->qtdirList->setTextElideMode(Qt::ElideNone);
230
    m_ui->qtdirList->sortByColumn(0, Qt::AscendingOrder);
231

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

    updateQtVersions(additions, QList<int>(), QList<int>());
235 236

    m_ui->qtdirList->expandAll();
237

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

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

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

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

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

257 258
    connect(QtVersionManager::instance(), &QtVersionManager::dumpUpdatedFor,
            this, &QtOptionsPageWidget::qtVersionsDumpUpdated);
259

260 261
    connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
262

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

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

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

283
QtVersionItem *QtOptionsPageWidget::currentItem() const
284
{
285 286
    QModelIndex idx = m_ui->qtdirList->selectionModel()->currentIndex();
    QModelIndex sourceIdx = m_filterModel->mapToSource(idx);
287
    return m_model->secondLevelItemForIndex(sourceIdx);
288
}
289

290 291
void QtOptionsPageWidget::cleanUpQtVersions()
{
292 293 294 295 296 297 298 299 300 301 302
    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());
        }
303 304 305 306 307
    }

    if (toRemove.isEmpty())
        return;

308

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

316 317 318
    foreach (QtVersionItem *item, toRemove) {
        m_model->takeItem(item);
        delete item;
319
    }
320

dt's avatar
dt committed
321
    updateCleanUpButton();
322 323
}

324 325
void QtOptionsPageWidget::toolChainsUpdated()
{
326 327 328 329 330 331
    m_model->forSecondLevelItems([this](QtVersionItem *item) {
        if (item == currentItem())
            updateDescriptionLabel();
        else
            updateVersionItem(item);
    });
332 333
}

hjk's avatar
hjk committed
334
void QtOptionsPageWidget::qtVersionsDumpUpdated(const FileName &qmakeCommand)
335
{
336 337 338 339
    m_model->forSecondLevelItems([this, qmakeCommand](QtVersionItem *item) {
        if (item->version()->qmakeCommand() == qmakeCommand)
            item->version()->recheckDumper();
    });
340

341
    if (currentVersion() && currentVersion()->qmakeCommand() == qmakeCommand) {
342 343 344 345 346
        updateWidgets();
        updateDescriptionLabel();
    }
}

347
void QtOptionsPageWidget::setInfoWidgetVisibility()
348
{
349 350
    m_ui->versionInfoWidget->setVisible(m_ui->infoWidget->state() == DetailsWidget::Collapsed);
    m_ui->infoWidget->setVisible(true);
351 352
}

353 354 355 356 357
void QtOptionsPageWidget::infoAnchorClicked(const QUrl &url)
{
    QDesktopServices::openUrl(url);
}

358 359 360 361 362 363 364 365
QtOptionsPageWidget::ValidityInfo QtOptionsPageWidget::validInformation(const BaseQtVersion *version)
{
    ValidityInfo info;
    info.icon = m_validVersionIcon;

    if (!version)
        return info;

366
    info.description = tr("Qt version %1 for %2").arg(version->qtVersionString(), version->description());
367 368 369 370 371 372 373 374 375
    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
376 377 378
    foreach (const Abi &abi, version->qtAbis()) {
        if (ToolChainManager::findToolChains(abi).isEmpty())
            missingToolChains.append(abi.toString());
379 380 381
        ++abiCount;
    }

382
    bool useable = true;
383
    QStringList warnings;
384 385 386
    if (!isNameUnique(version))
        warnings << tr("Display Name is not unique.");

387 388 389
    if (!missingToolChains.isEmpty()) {
        if (missingToolChains.count() == abiCount) {
            // Yes, this Qt version can't be used at all!
390
            info.message = tr("No compiler can produce code for this Qt version. Please define one or more compilers.");
391 392 393 394
            info.icon = m_invalidVersionIcon;
            useable = false;
        } else {
            // Yes, some ABIs are unsupported
395
            warnings << tr("Not all possible target environments can be supported due to missing compilers.");
396 397 398 399
            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;
        }
400
    }
401 402

    if (useable) {
403 404
        warnings += version->warningReason();
        if (!warnings.isEmpty()) {
hjk's avatar
hjk committed
405
            info.message = warnings.join(QLatin1Char('\n'));
406 407 408 409
            info.icon = m_warningVersionIcon;
        }
    }

410 411 412
    return info;
}

hjk's avatar
hjk committed
413
QList<ToolChain*> QtOptionsPageWidget::toolChains(const BaseQtVersion *version)
414
{
415
    QList<ToolChain*> toolChains;
416
    if (!version)
417 418
        return toolChains;

419
    QSet<QByteArray> ids;
420 421 422 423 424 425 426 427
    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);
        }
    }
428

429
    return toolChains;
430 431
}

432
QByteArray QtOptionsPageWidget::defaultToolChainId(const BaseQtVersion *version)
433
{
hjk's avatar
hjk committed
434
    QList<ToolChain*> possibleToolChains = toolChains(version);
435 436
    if (!possibleToolChains.isEmpty())
        return possibleToolChains.first()->id();
437
    return QByteArray();
438 439
}

440 441 442
bool QtOptionsPageWidget::isNameUnique(const BaseQtVersion *version)
{
    const QString name = version->displayName().trimmed();
443

444 445 446 447
    return !m_model->findSecondLevelItem([name, version](QtVersionItem *item) {
        BaseQtVersion *v = item->version();
        return v != version && v->displayName().trimmed() == name;
    });
448 449
}

450
void QtOptionsPageWidget::updateVersionItem(QtVersionItem *item)
451
{
452 453 454 455 456 457 458 459
    if (!item)
        return;
    if (!item->version())
        return;

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

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
// 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)
479
{
480 481 482 483
    m_ui.log->setPlainText(text); // Show and scroll to bottom
    m_ui.log->moveCursor(QTextCursor::End);
    m_ui.log->ensureCursorVisible();
}
484

485
void QtOptionsPageWidget::showDebuggingBuildLog(const QtVersionItem *item)
486
{
487 488
    BaseQtVersion *version = item->version();
    if (!version)
489
        return;
490
    BuildLogDialog *dialog = new BuildLogDialog(this->window());
491 492
    dialog->setWindowTitle(tr("Debugging Helper Build Log for \"%1\"").arg(version->displayName()));
    dialog->setText(item->buildLog());
493
    dialog->show();
494 495
}

496 497 498
void QtOptionsPageWidget::updateQtVersions(const QList<int> &additions, const QList<int> &removals,
                                           const QList<int> &changes)
{
499
    QList<QtVersionItem *> toRemove;
500 501 502
    QList<int> toAdd = additions;

    // Find existing items to remove/change:
503
    m_model->forSecondLevelItems([&](QtVersionItem *item) {
504
        int id = item->uniqueId();
505 506
        if (removals.contains(id)) {
            toRemove.append(item);
507
        } else if (changes.contains(id)) {
508 509 510
            toAdd.append(id);
            toRemove.append(item);
        }
511
    });
512 513

    // Remove changed/removed items:
514 515
    foreach (QtVersionItem *item, toRemove) {
        m_model->takeItem(item);
516 517 518 519 520
        delete item;
    }

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

524
        item->setToolChainId(defaultToolChainId(version));
525 526

        // Insert in the right place:
527 528
        Utils::TreeItem *parent = version->isAutodetected()? m_autoItem : m_manualItem;
        parent->appendChild(item);
529
    }
530

531
    m_model->forSecondLevelItems([this](QtVersionItem *item) { updateVersionItem(item); });
532 533
}

534
QtOptionsPageWidget::~QtOptionsPageWidget()
535 536
{
    delete m_ui;
dt's avatar
dt committed
537
    delete m_versionUi;
dt's avatar
dt committed
538
    delete m_configurationWidget;
539 540
}

dt_'s avatar
dt_ committed
541 542
void QtOptionsPageWidget::addQtDir()
{
hjk's avatar
hjk committed
543
    FileName qtVersion = FileName::fromString(
Tobias Hunger's avatar
Tobias Hunger committed
544
                QFileDialog::getOpenFileName(this,
Friedemann Kleint's avatar
Friedemann Kleint committed
545
                                             tr("Select a qmake Executable"),
Tobias Hunger's avatar
Tobias Hunger committed
546
                                             QString(),
547
                                             BuildableHelperLibrary::filterForQmakeFileDialog(),
Tobias Hunger's avatar
Tobias Hunger committed
548 549
                                             0,
                                             QFileDialog::DontResolveSymlinks));
dt's avatar
dt committed
550 551
    if (qtVersion.isNull())
        return;
552

553
    QFileInfo fi = qtVersion.toFileInfo();
554 555
    // should add all qt versions here ?
    if (BuildableHelperLibrary::isQtChooser(fi))
hjk's avatar
hjk committed
556
        qtVersion = FileName::fromString(BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget()));
557

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    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
575
        // Already exist
Friedemann Kleint's avatar
Friedemann Kleint committed
576
        QMessageBox::warning(this, tr("Qt Version Already Known"),
577
                             tr("This Qt version was already registered as \"%1\".")
578
                             .arg(otherName));
579
        return;
dt's avatar
dt committed
580
    }
581

582
    QString error;
583
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion, false, QString(), &error);
dt's avatar
dt committed
584
    if (version) {
585 586 587 588 589 590 591
        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
592 593
        m_versionUi->nameEdit->setFocus();
        m_versionUi->nameEdit->selectAll();
594
    } else {
595
        QMessageBox::warning(this, tr("Qmake Not Executable"),
Friedemann Kleint's avatar
Friedemann Kleint committed
596
                             tr("The qmake executable %1 could not be added: %2").arg(qtVersion.toUserOutput()).arg(error));
597
        return;
dt's avatar
dt committed
598 599
    }
    updateCleanUpButton();
600 601
}

602
void QtOptionsPageWidget::removeQtDir()
603
{
604 605
    QtVersionItem *item = currentItem();
    if (!item)
606 607
        return;

608
    m_model->takeItem(item);
609 610
    delete item;

dt's avatar
dt committed
611
    updateCleanUpButton();
612 613
}

dt_'s avatar
dt_ committed
614 615
void QtOptionsPageWidget::editPath()
{
616
    BaseQtVersion *current = currentVersion();
617
    QString dir = currentVersion()->qmakeCommand().toFileInfo().absolutePath();
hjk's avatar
hjk committed
618
    FileName qtVersion = FileName::fromString(
619
                QFileDialog::getOpenFileName(this,
Robert Loehning's avatar
Robert Loehning committed
620
                                             tr("Select a qmake Executable"),
621
                                             dir,
622
                                             BuildableHelperLibrary::filterForQmakeFileDialog(),
623 624
                                             0,
                                             QFileDialog::DontResolveSymlinks));
dt_'s avatar
dt_ committed
625 626 627
    if (qtVersion.isNull())
        return;
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
Daniel Teske's avatar
Daniel Teske committed
628 629
    if (!version)
        return;
dt_'s avatar
dt_ committed
630 631 632
    // Same type? then replace!
    if (current->type() != version->type()) {
        // not the same type, error out
Friedemann Kleint's avatar
Friedemann Kleint committed
633
        QMessageBox::critical(this, tr("Incompatible Qt Versions"),
Friedemann Kleint's avatar
Friedemann Kleint committed
634
                              tr("The Qt version selected must match the device type."),
dt_'s avatar
dt_ committed
635 636 637 638 639 640
                              QMessageBox::Ok);
        delete version;
        return;
    }
    // same type, replace
    version->setId(current->uniqueId());
641 642
    if (current->unexpandedDisplayName() != current->defaultUnexpandedDisplayName(current->qmakeCommand()))
        version->setUnexpandedDisplayName(current->displayName());
dt_'s avatar
dt_ committed
643 644

    // Update ui
645 646 647 648 649
    if (QtVersionItem *item = currentItem()) {
        item->setVersion(version);
        item->setToolChainId(defaultToolChainId(version));
        item->setIcon(version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
    }
650 651 652
    userChangedCurrentVersion();

    delete current;
dt_'s avatar
dt_ committed
653 654
}

Friedemann Kleint's avatar
Friedemann Kleint committed
655
// To be called if a Qt version was removed or added
dt's avatar
dt committed
656
void QtOptionsPageWidget::updateCleanUpButton()
657
{
658
    bool hasInvalidVersion = false;
659 660 661
    foreach (Utils::TreeItem *child, m_manualItem->children()) {
        auto item = static_cast<QtVersionItem *>(child);
        if (item->version() && !item->version()->isValid()) {
662
            hasInvalidVersion = true;
dt's avatar
dt committed
663
            break;
664 665
        }
    }
666

667
    m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
668
}
669

dt's avatar
dt committed
670
void QtOptionsPageWidget::userChangedCurrentVersion()
con's avatar
con committed
671
{
dt's avatar
dt committed
672 673
    updateWidgets();
    updateDescriptionLabel();
674 675
}

dt's avatar
dt committed
676
void QtOptionsPageWidget::qtVersionChanged()
677
{
678 679 680 681 682
    updateDescriptionLabel();
}

void QtOptionsPageWidget::updateDescriptionLabel()
{
683
    QtVersionItem *item = currentItem();
684
    const BaseQtVersion *version = item ? item->version() : 0;
685 686 687 688 689 690 691 692 693
    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);
694 695
    if (item)
        item->setIcon(info.icon);
696 697 698

    if (version) {
        m_infoBrowser->setHtml(version->toHtml(true));
699
        setInfoWidgetVisibility();
700
    } else {
701
        m_infoBrowser->clear();
702
        m_ui->versionInfoWidget->setVisible(false);
703 704
        m_ui->infoWidget->setVisible(false);
    }
705 706
}

707
void QtOptionsPageWidget::versionChanged(const QModelIndex &current, const QModelIndex &previous)
708
{
709 710
    Q_UNUSED(current);
    Q_UNUSED(previous);
dt's avatar
dt committed
711 712 713 714 715 716 717 718 719
    userChangedCurrentVersion();
}

void QtOptionsPageWidget::updateWidgets()
{
    delete m_configurationWidget;
    m_configurationWidget = 0;
    BaseQtVersion *version = currentVersion();
    if (version) {
720
        m_versionUi->nameEdit->setText(version->unexpandedDisplayName());
721
        m_versionUi->qmakePath->setText(version->qmakeCommand().toUserOutput());
dt's avatar
dt committed
722 723 724
        m_configurationWidget = version->createConfigurationWidget();
        if (m_configurationWidget) {
            m_versionUi->formLayout->addRow(m_configurationWidget);
dt's avatar
dt committed
725
            m_configurationWidget->setEnabled(!version->isAutodetected());
726 727
            connect(m_configurationWidget, &QtConfigWidget::changed,
                    this, &QtOptionsPageWidget::qtVersionChanged);
dt's avatar
dt committed
728
        }
729
    } else {
730
        m_versionUi->nameEdit->clear();
731
        m_versionUi->qmakePath->clear();
732 733
    }

dt's avatar
dt committed
734 735 736
    const bool enabled = version != 0;
    const bool isAutodetected = enabled && version->isAutodetected();
    m_ui->delButton->setEnabled(enabled && !isAutodetected);
737
    m_versionUi->nameEdit->setEnabled(enabled);
dt_'s avatar
dt_ committed
738
    m_versionUi->editPathPushButton->setEnabled(enabled && !isAutodetected);
739 740
}

741
void QtOptionsPageWidget::updateCurrentQtName()
742
{
743 744
    QtVersionItem *item = currentItem();
    if (!item || !item->version())
745
        return;
746

747 748
    item->version()->setUnexpandedDisplayName(m_versionUi->nameEdit->text());

749
    updateDescriptionLabel();
750
    m_model->forSecondLevelItems([this](QtVersionItem *item) { updateVersionItem(item); });
751 752
}

753 754
void QtOptionsPageWidget::apply()
{
755 756
    disconnect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
757

hjk's avatar
hjk committed
758
    QtVersionManager::setNewQtVersions(versions());
759

760 761
    connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
762 763
}

dt's avatar
dt committed
764
QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
765
{
dt's avatar
dt committed
766
    QList<BaseQtVersion *> result;
767

768 769 770
    m_model->forSecondLevelItems([this, &result](QtVersionItem *item) {
        result.append(item->version()->clone());
    });
771

772
    return result;
773 774
}

hjk's avatar
hjk committed
775 776
} // namespace Internal
} // namespace QtSupport