OSDN Git Service

Fix original string messages
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qtsupport / qtoptionspage.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
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.
18 **
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.
22 **
23 ** Other Usage
24 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
30 **
31 **************************************************************************/
32
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"
44
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>
53
54 #include <QtCore/QDir>
55 #include <QtGui/QToolTip>
56 #include <QtGui/QMessageBox>
57 #include <QtGui/QFileDialog>
58 #include <QtGui/QMainWindow>
59
60 enum ModelRoles { VersionIdRole = Qt::UserRole, BuildLogRole, BuildRunningRole};
61
62 using namespace QtSupport;
63 using namespace QtSupport::Internal;
64
65 ///
66 // QtOptionsPage
67 ///
68
69 QtOptionsPage::QtOptionsPage()
70     : m_widget(0)
71 {
72 }
73
74 QString QtOptionsPage::id() const
75 {
76     return QLatin1String(Constants::QTVERSION_SETTINGS_PAGE_ID);
77 }
78
79 QString QtOptionsPage::displayName() const
80 {
81     return QCoreApplication::translate("Qt4ProjectManager", Constants::QTVERSION_SETTINGS_PAGE_NAME);
82 }
83
84 QString QtOptionsPage::category() const
85 {
86     return QLatin1String(Constants::QT_SETTINGS_CATEGORY);
87 }
88
89 QString QtOptionsPage::displayCategory() const
90 {
91     return QCoreApplication::translate("Qt4ProjectManager", Constants::QT_SETTINGS_TR_CATEGORY);
92 }
93
94 QIcon QtOptionsPage::categoryIcon() const
95 {
96     return QIcon(QLatin1String(Constants::QT_SETTINGS_CATEGORY_ICON));
97 }
98
99 QWidget *QtOptionsPage::createPage(QWidget *parent)
100 {
101     QtVersionManager *vm = QtVersionManager::instance();
102     m_widget = new QtOptionsPageWidget(parent, vm->versions());
103     if (m_searchKeywords.isEmpty())
104         m_searchKeywords = m_widget->searchKeywords();
105     return m_widget;
106 }
107
108 void QtOptionsPage::apply()
109 {
110     if (!m_widget) // page was never shown
111         return;
112     m_widget->finish();
113
114     QtVersionManager *vm = QtVersionManager::instance();
115     vm->setNewQtVersions(m_widget->versions());
116 }
117
118 bool QtOptionsPage::matches(const QString &s) const
119 {
120     return m_searchKeywords.contains(s, Qt::CaseInsensitive);
121 }
122
123 //-----------------------------------------------------
124
125
126 QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent, QList<BaseQtVersion *> versions)
127     : QWidget(parent)
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)
135 {
136     // Initialize m_versions
137     foreach (BaseQtVersion *version, versions)
138         m_versions.push_back(version->clone());
139
140     QWidget *versionInfoWidget = new QWidget();
141     m_versionUi->setupUi(versionInfoWidget);
142     m_versionUi->editPathPushButton->setText(tr(Utils::PathChooser::browseButtonLabel));
143
144     QWidget *debuggingHelperDetailsWidget = new QWidget();
145     m_debuggingHelperUi->setupUi(debuggingHelperDetailsWidget);
146
147     m_ui->setupUi(this);
148
149     m_ui->versionInfoWidget->setWidget(versionInfoWidget);
150     m_ui->versionInfoWidget->setState(Utils::DetailsWidget::NoSummary);
151
152     m_ui->debuggingHelperWidget->setWidget(debuggingHelperDetailsWidget);
153
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);
167
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);
176     }
177     m_ui->qtdirList->expandAll();
178
179     connect(m_versionUi->nameEdit, SIGNAL(textEdited(const QString &)),
180             this, SLOT(updateCurrentQtName()));
181
182     connect(m_versionUi->editPathPushButton, SIGNAL(clicked()),
183             this, SLOT(editPath()));
184
185     connect(m_ui->addButton, SIGNAL(clicked()),
186             this, SLOT(addQtDir()));
187     connect(m_ui->delButton, SIGNAL(clicked()),
188             this, SLOT(removeQtDir()));
189
190     connect(m_ui->qtdirList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
191             this, SLOT(versionChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
192
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()));
203
204     connect(m_debuggingHelperUi->showLogButton, SIGNAL(clicked()),
205             this, SLOT(slotShowDebuggingBuildLog()));
206
207     connect(m_ui->cleanUpButton, SIGNAL(clicked()), this, SLOT(cleanUpQtVersions()));
208     userChangedCurrentVersion();
209     updateCleanUpButton();
210
211     connect(QtVersionManager::instance(), SIGNAL(dumpUpdatedFor(QString)),
212             this, SLOT(qtVersionsDumpUpdated(QString)));
213
214     connect(ProjectExplorer::ToolChainManager::instance(), SIGNAL(toolChainsChanged()),
215             this, SLOT(toolChainsUpdated()));
216 }
217
218 bool QtOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
219 {
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)
223         return false;
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);
227     if (!item)
228         return false;
229     const int index = indexForTreeItem(item);
230     if (index == -1)
231         return false;
232     const QString tooltip = m_versions.at(index)->toHtml(true);
233     QToolTip::showText(helpEvent->globalPos(), tooltip, m_ui->qtdirList);
234     helpEvent->accept();
235     return true;
236 }
237
238 int QtOptionsPageWidget::currentIndex() const
239 {
240     if (QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
241         return indexForTreeItem(currentItem);
242     return -1;
243 }
244
245 BaseQtVersion *QtOptionsPageWidget::currentVersion() const
246 {
247     const int currentItemIndex = currentIndex();
248     if (currentItemIndex >= 0 && currentItemIndex < m_versions.size())
249         return m_versions.at(currentItemIndex);
250     return 0;
251 }
252
253 static inline int findVersionById(const QList<BaseQtVersion *> &l, int id)
254 {
255     const int size = l.size();
256     for (int i = 0; i < size; i++)
257         if (l.at(i)->uniqueId() == id)
258             return i;
259     return -1;
260 }
261
262 // Update with results of terminated helper build
263 void QtOptionsPageWidget::debuggingHelperBuildFinished(int qtVersionId, const QString &output, DebuggingHelperBuildTask::Tools tools)
264 {
265     const int index = findVersionById(m_versions, qtVersionId);
266     if (index == -1)
267         return; // Oops, somebody managed to delete the version
268
269     BaseQtVersion *version = m_versions.at(index);
270
271     // Update item view
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);
279
280     bool success = true;
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();
289
290     // Update bottom control if the selection is still the same
291     if (index == currentIndex()) {
292         updateDebuggingHelperUi();
293     }
294
295     if (!success)
296         showDebuggingBuildLog(item);
297 }
298
299 void QtOptionsPageWidget::cleanUpQtVersions()
300 {
301     QStringList toRemove;
302     foreach (const BaseQtVersion *v, m_versions) {
303         if (!v->isValid() && !v->isAutodetected())
304             toRemove.append(v->displayName());
305     }
306
307     if (toRemove.isEmpty())
308         return;
309
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)
315         return;
316
317     for (int i = m_versions.count() - 1; i >= 0; --i) {
318         if (!m_versions.at(i)->isValid()) {
319             QTreeWidgetItem *item = treeItemForIndex(i);
320             delete item;
321
322             delete m_versions.at(i);
323             m_versions.removeAt(i);
324         }
325     }
326     updateCleanUpButton();
327 }
328
329 void QtOptionsPageWidget::toolChainsUpdated()
330 {
331     for (int i = 0; i < m_versions.count(); ++i) {
332         QTreeWidgetItem *item = treeItemForIndex(i);
333         if (item == m_ui->qtdirList->currentItem())
334             updateDescriptionLabel();
335         else {
336             const ValidityInfo info = validInformation(m_versions.at(i));
337             item->setIcon(0, info.icon);
338         }
339     }
340 }
341
342 void QtOptionsPageWidget::qtVersionsDumpUpdated(const QString &qmakeCommand)
343 {
344     foreach (BaseQtVersion *version, m_versions) {
345         if (version->qmakeCommand() == qmakeCommand)
346             version->recheckDumper();
347     }
348     if (currentVersion()
349             && currentVersion()->qmakeCommand() == qmakeCommand) {
350         updateWidgets();
351         updateDescriptionLabel();
352         updateDebuggingHelperUi();
353     }
354 }
355
356 QtOptionsPageWidget::ValidityInfo QtOptionsPageWidget::validInformation(const BaseQtVersion *version)
357 {
358     ValidityInfo info;
359     info.icon = m_validVersionIcon;
360
361     if (!version)
362         return info;
363
364     if (!version->isValid()) {
365         info.icon = m_invalidVersionIcon;
366         info.message = version->invalidReason();
367         return info;
368     }
369
370     // Do we have tool chain issues?
371     QStringList missingToolChains;
372     int abiCount = 0;
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)
376             continue;
377         if (ProjectExplorer::ToolChainManager::instance()->findToolChains(a).isEmpty())
378             missingToolChains.append(a.toString());
379         ++abiCount;
380     }
381
382     if (missingToolChains.isEmpty()) {
383         // No:
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;
389     } else {
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;
395     }
396     return info;
397 }
398
399 void QtOptionsPageWidget::buildDebuggingHelper(DebuggingHelperBuildTask::Tools tools)
400 {
401     const int index = currentIndex();
402     if (index < 0)
403         return;
404
405     QTreeWidgetItem *item = treeItemForIndex(index);
406     QTC_ASSERT(item, return);
407
408     DebuggingHelperBuildTask::Tools buildFlags
409             = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
410     buildFlags |= tools;
411     item->setData(0, BuildRunningRole, QVariant::fromValue(buildFlags));
412
413     BaseQtVersion *version = m_versions.at(index);
414     if (!version)
415         return;
416
417     updateDebuggingHelperUi();
418
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");
428
429     Core::ICore::instance()->progressManager()->addTask(task, taskName,
430                                                         QLatin1String("Qt4ProjectManager::BuildHelpers"));
431 }
432 void QtOptionsPageWidget::buildGdbHelper()
433 {
434     buildDebuggingHelper(DebuggingHelperBuildTask::GdbDebugging);
435 }
436
437 void QtOptionsPageWidget::buildQmlDump()
438 {
439     buildDebuggingHelper(DebuggingHelperBuildTask::QmlDump);
440 }
441
442 void QtOptionsPageWidget::buildQmlDebuggingLibrary()
443 {
444     buildDebuggingHelper(DebuggingHelperBuildTask::QmlDebugging);
445 }
446
447 void QtOptionsPageWidget::buildQmlObserver()
448 {
449     DebuggingHelperBuildTask::Tools qmlDbgTools =
450             DebuggingHelperBuildTask::QmlObserver;
451     qmlDbgTools |= DebuggingHelperBuildTask::QmlDebugging;
452     buildDebuggingHelper(qmlDbgTools);
453 }
454
455 // Non-modal dialog
456 class BuildLogDialog : public QDialog {
457 public:
458     explicit BuildLogDialog(QWidget *parent = 0);
459     void setText(const QString &text);
460
461 private:
462     Ui_ShowBuildLog m_ui;
463 };
464
465 BuildLogDialog::BuildLogDialog(QWidget *parent) : QDialog(parent)
466 {
467     m_ui.setupUi(this);
468     setAttribute(Qt::WA_DeleteOnClose, true);
469 }
470
471 void BuildLogDialog::setText(const QString &text)
472 {
473     m_ui.log->setPlainText(text); // Show and scroll to bottom
474     m_ui.log->moveCursor(QTextCursor::End);
475     m_ui.log->ensureCursorVisible();
476 }
477
478 void QtOptionsPageWidget::slotShowDebuggingBuildLog()
479 {
480     if (const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
481         showDebuggingBuildLog(currentItem);
482 }
483
484 void QtOptionsPageWidget::showDebuggingBuildLog(const QTreeWidgetItem *currentItem)
485 {
486     const int currentItemIndex = indexForTreeItem(currentItem);
487     if (currentItemIndex < 0)
488         return;
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());
492     dialog->show();
493 }
494
495 QtOptionsPageWidget::~QtOptionsPageWidget()
496 {
497     delete m_ui;
498     delete m_versionUi;
499     delete m_debuggingHelperUi;
500     delete m_configurationWidget;
501     qDeleteAll(m_versions);
502 }
503
504 static QString filterForQmakeFileDialog()
505 {
506     QString filter("qmake (");
507     foreach (const QString &s, Utils::BuildableHelperLibrary::possibleQMakeCommands()) {
508 #ifdef Q_WS_MAC
509         // work around QTBUG-7739 that prohibits filters that don't start with *
510         filter += QLatin1Char('*');
511 #endif
512         filter += s + QLatin1Char(' ');
513     }
514     filter += QLatin1Char(')');
515     return filter;
516 }
517
518 void QtOptionsPageWidget::addQtDir()
519 {
520     QString qtVersion = QFileDialog::getOpenFileName(this,
521                                                      tr("Select a qmake executable"),
522                                                      QString(), filterForQmakeFileDialog());
523     if (qtVersion.isNull())
524         return;
525     if (QtVersionManager::instance()->qtVersionForQMakeBinary(qtVersion)) {
526         // Already exist
527     }
528
529     BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
530     if (version) {
531         m_versions.append(version);
532
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();
541     }
542     updateCleanUpButton();
543 }
544
545 void QtOptionsPageWidget::removeQtDir()
546 {
547     QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
548     int index = indexForTreeItem(item);
549     if (index < 0)
550         return;
551
552     delete item;
553
554     BaseQtVersion *version = m_versions.at(index);
555     m_versions.removeAt(index);
556     delete version;
557     updateCleanUpButton();
558 }
559
560 void QtOptionsPageWidget::editPath()
561 {
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())
568         return;
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."),
575                               QMessageBox::Ok);
576         delete version;
577         return;
578     }
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);
584     delete current;
585
586     // Update ui
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);
593 }
594
595 void QtOptionsPageWidget::updateDebuggingHelperUi()
596 {
597     BaseQtVersion *version = currentVersion();
598     const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
599
600     if (!version || !version->isValid()) {
601         m_ui->debuggingHelperWidget->setVisible(false);
602     } else {
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;
608
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();
614
615         bool isBuildingGdbHelper = false;
616         bool isBuildingQmlDumper = false;
617         bool isBuildingQmlDebuggingLib = false;
618         bool isBuildingQmlObserver = false;
619
620         if (currentItem) {
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;
627         }
628
629         // get names of tools from labels
630         QStringList helperNames;
631         if (hasGdbHelper)
632             helperNames << m_debuggingHelperUi->gdbHelperLabel->text().remove(':');
633         if (hasQmlDumper)
634             helperNames << m_debuggingHelperUi->qmlDumpLabel->text().remove(':');
635         if (hasQmlDebuggingLib)
636             helperNames << m_debuggingHelperUi->qmlDebuggingLibLabel->text().remove(':');
637         if (hasQmlObserver)
638             helperNames << m_debuggingHelperUi->qmlObserverLabel->text().remove(':');
639
640         QString status;
641         if (helperNames.isEmpty()) {
642             status = tr("Helpers: None available");
643         } else {
644             //: %1 is list of tool names.
645             status = tr("Helpers: %1.").arg(helperNames.join(QLatin1String(", ")));
646         }
647
648         m_ui->debuggingHelperWidget->setSummaryText(status);
649
650         QString gdbHelperText;
651         Qt::TextInteractionFlags gdbHelperTextFlags = Qt::NoTextInteraction;
652         if (hasGdbHelper) {
653             gdbHelperText = QDir::toNativeSeparators(version->gdbDebuggingHelperLibrary());
654             gdbHelperTextFlags = Qt::TextSelectableByMouse;
655         } else {
656             if (canBuildGdbHelper) {
657                 gdbHelperText =  tr("<i>Not yet built.</i>");
658             } else {
659                 gdbHelperText =  tr("<i>Not needed.</i>");
660             }
661         }
662         m_debuggingHelperUi->gdbHelperStatus->setText(gdbHelperText);
663         m_debuggingHelperUi->gdbHelperStatus->setTextInteractionFlags(gdbHelperTextFlags);
664         m_debuggingHelperUi->gdbHelperBuildButton->setEnabled(canBuildGdbHelper && !isBuildingGdbHelper);
665
666         QString qmlDumpStatusText, qmlDumpStatusToolTip;
667         Qt::TextInteractionFlags qmlDumpStatusTextFlags = Qt::NoTextInteraction;
668         if (hasQmlDumper) {
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;
676             }
677             qmlDumpStatusTextFlags = Qt::TextSelectableByMouse;
678         } else {
679             if (canBuildQmlDumper) {
680                 qmlDumpStatusText = tr("<i>Not yet built.</i>");
681             } else {
682                 qmlDumpStatusText = tr("<i>Cannot be compiled.</i>");
683                 QmlDumpTool::canBuild(version, &qmlDumpStatusToolTip);
684             }
685         }
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);
690
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));
698
699             if (qmlDebuggingLibStatusText != debugPath) {
700                 if (!qmlDebuggingLibStatusText.isEmpty()
701                         && !debugPath.isEmpty()) {
702                     qmlDebuggingLibStatusText += QLatin1Char('\n');
703                 }
704                 qmlDebuggingLibStatusText += debugPath;
705             }
706             qmlDebuggingLibStatusTextFlags = Qt::TextSelectableByMouse;
707         } else {
708             if (!needsQmlDebuggingLib) {
709                 qmlDebuggingLibStatusText = tr("<i>Not needed.</i>");
710             } else if (canBuildQmlDebuggingLib) {
711                 qmlDebuggingLibStatusText = tr("<i>Not yet built.</i>");
712             } else {
713                 qmlDebuggingLibStatusText = tr("<i>Cannot be compiled.</i>");
714                 QmlDebuggingLibrary::canBuild(version, &qmlDebuggingLibToolTip);
715             }
716         }
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);
723
724         QString qmlObserverStatusText, qmlObserverToolTip;
725         Qt::TextInteractionFlags qmlObserverStatusTextFlags = Qt::NoTextInteraction;
726         if (hasQmlObserver) {
727             qmlObserverStatusText = QDir::toNativeSeparators(version->qmlObserverTool());
728             qmlObserverStatusTextFlags = Qt::TextSelectableByMouse;
729         }  else {
730             if (!needsQmlDebuggingLib) {
731                 qmlObserverStatusText = tr("<i>Not needed.</i>");
732             } else if (canBuildQmlObserver) {
733                 qmlObserverStatusText = tr("<i>Not yet built.</i>");
734             } else {
735                 qmlObserverStatusText = tr("<i>Cannot be compiled.</i>");
736                 QmlObserverTool::canBuild(version, &qmlObserverToolTip);
737             }
738         }
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);
744
745         const bool hasLog = currentItem && !currentItem->data(0, BuildLogRole).toString().isEmpty();
746         m_debuggingHelperUi->showLogButton->setEnabled(hasLog);
747
748         m_debuggingHelperUi->rebuildButton->setEnabled((!isBuildingGdbHelper
749                                                         && !isBuildingQmlDumper
750                                                         && !isBuildingQmlDebuggingLib
751                                                         && !isBuildingQmlObserver)
752                                                        && (canBuildGdbHelper
753                                                            || canBuildQmlDumper
754                                                            || (canBuildQmlDebuggingLib && needsQmlDebuggingLib)
755                                                            || canBuildQmlObserver));
756
757         m_ui->debuggingHelperWidget->setVisible(true);
758     }
759 }
760
761 // To be called if a qt version was removed or added
762 void QtOptionsPageWidget::updateCleanUpButton()
763 {
764     bool hasInvalidVersion = false;
765     for (int i = 0; i < m_versions.count(); ++i) {
766         if (!m_versions.at(i)->isValid()) {
767             hasInvalidVersion = true;
768             break;
769         }
770     }
771     m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
772 }
773
774 void QtOptionsPageWidget::userChangedCurrentVersion()
775 {
776     updateWidgets();
777     updateDescriptionLabel();
778     updateDebuggingHelperUi();
779 }
780
781 void QtOptionsPageWidget::qtVersionChanged()
782 {
783     updateDescriptionLabel();
784     updateDebuggingHelperUi();
785 }
786
787 void QtOptionsPageWidget::updateDescriptionLabel()
788 {
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);
793     if (item)
794         item->setIcon(0, info.icon);
795 }
796
797 int QtOptionsPageWidget::indexForTreeItem(const QTreeWidgetItem *item) const
798 {
799     if (!item || !item->parent())
800         return -1;
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)
804             return index;
805     }
806     return -1;
807 }
808
809 QTreeWidgetItem *QtOptionsPageWidget::treeItemForIndex(int index) const
810 {
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) {
817                 return item;
818             }
819         }
820     }
821     return 0;
822 }
823
824 void QtOptionsPageWidget::versionChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *old)
825 {
826     Q_UNUSED(newItem)
827     if (old)
828         fixQtVersionName(indexForTreeItem(old));
829     userChangedCurrentVersion();
830 }
831
832 void QtOptionsPageWidget::updateWidgets()
833 {
834     delete m_configurationWidget;
835     m_configurationWidget = 0;
836     BaseQtVersion *version = currentVersion();
837     if (version) {
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()));
846         }
847     } else {
848         m_versionUi->nameEdit->clear();
849         m_versionUi->qmakePath->setText(QString()); // clear()
850     }
851
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);
857 }
858
859 void QtOptionsPageWidget::updateCurrentQtName()
860 {
861     QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
862     Q_ASSERT(currentItem);
863     int currentItemIndex = indexForTreeItem(currentItem);
864     if (currentItemIndex < 0)
865         return;
866     m_versions[currentItemIndex]->setDisplayName(m_versionUi->nameEdit->text());
867     currentItem->setText(0, m_versions[currentItemIndex]->displayName());
868     updateDescriptionLabel();
869 }
870
871
872 void QtOptionsPageWidget::finish()
873 {
874     if (QTreeWidgetItem *item = m_ui->qtdirList->currentItem())
875         fixQtVersionName(indexForTreeItem(item));
876 }
877
878 /* Checks that the qt version name is unique
879  * and otherwise changes the name
880  *
881  */
882 void QtOptionsPageWidget::fixQtVersionName(int index)
883 {
884     if (index < 0)
885         return;
886     int count = m_versions.count();
887     QString name = m_versions.at(index)->displayName();
888     if (name.isEmpty())
889         return;
890     for (int i = 0; i < count; ++i) {
891         if (i != index) {
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(')');
901                 } else {
902                     name +=  QLatin1String(" (2)");
903                 }
904                 // set new name
905                 m_versions[index]->setDisplayName(name);
906                 treeItemForIndex(index)->setText(0, name);
907
908                 // Now check again...
909                 fixQtVersionName(index);
910             }
911         }
912     }
913 }
914
915 QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
916 {
917     QList<BaseQtVersion *> result;
918     for (int i = 0; i < m_versions.count(); ++i)
919         result.append(m_versions.at(i)->clone());
920     return result;
921 }
922
923 QString QtOptionsPageWidget::searchKeywords() const
924 {
925     QString rc;
926     QLatin1Char sep(' ');
927     QTextStream ts(&rc);
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();
933
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:");
939
940
941     rc.remove(QLatin1Char('&'));
942     return rc;
943 }