1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
31 **************************************************************************/
33 #include "qtoptionspage.h"
34 #include "ui_showbuildlog.h"
35 #include "ui_qtversionmanager.h"
36 #include "ui_qtversioninfo.h"
37 #include "ui_debugginghelper.h"
38 #include "qtsupportconstants.h"
39 #include "qtversionmanager.h"
40 #include "qtversionfactory.h"
41 #include "qmldumptool.h"
42 #include "qmldebugginglibrary.h"
43 #include "qmlobservertool.h"
45 #include <coreplugin/icore.h>
46 #include <coreplugin/progressmanager/progressmanager.h>
47 #include <utils/treewidgetcolumnstretcher.h>
48 #include <utils/qtcassert.h>
49 #include <utils/buildablehelperlibrary.h>
50 #include <utils/pathchooser.h>
51 #include <projectexplorer/toolchainmanager.h>
52 #include <qtconcurrent/runextensions.h>
54 #include <QtCore/QDir>
55 #include <QtGui/QToolTip>
56 #include <QtGui/QMessageBox>
57 #include <QtGui/QFileDialog>
58 #include <QtGui/QMainWindow>
60 enum ModelRoles { VersionIdRole = Qt::UserRole, BuildLogRole, BuildRunningRole};
62 using namespace QtSupport;
63 using namespace QtSupport::Internal;
69 QtOptionsPage::QtOptionsPage()
74 QString QtOptionsPage::id() const
76 return QLatin1String(Constants::QTVERSION_SETTINGS_PAGE_ID);
79 QString QtOptionsPage::displayName() const
81 return QCoreApplication::translate("Qt4ProjectManager", Constants::QTVERSION_SETTINGS_PAGE_NAME);
84 QString QtOptionsPage::category() const
86 return QLatin1String(Constants::QT_SETTINGS_CATEGORY);
89 QString QtOptionsPage::displayCategory() const
91 return QCoreApplication::translate("Qt4ProjectManager", Constants::QT_SETTINGS_TR_CATEGORY);
94 QIcon QtOptionsPage::categoryIcon() const
96 return QIcon(QLatin1String(Constants::QT_SETTINGS_CATEGORY_ICON));
99 QWidget *QtOptionsPage::createPage(QWidget *parent)
101 QtVersionManager *vm = QtVersionManager::instance();
102 m_widget = new QtOptionsPageWidget(parent, vm->versions());
103 if (m_searchKeywords.isEmpty())
104 m_searchKeywords = m_widget->searchKeywords();
108 void QtOptionsPage::apply()
110 if (!m_widget) // page was never shown
114 QtVersionManager *vm = QtVersionManager::instance();
115 vm->setNewQtVersions(m_widget->versions());
118 bool QtOptionsPage::matches(const QString &s) const
120 return m_searchKeywords.contains(s, Qt::CaseInsensitive);
123 //-----------------------------------------------------
126 QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent, QList<BaseQtVersion *> versions)
128 , m_specifyNameString(tr("<specify a name>"))
129 , m_ui(new Internal::Ui::QtVersionManager())
130 , m_versionUi(new Internal::Ui::QtVersionInfo())
131 , m_debuggingHelperUi(new Internal::Ui::DebuggingHelper())
132 , m_invalidVersionIcon(":/projectexplorer/images/compile_error.png")
133 , m_warningVersionIcon(":/projectexplorer/images/compile_warning.png")
134 , m_configurationWidget(0)
136 // Initialize m_versions
137 foreach (BaseQtVersion *version, versions)
138 m_versions.push_back(version->clone());
140 QWidget *versionInfoWidget = new QWidget();
141 m_versionUi->setupUi(versionInfoWidget);
142 m_versionUi->editPathPushButton->setText(tr(Utils::PathChooser::browseButtonLabel));
144 QWidget *debuggingHelperDetailsWidget = new QWidget();
145 m_debuggingHelperUi->setupUi(debuggingHelperDetailsWidget);
149 m_ui->versionInfoWidget->setWidget(versionInfoWidget);
150 m_ui->versionInfoWidget->setState(Utils::DetailsWidget::NoSummary);
152 m_ui->debuggingHelperWidget->setWidget(debuggingHelperDetailsWidget);
154 // setup parent items for auto-detected and manual versions
155 m_ui->qtdirList->header()->setResizeMode(QHeaderView::ResizeToContents);
156 m_ui->qtdirList->header()->setStretchLastSection(false);
157 m_ui->qtdirList->setTextElideMode(Qt::ElideNone);
158 QTreeWidgetItem *autoItem = new QTreeWidgetItem(m_ui->qtdirList);
159 m_ui->qtdirList->installEventFilter(this);
160 autoItem->setText(0, tr("Auto-detected"));
161 autoItem->setFirstColumnSpanned(true);
162 autoItem->setFlags(Qt::ItemIsEnabled);
163 QTreeWidgetItem *manualItem = new QTreeWidgetItem(m_ui->qtdirList);
164 manualItem->setText(0, tr("Manual"));
165 manualItem->setFirstColumnSpanned(true);
166 manualItem->setFlags(Qt::ItemIsEnabled);
168 for (int i = 0; i < m_versions.count(); ++i) {
169 BaseQtVersion *version = m_versions.at(i);
170 QTreeWidgetItem *item = new QTreeWidgetItem(version->isAutodetected()? autoItem : manualItem);
171 item->setText(0, version->displayName());
172 item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
173 item->setData(0, VersionIdRole, version->uniqueId());
174 const ValidityInfo info = validInformation(version);
175 item->setIcon(0, info.icon);
177 m_ui->qtdirList->expandAll();
179 connect(m_versionUi->nameEdit, SIGNAL(textEdited(const QString &)),
180 this, SLOT(updateCurrentQtName()));
182 connect(m_versionUi->editPathPushButton, SIGNAL(clicked()),
183 this, SLOT(editPath()));
185 connect(m_ui->addButton, SIGNAL(clicked()),
186 this, SLOT(addQtDir()));
187 connect(m_ui->delButton, SIGNAL(clicked()),
188 this, SLOT(removeQtDir()));
190 connect(m_ui->qtdirList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
191 this, SLOT(versionChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
193 connect(m_debuggingHelperUi->rebuildButton, SIGNAL(clicked()),
194 this, SLOT(buildDebuggingHelper()));
195 connect(m_debuggingHelperUi->gdbHelperBuildButton, SIGNAL(clicked()),
196 this, SLOT(buildGdbHelper()));
197 connect(m_debuggingHelperUi->qmlDumpBuildButton, SIGNAL(clicked()),
198 this, SLOT(buildQmlDump()));
199 connect(m_debuggingHelperUi->qmlDebuggingLibBuildButton, SIGNAL(clicked()),
200 this, SLOT(buildQmlDebuggingLibrary()));
201 connect(m_debuggingHelperUi->qmlObserverBuildButton, SIGNAL(clicked()),
202 this, SLOT(buildQmlObserver()));
204 connect(m_debuggingHelperUi->showLogButton, SIGNAL(clicked()),
205 this, SLOT(slotShowDebuggingBuildLog()));
207 connect(m_ui->cleanUpButton, SIGNAL(clicked()), this, SLOT(cleanUpQtVersions()));
208 userChangedCurrentVersion();
209 updateCleanUpButton();
211 connect(QtVersionManager::instance(), SIGNAL(dumpUpdatedFor(QString)),
212 this, SLOT(qtVersionsDumpUpdated(QString)));
214 connect(ProjectExplorer::ToolChainManager::instance(), SIGNAL(toolChainsChanged()),
215 this, SLOT(toolChainsUpdated()));
218 bool QtOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
220 // Set the items tooltip, which may cause costly initialization
221 // of QtVersion and must be up-to-date
222 if (o != m_ui->qtdirList || e->type() != QEvent::ToolTip)
224 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
225 const QPoint treePos = helpEvent->pos() - QPoint(0, m_ui->qtdirList->header()->height());
226 QTreeWidgetItem *item = m_ui->qtdirList->itemAt(treePos);
229 const int index = indexForTreeItem(item);
232 const QString tooltip = m_versions.at(index)->toHtml(true);
233 QToolTip::showText(helpEvent->globalPos(), tooltip, m_ui->qtdirList);
238 int QtOptionsPageWidget::currentIndex() const
240 if (QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
241 return indexForTreeItem(currentItem);
245 BaseQtVersion *QtOptionsPageWidget::currentVersion() const
247 const int currentItemIndex = currentIndex();
248 if (currentItemIndex >= 0 && currentItemIndex < m_versions.size())
249 return m_versions.at(currentItemIndex);
253 static inline int findVersionById(const QList<BaseQtVersion *> &l, int id)
255 const int size = l.size();
256 for (int i = 0; i < size; i++)
257 if (l.at(i)->uniqueId() == id)
262 // Update with results of terminated helper build
263 void QtOptionsPageWidget::debuggingHelperBuildFinished(int qtVersionId, const QString &output, DebuggingHelperBuildTask::Tools tools)
265 const int index = findVersionById(m_versions, qtVersionId);
267 return; // Oops, somebody managed to delete the version
269 BaseQtVersion *version = m_versions.at(index);
272 QTreeWidgetItem *item = treeItemForIndex(index);
273 QTC_ASSERT(item, return);
274 DebuggingHelperBuildTask::Tools buildFlags
275 = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
276 buildFlags &= ~tools;
277 item->setData(0, BuildRunningRole, QVariant::fromValue(buildFlags));
278 item->setData(0, BuildLogRole, output);
281 if (tools & DebuggingHelperBuildTask::GdbDebugging)
282 success &= version->hasGdbDebuggingHelper();
283 if (tools & DebuggingHelperBuildTask::QmlDebugging)
284 success &= version->hasQmlDebuggingLibrary();
285 if (tools & DebuggingHelperBuildTask::QmlDump)
286 success &= version->hasQmlDump();
287 if (tools & DebuggingHelperBuildTask::QmlObserver)
288 success &= version->hasQmlObserver();
290 // Update bottom control if the selection is still the same
291 if (index == currentIndex()) {
292 updateDebuggingHelperUi();
296 showDebuggingBuildLog(item);
299 void QtOptionsPageWidget::cleanUpQtVersions()
301 QStringList toRemove;
302 foreach (const BaseQtVersion *v, m_versions) {
303 if (!v->isValid() && !v->isAutodetected())
304 toRemove.append(v->displayName());
307 if (toRemove.isEmpty())
310 if (QMessageBox::warning(0, tr("Remove invalid Qt Versions"),
311 tr("Do you want to remove all invalid Qt Versions?<br>"
312 "<ul><li>%1</li></ul><br>"
313 "will be removed.").arg(toRemove.join(QLatin1String("</li><li>"))),
314 QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
317 for (int i = m_versions.count() - 1; i >= 0; --i) {
318 if (!m_versions.at(i)->isValid()) {
319 QTreeWidgetItem *item = treeItemForIndex(i);
322 delete m_versions.at(i);
323 m_versions.removeAt(i);
326 updateCleanUpButton();
329 void QtOptionsPageWidget::toolChainsUpdated()
331 for (int i = 0; i < m_versions.count(); ++i) {
332 QTreeWidgetItem *item = treeItemForIndex(i);
333 if (item == m_ui->qtdirList->currentItem())
334 updateDescriptionLabel();
336 const ValidityInfo info = validInformation(m_versions.at(i));
337 item->setIcon(0, info.icon);
342 void QtOptionsPageWidget::qtVersionsDumpUpdated(const QString &qmakeCommand)
344 foreach (BaseQtVersion *version, m_versions) {
345 if (version->qmakeCommand() == qmakeCommand)
346 version->recheckDumper();
349 && currentVersion()->qmakeCommand() == qmakeCommand) {
351 updateDescriptionLabel();
352 updateDebuggingHelperUi();
356 QtOptionsPageWidget::ValidityInfo QtOptionsPageWidget::validInformation(const BaseQtVersion *version)
359 info.icon = m_validVersionIcon;
364 if (!version->isValid()) {
365 info.icon = m_invalidVersionIcon;
366 info.message = version->invalidReason();
370 // Do we have tool chain issues?
371 QStringList missingToolChains;
373 foreach (const ProjectExplorer::Abi &a, version->qtAbis()) {
374 // Ignore symbian emulator since we do not support it.
375 if (a.osFlavor() == ProjectExplorer::Abi::SymbianEmulatorFlavor)
377 if (ProjectExplorer::ToolChainManager::instance()->findToolChains(a).isEmpty())
378 missingToolChains.append(a.toString());
382 if (missingToolChains.isEmpty()) {
384 info.message = tr("Qt version %1 for %2").arg(version->qtVersionString(), version->description());
385 } else if (missingToolChains.count() == abiCount) {
386 // Yes, this Qt version can't be used at all!
387 info.message = tr("No tool chain can produce code for this Qt version. Please define one or more tool chains.");
388 info.icon = m_invalidVersionIcon;
390 // Yes, some ABIs are unsupported
391 info.message = tr("Not all possible target environments can be supported due to missing tool chains.");
392 info.toolTip = tr("The following ABIs are currently not supported:<ul><li>%1</li></ul>")
393 .arg(missingToolChains.join(QLatin1String("</li><li>")));
394 info.icon = m_warningVersionIcon;
399 void QtOptionsPageWidget::buildDebuggingHelper(DebuggingHelperBuildTask::Tools tools)
401 const int index = currentIndex();
405 QTreeWidgetItem *item = treeItemForIndex(index);
406 QTC_ASSERT(item, return);
408 DebuggingHelperBuildTask::Tools buildFlags
409 = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
411 item->setData(0, BuildRunningRole, QVariant::fromValue(buildFlags));
413 BaseQtVersion *version = m_versions.at(index);
417 updateDebuggingHelperUi();
419 // Run a debugging helper build task in the background.
420 DebuggingHelperBuildTask *buildTask = new DebuggingHelperBuildTask(version, tools);
421 // Don't open General Messages pane with errors
422 buildTask->showOutputOnError(false);
423 connect(buildTask, SIGNAL(finished(int,QString,DebuggingHelperBuildTask::Tools)),
424 this, SLOT(debuggingHelperBuildFinished(int,QString,DebuggingHelperBuildTask::Tools)),
425 Qt::QueuedConnection);
426 QFuture<void> task = QtConcurrent::run(&DebuggingHelperBuildTask::run, buildTask);
427 const QString taskName = tr("Building helpers");
429 Core::ICore::instance()->progressManager()->addTask(task, taskName,
430 QLatin1String("Qt4ProjectManager::BuildHelpers"));
432 void QtOptionsPageWidget::buildGdbHelper()
434 buildDebuggingHelper(DebuggingHelperBuildTask::GdbDebugging);
437 void QtOptionsPageWidget::buildQmlDump()
439 buildDebuggingHelper(DebuggingHelperBuildTask::QmlDump);
442 void QtOptionsPageWidget::buildQmlDebuggingLibrary()
444 buildDebuggingHelper(DebuggingHelperBuildTask::QmlDebugging);
447 void QtOptionsPageWidget::buildQmlObserver()
449 DebuggingHelperBuildTask::Tools qmlDbgTools =
450 DebuggingHelperBuildTask::QmlObserver;
451 qmlDbgTools |= DebuggingHelperBuildTask::QmlDebugging;
452 buildDebuggingHelper(qmlDbgTools);
456 class BuildLogDialog : public QDialog {
458 explicit BuildLogDialog(QWidget *parent = 0);
459 void setText(const QString &text);
462 Ui_ShowBuildLog m_ui;
465 BuildLogDialog::BuildLogDialog(QWidget *parent) : QDialog(parent)
468 setAttribute(Qt::WA_DeleteOnClose, true);
471 void BuildLogDialog::setText(const QString &text)
473 m_ui.log->setPlainText(text); // Show and scroll to bottom
474 m_ui.log->moveCursor(QTextCursor::End);
475 m_ui.log->ensureCursorVisible();
478 void QtOptionsPageWidget::slotShowDebuggingBuildLog()
480 if (const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
481 showDebuggingBuildLog(currentItem);
484 void QtOptionsPageWidget::showDebuggingBuildLog(const QTreeWidgetItem *currentItem)
486 const int currentItemIndex = indexForTreeItem(currentItem);
487 if (currentItemIndex < 0)
489 BuildLogDialog *dialog = new BuildLogDialog(this);
490 dialog->setWindowTitle(tr("Debugging Helper Build Log for '%1'").arg(currentItem->text(0)));
491 dialog->setText(currentItem->data(0, BuildLogRole).toString());
495 QtOptionsPageWidget::~QtOptionsPageWidget()
499 delete m_debuggingHelperUi;
500 delete m_configurationWidget;
501 qDeleteAll(m_versions);
504 static QString filterForQmakeFileDialog()
506 QString filter("qmake (");
507 foreach (const QString &s, Utils::BuildableHelperLibrary::possibleQMakeCommands()) {
509 // work around QTBUG-7739 that prohibits filters that don't start with *
510 filter += QLatin1Char('*');
512 filter += s + QLatin1Char(' ');
514 filter += QLatin1Char(')');
518 void QtOptionsPageWidget::addQtDir()
520 QString qtVersion = QFileDialog::getOpenFileName(this,
521 tr("Select a qmake executable"),
522 QString(), filterForQmakeFileDialog());
523 if (qtVersion.isNull())
525 if (QtVersionManager::instance()->qtVersionForQMakeBinary(qtVersion)) {
529 BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
531 m_versions.append(version);
533 QTreeWidgetItem *item = new QTreeWidgetItem(m_ui->qtdirList->topLevelItem(1));
534 item->setText(0, version->displayName());
535 item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
536 item->setData(0, VersionIdRole, version->uniqueId());
537 item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
538 m_ui->qtdirList->setCurrentItem(item); // should update the rest of the ui
539 m_versionUi->nameEdit->setFocus();
540 m_versionUi->nameEdit->selectAll();
542 updateCleanUpButton();
545 void QtOptionsPageWidget::removeQtDir()
547 QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
548 int index = indexForTreeItem(item);
554 BaseQtVersion *version = m_versions.at(index);
555 m_versions.removeAt(index);
557 updateCleanUpButton();
560 void QtOptionsPageWidget::editPath()
562 BaseQtVersion *current = currentVersion();
563 QString dir = QFileInfo(currentVersion()->qmakeCommand()).absolutePath();
564 QString qtVersion = QFileDialog::getOpenFileName(this,
565 tr("Select a qmake executable"),
566 dir, filterForQmakeFileDialog());
567 if (qtVersion.isNull())
569 BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
570 // Same type? then replace!
571 if (current->type() != version->type()) {
572 // not the same type, error out
573 QMessageBox::critical(this, tr("Qt versions incompatible"),
574 tr("The qt version selected must be for the same target."),
579 // same type, replace
580 version->setId(current->uniqueId());
581 if (current->displayName() != current->defaultDisplayName(current->qtVersionString(), current->qmakeCommand()))
582 version->setDisplayName(current->displayName());
583 m_versions.replace(m_versions.indexOf(current), version);
587 userChangedCurrentVersion();
588 QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
589 item->setText(0, version->displayName());
590 item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
591 item->setData(0, VersionIdRole, version->uniqueId());
592 item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
595 void QtOptionsPageWidget::updateDebuggingHelperUi()
597 BaseQtVersion *version = currentVersion();
598 const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
600 if (!version || !version->isValid()) {
601 m_ui->debuggingHelperWidget->setVisible(false);
603 const DebuggingHelperBuildTask::Tools availableTools = DebuggingHelperBuildTask::availableTools(version);
604 const bool canBuildGdbHelper = availableTools & DebuggingHelperBuildTask::GdbDebugging;
605 const bool canBuildQmlDumper = availableTools & DebuggingHelperBuildTask::QmlDump;
606 const bool canBuildQmlDebuggingLib = availableTools & DebuggingHelperBuildTask::QmlDebugging;
607 const bool canBuildQmlObserver = availableTools & DebuggingHelperBuildTask::QmlObserver;
609 const bool hasGdbHelper = !version->gdbDebuggingHelperLibrary().isEmpty();
610 const bool hasQmlDumper = version->hasQmlDump();
611 const bool hasQmlDebuggingLib = version->hasQmlDebuggingLibrary();
612 const bool needsQmlDebuggingLib = version->needsQmlDebuggingLibrary();
613 const bool hasQmlObserver = !version->qmlObserverTool().isEmpty();
615 bool isBuildingGdbHelper = false;
616 bool isBuildingQmlDumper = false;
617 bool isBuildingQmlDebuggingLib = false;
618 bool isBuildingQmlObserver = false;
621 DebuggingHelperBuildTask::Tools buildingTools
622 = currentItem->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
623 isBuildingGdbHelper = buildingTools & DebuggingHelperBuildTask::GdbDebugging;
624 isBuildingQmlDumper = buildingTools & DebuggingHelperBuildTask::QmlDump;
625 isBuildingQmlDebuggingLib = buildingTools & DebuggingHelperBuildTask::QmlDebugging;
626 isBuildingQmlObserver = buildingTools & DebuggingHelperBuildTask::QmlObserver;
629 // get names of tools from labels
630 QStringList helperNames;
632 helperNames << m_debuggingHelperUi->gdbHelperLabel->text().remove(':');
634 helperNames << m_debuggingHelperUi->qmlDumpLabel->text().remove(':');
635 if (hasQmlDebuggingLib)
636 helperNames << m_debuggingHelperUi->qmlDebuggingLibLabel->text().remove(':');
638 helperNames << m_debuggingHelperUi->qmlObserverLabel->text().remove(':');
641 if (helperNames.isEmpty()) {
642 status = tr("Helpers: None available");
644 //: %1 is list of tool names.
645 status = tr("Helpers: %1.").arg(helperNames.join(QLatin1String(", ")));
648 m_ui->debuggingHelperWidget->setSummaryText(status);
650 QString gdbHelperText;
651 Qt::TextInteractionFlags gdbHelperTextFlags = Qt::NoTextInteraction;
653 gdbHelperText = QDir::toNativeSeparators(version->gdbDebuggingHelperLibrary());
654 gdbHelperTextFlags = Qt::TextSelectableByMouse;
656 if (canBuildGdbHelper) {
657 gdbHelperText = tr("<i>Not yet built.</i>");
659 gdbHelperText = tr("<i>Not needed.</i>");
662 m_debuggingHelperUi->gdbHelperStatus->setText(gdbHelperText);
663 m_debuggingHelperUi->gdbHelperStatus->setTextInteractionFlags(gdbHelperTextFlags);
664 m_debuggingHelperUi->gdbHelperBuildButton->setEnabled(canBuildGdbHelper && !isBuildingGdbHelper);
666 QString qmlDumpStatusText, qmlDumpStatusToolTip;
667 Qt::TextInteractionFlags qmlDumpStatusTextFlags = Qt::NoTextInteraction;
669 qmlDumpStatusText = QDir::toNativeSeparators(version->qmlDumpTool(false));
670 const QString debugQmlDumpPath = QDir::toNativeSeparators(version->qmlDumpTool(true));
671 if (qmlDumpStatusText != debugQmlDumpPath) {
672 if (!qmlDumpStatusText.isEmpty()
673 && !debugQmlDumpPath.isEmpty())
674 qmlDumpStatusText += QLatin1String("\n");
675 qmlDumpStatusText += debugQmlDumpPath;
677 qmlDumpStatusTextFlags = Qt::TextSelectableByMouse;
679 if (canBuildQmlDumper) {
680 qmlDumpStatusText = tr("<i>Not yet built.</i>");
682 qmlDumpStatusText = tr("<i>Cannot be compiled.</i>");
683 QmlDumpTool::canBuild(version, &qmlDumpStatusToolTip);
686 m_debuggingHelperUi->qmlDumpStatus->setText(qmlDumpStatusText);
687 m_debuggingHelperUi->qmlDumpStatus->setTextInteractionFlags(qmlDumpStatusTextFlags);
688 m_debuggingHelperUi->qmlDumpStatus->setToolTip(qmlDumpStatusToolTip);
689 m_debuggingHelperUi->qmlDumpBuildButton->setEnabled(canBuildQmlDumper & !isBuildingQmlDumper);
691 QString qmlDebuggingLibStatusText, qmlDebuggingLibToolTip;
692 Qt::TextInteractionFlags qmlDebuggingLibStatusTextFlags = Qt::NoTextInteraction;
693 if (hasQmlDebuggingLib) {
694 qmlDebuggingLibStatusText = QDir::toNativeSeparators(
695 version->qmlDebuggingHelperLibrary(false));
696 const QString debugPath = QDir::toNativeSeparators(
697 version->qmlDebuggingHelperLibrary(true));
699 if (qmlDebuggingLibStatusText != debugPath) {
700 if (!qmlDebuggingLibStatusText.isEmpty()
701 && !debugPath.isEmpty()) {
702 qmlDebuggingLibStatusText += QLatin1Char('\n');
704 qmlDebuggingLibStatusText += debugPath;
706 qmlDebuggingLibStatusTextFlags = Qt::TextSelectableByMouse;
708 if (!needsQmlDebuggingLib) {
709 qmlDebuggingLibStatusText = tr("<i>Not needed.</i>");
710 } else if (canBuildQmlDebuggingLib) {
711 qmlDebuggingLibStatusText = tr("<i>Not yet built.</i>");
713 qmlDebuggingLibStatusText = tr("<i>Cannot be compiled.</i>");
714 QmlDebuggingLibrary::canBuild(version, &qmlDebuggingLibToolTip);
717 m_debuggingHelperUi->qmlDebuggingLibStatus->setText(qmlDebuggingLibStatusText);
718 m_debuggingHelperUi->qmlDebuggingLibStatus->setTextInteractionFlags(qmlDebuggingLibStatusTextFlags);
719 m_debuggingHelperUi->qmlDebuggingLibStatus->setToolTip(qmlDebuggingLibToolTip);
720 m_debuggingHelperUi->qmlDebuggingLibBuildButton->setEnabled(needsQmlDebuggingLib
721 && canBuildQmlDebuggingLib
722 && !isBuildingQmlDebuggingLib);
724 QString qmlObserverStatusText, qmlObserverToolTip;
725 Qt::TextInteractionFlags qmlObserverStatusTextFlags = Qt::NoTextInteraction;
726 if (hasQmlObserver) {
727 qmlObserverStatusText = QDir::toNativeSeparators(version->qmlObserverTool());
728 qmlObserverStatusTextFlags = Qt::TextSelectableByMouse;
730 if (!needsQmlDebuggingLib) {
731 qmlObserverStatusText = tr("<i>Not needed.</i>");
732 } else if (canBuildQmlObserver) {
733 qmlObserverStatusText = tr("<i>Not yet built.</i>");
735 qmlObserverStatusText = tr("<i>Cannot be compiled.</i>");
736 QmlObserverTool::canBuild(version, &qmlObserverToolTip);
739 m_debuggingHelperUi->qmlObserverStatus->setText(qmlObserverStatusText);
740 m_debuggingHelperUi->qmlObserverStatus->setTextInteractionFlags(qmlObserverStatusTextFlags);
741 m_debuggingHelperUi->qmlObserverStatus->setToolTip(qmlObserverToolTip);
742 m_debuggingHelperUi->qmlObserverBuildButton->setEnabled(canBuildQmlObserver
743 & !isBuildingQmlObserver);
745 const bool hasLog = currentItem && !currentItem->data(0, BuildLogRole).toString().isEmpty();
746 m_debuggingHelperUi->showLogButton->setEnabled(hasLog);
748 m_debuggingHelperUi->rebuildButton->setEnabled((!isBuildingGdbHelper
749 && !isBuildingQmlDumper
750 && !isBuildingQmlDebuggingLib
751 && !isBuildingQmlObserver)
752 && (canBuildGdbHelper
754 || (canBuildQmlDebuggingLib && needsQmlDebuggingLib)
755 || canBuildQmlObserver));
757 m_ui->debuggingHelperWidget->setVisible(true);
761 // To be called if a qt version was removed or added
762 void QtOptionsPageWidget::updateCleanUpButton()
764 bool hasInvalidVersion = false;
765 for (int i = 0; i < m_versions.count(); ++i) {
766 if (!m_versions.at(i)->isValid()) {
767 hasInvalidVersion = true;
771 m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
774 void QtOptionsPageWidget::userChangedCurrentVersion()
777 updateDescriptionLabel();
778 updateDebuggingHelperUi();
781 void QtOptionsPageWidget::qtVersionChanged()
783 updateDescriptionLabel();
784 updateDebuggingHelperUi();
787 void QtOptionsPageWidget::updateDescriptionLabel()
789 QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
790 const ValidityInfo info = validInformation(currentVersion());
791 m_versionUi->errorLabel->setText(info.message);
792 m_versionUi->errorLabel->setToolTip(info.toolTip);
794 item->setIcon(0, info.icon);
797 int QtOptionsPageWidget::indexForTreeItem(const QTreeWidgetItem *item) const
799 if (!item || !item->parent())
801 const int uniqueId = item->data(0, VersionIdRole).toInt();
802 for (int index = 0; index < m_versions.size(); ++index) {
803 if (m_versions.at(index)->uniqueId() == uniqueId)
809 QTreeWidgetItem *QtOptionsPageWidget::treeItemForIndex(int index) const
811 const int uniqueId = m_versions.at(index)->uniqueId();
812 for (int i = 0; i < m_ui->qtdirList->topLevelItemCount(); ++i) {
813 QTreeWidgetItem *toplevelItem = m_ui->qtdirList->topLevelItem(i);
814 for (int j = 0; j < toplevelItem->childCount(); ++j) {
815 QTreeWidgetItem *item = toplevelItem->child(j);
816 if (item->data(0, VersionIdRole).toInt() == uniqueId) {
824 void QtOptionsPageWidget::versionChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *old)
828 fixQtVersionName(indexForTreeItem(old));
829 userChangedCurrentVersion();
832 void QtOptionsPageWidget::updateWidgets()
834 delete m_configurationWidget;
835 m_configurationWidget = 0;
836 BaseQtVersion *version = currentVersion();
838 m_versionUi->nameEdit->setText(version->displayName());
839 m_versionUi->qmakePath->setText(QDir::toNativeSeparators(version->qmakeCommand()));
840 m_configurationWidget = version->createConfigurationWidget();
841 if (m_configurationWidget) {
842 m_versionUi->formLayout->addRow(m_configurationWidget);
843 m_configurationWidget->setEnabled(!version->isAutodetected());
844 connect(m_configurationWidget, SIGNAL(changed()),
845 this, SLOT(qtVersionChanged()));
848 m_versionUi->nameEdit->clear();
849 m_versionUi->qmakePath->setText(QString()); // clear()
852 const bool enabled = version != 0;
853 const bool isAutodetected = enabled && version->isAutodetected();
854 m_ui->delButton->setEnabled(enabled && !isAutodetected);
855 m_versionUi->nameEdit->setEnabled(enabled && !isAutodetected);
856 m_versionUi->editPathPushButton->setEnabled(enabled && !isAutodetected);
859 void QtOptionsPageWidget::updateCurrentQtName()
861 QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
862 Q_ASSERT(currentItem);
863 int currentItemIndex = indexForTreeItem(currentItem);
864 if (currentItemIndex < 0)
866 m_versions[currentItemIndex]->setDisplayName(m_versionUi->nameEdit->text());
867 currentItem->setText(0, m_versions[currentItemIndex]->displayName());
868 updateDescriptionLabel();
872 void QtOptionsPageWidget::finish()
874 if (QTreeWidgetItem *item = m_ui->qtdirList->currentItem())
875 fixQtVersionName(indexForTreeItem(item));
878 /* Checks that the qt version name is unique
879 * and otherwise changes the name
882 void QtOptionsPageWidget::fixQtVersionName(int index)
886 int count = m_versions.count();
887 QString name = m_versions.at(index)->displayName();
890 for (int i = 0; i < count; ++i) {
892 if (m_versions.at(i)->displayName() == m_versions.at(index)->displayName()) {
893 // Same name, find new name
894 QRegExp regexp("^(.*)\\((\\d)\\)$");
895 if (regexp.exactMatch(name)) {
896 // Already in Name (#) format
897 name = regexp.cap(1);
898 name += QLatin1Char('(');
899 name += QString::number(regexp.cap(2).toInt() + 1);
900 name += QLatin1Char(')');
902 name += QLatin1String(" (2)");
905 m_versions[index]->setDisplayName(name);
906 treeItemForIndex(index)->setText(0, name);
908 // Now check again...
909 fixQtVersionName(index);
915 QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
917 QList<BaseQtVersion *> result;
918 for (int i = 0; i < m_versions.count(); ++i)
919 result.append(m_versions.at(i)->clone());
923 QString QtOptionsPageWidget::searchKeywords() const
926 QLatin1Char sep(' ');
928 ts << sep << m_versionUi->versionNameLabel->text()
929 << sep << m_versionUi->pathLabel->text()
930 << sep << m_debuggingHelperUi->gdbHelperLabel->text()
931 << sep << m_debuggingHelperUi->qmlDumpLabel->text()
932 << sep << m_debuggingHelperUi->qmlObserverLabel->text();
934 // Symbian specific, could be factored out to the factory
935 // checking m_configurationWidget is not enough, we want them to be a keyword
936 // regardless of which qt versions configuration widget is currently active
937 ts << sep << tr("S60 SDK:")
938 << sep << tr("SBS v2 directory:");
941 rc.remove(QLatin1Char('&'));