diff --git a/dist/changes-3.1.0 b/dist/changes-3.1.0 index e60625d25e5e39c06ba49950a1f9ae09a3b8783f..dec584e72bae18496577f0317f53157e310ba88f 100644 --- a/dist/changes-3.1.0 +++ b/dist/changes-3.1.0 @@ -26,6 +26,7 @@ Editing Managing and Building Projects * Re-added option to import existing builds even after project configuration (QTCREATORBUG-7836) * Fixed that compiler output in issues list was not using monospace font (QTCREATORBUG-11345) + * Fixed crash when removing run configuration that was about to be run (QTCREATORBUG-11594) QMake Projects * Added context menu item "Add Existing Directory" that adds all @@ -46,20 +47,24 @@ Debugging * Removed support for GDB without Python * Added context menu item for saving backtrace as tasks-file * GDB, LLDB - * Added pretty printer for std::unordered_set + * Added pretty printers for std::unordered_set and boost::container::list * Fixed various pretty printers * CDB * Added pretty printer for std::complex and C++11 std::array * LLDB + * Added support for debugging applications that run in terminal (QTCREATORBUG-9650) + * Added support for "Create Full Backtrace" (QTCREATORBUG-11642) * Fixed that debugging was not possible with MallocScribble environment variable set (QTCREATORBUG-11371) * Fixed "Jump to Line", "Run to Line" and "Jump to Address" + * Fixed updating breakpoint locations while debugging (QTCREATORBUG-11564) QML Profiler * Improved performance (QTCREATORBUG-10950) * Improved layout of details views * Added JavaScript calls in Events view and Timeline view * Fixed opening files from JavaScript profiling output (QTCREATORBUG-11094) + * Fixed hovering over narrow items in Timeline view (QTCREATORBUG-11692) C++ Support * Added code model inspector @@ -72,6 +77,7 @@ C++ Support * Fixed syntax highlighting of multiline strings and comments (QTCREATORBUG-662) * Fixed that symbol dropdown was jumping to the wrong editor (QTCREATORBUG-11157) * Fixed highlighting when #undef is used (QTCREATORBUG-10454) + * Fixed issue with follow symbol and overloaded functions (QTCREATORBUG-10295) * Improved the Insert Virtual Functions refactoring action: * Check only pure virtual functions by default * Display all overrides of a function @@ -131,6 +137,7 @@ QNX * Added support for attaching debugger to running applications * Fixed several issues with certificate password dialog in BlackBerry options (QTCREATORBUG-10948) + * Fixed mkspec setting in the qmake build step (QTCREATORBUG-11674) Android * Made it possible to cancel waiting for an AVD to boot up @@ -146,9 +153,14 @@ Android * Fixed that Qt Creator restart was required after configuring Android SDK (QTCREATORBUG-10936) iOS + * Enabled iOS support by default + * Added support for QML debugging * Added check for already running application on device * Added automatic detection that developer mode becomes activated on connected device +WinRT + * Added experimental support + Credits for these changes go to: Alessandro Portale diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index f51cfaa01db53a5af2dace856a84b0b4fa454a61..ca4b96578373540cfb4ccb26852f7720f995815e 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -7213,7 +7213,7 @@ Add, modify, and remove document filters, which determine the documentation set </message> <message> <source>Error while building/deploying project %1 (kit: %2)</source> - <translation>Fehler beim Erstellen/Deployment des Projekts %1(Kit: %2)</translation> + <translation>Fehler beim Erstellen/Deployment des Projekts %1 (Kit: %2)</translation> </message> <message> <source>When executing step '%1'</source> diff --git a/share/qtcreator/welcomescreen/examples.qml b/share/qtcreator/welcomescreen/examples.qml index 53d77a0d3bf7f2f599856ba7b057595114f7271c..5dc5d53bde68a83c13274863742c0384e114756c 100644 --- a/share/qtcreator/welcomescreen/examples.qml +++ b/share/qtcreator/welcomescreen/examples.qml @@ -56,8 +56,13 @@ Rectangle { anchors.right: parent.right anchors.leftMargin: 18 + text: examplesModel.readSearchStringsFromSettings() + placeholderText: qsTr("Search in Examples...") - onTextChanged: examplesModel.parseSearchString(text) + onTextChanged: { + examplesModel.parseSearchString(text); + examplesModel.writeSearchStringToSettings(text); + } } ComboBox { diff --git a/share/qtcreator/welcomescreen/widgets/SideBar.qml b/share/qtcreator/welcomescreen/widgets/SideBar.qml index a3abe54fe72cc2673a17c1ddd9922dacb54523c0..5cb9b5e2a19036c417fbd94f11a8f9fe2102046b 100644 --- a/share/qtcreator/welcomescreen/widgets/SideBar.qml +++ b/share/qtcreator/welcomescreen/widgets/SideBar.qml @@ -140,7 +140,7 @@ ColumnLayout { IconAndLink { iconSource: "images/icons/qt_cloud.png" title: qsTr("Qt Cloud Services") - openUrl: "https://developer.qtc.io?utm_source=qtcreator31" + openUrl: "https://developer.qtcloudservices.com?utm_source=qtcreator31" } IconAndLink { iconSource: "images/icons/onlineCommunity.png" diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 89b52fde81d9afea6b0802582a2f9eecea4fc1d0..e514199616e7cf52d7083bbda3ea7042eede755c 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1763,6 +1763,13 @@ void GdbEngine::handlePythonSetup(const GdbResponse &response) showMessage(_("ENGINE SUCCESSFULLY STARTED")); notifyEngineSetupOk(); } else { + QByteArray msg = response.data["msg"].data(); + if (msg.contains("Python scripting is not supported in this copy of GDB.")) { + QString out1 = _("The selected build of GDB does not support Python scripting."); + QString out2 = _("It cannot be used in Qt Creator."); + showStatusMessage(out1 + QLatin1Char(' ') + out2); + showMessageBox(QMessageBox::Critical, tr("Execution Error"), out1 + _("<br>") + out2); + } notifyEngineSetupFailed(); } } diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 756121aeef2e113910a35c482c33e96f0841c847..1ec80f51079cd4483c59f07270ecd47242e578f5 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -2123,6 +2123,7 @@ void FakeVimPluginPrivate::showExtraInformation(const QString &text) IEditor *iedit = EditorManager::openEditorWithContents(Id(), &title, text.toUtf8()); EditorManager::activateEditor(iedit); FakeVimHandler *handler = m_editorToHandler.value(iedit, 0); + QTC_ASSERT(handler, return); handler->handleCommand(_("0")); } diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp index f71c1892cc9d1210ef3166735383ed8f4ec774e2..3964f8f8e078a65466391b73076a2e41bcbc95ae 100644 --- a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp +++ b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp @@ -243,17 +243,11 @@ bool AbstractMsvcToolChain::generateEnvironmentSettings(Utils::Environment &env, const QString &batchArgs, QMap<QString, QString> &envPairs) { + const QByteArray marker = "####################\r\n"; // Create a temporary file name for the output. Use a temporary file here // as I don't know another way to do this in Qt... // Note, can't just use a QTemporaryFile all the way through as it remains open // internally so it can't be streamed to later. - QString tempOutFile; - QTemporaryFile* pVarsTempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/XXXXXX.txt")); - pVarsTempFile->setAutoRemove(false); - pVarsTempFile->open(); - pVarsTempFile->close(); - tempOutFile = pVarsTempFile->fileName(); - delete pVarsTempFile; // Create a batch file to create and save the env settings Utils::TempFileSaver saver(QDir::tempPath() + QLatin1String("/XXXXXX.bat")); @@ -265,10 +259,9 @@ bool AbstractMsvcToolChain::generateEnvironmentSettings(Utils::Environment &env, call += batchArgs.toLocal8Bit(); } saver.write(call + "\r\n"); - - const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg( - QDir::toNativeSeparators(tempOutFile)).toLocal8Bit() + "\r\n"; - saver.write(redirect); + saver.write("@echo " + marker); + saver.write("set\r\n"); + saver.write("@echo " + marker); if (!saver.finalize()) { qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString())); return false; @@ -304,19 +297,31 @@ bool AbstractMsvcToolChain::generateEnvironmentSettings(Utils::Environment &env, return false; } // The SDK/MSVC scripts do not return exit codes != 0. Check on stdout. - const QByteArray stdOut = run.readAllStandardOutput(); + QByteArray stdOut = run.readAllStandardOutput(); if (!stdOut.isEmpty() && (stdOut.contains("Unknown") || stdOut.contains("Error"))) qWarning("%s: '%s' reports:\n%s", Q_FUNC_INFO, call.constData(), stdOut.constData()); // // Now parse the file to get the environment settings - QFile varsFile(tempOutFile); - if (!varsFile.open(QIODevice::ReadOnly)) + int start = stdOut.indexOf(marker); + if (start == -1) { + qWarning("Could not find start marker in stdout output."); + return false; + } + + stdOut = stdOut.mid(start + marker.size()); + + int end = stdOut.indexOf(marker); + if (end == -1) { + qWarning("Could not find end marker in stdout output."); return false; + } + stdOut = stdOut.left(end); + + QStringList lines = QString::fromLocal8Bit(stdOut).split(QLatin1String("\r\n")); QRegExp regexp(QLatin1String("(\\w*)=(.*)")); - while (!varsFile.atEnd()) { - const QString line = QString::fromLocal8Bit(varsFile.readLine()).trimmed(); + foreach (const QString &line, lines) { if (regexp.exactMatch(line)) { const QString varName = regexp.cap(1); const QString varValue = regexp.cap(2); @@ -326,10 +331,6 @@ bool AbstractMsvcToolChain::generateEnvironmentSettings(Utils::Environment &env, } } - // Tidy up and remove the file - varsFile.close(); - varsFile.remove(); - return true; } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 5ef12e0db8db642988e7f706f162fd075ddf4310..81536e7096ae3fd9934403f3d27339355e075ce8 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -990,6 +990,20 @@ QtSupport::ProFileReader *QmakeProject::createProFileReader(const QmakeProFileNo m_qmakeGlobals->setCommandLineArguments(m_rootProjectNode->buildDir(), qmakeArgs); QtSupport::ProFileCacheManager::instance()->incRefCount(); + + // On ios, qmake is called recursively, and the second call with a different + // spec. + // macx-ios-clang just creates supporting makefiles, and to avoid being + // slow does not evaluate everything, and contains misleading information + // (that is never used). + // macx-xcode correctly evaluates the variables and generates the xcodeproject + // that is actually used to build the application. + // + // It is important to override the spec file only for the creator evaluator, + // and not the qmake buildstep used to build the app (as we use the makefiles). + const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; // from Ios::Constants + if (qtVersion->type() == QLatin1String(IOSQT)) + m_qmakeGlobals->xqmakespec = QLatin1String("macx-xcode"); } ++m_qmakeGlobalsRefCnt; diff --git a/src/plugins/qmlprofiler/qml/MainView.qml b/src/plugins/qmlprofiler/qml/MainView.qml index c97814e2ed2667169ce29ebeae741742e0a20fad..3455e262a56afedecd7c3b8c130c5cc43be6470c 100644 --- a/src/plugins/qmlprofiler/qml/MainView.qml +++ b/src/plugins/qmlprofiler/qml/MainView.qml @@ -70,7 +70,12 @@ Rectangle { mainviewTimePerPixel = Math.abs(endTime - startTime) / root.width; backgroundMarks.updateMarks(startTime, endTime); - view.updateFlickRange(startTime, endTime); + view.startTime = startTime; + view.endTime = endTime; + view.updateWindow(); + } + onWindowChanged: { + view.updateWindow(); } } @@ -250,7 +255,7 @@ Rectangle { onWidthChanged: { var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime()); if (duration > 0) - contentWidth = qmlProfilerModelProxy.traceDuration() * width / duration; + contentWidth = zoomControl.windowLength() * width / duration; } // ***** child items @@ -293,33 +298,29 @@ Rectangle { return; var newStartTime = Math.round(flick.contentX * (endTime - startTime) / flick.width) + - qmlProfilerModelProxy.traceStartTime(); + zoomControl.windowStart(); if (Math.abs(newStartTime - startTime) > 1) { var newEndTime = Math.round((flick.contentX + flick.width) * (endTime - startTime) / - flick.width) + - qmlProfilerModelProxy.traceStartTime(); + flick.width) + zoomControl.windowStart(); zoomControl.setRange(newStartTime, newEndTime); } } - function updateFlickRange(start, end) { - var duration = end - start; - if (recursionGuard || duration <= 0 || (start === startTime && end === endTime)) + function updateWindow() { + var duration = zoomControl.duration(); + if (recursionGuard || duration <= 0) return; recursionGuard = true; - startTime = start; - endTime = end; - if (!flick.flickingHorizontally) { + if (!flick.movingHorizontally) { // This triggers an unwanted automatic change in contentX. We ignore that by // checking recursionGuard in this function and in updateZoomControl. - flick.contentWidth = qmlProfilerModelProxy.traceDuration() * flick.width / - duration; + flick.contentWidth = zoomControl.windowLength() * flick.width / duration; - var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) * - flick.width / duration; + var newStartX = (startTime - zoomControl.windowStart()) * flick.width / + duration; if (isFinite(newStartX) && Math.abs(newStartX - flick.contentX) >= 1) flick.contentX = newStartX; @@ -418,7 +419,9 @@ Rectangle { function updateZoomLevel() { zoomSlider.externalUpdate = true; - zoomSlider.value = Math.pow((view.endTime - view.startTime) / qmlProfilerModelProxy.traceDuration(), 1 / zoomSlider.exponent) * zoomSlider.maximumValue; + zoomSlider.value = Math.pow((view.endTime - view.startTime) / + zoomControl.windowLength(), + 1 / zoomSlider.exponent) * zoomSlider.maximumValue; } @@ -434,7 +437,7 @@ Rectangle { property int minWindowLength: 1e5 // 0.1 ms onValueChanged: { - if (externalUpdate || qmlProfilerModelProxy.traceEndTime() <= qmlProfilerModelProxy.traceStartTime()) { + if (externalUpdate || zoomControl.windowEnd() <= zoomControl.windowStart()) { // Zoom range is independently updated. We shouldn't mess // with it here as otherwise we might introduce rounding // or arithmetic errors. @@ -443,7 +446,7 @@ Rectangle { } var windowLength = Math.max( - Math.pow(value / maximumValue, exponent) * qmlProfilerModelProxy.traceDuration(), + Math.pow(value / maximumValue, exponent) * zoomControl.windowLength(), minWindowLength); var fixedPoint = (view.startTime + view.endTime) / 2; @@ -454,7 +457,7 @@ Rectangle { fixedPoint = newFixedPoint; } - var startTime = Math.max(qmlProfilerModelProxy.traceStartTime(), fixedPoint - windowLength / 2) + var startTime = Math.max(zoomControl.windowStart(), fixedPoint - windowLength / 2) zoomControl.setRange(startTime, startTime + windowLength); } } diff --git a/src/plugins/qmlprofiler/qml/SelectionRange.qml b/src/plugins/qmlprofiler/qml/SelectionRange.qml index b54d0d3eeeed59dd18479092deebb4727bb0c63e..7931bdea3a5ddf5fb57c16eb37f91997b6e49013 100644 --- a/src/plugins/qmlprofiler/qml/SelectionRange.qml +++ b/src/plugins/qmlprofiler/qml/SelectionRange.qml @@ -38,7 +38,7 @@ RangeMover { property string endTimeString: detailedPrintTime(startTime+duration) property string durationString: detailedPrintTime(duration) - property double startTime: getLeft() * viewTimePerPixel + qmlProfilerModelProxy.traceStartTime() + property double startTime: getLeft() * viewTimePerPixel + zoomControl.windowStart() property double duration: Math.max(getWidth() * viewTimePerPixel, 500) property double viewTimePerPixel: 1 property double creationReference : 0 diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index 17b894647ede92c130276f3ee87a9e663aec041d..4ec8c71ed0a04790a5a1788fe7c35a7b6e36de1f 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -112,18 +112,24 @@ qint64 QmlProfilerTraceTime::duration() const void QmlProfilerTraceTime::clear() { - m_startTime = -1; - m_endTime = -1; + setStartTime(-1); + setEndTime(-1); } void QmlProfilerTraceTime::setStartTime(qint64 time) { - m_startTime = time; + if (time != m_startTime) { + m_startTime = time; + emit startTimeChanged(time); + } } void QmlProfilerTraceTime::setEndTime(qint64 time) { - m_endTime = time; + if (time != m_endTime) { + m_endTime = time; + emit endTimeChanged(time); + } } diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h index c9e2047cead01f2d92068d2c861d21ef3f9bef26..1be9abd973f0f57a291110cf7dba6321678d2b90 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h @@ -84,6 +84,10 @@ public: qint64 endTime() const; qint64 duration() const; +signals: + void startTimeChanged(qint64); + void endTimeChanged(qint64); + public slots: void clear(); void setStartTime(qint64 time); diff --git a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp index c8f6562704d1c42dc1b260b9f5fe586e37747bda..6d7fa6a5944127f4cf8c65f68d87b47f0aa5b7d0 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp @@ -61,15 +61,88 @@ namespace QmlProfiler { namespace Internal { ///////////////////////////////////////////////////////// +ZoomControl::ZoomControl(const QmlProfilerTraceTime *traceTime, QObject *parent) : + QObject(parent), m_startTime(traceTime->startTime()), m_endTime(traceTime->endTime()), + m_windowStart(traceTime->startTime()), m_windowEnd(traceTime->endTime()), + m_traceTime(traceTime), m_windowLocked(false) +{ + connect(traceTime, SIGNAL(startTimeChanged(qint64)), this, SLOT(rebuildWindow())); + connect(traceTime, SIGNAL(endTimeChanged(qint64)), this, SLOT(rebuildWindow())); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(moveWindow())); +} + void ZoomControl::setRange(qint64 startTime, qint64 endTime) { if (m_startTime != startTime || m_endTime != endTime) { + m_timer.stop(); m_startTime = startTime; m_endTime = endTime; + rebuildWindow(); emit rangeChanged(); } } +void ZoomControl::rebuildWindow() +{ + qint64 minDuration = 1; // qMax needs equal data types, so literal 1 won't do + qint64 shownDuration = qMax(duration(), minDuration); + + qint64 oldWindowStart = m_windowStart; + qint64 oldWindowEnd = m_windowEnd; + if (m_traceTime->duration() / shownDuration < MAX_ZOOM_FACTOR) { + m_windowStart = m_traceTime->startTime(); + m_windowEnd = m_traceTime->endTime(); + } else if (windowLength() / shownDuration > MAX_ZOOM_FACTOR || + windowLength() / shownDuration * 2 < MAX_ZOOM_FACTOR) { + qint64 keep = shownDuration * MAX_ZOOM_FACTOR / 2 - shownDuration; + m_windowStart = m_startTime - keep; + if (m_windowStart < m_traceTime->startTime()) { + keep += m_traceTime->startTime() - m_windowStart; + m_windowStart = m_traceTime->startTime(); + } + + m_windowEnd = m_endTime + keep; + if (m_windowEnd > m_traceTime->endTime()) { + m_windowStart = qMax(m_traceTime->startTime(), + m_windowStart - m_windowEnd - m_traceTime->endTime()); + m_windowEnd = m_traceTime->endTime(); + } + } else { + m_timer.start(500); + } + if (oldWindowStart != m_windowStart || oldWindowEnd != m_windowEnd) + emit windowChanged(); +} + +void ZoomControl::moveWindow() +{ + if (m_windowLocked) + return; + m_timer.stop(); + + qint64 offset = (m_endTime - m_windowEnd + m_startTime - m_windowStart) / 2; + if (offset == 0 || (offset < 0 && m_windowStart == m_traceTime->startTime()) || + (offset > 0 && m_windowEnd == m_traceTime->endTime())) { + return; + } else if (offset > duration()) { + offset = (offset + duration()) / 2; + } else if (offset < -duration()) { + offset = (offset - duration()) / 2; + } + m_windowStart += offset; + if (m_windowStart < m_traceTime->startTime()) { + m_windowEnd += m_traceTime->startTime() - m_windowStart; + m_windowStart = m_traceTime->startTime(); + } + m_windowEnd += offset; + if (m_windowEnd > m_traceTime->endTime()) { + m_windowStart -= m_windowEnd - m_traceTime->endTime(); + m_windowEnd = m_traceTime->endTime(); + } + emit windowChanged(); + m_timer.start(100); +} + ///////////////////////////////////////////////////////// class QmlProfilerTraceView::QmlProfilerTraceViewPrivate { @@ -108,7 +181,7 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerT { setObjectName(QLatin1String("QML Profiler")); - d->m_zoomControl = new ZoomControl(this); + d->m_zoomControl = new ZoomControl(modelManager->traceTime(), this); connect(d->m_zoomControl, SIGNAL(rangeChanged()), this, SLOT(updateRange())); QVBoxLayout *groupLayout = new QVBoxLayout; @@ -396,6 +469,18 @@ void QmlProfilerTraceView::resizeEvent(QResizeEvent *event) emit resized(); } +void QmlProfilerTraceView::mousePressEvent(QMouseEvent *event) +{ + d->m_zoomControl->setWindowLocked(true); + QWidget::mousePressEvent(event); +} + +void QmlProfilerTraceView::mouseReleaseEvent(QMouseEvent *event) +{ + d->m_zoomControl->setWindowLocked(false); + QWidget::mouseReleaseEvent(event); +} + //////////////////////////////////////////////////////////////// // Context menu void QmlProfilerTraceView::contextMenuEvent(QContextMenuEvent *ev) diff --git a/src/plugins/qmlprofiler/qmlprofilertraceview.h b/src/plugins/qmlprofiler/qmlprofilertraceview.h index d6c0210c547c600605eee9113111b60903b154d5..2203e6434744d36451e9e8af02df0c85eef54942 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceview.h +++ b/src/plugins/qmlprofiler/qmlprofilertraceview.h @@ -30,8 +30,10 @@ #ifndef QMLPROFILERTRACEVIEW_H #define QMLPROFILERTRACEVIEW_H +#include "qmlprofilermodelmanager.h" #include <QQuickView> #include <QWidget> +#include <QTimer> namespace Analyzer { class IAnalyzerTool; } @@ -47,19 +49,38 @@ class QmlProfilerViewManager; class ZoomControl : public QObject { Q_OBJECT public: - ZoomControl(QObject *parent=0):QObject(parent),m_startTime(0),m_endTime(0) {} + static const qint64 MAX_ZOOM_FACTOR = 1 << 12; + + ZoomControl(const QmlProfilerTraceTime *traceTime, QObject *parent = 0); ~ZoomControl(){} Q_INVOKABLE void setRange(qint64 startTime, qint64 endTime); - Q_INVOKABLE qint64 startTime() { return m_startTime; } - Q_INVOKABLE qint64 endTime() { return m_endTime; } + Q_INVOKABLE qint64 startTime() const { return m_startTime; } + Q_INVOKABLE qint64 endTime() const { return m_endTime; } + Q_INVOKABLE qint64 duration() const { return m_endTime - m_startTime; } + + Q_INVOKABLE qint64 windowStart() const { return m_windowStart; } + Q_INVOKABLE qint64 windowEnd() const { return m_windowEnd; } + Q_INVOKABLE qint64 windowLength() const { return m_windowEnd - m_windowStart; } + void setWindowLocked(bool lock) { m_windowLocked = lock; } signals: void rangeChanged(); + void windowChanged(); + +private slots: + void rebuildWindow(); + void moveWindow(); private: qint64 m_startTime; qint64 m_endTime; + qint64 m_windowStart; + qint64 m_windowEnd; + + const QmlProfilerTraceTime *m_traceTime; + QTimer m_timer; + bool m_windowLocked; }; class QmlProfilerTraceView : public QWidget @@ -97,6 +118,8 @@ private slots: protected: virtual void resizeEvent(QResizeEvent *event); virtual void contextMenuEvent(QContextMenuEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); private slots: void setZoomSliderEnabled(bool enabled); diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 22f4bf66d1fc4723012f36be4781962d452db708..ebab776318044b580bbcb08b78873d7109f61313 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -54,6 +54,7 @@ static bool debugExamples() } static const char kSelectedExampleSetKey[] = "WelcomePage/SelectedExampleSet"; +static const char kExamplesSearchStringKey[] = "WelcomePage/ExamplesSearchString"; void ExampleSetModel::writeCurrentIdToSettings(int currentIndex) const { @@ -841,6 +842,16 @@ void ExamplesListModelFilter::filterForExampleSet(int index) m_sourceModel->selectExampleSet(index); } +void ExamplesListModelFilter::writeSearchStringToSettings(const QString &string) +{ + Core::ICore::settings()->setValue(QLatin1String(kExamplesSearchStringKey), string); +} + +QString ExamplesListModelFilter::readSearchStringsFromSettings() +{ + return Core::ICore::settings()->value(QLatin1String(kExamplesSearchStringKey)).toString(); +} + void ExamplesListModelFilter::setShowTutorialsOnly(bool showTutorialsOnly) { m_showTutorialsOnly = showTutorialsOnly; diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h index 6a2607de741a1b909f1a9e2eb2decad0b39507a6..ae30ec9290fb66540bfd7abc54a6868417fd64d7 100644 --- a/src/plugins/qtsupport/exampleslistmodel.h +++ b/src/plugins/qtsupport/exampleslistmodel.h @@ -185,6 +185,8 @@ public: QAbstractItemModel* exampleSetModel(); Q_INVOKABLE void filterForExampleSet(int index); + Q_INVOKABLE void writeSearchStringToSettings(const QString &string); + Q_INVOKABLE QString readSearchStringsFromSettings(); public slots: void setFilterTags(const QStringList &arg) diff --git a/src/plugins/winrt/winrtpackagedeploymentstep.cpp b/src/plugins/winrt/winrtpackagedeploymentstep.cpp index ff746e2c3d7ea8d11f4685ebe12ed31ea85cb2b2..71a53155d391185e9424f18c3232d58f33ef0332 100644 --- a/src/plugins/winrt/winrtpackagedeploymentstep.cpp +++ b/src/plugins/winrt/winrtpackagedeploymentstep.cpp @@ -35,8 +35,14 @@ #include <projectexplorer/target.h> #include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildtargetinfo.h> +#include <projectexplorer/deployablefile.h> +#include <projectexplorer/deploymentdata.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <qtsupport/qtkitinformation.h> #include <utils/qtcprocess.h> +#include <QRegularExpression> + using namespace ProjectExplorer; using Utils::QtcProcess; @@ -45,6 +51,7 @@ namespace Internal { WinRtPackageDeploymentStep::WinRtPackageDeploymentStep(BuildStepList *bsl) : AbstractProcessStep(bsl, Constants::WINRT_BUILD_STEP_DEPLOY) + , m_createMappingFile(false) { setDisplayName(tr("Run windeployqt")); m_args = defaultWinDeployQtArguments(); @@ -56,11 +63,46 @@ bool WinRtPackageDeploymentStep::init() const QString targetPath = target()->applicationTargets().targetForProject(proFile).toString() + QLatin1String(".exe"); + QString targetDir = targetPath.left(targetPath.lastIndexOf(QLatin1Char('/')) + 1); // ### Actually, targetForProject is supposed to return the file path including the file // extension. Whenever this will eventually work, we have to remove the .exe suffix here. + const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit()); + if (!qt) + return false; + + m_isWinPhone = (qt->type() == QLatin1String(Constants::WINRT_WINPHONEQT)); + QString args = QtcProcess::quoteArg(QDir::toNativeSeparators(targetPath)); args += QLatin1Char(' ') + m_args; + if (m_isWinPhone) { + m_manifestFileName = QLatin1String("WMAppManifest"); + m_createMappingFile = true; + } else { + m_manifestFileName = QLatin1String("AppxManifest"); + } + + if (m_createMappingFile) { + args += QLatin1String(" -list mapping"); + m_mappingFileContent = QLatin1String("[Files]\n\"") + QDir::toNativeSeparators(targetDir) + + m_manifestFileName + QLatin1String(".xml\" \"") + m_manifestFileName + QLatin1String(".xml\"\n"); + + QDir assetDirectory(targetDir + QLatin1String("assets")); + if (assetDirectory.exists()) { + QStringList iconsToDeploy; + const QString fullManifestPath = targetDir + m_manifestFileName + QLatin1String(".xml"); + if (!parseIconsAndExecutableFromManifest(fullManifestPath, &iconsToDeploy, + &m_executablePathInManifest)) { + raiseError(tr("Cannot parse manifest file %1.").arg(fullManifestPath)); + return false; + } + foreach (QString icon, iconsToDeploy) { + m_mappingFileContent += QLatin1Char('"') + + QDir::toNativeSeparators(targetDir + icon) + QLatin1String("\" \"") + + QDir::toNativeSeparators(icon) + QLatin1String("\"\n"); + } + } + } ProcessParameters *params = processParameters(); params->setCommand(QLatin1String("windeployqt.exe")); @@ -70,6 +112,67 @@ bool WinRtPackageDeploymentStep::init() return AbstractProcessStep::init(); } +bool WinRtPackageDeploymentStep::processSucceeded(int exitCode, QProcess::ExitStatus status) +{ + if (m_createMappingFile) { + Utils::FileName proFile = Utils::FileName::fromString(project()->projectFilePath()); + QString targetPath + = target()->applicationTargets().targetForProject(proFile).toString(); + QString targetDir = targetPath.left(targetPath.lastIndexOf(QLatin1Char('/')) + 1); + QString targetInstallationPath; + // The list holds the local file paths and the "remote" file paths + QList<QPair<QString, QString> > installableFilesList; + foreach (DeployableFile file, target()->deploymentData().allFiles()) { + QString remoteFilePath = file.remoteFilePath(); + QString localFilePath = file.localFilePath().toString(); + if (localFilePath == targetPath) { + if (!targetPath.endsWith(QLatin1String(".exe"))) { + remoteFilePath += QLatin1String(".exe"); + localFilePath += QLatin1String(".exe"); + } + targetInstallationPath = remoteFilePath; + } + installableFilesList.append(QPair<QString, QString>(localFilePath, remoteFilePath)); + } + + // if there are no INSTALLS set we just deploy the files from windeployqt, the manifest + // and the icons referenced in there and the actual build target + if (targetInstallationPath.isEmpty()) { + targetPath += QLatin1String(".exe"); + m_mappingFileContent + += QLatin1Char('"') + QDir::toNativeSeparators(targetPath) + QLatin1String("\" \"") + + QDir::toNativeSeparators(m_executablePathInManifest) + QLatin1String("\"\n"); + } else { + targetInstallationPath = targetInstallationPath.left(targetInstallationPath.lastIndexOf(QLatin1Char('/')) + 1); + for (int i = 0; i < installableFilesList.length(); ++i) { + QPair<QString, QString> pair = installableFilesList.at(i); + // For the mapping file we need the remote paths relative to the application's executable + const QString relativeRemotePath = QDir(targetInstallationPath).relativeFilePath(pair.second); + m_mappingFileContent += QLatin1Char('"') + QDir::toNativeSeparators(pair.first) + + QLatin1String("\" \"") + QDir::toNativeSeparators(relativeRemotePath) + + QLatin1String("\"\n"); + } + } + + const QString mappingFilePath = targetDir + m_manifestFileName + QLatin1String(".map"); + QFile mappingFile(mappingFilePath); + if (!mappingFile.open(QFile::WriteOnly | QFile::Text)) { + raiseError(tr("Cannot open mapping file %1 for writing.").arg(mappingFilePath)); + return false; + } + mappingFile.write(m_mappingFileContent.toUtf8()); + } + + return AbstractProcessStep::processSucceeded(exitCode, status); +} + +void WinRtPackageDeploymentStep::stdOutput(const QString &line) +{ + if (m_createMappingFile) + m_mappingFileContent += line; + AbstractProcessStep::stdOutput(line); +} + BuildStepConfigWidget *WinRtPackageDeploymentStep::createConfigWidget() { return new WinRtPackageDeploymentStepWidget(this); @@ -93,6 +196,13 @@ QString WinRtPackageDeploymentStep::defaultWinDeployQtArguments() const return args; } +void WinRtPackageDeploymentStep::raiseError(const QString &errorMessage) +{ + emit addOutput(errorMessage, BuildStep::ErrorMessageOutput); + emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error, errorMessage, Utils::FileName(), -1, + ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT)); +} + bool WinRtPackageDeploymentStep::fromMap(const QVariantMap &map) { if (!AbstractProcessStep::fromMap(map)) @@ -110,5 +220,31 @@ QVariantMap WinRtPackageDeploymentStep::toMap() const return map; } +bool WinRtPackageDeploymentStep::parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *icons, QString *executable) +{ + if (!icons->isEmpty()) + icons->clear(); + QFile manifestFile(manifestFileName); + if (!manifestFile.open(QFile::ReadOnly)) + return false; + const QString contents = QString::fromUtf8(manifestFile.readAll()); + + QRegularExpression iconPattern(QStringLiteral("[\\\\/a-zA-Z0-9_\\-\\!]*\\.(png|jpg|jpeg)")); + QRegularExpressionMatchIterator iterator = iconPattern.globalMatch(contents); + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + const QString icon = match.captured(0); + icons->append(icon); + } + + QRegularExpression executablePattern(QStringLiteral("ImagePath=\"([a-zA-Z0-9_-]*\\.exe)\"")); + QRegularExpressionMatch match = executablePattern.match(contents); + if (!match.hasMatch()) + return false; + *executable = match.captured(1); + + return true; +} + } // namespace Internal } // namespace WinRt diff --git a/src/plugins/winrt/winrtpackagedeploymentstep.h b/src/plugins/winrt/winrtpackagedeploymentstep.h index 592395827b14146b3a59df56723181e15a74dd8b..0c567b93d4f916d926d17c3bdddafeecebea380a 100644 --- a/src/plugins/winrt/winrtpackagedeploymentstep.h +++ b/src/plugins/winrt/winrtpackagedeploymentstep.h @@ -41,17 +41,28 @@ class WinRtPackageDeploymentStep : public ProjectExplorer::AbstractProcessStep public: explicit WinRtPackageDeploymentStep(ProjectExplorer::BuildStepList *bsl); bool init(); + bool processSucceeded(int exitCode, QProcess::ExitStatus status); + void stdOutput(const QString &line); ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); void setWinDeployQtArguments(const QString &args); QString winDeployQtArguments() const; QString defaultWinDeployQtArguments() const; + void raiseError(const QString &errorMessage); + bool fromMap(const QVariantMap &map); QVariantMap toMap() const; private: + bool parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *items, QString *executable); + QString m_args; + QString m_executablePathInManifest; + QString m_mappingFileContent; + QString m_manifestFileName; + bool m_isWinPhone; + bool m_createMappingFile; }; } // namespace Internal diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index bb781a50a5aebb52de1cd72e62d4a7dce042e98d..024dbb52fc6af38699beb114ce1b9f261d7b0147 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -100,7 +100,8 @@ QString ProFileEvaluator::sysrootify(const QString &path, const QString &baseDir #endif const bool isHostSystemPath = option->sysroot.isEmpty() || path.startsWith(option->sysroot, cs) - || path.startsWith(baseDir, cs) || path.startsWith(d->m_outputDir, cs); + || path.startsWith(baseDir, cs) || path.startsWith(d->m_outputDir, cs) + || !QFileInfo(option->sysroot + path).exists(); return isHostSystemPath ? path : option->sysroot + path; } diff --git a/tests/system/suite_QMLS/tst_QMLS03/test.py b/tests/system/suite_QMLS/tst_QMLS03/test.py index d8b435b24e1e4df8b434fe955e6c6290dc41de20..a46a13999cf9682e49513b4f05bd1bd0701722b7 100644 --- a/tests/system/suite_QMLS/tst_QMLS03/test.py +++ b/tests/system/suite_QMLS/tst_QMLS03/test.py @@ -79,7 +79,7 @@ def main(): if not startedWithoutPluginError(): return # open example project - openQmakeProject(examplePath) + openQmakeProject(examplePath, Targets.DESKTOP_480_GCC) # open qml file openDocument("propertyanimation.QML.qml.color-animation\\.qml") # get editor diff --git a/tests/system/suite_editors/tst_qml_editor/test.py b/tests/system/suite_editors/tst_qml_editor/test.py index fe188db512903981b18b86b0a95575eac0d6e075..cd6fca515857aec3a437804aa591b34086f46b93 100644 --- a/tests/system/suite_editors/tst_qml_editor/test.py +++ b/tests/system/suite_editors/tst_qml_editor/test.py @@ -43,7 +43,7 @@ def main(): addHelpDocumentation([os.path.join(sdkPath, "Documentation", "qt.qch")]) templateDir = prepareTemplate(sourceExample) installLazySignalHandler("{type='Core::FutureProgress' unnamed='1'}", "finished()", "__handleFutureProgress__") - openQmakeProject(os.path.join(templateDir,proFile)) + openQmakeProject(os.path.join(templateDir,proFile), Targets.DESKTOP_480_GCC) openDocument("focus.QML.qml.focus\\.qml") testRenameId() testFindUsages() diff --git a/tests/system/suite_general/tst_session_handling/test.py b/tests/system/suite_general/tst_session_handling/test.py index 9d81da376d035321898f823dc532e6e1bbacfed1..1bfec7e6951069b2a4c0ea514874ad871a092204 100644 --- a/tests/system/suite_general/tst_session_handling/test.py +++ b/tests/system/suite_general/tst_session_handling/test.py @@ -42,7 +42,7 @@ def main(): test.verify(waitFor("sessionName in str(mainWindow.windowTitle)", 2000), "Verifying window title contains created session name.") for project in projects: - openQmakeProject(project) + openQmakeProject(project, Targets.DESKTOP_480_GCC) progressBarWait(20000) checkNavigator(68, "Verifying whether all projects have been opened.") openDocument("propertyanimation.QML.qml.color-animation\\.qml") diff --git a/tests/system/suite_qtquick/tst_qml_outline/test.py b/tests/system/suite_qtquick/tst_qml_outline/test.py index 46420f3310d4ff38d6fa8c1da1ab66e734584583..879e05e308984efd777474ca4bb28dfa5ab1f96f 100644 --- a/tests/system/suite_qtquick/tst_qml_outline/test.py +++ b/tests/system/suite_qtquick/tst_qml_outline/test.py @@ -42,11 +42,7 @@ def main(): startApplication("qtcreator" + SettingsPath) if not startedWithoutPluginError(): return - targets = openQmakeProject(os.path.join(templateDir, proFile)) - # make sure we use the 474 kit for having QtQuick 1.0 support - switchViewTo(ViewConstants.PROJECTS) - switchToBuildOrRunSettingsFor(len(targets), 0, ProjectSettings.BUILD) - switchViewTo(ViewConstants.EDIT) + openQmakeProject(os.path.join(templateDir, proFile), Targets.DESKTOP_480_GCC) qmlFiles = ["focus.QML.qml.focus\\.qml", "focus.QML.qml.Core.ListMenu\\.qml"] checkOutlineFor(qmlFiles) testModify()