qtoptionspage.cpp 29.3 KB
Newer Older
Tobias Hunger's avatar
Tobias Hunger committed
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
Tobias Hunger's avatar
Tobias Hunger committed
6
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
Tobias Hunger's avatar
Tobias Hunger committed
8
9
10
11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
Tobias Hunger's avatar
Tobias Hunger committed
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
Tobias Hunger's avatar
Tobias Hunger committed
30
31
32
**
**************************************************************************/

33
34
35
#include "qtoptionspage.h"
#include "ui_showbuildlog.h"
#include "ui_qtversionmanager.h"
36
37
#include "ui_qtversioninfo.h"
#include "ui_debugginghelper.h"
38
#include "qt4projectmanagerconstants.h"
39
#include "qtversionmanager.h"
dt's avatar
dt committed
40
#include "qtversionfactory.h"
41
42
43

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

#include <QtCore/QDir>
50
#include <QtGui/QToolTip>
51
#include <QtGui/QMessageBox>
dt's avatar
dt committed
52
53
#include <QtGui/QFileDialog>
#include <QtGui/QMainWindow>
54

55
enum ModelRoles { VersionIdRole = Qt::UserRole, BuildLogRole, BuildRunningRole};
56

57
58
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
59

60
61
62
63
64
///
// QtOptionsPage
///

QtOptionsPage::QtOptionsPage()
dt's avatar
dt committed
65
    : m_widget(0)
66
67
68
69
70
{
}

QString QtOptionsPage::id() const
{
71
    return QLatin1String(Constants::QTVERSION_SETTINGS_PAGE_ID);
72
73
}

74
QString QtOptionsPage::displayName() const
75
{
76
    return QCoreApplication::translate("Qt4ProjectManager", Constants::QTVERSION_SETTINGS_PAGE_NAME);
77
78
79
80
}

QString QtOptionsPage::category() const
{
81
    return QLatin1String(Constants::QT_SETTINGS_CATEGORY);
82
83
}

84
QString QtOptionsPage::displayCategory() const
85
{
86
    return QCoreApplication::translate("Qt4ProjectManager", Constants::QT_SETTINGS_TR_CATEGORY);
87
88
}

89
90
91
92
93
QIcon QtOptionsPage::categoryIcon() const
{
    return QIcon(QLatin1String(Constants::QT_SETTINGS_CATEGORY_ICON));
}

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

void QtOptionsPage::apply()
{
105
106
    if (!m_widget) // page was never shown
        return;
107
108
109
    m_widget->finish();

    QtVersionManager *vm = QtVersionManager::instance();
110
    vm->setNewQtVersions(m_widget->versions());
111
112
}

113
114
115
116
117
bool QtOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

118
//-----------------------------------------------------
119
120


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

134
135
    QWidget *versionInfoWidget = new QWidget();
    m_versionUi->setupUi(versionInfoWidget);
136

137
138
139
    QWidget *debuggingHelperDetailsWidget = new QWidget();
    m_debuggingHelperUi->setupUi(debuggingHelperDetailsWidget);

140
    m_ui->setupUi(this);
141
142
143
144
145

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

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

147
148
149
    // setup parent items for auto-detected and manual versions
    m_ui->qtdirList->header()->setResizeMode(QHeaderView::ResizeToContents);
    QTreeWidgetItem *autoItem = new QTreeWidgetItem(m_ui->qtdirList);
150
    m_ui->qtdirList->installEventFilter(this);
151
152
153
154
155
156
    autoItem->setText(0, tr("Auto-detected"));
    autoItem->setFirstColumnSpanned(true);
    QTreeWidgetItem *manualItem = new QTreeWidgetItem(m_ui->qtdirList);
    manualItem->setText(0, tr("Manual"));
    manualItem->setFirstColumnSpanned(true);

157
    for (int i = 0; i < m_versions.count(); ++i) {
dt's avatar
dt committed
158
        BaseQtVersion *version = m_versions.at(i);
159
        QTreeWidgetItem *item = new QTreeWidgetItem(version->isAutodetected()? autoItem : manualItem);
160
        item->setText(0, version->displayName());
161
        item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
162
        item->setData(0, VersionIdRole, version->uniqueId());
dt's avatar
dt committed
163
        item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
164
    }
165
    m_ui->qtdirList->expandAll();
166

167
    connect(m_versionUi->nameEdit, SIGNAL(textEdited(const QString &)),
168
169
170
171
172
173
174
175
176
177
            this, SLOT(updateCurrentQtName()));

    connect(m_ui->addButton, SIGNAL(clicked()),
            this, SLOT(addQtDir()));
    connect(m_ui->delButton, SIGNAL(clicked()),
            this, SLOT(removeQtDir()));

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

178
    connect(m_debuggingHelperUi->rebuildButton, SIGNAL(clicked()),
179
            this, SLOT(buildDebuggingHelper()));
180
181
182
183
    connect(m_debuggingHelperUi->gdbHelperBuildButton, SIGNAL(clicked()),
            this, SLOT(buildGdbHelper()));
    connect(m_debuggingHelperUi->qmlDumpBuildButton, SIGNAL(clicked()),
            this, SLOT(buildQmlDump()));
184
185
    connect(m_debuggingHelperUi->qmlDebuggingLibBuildButton, SIGNAL(clicked()),
            this, SLOT(buildQmlDebuggingLibrary()));
186
187
188
189
    connect(m_debuggingHelperUi->qmlObserverBuildButton, SIGNAL(clicked()),
            this, SLOT(buildQmlObserver()));

    connect(m_debuggingHelperUi->showLogButton, SIGNAL(clicked()),
190
            this, SLOT(slotShowDebuggingBuildLog()));
191

192
    connect(m_ui->cleanUpButton, SIGNAL(clicked()), this, SLOT(cleanUpQtVersions()));
dt's avatar
dt committed
193
194
    userChangedCurrentVersion();
    updateCleanUpButton();
195
196
}

197
198
199
200
201
bool QtOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
{
    // Set the items tooltip, which may cause costly initialization
    // of QtVersion and must be up-to-date
    if (o != m_ui->qtdirList || e->type() != QEvent::ToolTip)
202
        return false;
203
204
205
206
207
208
209
210
    QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
    const QPoint treePos = helpEvent->pos() - QPoint(0, m_ui->qtdirList->header()->height());
    QTreeWidgetItem *item = m_ui->qtdirList->itemAt(treePos);
    if (!item)
        return false;
    const int index = indexForTreeItem(item);
    if (index == -1)
        return false;
211
    const QString tooltip = m_versions.at(index)->toHtml(true);
212
213
214
215
216
    QToolTip::showText(helpEvent->globalPos(), tooltip, m_ui->qtdirList);
    helpEvent->accept();
    return true;
}

217
int QtOptionsPageWidget::currentIndex() const
218
{
219
220
221
222
    if (QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
        return indexForTreeItem(currentItem);
    return -1;
}
223

dt's avatar
dt committed
224
BaseQtVersion *QtOptionsPageWidget::currentVersion() const
225
226
227
{
    const int currentItemIndex = currentIndex();
    if (currentItemIndex >= 0 && currentItemIndex < m_versions.size())
228
        return m_versions.at(currentItemIndex);
229
230
    return 0;
}
231

dt's avatar
dt committed
232
static inline int findVersionById(const QList<BaseQtVersion *> &l, int id)
233
234
235
{
    const int size = l.size();
    for (int i = 0; i < size; i++)
236
        if (l.at(i)->uniqueId() == id)
237
238
239
            return i;
    return -1;
}
240

241
// Update with results of terminated helper build
242
void QtOptionsPageWidget::debuggingHelperBuildFinished(int qtVersionId, const QString &output, DebuggingHelperBuildTask::Tools tools)
243
{
244
    const int index = findVersionById(m_versions, qtVersionId);
245
246
    if (index == -1)
        return; // Oops, somebody managed to delete the version
247

dt's avatar
dt committed
248
249
    BaseQtVersion *version = m_versions.at(index);
    version->recheckDumper();
250

251
252
    // Update item view
    QTreeWidgetItem *item = treeItemForIndex(index);
253
254
255
256
257
    QTC_ASSERT(item, return);
    DebuggingHelperBuildTask::Tools buildFlags
            = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
    buildFlags &= ~tools;
    item->setData(0, BuildRunningRole,  QVariant::fromValue(buildFlags));
258
    item->setData(0, BuildLogRole, output);
259

260
261
    bool success = true;
    if (tools & DebuggingHelperBuildTask::GdbDebugging)
dt's avatar
dt committed
262
        success &= version->hasGdbDebuggingHelper();
263
    if (tools & DebuggingHelperBuildTask::QmlDebugging)
dt's avatar
dt committed
264
        success &= version->hasQmlDebuggingLibrary();
265
    if (tools & DebuggingHelperBuildTask::QmlDump)
dt's avatar
dt committed
266
        success &= version->hasQmlDump();
267
    if (tools & DebuggingHelperBuildTask::QmlObserver)
dt's avatar
dt committed
268
        success &= version->hasQmlObserver();
269
270
271

    // Update bottom control if the selection is still the same
    if (index == currentIndex()) {
272
        updateDebuggingHelperUi();
273
    }
274
275
    if (!success)
        showDebuggingBuildLog(item);
276
277
}

278
279
280
void QtOptionsPageWidget::cleanUpQtVersions()
{
    QStringList toRemove;
dt's avatar
dt committed
281
    foreach (const BaseQtVersion *v, m_versions) {
282
        if (!v->isValid() && !v->isAutodetected())
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
            toRemove.append(v->displayName());
    }

    if (toRemove.isEmpty())
        return;

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

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

            delete m_versions.at(i);
            m_versions.removeAt(i);
        }
    }
dt's avatar
dt committed
305
    updateCleanUpButton();
306
307
}

308
void QtOptionsPageWidget::buildDebuggingHelper(DebuggingHelperBuildTask::Tools tools)
309
310
311
312
313
{
    const int index = currentIndex();
    if (index < 0)
        return;

314
315
    QTreeWidgetItem *item = treeItemForIndex(index);
    QTC_ASSERT(item, return);
316

317
318
319
320
    DebuggingHelperBuildTask::Tools buildFlags
            = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
    buildFlags |= tools;
    item->setData(0, BuildRunningRole, QVariant::fromValue(buildFlags));
321

dt's avatar
dt committed
322
    BaseQtVersion *version = m_versions.at(index);
323
324
325
    if (!version)
        return;

326
    updateDebuggingHelperUi();
327

328
    // Run a debugging helper build task in the background.
329
    DebuggingHelperBuildTask *buildTask = new DebuggingHelperBuildTask(version, tools);
330
331
    connect(buildTask, SIGNAL(finished(int,QString,DebuggingHelperBuildTask::Tools)),
            this, SLOT(debuggingHelperBuildFinished(int,QString,DebuggingHelperBuildTask::Tools)),
332
            Qt::QueuedConnection);
333
    QFuture<void> task = QtConcurrent::run(&DebuggingHelperBuildTask::run, buildTask);
334
    const QString taskName = tr("Building helpers");
335

336
    Core::ICore::instance()->progressManager()->addTask(task, taskName,
337
                                                        QLatin1String("Qt4ProjectManager::BuildHelpers"));
338
}
339
340
341
342
343
344
345
346
347
348
void QtOptionsPageWidget::buildGdbHelper()
{
    buildDebuggingHelper(DebuggingHelperBuildTask::GdbDebugging);
}

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

349
350
351
352
353
void QtOptionsPageWidget::buildQmlDebuggingLibrary()
{
    buildDebuggingHelper(DebuggingHelperBuildTask::QmlDebugging);
}

354
355
void QtOptionsPageWidget::buildQmlObserver()
{
356
    DebuggingHelperBuildTask::Tools qmlDbgTools =
Kai Koehne's avatar
Kai Koehne committed
357
358
            DebuggingHelperBuildTask::QmlObserver;
    qmlDbgTools |= DebuggingHelperBuildTask::QmlDebugging;
359
    buildDebuggingHelper(qmlDbgTools);
360
}
361

362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
// 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)
379
{
380
381
382
383
    m_ui.log->setPlainText(text); // Show and scroll to bottom
    m_ui.log->moveCursor(QTextCursor::End);
    m_ui.log->ensureCursorVisible();
}
384

385
386
387
388
389
390
391
392
393
void QtOptionsPageWidget::slotShowDebuggingBuildLog()
{
    if (const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
        showDebuggingBuildLog(currentItem);
}

void QtOptionsPageWidget::showDebuggingBuildLog(const QTreeWidgetItem *currentItem)
{
    const int currentItemIndex = indexForTreeItem(currentItem);
394
395
    if (currentItemIndex < 0)
        return;
396
397
    BuildLogDialog *dialog = new BuildLogDialog(this);
    dialog->setWindowTitle(tr("Debugging Helper Build Log for '%1'").arg(currentItem->text(0)));
398
    dialog->setText(currentItem->data(0, BuildLogRole).toString());
399
    dialog->show();
400
401
}

402
QtOptionsPageWidget::~QtOptionsPageWidget()
403
404
{
    delete m_ui;
dt's avatar
dt committed
405
406
    delete m_versionUi;
    delete m_debuggingHelperUi;
dt's avatar
dt committed
407
    delete m_configurationWidget;
408
    qDeleteAll(m_versions);
409
410
}

411
void QtOptionsPageWidget::addQtDir()
412
{
dt's avatar
dt committed
413
414
415
416
417
    QString filter("qmake (");
    foreach (const QString &s, Utils::BuildableHelperLibrary::possibleQMakeCommands()) {
        filter += s + " ";
    }
    filter += ")";
418

dt's avatar
dt committed
419
420
421
422
423
424
425
    QString qtVersion = QFileDialog::getOpenFileName(Core::ICore::instance()->mainWindow(),
                                                     tr("Select a qmake executable"), QString(), filter);
    if (qtVersion.isNull())
        return;
    if (QtVersionManager::instance()->qtVersionForQMakeBinary(qtVersion)) {
        // Already exist
    }
426

dt's avatar
dt committed
427
428
429
    BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
    if (version) {
        m_versions.append(version);
430

dt's avatar
dt committed
431
432
433
434
435
436
437
438
439
440
        QTreeWidgetItem *item = new QTreeWidgetItem(m_ui->qtdirList->topLevelItem(1));
        item->setText(0, version->displayName());
        item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
        item->setData(0, VersionIdRole, version->uniqueId());
        item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
        m_ui->qtdirList->setCurrentItem(item); // should update the rest of the ui
        m_versionUi->nameEdit->setFocus();
        m_versionUi->nameEdit->selectAll();
    }
    updateCleanUpButton();
441
442
}

443
void QtOptionsPageWidget::removeQtDir()
444
445
{
    QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
446
    int index = indexForTreeItem(item);
447
448
449
450
451
    if (index < 0)
        return;

    delete item;

dt's avatar
dt committed
452
    BaseQtVersion *version = m_versions.at(index);
453
    m_versions.removeAt(index);
454
    delete version;
dt's avatar
dt committed
455
    updateCleanUpButton();
456
457
}

458
void QtOptionsPageWidget::updateDebuggingHelperUi()
459
{
dt's avatar
dt committed
460
    BaseQtVersion *version = currentVersion();
461
    const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
462

463
    if (!version || !version->isValid()) {
464
        m_ui->debuggingHelperWidget->setVisible(false);
465
    } else {
466
467
468
469
470
        const DebuggingHelperBuildTask::Tools availableTools = DebuggingHelperBuildTask::availableTools(version);
        const bool canBuildGdbHelper = availableTools & DebuggingHelperBuildTask::GdbDebugging;
        const bool canBuildQmlDumper = availableTools & DebuggingHelperBuildTask::QmlDump;
        const bool canBuildQmlDebuggingLib = availableTools & DebuggingHelperBuildTask::QmlDebugging;
        const bool canBuildQmlObserver = availableTools & DebuggingHelperBuildTask::QmlObserver;
471

472
473
474
        const bool hasGdbHelper = !version->gdbDebuggingHelperLibrary().isEmpty();
        const bool hasQmlDumper = version->hasQmlDump();
        const bool hasQmlDebuggingLib = version->hasQmlDebuggingLibrary();
475
        const bool needsQmlDebuggingLib = version->needsQmlDebuggingLibrary();
476
        const bool hasQmlObserver = !version->qmlObserverTool().isEmpty();
477

478
479
        bool isBuildingGdbHelper = false;
        bool isBuildingQmlDumper = false;
480
        bool isBuildingQmlDebuggingLib = false;
481
482
483
484
485
486
487
        bool isBuildingQmlObserver = false;

        if (currentItem) {
            DebuggingHelperBuildTask::Tools buildingTools
                    = currentItem->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
            isBuildingGdbHelper = buildingTools & DebuggingHelperBuildTask::GdbDebugging;
            isBuildingQmlDumper = buildingTools & DebuggingHelperBuildTask::QmlDump;
488
            isBuildingQmlDebuggingLib = buildingTools & DebuggingHelperBuildTask::QmlDebugging;
489
490
491
            isBuildingQmlObserver = buildingTools & DebuggingHelperBuildTask::QmlObserver;
        }

492
493
494
495
496
497
        // get names of tools from labels
        QStringList helperNames;
        if (hasGdbHelper)
            helperNames << m_debuggingHelperUi->gdbHelperLabel->text().remove(':');
        if (hasQmlDumper)
            helperNames << m_debuggingHelperUi->qmlDumpLabel->text().remove(':');
498
499
        if (hasQmlDebuggingLib)
            helperNames << m_debuggingHelperUi->qmlDebuggingLibLabel->text().remove(':');
500
501
502
503
504
        if (hasQmlObserver)
            helperNames << m_debuggingHelperUi->qmlObserverLabel->text().remove(':');

        QString status;
        if (helperNames.isEmpty()) {
505
            status = tr("Helpers: None available");
506
        } else {
Friedemann Kleint's avatar
Friedemann Kleint committed
507
            //: %1 is list of tool names.
508
            status = tr("Helpers: %1.").arg(helperNames.join(QLatin1String(", ")));
509
510
511
512
        }

        m_ui->debuggingHelperWidget->setSummaryText(status);

513
514
        QString gdbHelperText;
        Qt::TextInteractionFlags gdbHelperTextFlags = Qt::NoTextInteraction;
515
        if (hasGdbHelper) {
516
            gdbHelperText = QDir::toNativeSeparators(version->gdbDebuggingHelperLibrary());
517
            gdbHelperTextFlags = Qt::TextSelectableByMouse;
518
        } else {
519
520
521
522
523
            if (canBuildGdbHelper) {
                gdbHelperText =  tr("<i>Not yet built.</i>");
            } else {
                gdbHelperText =  tr("<i>Not needed.</i>");
            }
524
        }
525
526
        m_debuggingHelperUi->gdbHelperStatus->setText(gdbHelperText);
        m_debuggingHelperUi->gdbHelperStatus->setTextInteractionFlags(gdbHelperTextFlags);
527
        m_debuggingHelperUi->gdbHelperBuildButton->setEnabled(canBuildGdbHelper && !isBuildingGdbHelper);
528
529

        QString qmlDumpStatusText;
530
        Qt::TextInteractionFlags qmlDumpStatusTextFlags = Qt::NoTextInteraction;
531
        if (hasQmlDumper) {
532
533
            qmlDumpStatusText = QDir::toNativeSeparators(version->qmlDumpTool(false));
            const QString debugQmlDumpPath = QDir::toNativeSeparators(version->qmlDumpTool(true));
534
            if (qmlDumpStatusText != debugQmlDumpPath) {
535
536
                if (!qmlDumpStatusText.isEmpty()
                        && !debugQmlDumpPath.isEmpty())
537
538
539
                    qmlDumpStatusText += QLatin1String("\n");
                qmlDumpStatusText += debugQmlDumpPath;
            }
540
            qmlDumpStatusTextFlags = Qt::TextSelectableByMouse;
541
        } else {
542
543
544
545
546
            if (canBuildQmlDumper) {
                qmlDumpStatusText = tr("<i>Not yet built.</i>");
            } else {
                qmlDumpStatusText = tr("<i>Cannot be compiled.</i>");
            }
547
        }
548
        m_debuggingHelperUi->qmlDumpStatus->setText(qmlDumpStatusText);
549
        m_debuggingHelperUi->qmlDumpStatus->setTextInteractionFlags(qmlDumpStatusTextFlags);
550
        m_debuggingHelperUi->qmlDumpBuildButton->setEnabled(canBuildQmlDumper & !isBuildingQmlDumper);
551

552
553
554
555
556
557
558
559
560
561
562
        QString qmlDebuggingLibStatusText;
        Qt::TextInteractionFlags qmlDebuggingLibStatusTextFlags = Qt::NoTextInteraction;
        if (hasQmlDebuggingLib) {
            qmlDebuggingLibStatusText = QDir::toNativeSeparators(
                        version->qmlDebuggingHelperLibrary(false));
            const QString debugPath = QDir::toNativeSeparators(
                        version->qmlDebuggingHelperLibrary(true));

            if (qmlDebuggingLibStatusText != debugPath) {
                if (!qmlDebuggingLibStatusText.isEmpty()
                        && !debugPath.isEmpty()) {
563
                    qmlDebuggingLibStatusText += QLatin1Char('\n');
564
565
566
567
                }
                qmlDebuggingLibStatusText += debugPath;
            }
            qmlDebuggingLibStatusTextFlags = Qt::TextSelectableByMouse;
568
569
570
571
        } else {
            if (!needsQmlDebuggingLib) {
                qmlDebuggingLibStatusText = tr("<i>Not needed.</i>");
            } else if (canBuildQmlDebuggingLib) {
572
573
574
575
576
577
578
                qmlDebuggingLibStatusText = tr("<i>Not yet built.</i>");
            } else {
                qmlDebuggingLibStatusText = tr("<i>Cannot be compiled.</i>");
            }
        }
        m_debuggingHelperUi->qmlDebuggingLibStatus->setText(qmlDebuggingLibStatusText);
        m_debuggingHelperUi->qmlDebuggingLibStatus->setTextInteractionFlags(qmlDebuggingLibStatusTextFlags);
579
580
        m_debuggingHelperUi->qmlDebuggingLibBuildButton->setEnabled(needsQmlDebuggingLib
                                                                    && canBuildQmlDebuggingLib
581
582
                                                                    && !isBuildingQmlDebuggingLib);

583
        QString qmlObserverStatusText;
584
        Qt::TextInteractionFlags qmlObserverStatusTextFlags = Qt::NoTextInteraction;
585
        if (hasQmlObserver) {
586
            qmlObserverStatusText = QDir::toNativeSeparators(version->qmlObserverTool());
587
            qmlObserverStatusTextFlags = Qt::TextSelectableByMouse;
588
        }  else {
589
590
591
            if (!needsQmlDebuggingLib) {
                qmlObserverStatusText = tr("<i>Not needed.</i>");
            } else if (canBuildQmlObserver) {
592
593
594
595
                qmlObserverStatusText = tr("<i>Not yet built.</i>");
            } else {
                qmlObserverStatusText = tr("<i>Cannot be compiled.</i>");
            }
596
        }
597
        m_debuggingHelperUi->qmlObserverStatus->setText(qmlObserverStatusText);
598
        m_debuggingHelperUi->qmlObserverStatus->setTextInteractionFlags(qmlObserverStatusTextFlags);
599
600
        m_debuggingHelperUi->qmlObserverBuildButton->setEnabled(canBuildQmlObserver
                                                                & !isBuildingQmlObserver);
601
602
603
604

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

605
606
607
608
609
610
        m_debuggingHelperUi->rebuildButton->setEnabled((!isBuildingGdbHelper
                                                        && !isBuildingQmlDumper
                                                        && !isBuildingQmlDebuggingLib
                                                        && !isBuildingQmlObserver)
                                                       && (canBuildGdbHelper
                                                           || canBuildQmlDumper
611
                                                           || (canBuildQmlDebuggingLib && needsQmlDebuggingLib)
612
                                                           || canBuildQmlObserver));
613

614
        m_ui->debuggingHelperWidget->setVisible(true);
615
616
617
    }
}

dt's avatar
dt committed
618
619
// To be called if a qt version was removed or added
void QtOptionsPageWidget::updateCleanUpButton()
620
{
621
    bool hasInvalidVersion = false;
622
623
    for (int i = 0; i < m_versions.count(); ++i) {
        if (!m_versions.at(i)->isValid()) {
624
            hasInvalidVersion = true;
dt's avatar
dt committed
625
            break;
626
627
        }
    }
628
    m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
629
}
630

dt's avatar
dt committed
631
void QtOptionsPageWidget::userChangedCurrentVersion()
con's avatar
con committed
632
{
dt's avatar
dt committed
633
634
635
    updateWidgets();
    updateDescriptionLabel();
    updateDebuggingHelperUi();
636
637
}

dt's avatar
dt committed
638
void QtOptionsPageWidget::qtVersionChanged()
639
{
dt's avatar
dt committed
640
641
642
643
    QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
    if (item) {
        BaseQtVersion *version = currentVersion();
        item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
644
    }
645
    updateDescriptionLabel();
dt's avatar
dt committed
646
    updateDebuggingHelperUi();
647
648
649
650
}

void QtOptionsPageWidget::updateDescriptionLabel()
{
dt's avatar
dt committed
651
    BaseQtVersion *version = currentVersion();
652
653
654
    if (!version)
        m_versionUi->errorLabel->setText("");
    else if (version->isValid())
dt's avatar
dt committed
655
656
        m_versionUi->errorLabel->setText( tr("Qt version %1 for %2").arg(version->qtVersionString(),
                                                                         version->description()));
657
658
    else
        m_versionUi->errorLabel->setText(version->invalidReason());
659
660
}

661
int QtOptionsPageWidget::indexForTreeItem(const QTreeWidgetItem *item) const
662
663
664
{
    if (!item || !item->parent())
        return -1;
665
    const int uniqueId = item->data(0, VersionIdRole).toInt();
666
667
668
669
670
671
672
    for (int index = 0; index < m_versions.size(); ++index) {
        if (m_versions.at(index)->uniqueId() == uniqueId)
            return index;
    }
    return -1;
}

673
674
QTreeWidgetItem *QtOptionsPageWidget::treeItemForIndex(int index) const
{
675
    const int uniqueId = m_versions.at(index)->uniqueId();
676
677
678
679
    for (int i = 0; i < m_ui->qtdirList->topLevelItemCount(); ++i) {
        QTreeWidgetItem *toplevelItem = m_ui->qtdirList->topLevelItem(i);
        for (int j = 0; j < toplevelItem->childCount(); ++j) {
            QTreeWidgetItem *item = toplevelItem->child(j);
680
            if (item->data(0, VersionIdRole).toInt() == uniqueId) {
681
682
683
684
685
686
687
                return item;
            }
        }
    }
    return 0;
}

dt's avatar
dt committed
688
void QtOptionsPageWidget::versionChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *old)
689
{
dt's avatar
dt committed
690
691
    Q_UNUSED(newItem)
    if (old)
692
        fixQtVersionName(indexForTreeItem(old));
dt's avatar
dt committed
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
    userChangedCurrentVersion();
}

void QtOptionsPageWidget::updateWidgets()
{
    delete m_configurationWidget;
    m_configurationWidget = 0;
    BaseQtVersion *version = currentVersion();
    if (version) {
        m_versionUi->nameEdit->setText(version->displayName());
        m_versionUi->qmakePath->setText(QDir::toNativeSeparators(version->qmakeCommand()));
        m_configurationWidget = version->createConfigurationWidget();
        if (m_configurationWidget) {
            m_versionUi->formLayout->addRow(m_configurationWidget);
            connect(m_configurationWidget, SIGNAL(changed()),
                    this, SLOT(qtVersionChanged()));
        }
710
    } else {
711
        m_versionUi->nameEdit->clear();
dt's avatar
dt committed
712
        m_versionUi->qmakePath->setText(QString()); // clear()
713
714
    }

dt's avatar
dt committed
715
716
717
718
    const bool enabled = version != 0;
    const bool isAutodetected = enabled && version->isAutodetected();
    m_ui->delButton->setEnabled(enabled && !isAutodetected);
    m_versionUi->nameEdit->setEnabled(enabled && !isAutodetected);
719
720
}

721
void QtOptionsPageWidget::updateCurrentQtName()
722
723
724
{
    QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
    Q_ASSERT(currentItem);
725
726
727
    int currentItemIndex = indexForTreeItem(currentItem);
    if (currentItemIndex < 0)
        return;
728
    m_versions[currentItemIndex]->setDisplayName(m_versionUi->nameEdit->text());
729
    currentItem->setText(0, m_versions[currentItemIndex]->displayName());
730
731
732
}


733
void QtOptionsPageWidget::finish()
734
735
{
    if (QTreeWidgetItem *item = m_ui->qtdirList->currentItem())
736
        fixQtVersionName(indexForTreeItem(item));
737
738
739
740
741
742
}

/* Checks that the qt version name is unique
 * and otherwise changes the name
 *
 */
743
void QtOptionsPageWidget::fixQtVersionName(int index)
744
{
745
746
    if (index < 0)
        return;
747
    int count = m_versions.count();
748
    QString name = m_versions.at(index)->displayName();
749
750
    for (int i = 0; i < count; ++i) {
        if (i != index) {
751
            if (m_versions.at(i)->displayName() == m_versions.at(index)->displayName()) {
752
753
754
                // Same name, find new name
                QRegExp regexp("^(.*)\\((\\d)\\)$");
                if (regexp.exactMatch(name)) {
Tobias Hunger's avatar
Tobias Hunger committed
755
                    // Already in Name (#) format
756
757
758
759
                    name = regexp.cap(1);
                    name += QLatin1Char('(');
                    name += QString::number(regexp.cap(2).toInt() + 1);
                    name += QLatin1Char(')');
760
                } else {
761
                    name +=  QLatin1String(" (2)");
762
763
                }
                // set new name
764
                m_versions[index]->setDisplayName(name);
765
                treeItemForIndex(index)->setText(0, name);
766
767
768
769
770
771
772
773

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

dt's avatar
dt committed
774
QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
775
{
dt's avatar
dt committed
776
    QList<BaseQtVersion *> result;
777
    for (int i = 0; i < m_versions.count(); ++i)
dt's avatar
dt committed
778
        result.append(m_versions.at(i)->clone());
779
    return result;
780
781
}

782
783
784
QString QtOptionsPageWidget::searchKeywords() const
{
    QString rc;
785
    QLatin1Char sep(' ');
dt's avatar
dt committed
786
787
788
789
790
791
792
793
794
795
796
797
798
799
    QTextStream ts(&rc);
    ts << sep << m_versionUi->versionNameLabel->text()
       << sep << m_versionUi->pathLabel->text()
       << sep << m_debuggingHelperUi->gdbHelperLabel->text()
       << sep << m_debuggingHelperUi->qmlDumpLabel->text()
       << sep << m_debuggingHelperUi->qmlObserverLabel->text();

    // Symbian specific, could be factored out to the factory
    // checking m_configurationWidget is not enough, we want them to be a keyword
    // regardless of which qt versions configuration widget is currently active
    ts << sep << tr("S60 SDK:")
       << sep << tr("SBS v2 directory:");


800
801
802
    rc.remove(QLatin1Char('&'));
    return rc;
}