qtoptionspage.cpp 24.5 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(tr("Auto-detected"));
    m_manualItem = new StaticTreeItem(tr("Manual"));
225

hjk's avatar
hjk committed
226
    m_model = new TreeModel<Utils::TreeItem, Utils::TreeItem, QtVersionItem>();
227
    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);
hjk's avatar
hjk committed
302
    return m_model->itemForIndexAtLevel<2>(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
    foreach (QtVersionItem *item, toRemove)
        m_model->destroyItem(item);
333

dt's avatar
dt committed
334
    updateCleanUpButton();
335 336
}

337 338
void QtOptionsPageWidget::toolChainsUpdated()
{
hjk's avatar
hjk committed
339
    m_model->forItemsAtLevel<2>([this](QtVersionItem *item) {
340 341 342 343 344
        if (item == currentItem())
            updateDescriptionLabel();
        else
            updateVersionItem(item);
    });
345 346
}

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

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

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

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

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

    if (!version)
        return info;

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

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

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

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

423 424 425
    return info;
}

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

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

442
    return toolChains;
443 444
}

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

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

hjk's avatar
hjk committed
457
    return !m_model->findItemAtLevel<2>([name, version](QtVersionItem *item) {
458 459 460
        BaseQtVersion *v = item->version();
        return v != version && v->displayName().trimmed() == name;
    });
461 462
}

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

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

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

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

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

    // Find existing items to remove/change:
hjk's avatar
hjk committed
516
    m_model->forItemsAtLevel<2>([&](QtVersionItem *item) {
517
        int id = item->uniqueId();
518 519
        if (removals.contains(id)) {
            toRemove.append(item);
520
        } else if (changes.contains(id)) {
521 522 523
            toAdd.append(id);
            toRemove.append(item);
        }
524
    });
525 526

    // Remove changed/removed items:
527 528
    foreach (QtVersionItem *item, toRemove)
        m_model->destroyItem(item);
529 530 531

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

535
        item->setToolChainId(defaultToolChainId(version));
536 537

        // Insert in the right place:
538 539
        Utils::TreeItem *parent = version->isAutodetected()? m_autoItem : m_manualItem;
        parent->appendChild(item);
540
    }
541

hjk's avatar
hjk committed
542
    m_model->forItemsAtLevel<2>([this](QtVersionItem *item) { updateVersionItem(item); });
543 544
}

545
QtOptionsPageWidget::~QtOptionsPageWidget()
546 547
{
    delete m_ui;
dt's avatar
dt committed
548
    delete m_versionUi;
dt's avatar
dt committed
549
    delete m_configurationWidget;
550 551
}

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

564
    QFileInfo fi = qtVersion.toFileInfo();
565 566
    // should add all qt versions here ?
    if (BuildableHelperLibrary::isQtChooser(fi))
hjk's avatar
hjk committed
567
        qtVersion = FileName::fromString(BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget()));
568

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

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

613
void QtOptionsPageWidget::removeQtDir()
614
{
615 616
    QtVersionItem *item = currentItem();
    if (!item)
617 618
        return;

619
    m_model->destroyItem(item);
620

dt's avatar
dt committed
621
    updateCleanUpButton();
622 623
}

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

    // Update ui
655 656 657 658 659
    if (QtVersionItem *item = currentItem()) {
        item->setVersion(version);
        item->setToolChainId(defaultToolChainId(version));
        item->setIcon(version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
    }
660 661 662
    userChangedCurrentVersion();

    delete current;
dt_'s avatar
dt_ committed
663 664
}

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

677
    m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
678
}
679

dt's avatar
dt committed
680
void QtOptionsPageWidget::userChangedCurrentVersion()
con's avatar
con committed
681
{
dt's avatar
dt committed
682 683
    updateWidgets();
    updateDescriptionLabel();
684 685
}

dt's avatar
dt committed
686
void QtOptionsPageWidget::qtVersionChanged()
687
{
688 689 690 691 692
    updateDescriptionLabel();
}

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

    if (version) {
        m_infoBrowser->setHtml(version->toHtml(true));
709
        setInfoWidgetVisibility();
710
    } else {
711
        m_infoBrowser->clear();
712
        m_ui->versionInfoWidget->setVisible(false);
713 714
        m_ui->infoWidget->setVisible(false);
    }
715 716
}

717
void QtOptionsPageWidget::versionChanged(const QModelIndex &current, const QModelIndex &previous)
718
{
719 720
    Q_UNUSED(current);
    Q_UNUSED(previous);
dt's avatar
dt committed
721 722 723 724 725 726 727 728 729
    userChangedCurrentVersion();
}

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

dt's avatar
dt committed
744 745 746
    const bool enabled = version != 0;
    const bool isAutodetected = enabled && version->isAutodetected();
    m_ui->delButton->setEnabled(enabled && !isAutodetected);
747
    m_versionUi->nameEdit->setEnabled(enabled);
dt_'s avatar
dt_ committed
748
    m_versionUi->editPathPushButton->setEnabled(enabled && !isAutodetected);
749 750
}

751
void QtOptionsPageWidget::updateCurrentQtName()
752
{
753 754
    QtVersionItem *item = currentItem();
    if (!item || !item->version())
755
        return;
756

757
    item->setChanged(true);
758 759
    item->version()->setUnexpandedDisplayName(m_versionUi->nameEdit->text());

760
    updateDescriptionLabel();
hjk's avatar
hjk committed
761
    m_model->forItemsAtLevel<2>([this](QtVersionItem *item) { updateVersionItem(item); });
762 763
}

764 765
void QtOptionsPageWidget::apply()
{
766 767
    disconnect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
768

769
    QList<BaseQtVersion *> versions;
770

hjk's avatar
hjk committed
771
    m_model->forItemsAtLevel<2>([this, &versions](QtVersionItem *item) {
772 773 774
        item->setChanged(false);
        versions.append(item->version()->clone());
    });
775

776
    QtVersionManager::setNewQtVersions(versions);
777 778


779 780
    connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
            this, &QtOptionsPageWidget::updateQtVersions);
781 782
}

hjk's avatar
hjk committed
783 784
} // namespace Internal
} // namespace QtSupport