diff options
23 files changed, 332 insertions, 74 deletions
diff --git a/README.md b/README.md index d195cbf6790..05efbffd27f 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,15 @@ Prerequisites: * jom * On Mac OS X: latest Xcode * On Linux: g++ 4.8 or later -* LLVM 3.8.0 or later for the Clang Code Model +* LLVM 3.8.0 or later (optional, needed for the Clang Code Model) The installed toolchains have to match the one Qt was compiled with. You can build Qt Creator with + # Optional, needed for the Clang Code Model: + export LLVM_INSTALL_DIR=/path/to/llvm (or "set" on Windows) + cd $SOURCE_DIRECTORY qmake -r make (or mingw32-make or nmake or jom, depending on your platform) diff --git a/dist/changes-4.1.0.md b/dist/changes-4.1.0.md index ce25b28dfe0..f9160eb7b4f 100644 --- a/dist/changes-4.1.0.md +++ b/dist/changes-4.1.0.md @@ -48,6 +48,10 @@ CMake Projects (QTCREATORBUG-15934) * Fixed that CMake was automatically run even if the Qt Creator application is not in the foreground (QTCREATORBUG-16354) +* QML_IMPORT_PATH can now be set in CMakeLists.txt files. This information + will be passed on to the QmlJS code model (QTCREATORBUG-11328) + Example CMakeLists.txt code: + `set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/qml ${CMAKE_BINARY_DIR}/imports CACHE string "" FORCE)` Qbs Projects diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/ComboBox.qml index 85af3f1638b..849a7eb78aa 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/ComboBox.qml @@ -43,6 +43,8 @@ Controls.ComboBox { signal valueFromBackendChanged + property bool block: false + ColorLogic { id: colorLogic backendValue: comboBox.backendValue @@ -52,6 +54,11 @@ Controls.ComboBox { function invalidate() { + if (block) + return + + block = true + if (manualMapping) { valueFromBackendChanged(); } else if (!comboBox.useInteger) { @@ -72,6 +79,8 @@ Controls.ComboBox { if (comboBox.currentIndex !== backendValue.value) comboBox.currentIndex = backendValue.value } + + block = false } } diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index 6ed3b7c4d14..c66a32305b3 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -241,7 +241,7 @@ void QtTestOutputReader::processOutput() break; default: // this must come from plain printf() calls - but this will be ignored anyhow - qWarning() << "Ignored plain output:" << text.toString(); + qWarning() << "AutoTest.Run: Ignored plain output:" << text.toString(); break; } break; diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp index a6bfdbd1d1c..f28775128e7 100644 --- a/src/plugins/autotest/testoutputreader.cpp +++ b/src/plugins/autotest/testoutputreader.cpp @@ -45,7 +45,7 @@ TestOutputReader::TestOutputReader(const QFutureInterface<TestResultPtr> &future void TestOutputReader::processStdError() { - qWarning() << "Ignored plain output:" << m_testApplication->readAllStandardError(); + qWarning() << "AutoTest.Run: Ignored plain output:" << m_testApplication->readAllStandardError(); } } // namespace Internal diff --git a/src/plugins/autotest/testresult.cpp b/src/plugins/autotest/testresult.cpp index 55ae77596cf..df89706c8db 100644 --- a/src/plugins/autotest/testresult.cpp +++ b/src/plugins/autotest/testresult.cpp @@ -65,6 +65,8 @@ Result::Type TestResult::resultFromString(const QString &resultString) return Result::Skip; if (resultString == QLatin1String("qdebug")) return Result::MessageDebug; + if (resultString == QLatin1String("qinfo")) + return Result::MessageInfo; if (resultString == QLatin1String("warn") || resultString == QLatin1String("qwarn")) return Result::MessageWarn; if (resultString == QLatin1String("qfatal")) @@ -105,6 +107,8 @@ QString TestResult::resultToString(const Result::Type type) return QLatin1String("BENCH"); case Result::MessageDebug: return QLatin1String("DEBUG"); + case Result::MessageInfo: + return QLatin1String("INFO"); case Result::MessageWarn: return QLatin1String("WARN"); case Result::MessageFatal: @@ -136,6 +140,7 @@ QColor TestResult::colorForType(const Result::Type type) case Result::Skip: return creatorTheme->color(Utils::Theme::OutputPanes_TestSkipTextColor); case Result::MessageDebug: + case Result::MessageInfo: return creatorTheme->color(Utils::Theme::OutputPanes_TestDebugTextColor); case Result::MessageWarn: return creatorTheme->color(Utils::Theme::OutputPanes_TestWarnTextColor); diff --git a/src/plugins/autotest/testresult.h b/src/plugins/autotest/testresult.h index 4756d1225b5..86c7f8e3c65 100644 --- a/src/plugins/autotest/testresult.h +++ b/src/plugins/autotest/testresult.h @@ -46,6 +46,7 @@ enum Type { BlacklistedFail, Benchmark, MessageDebug, + MessageInfo, MessageWarn, MessageFatal, diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp index b42ab5cd628..05d53a69563 100644 --- a/src/plugins/autotest/testresultmodel.cpp +++ b/src/plugins/autotest/testresultmodel.cpp @@ -46,7 +46,7 @@ TestResultItem::~TestResultItem() } static QIcon testResultIcon(Result::Type result) { - static QIcon icons[11] = { + static QIcon icons[] = { QIcon(QLatin1String(":/images/pass.png")), QIcon(QLatin1String(":/images/fail.png")), QIcon(QLatin1String(":/images/xfail.png")), @@ -56,6 +56,7 @@ static QIcon testResultIcon(Result::Type result) { QIcon(QLatin1String(":/images/blacklisted_fail.png")), QIcon(QLatin1String(":/images/benchmark.png")), QIcon(QLatin1String(":/images/debug.png")), + QIcon(QLatin1String(":/images/debug.png")), // Info get's the same handling as Debug for now QIcon(QLatin1String(":/images/warn.png")), QIcon(QLatin1String(":/images/fatal.png")), }; // provide an icon for unknown?? @@ -298,7 +299,7 @@ void TestResultFilterModel::enableAllResultTypes() << Result::MessageCurrentTest << Result::MessageTestCaseStart << Result::MessageTestCaseSuccess << Result::MessageTestCaseWarn << Result::MessageTestCaseFail << Result::MessageTestCaseEnd - << Result::MessageTestCaseRepetition; + << Result::MessageTestCaseRepetition << Result::MessageInfo; invalidateFilter(); } @@ -308,10 +309,14 @@ void TestResultFilterModel::toggleTestResultType(Result::Type type) m_enabled.remove(type); if (type == Result::MessageInternal) m_enabled.remove(Result::MessageTestCaseEnd); + if (type == Result::MessageDebug) + m_enabled.remove(Result::MessageInfo); } else { m_enabled.insert(type); if (type == Result::MessageInternal) m_enabled.insert(Result::MessageTestCaseEnd); + if (type == Result::MessageDebug) + m_enabled.insert(Result::MessageInfo); } invalidateFilter(); } diff --git a/src/plugins/coreplugin/fancyactionbar.cpp b/src/plugins/coreplugin/fancyactionbar.cpp index 28a334637cb..e6ad99bc1bd 100644 --- a/src/plugins/coreplugin/fancyactionbar.cpp +++ b/src/plugins/coreplugin/fancyactionbar.cpp @@ -230,10 +230,15 @@ void FancyToolButton::paintEvent(QPaintEvent *event) } else { splitBuildConfiguration = splitInTwoLines(buildConfiguration, boldFm, availableWidth); } - // draw the two lines for the build configuration + + // draw the two text lines for the build configuration painter.setPen(creatorTheme()->color(isEnabled() - ? Theme::FancyTabWidgetEnabledSelectedTextColor - : Theme::FancyTabWidgetDisabledSelectedTextColor)); + // Intentionally using the "Unselected" colors, + // because the text color won't change in the pressed + // state as they would do on the mode buttons. + ? Theme::FancyTabWidgetEnabledUnselectedTextColor + : Theme::FancyTabWidgetDisabledUnselectedTextColor)); + for (int i = 0; i < 2; ++i) { if (splitBuildConfiguration[i].isEmpty()) continue; diff --git a/src/plugins/coreplugin/opendocumentstreeview.cpp b/src/plugins/coreplugin/opendocumentstreeview.cpp index 1f3a6463d86..b7da6cb0bee 100644 --- a/src/plugins/coreplugin/opendocumentstreeview.cpp +++ b/src/plugins/coreplugin/opendocumentstreeview.cpp @@ -108,6 +108,7 @@ OpenDocumentsTreeView::OpenDocumentsTreeView(QWidget *parent) : setTextElideMode(Qt::ElideMiddle); setFrameStyle(QFrame::NoFrame); setAttribute(Qt::WA_MacShowFocusRect, false); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); viewport()->setAttribute(Qt::WA_Hover); setSelectionMode(QAbstractItemView::SingleSelection); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index eb35908f4d7..bb084b644e9 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -622,9 +622,11 @@ static ToolChain *findOrCreateToolChain(const QList<ToolChain *> &alreadyKnown, ToolChain::Detection d = ToolChain::ManualDetection) { ToolChain *tc = Utils::findOrDefault(alreadyKnown, - [&varsBat, &varsBatArg](ToolChain *tc) -> bool { + [&varsBat, &varsBatArg, &abi](ToolChain *tc) -> bool { if (tc->typeId() != Constants::MSVC_TOOLCHAIN_TYPEID) return false; + if (tc->targetAbi() != abi) + return false; auto mtc = static_cast<MsvcToolChain *>(tc); return mtc->varsBat() == varsBat && mtc->varsBatArg() == varsBatArg; diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp index a5ce3183c64..31b16e2e2d2 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp @@ -758,16 +758,21 @@ void QmlAnchorBindingProxy::anchorTop() { m_locked = true; + bool topTargetIsParent = m_topTarget == m_qmlItemNode.instanceParentItem(); + if (m_relativeTopTarget == SameEdge) { - qreal topMargin = transformedBoundingBox().top() - parentBoundingBox().top(); + qreal topPos = topTargetIsParent ? parentBoundingBox().top() : boundingBox(m_topTarget).top(); + qreal topMargin = transformedBoundingBox().top() - topPos; m_qmlItemNode.anchors().setMargin( AnchorLineTop, topMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineTop, m_topTarget, AnchorLineTop); } else if (m_relativeTopTarget == OppositeEdge) { - qreal topMargin = boundingBox(m_qmlItemNode).top() - boundingBox(m_topTarget).bottom(); + qreal bottomPos = topTargetIsParent ? parentBoundingBox().bottom() : boundingBox(m_topTarget).bottom(); + qreal topMargin = transformedBoundingBox().top() - bottomPos; m_qmlItemNode.anchors().setMargin( AnchorLineTop, topMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineTop, m_topTarget, AnchorLineBottom); } else if (m_relativeTopTarget == Center) { - qreal topMargin = boundingBox(m_qmlItemNode).top() - boundingBox(m_topTarget).center().y(); + qreal centerPos = topTargetIsParent ? parentBoundingBox().center().y() : boundingBox(m_topTarget).center().y(); + qreal topMargin = transformedBoundingBox().top() - centerPos; m_qmlItemNode.anchors().setMargin(AnchorLineTop, topMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineTop, m_topTarget, AnchorLineVerticalCenter); } @@ -779,16 +784,21 @@ void QmlAnchorBindingProxy::anchorBottom() { m_locked = true; + bool bottomTargetIsParent = m_bottomTarget == m_qmlItemNode.instanceParentItem(); + if (m_relativeBottomTarget == SameEdge) { - qreal bottomMargin = parentBoundingBox().bottom() - transformedBoundingBox().bottom(); + qreal bottomPos = bottomTargetIsParent ? parentBoundingBox().bottom() : boundingBox(m_bottomTarget).bottom(); + qreal bottomMargin = bottomPos - transformedBoundingBox().bottom(); m_qmlItemNode.anchors().setMargin( AnchorLineBottom, bottomMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineBottom, m_bottomTarget, AnchorLineBottom); } else if (m_relativeBottomTarget == OppositeEdge) { - qreal bottomMargin = boundingBox(m_bottomTarget).top()- boundingBox(m_qmlItemNode).bottom(); + qreal topPos = bottomTargetIsParent ? parentBoundingBox().top() : boundingBox(m_bottomTarget).top(); + qreal bottomMargin = topPos - transformedBoundingBox().bottom(); m_qmlItemNode.anchors().setMargin( AnchorLineBottom, bottomMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineBottom, m_bottomTarget, AnchorLineTop); } else if (m_relativeBottomTarget == Center) { - qreal bottomMargin = boundingBox(m_qmlItemNode).top() - boundingBox(m_bottomTarget).center().y(); + qreal centerPos = bottomTargetIsParent ? parentBoundingBox().center().y() : boundingBox(m_bottomTarget).center().y(); + qreal bottomMargin = centerPos - transformedBoundingBox().bottom(); m_qmlItemNode.anchors().setMargin(AnchorLineBottom, bottomMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineBottom, m_bottomTarget, AnchorLineVerticalCenter); } @@ -800,16 +810,21 @@ void QmlAnchorBindingProxy::anchorLeft() { m_locked = true; + bool leftTargetIsParent = m_leftTarget == m_qmlItemNode.instanceParentItem(); + if (m_relativeLeftTarget == SameEdge) { - qreal leftMargin = transformedBoundingBox().left() - parentBoundingBox().left(); + qreal leftPos = leftTargetIsParent ? parentBoundingBox().left() : boundingBox(m_leftTarget).left(); + qreal leftMargin = transformedBoundingBox().left() - leftPos; m_qmlItemNode.anchors().setMargin(AnchorLineLeft, leftMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineLeft, m_leftTarget, AnchorLineLeft); } else if (m_relativeLeftTarget == OppositeEdge) { - qreal leftMargin = boundingBox(m_qmlItemNode).left() - boundingBox(m_leftTarget).right(); + qreal rightPos = leftTargetIsParent ? parentBoundingBox().right() : boundingBox(m_leftTarget).right(); + qreal leftMargin = transformedBoundingBox().left() - rightPos; m_qmlItemNode.anchors().setMargin( AnchorLineLeft, leftMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineLeft, m_leftTarget, AnchorLineRight); } else if (m_relativeLeftTarget == Center) { - qreal leftMargin = boundingBox(m_qmlItemNode).top() - boundingBox(m_leftTarget).center().x(); + qreal centerPos = leftTargetIsParent ? parentBoundingBox().center().x() : boundingBox(m_leftTarget).center().x(); + qreal leftMargin = transformedBoundingBox().left() - centerPos; m_qmlItemNode.anchors().setMargin(AnchorLineLeft, leftMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineLeft, m_leftTarget, AnchorLineHorizontalCenter); } @@ -821,16 +836,21 @@ void QmlAnchorBindingProxy::anchorRight() { m_locked = true; + bool rightTargetIsParent = m_rightTarget == m_qmlItemNode.instanceParentItem(); + if (m_relativeRightTarget == SameEdge) { - qreal rightMargin = parentBoundingBox().right() - transformedBoundingBox().right(); + qreal rightPos = rightTargetIsParent ? parentBoundingBox().right() : boundingBox(m_rightTarget).right(); + qreal rightMargin = rightPos - transformedBoundingBox().right(); m_qmlItemNode.anchors().setMargin( AnchorLineRight, rightMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineRight, m_rightTarget, AnchorLineRight); } else if (m_relativeRightTarget == OppositeEdge) { - qreal rightMargin = boundingBox(m_rightTarget).left() - boundingBox(m_qmlItemNode).right(); + qreal leftPos = rightTargetIsParent ? parentBoundingBox().left() : boundingBox(m_rightTarget).left(); + qreal rightMargin = leftPos - transformedBoundingBox().right(); m_qmlItemNode.anchors().setMargin( AnchorLineRight, rightMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineRight, m_rightTarget, AnchorLineLeft); } else if (m_relativeRightTarget == Center) { - qreal rightMargin = boundingBox(m_qmlItemNode).top() - boundingBox(m_rightTarget).center().x(); + qreal centerPos = rightTargetIsParent ? parentBoundingBox().center().x() : boundingBox(m_rightTarget).center().x(); + qreal rightMargin = centerPos - transformedBoundingBox().right(); m_qmlItemNode.anchors().setMargin(AnchorLineRight, rightMargin); m_qmlItemNode.anchors().setAnchor(AnchorLineRight, m_rightTarget, AnchorLineHorizontalCenter); } diff --git a/src/plugins/qmldesigner/componentsplugin/Controls/TabPositionComboBox.qml b/src/plugins/qmldesigner/componentsplugin/Controls/TabPositionComboBox.qml index 3f2065f7bc0..8900276d27c 100644 --- a/src/plugins/qmldesigner/componentsplugin/Controls/TabPositionComboBox.qml +++ b/src/plugins/qmldesigner/componentsplugin/Controls/TabPositionComboBox.qml @@ -23,10 +23,8 @@ ** ****************************************************************************/ -import QtQuick 2.1 +import QtQuick 2.6 import HelperWidgets 2.0 -import QtQuick.Layouts 1.0 -import QtQuick.Controls 1.1 as Controls ComboBox { useInteger: true diff --git a/src/plugins/qmlprofiler/memoryusagemodel.cpp b/src/plugins/qmlprofiler/memoryusagemodel.cpp index d07b40df2fb..b0541fa7d00 100644 --- a/src/plugins/qmlprofiler/memoryusagemodel.cpp +++ b/src/plugins/qmlprofiler/memoryusagemodel.cpp @@ -177,11 +177,19 @@ void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type m_currentUsage = allocation.size; if (m_currentUsageIndex != -1) { - insertEnd(m_currentUsageIndex, - event.timestamp() - startTime(m_currentUsageIndex) - 1); + qint64 duration = event.timestamp() - startTime(m_currentUsageIndex); + if (duration > 0) { + insertEnd(m_currentUsageIndex, duration - 1); + m_currentUsageIndex = insertStart(event.timestamp(), SmallItem); + m_data.insert(m_currentUsageIndex, allocation); + } else { + // Ignore ranges of 0 duration. We only need to keep track of the sizes. + m_data[m_currentUsageIndex] = allocation; + } + } else { + m_currentUsageIndex = insertStart(event.timestamp(), SmallItem); + m_data.insert(m_currentUsageIndex, allocation); } - m_currentUsageIndex = insertStart(event.timestamp(), SmallItem); - m_data.insert(m_currentUsageIndex, allocation); m_continuation = m_continuation | ContinueUsage; } } @@ -201,11 +209,22 @@ void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type if (m_currentSize > m_maxSize) m_maxSize = m_currentSize; - if (m_currentJSHeapIndex != -1) - insertEnd(m_currentJSHeapIndex, - event.timestamp() - startTime(m_currentJSHeapIndex) - 1); - m_currentJSHeapIndex = insertStart(event.timestamp(), type.detailType()); - m_data.insert(m_currentJSHeapIndex, allocation); + + if (m_currentJSHeapIndex != -1) { + qint64 duration = event.timestamp() - startTime(m_currentJSHeapIndex); + if (duration > 0){ + insertEnd(m_currentJSHeapIndex, duration - 1); + m_currentJSHeapIndex = insertStart(event.timestamp(), type.detailType()); + m_data.insert(m_currentJSHeapIndex, allocation); + } else { + // Ignore ranges of 0 duration. We only need to keep track of the sizes. + m_data[m_currentJSHeapIndex] = allocation; + } + } else { + m_currentJSHeapIndex = insertStart(event.timestamp(), type.detailType()); + m_data.insert(m_currentJSHeapIndex, allocation); + } + m_continuation = m_continuation | ContinueAllocation; } } @@ -215,10 +234,10 @@ void MemoryUsageModel::finalize() { if (m_currentJSHeapIndex != -1) insertEnd(m_currentJSHeapIndex, modelManager()->traceTime()->endTime() - - startTime(m_currentJSHeapIndex) - 1); + startTime(m_currentJSHeapIndex)); if (m_currentUsageIndex != -1) insertEnd(m_currentUsageIndex, modelManager()->traceTime()->endTime() - - startTime(m_currentUsageIndex) - 1); + startTime(m_currentUsageIndex)); computeNesting(); diff --git a/src/plugins/qmlprofiler/pixmapcachemodel.cpp b/src/plugins/qmlprofiler/pixmapcachemodel.cpp index e21fcca8231..b38256c9a8c 100644 --- a/src/plugins/qmlprofiler/pixmapcachemodel.cpp +++ b/src/plugins/qmlprofiler/pixmapcachemodel.cpp @@ -214,8 +214,6 @@ void PixmapCacheModel::loadEvent(const QmlEvent &event, const QmlEventType &type break; } case PixmapCacheCountChanged: {// Cache Size Changed Event - pixmapStartTime = event.timestamp() + 1; // delay 1 ns for proper sorting - bool uncache = m_cumulatedCount > event.number<qint32>(2); m_cumulatedCount = event.number<qint32>(2); qint64 pixSize = 0; @@ -433,11 +431,16 @@ void PixmapCacheModel::computeMaxCacheSize() void PixmapCacheModel::resizeUnfinishedLoads() { - // all the "load start" events with duration 0 continue till the end of the trace - for (int i = 0; i < count(); i++) { - if (m_data[i].pixmapEventType == PixmapCacheModel::PixmapLoadingStarted && - duration(i) == 0) { - insertEnd(i, modelManager()->traceTime()->endTime() - startTime(i)); + // all the unfinished "load start" events continue till the end of the trace + for (auto pixmap = m_pixmaps.begin(), pixmapsEnd = m_pixmaps.end(); + pixmap != pixmapsEnd; ++pixmap) { + for (auto size = pixmap->sizes.begin(), sizesEnd = pixmap->sizes.end(); size != sizesEnd; + ++size) { + if (size->loadState == Loading) { + insertEnd(size->started, + modelManager()->traceTime()->endTime() - startTime(size->started)); + size->loadState = Error; + } } } } @@ -477,17 +480,26 @@ int PixmapCacheModel::updateCacheCount(int lastCacheSizeEvent, { newEvent.pixmapEventType = PixmapCacheCountChanged; newEvent.rowNumberCollapsed = 1; + newEvent.typeId = typeId; - qint64 prevSize = 0; + int index = lastCacheSizeEvent; if (lastCacheSizeEvent != -1) { - prevSize = m_data[lastCacheSizeEvent].cacheSize; - insertEnd(lastCacheSizeEvent, pixmapStartTime - startTime(lastCacheSizeEvent)); + newEvent.cacheSize = m_data[lastCacheSizeEvent].cacheSize + pixSize; + qint64 duration = pixmapStartTime - startTime(lastCacheSizeEvent); + if (duration > 0) { + insertEnd(lastCacheSizeEvent, duration); + index = insertStart(pixmapStartTime, 0); + m_data.insert(index, newEvent); + } else { + // If the timestamps are the same, just replace it + m_data[index] = newEvent; + } + } else { + newEvent.cacheSize = pixSize; + index = insertStart(pixmapStartTime, 0); + m_data.insert(index, newEvent); } - newEvent.cacheSize = prevSize + pixSize; - newEvent.typeId = typeId; - int index = insertStart(pixmapStartTime, 0); - m_data.insert(index, newEvent); return index; } diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp index c5908924926..0390d493cd0 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp @@ -187,6 +187,15 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeInde detailsRewriter->requestDetailsForLocation(typeIndex, type.location()); } +static bool isStateful(const QmlEventType &type) +{ + // Events of these types carry state that has to be taken into account when adding later events: + // PixmapCacheEvent: Total size of the cache and size of pixmap currently being loaded + // MemoryAllocation: Total size of the JS heap and the amount of it currently in use + const Message message = type.message(); + return message == PixmapCacheEvent || message == MemoryAllocation; +} + void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, QmlProfilerModelManager::EventLoader loader) const { @@ -196,6 +205,7 @@ void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, QFile file(d->file.fileName()); file.open(QIODevice::ReadOnly); QDataStream stream(&file); + bool crossedRangeStart = false; while (!stream.atEnd()) { stream >> event; if (stream.status() == QDataStream::ReadPastEnd) @@ -203,35 +213,48 @@ void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, const QmlEventType &type = d->eventTypes[event.typeIndex()]; if (rangeStart != -1 && rangeEnd != -1) { - if (event.timestamp() < rangeStart) { + // Double-check if rangeStart has been crossed. Some versions of Qt send dirty data. + if (event.timestamp() < rangeStart && !crossedRangeStart) { if (type.rangeType() != MaximumRangeType) { if (event.rangeStage() == RangeStart) stack.push(event); else if (event.rangeStage() == RangeEnd) stack.pop(); + continue; + } else if (isStateful(type)) { + event.setTimestamp(rangeStart); + } else { + continue; } - continue; - } else if (event.timestamp() > rangeEnd) { - if (type.rangeType() != MaximumRangeType) { - if (event.rangeStage() == RangeEnd) { - if (stack.isEmpty()) { - QmlEvent endEvent(event); - endEvent.setTimestamp(rangeEnd); - loader(endEvent, d->eventTypes[event.typeIndex()]); - } else { - stack.pop(); - } - } else if (event.rangeStage() == RangeStart) { - stack.push(event); + } else { + if (!crossedRangeStart) { + foreach (QmlEvent stashed, stack) { + stashed.setTimestamp(rangeStart); + loader(stashed, d->eventTypes[stashed.typeIndex()]); } + stack.clear(); + crossedRangeStart = true; } - continue; - } else if (!stack.isEmpty()) { - foreach (QmlEvent stashed, stack) { - stashed.setTimestamp(rangeStart); - loader(stashed, d->eventTypes[stashed.typeIndex()]); + if (event.timestamp() > rangeEnd) { + if (type.rangeType() != MaximumRangeType) { + if (event.rangeStage() == RangeEnd) { + if (stack.isEmpty()) { + QmlEvent endEvent(event); + endEvent.setTimestamp(rangeEnd); + loader(endEvent, d->eventTypes[event.typeIndex()]); + } else { + stack.pop(); + } + } else if (event.rangeStage() == RangeStart) { + stack.push(event); + } + continue; + } else if (isStateful(type)) { + event.setTimestamp(rangeEnd); + } else { + continue; + } } - stack.clear(); } } diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index 4c586a37eaf..0e8b16d444d 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -32,6 +32,8 @@ #include <qmldebug/qpacketprotocol.h> #include <utils/qtcassert.h> +#include <QQueue> + namespace QmlProfiler { class QmlProfilerTraceClientPrivate { @@ -70,6 +72,7 @@ public: QHash<QmlEventType, int> eventTypeIds; QHash<qint64, int> serverTypeIds; QStack<QmlTypedEvent> rangesInProgress; + QQueue<QmlEvent> pendingMessages; }; int QmlProfilerTraceClientPrivate::resolveType(const QmlTypedEvent &event) @@ -109,6 +112,10 @@ int QmlProfilerTraceClientPrivate::resolveStackTop() typeIndex = resolveType(typedEvent); typedEvent.event.setTypeIndex(typeIndex); + while (!pendingMessages.isEmpty() + && pendingMessages.head().timestamp() < typedEvent.event.timestamp()) { + model->addEvent(pendingMessages.dequeue()); + } model->addEvent(typedEvent.event); return typeIndex; } @@ -130,6 +137,8 @@ void QmlProfilerTraceClientPrivate::processCurrentEvent() int typeIndex = resolveStackTop(); QTC_ASSERT(typeIndex != -1, break); currentEvent.event.setTypeIndex(typeIndex); + while (!pendingMessages.isEmpty()) + model->addEvent(pendingMessages.dequeue()); model->addEvent(currentEvent.event); rangesInProgress.pop(); break; @@ -143,7 +152,10 @@ void QmlProfilerTraceClientPrivate::processCurrentEvent() default: { int typeIndex = resolveType(currentEvent); currentEvent.event.setTypeIndex(typeIndex); - model->addEvent(currentEvent.event); + if (rangesInProgress.isEmpty()) + model->addEvent(currentEvent.event); + else + pendingMessages.enqueue(currentEvent.event); break; } } @@ -281,6 +293,12 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data) d->maximumTime = qMax(d->currentEvent.event.timestamp(), d->maximumTime); if (d->currentEvent.type.message() == Complete) { + while (!d->rangesInProgress.isEmpty()) { + d->currentEvent = d->rangesInProgress.top(); + d->currentEvent.event.setRangeStage(RangeEnd); + d->currentEvent.event.setTimestamp(d->maximumTime); + d->processCurrentEvent(); + } emit complete(d->maximumTime); setRecordingFromServer(false); } else if (d->currentEvent.type.message() == Event diff --git a/tests/auto/algorithm/algorithm.pro b/tests/auto/algorithm/algorithm.pro new file mode 100644 index 00000000000..d1e88a924d5 --- /dev/null +++ b/tests/auto/algorithm/algorithm.pro @@ -0,0 +1,5 @@ +QTC_LIB_DEPENDS = utils +include(../qttest.pri) + +SOURCES += tst_algorithm.cpp +OTHER_FILES += $$IDE_SOURCE_TREE/src/libs/utils/algorithm.h diff --git a/tests/auto/algorithm/algorithm.qbs b/tests/auto/algorithm/algorithm.qbs new file mode 100644 index 00000000000..6131f95f86e --- /dev/null +++ b/tests/auto/algorithm/algorithm.qbs @@ -0,0 +1,10 @@ +import qbs + +QtcAutotest { + name: "Algorithm autotest" + Depends { name: "Utils" } + + files: [ + "tst_algorithm.cpp", + ] +} diff --git a/tests/auto/algorithm/tst_algorithm.cpp b/tests/auto/algorithm/tst_algorithm.cpp new file mode 100644 index 00000000000..e591965dfcc --- /dev/null +++ b/tests/auto/algorithm/tst_algorithm.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include <utils/algorithm.h> + +#include <QtTest> + +class tst_Algorithm : public QObject +{ + Q_OBJECT + +private slots: + void transform(); +}; + + +int stringToInt(const QString &s) +{ + return s.toInt(); +} + +void tst_Algorithm::transform() +{ + // same container type + { + // QList has standard inserter + const QList<QString> strings({"1", "3", "132"}); + const QList<int> i1 = Utils::transform(strings, [](const QString &s) { return s.toInt(); }); + QCOMPARE(i1, QList<int>({1, 3, 132})); + const QList<int> i2 = Utils::transform(strings, stringToInt); + QCOMPARE(i2, QList<int>({1, 3, 132})); + const QList<int> i3 = Utils::transform(strings, &QString::size); + QCOMPARE(i3, QList<int>({1, 1, 3})); + } + { + // QStringList + const QStringList strings({"1", "3", "132"}); + const QList<int> i1 = Utils::transform(strings, [](const QString &s) { return s.toInt(); }); + QCOMPARE(i1, QList<int>({1, 3, 132})); + const QList<int> i2 = Utils::transform(strings, stringToInt); + QCOMPARE(i2, QList<int>({1, 3, 132})); + const QList<int> i3 = Utils::transform(strings, &QString::size); + QCOMPARE(i3, QList<int>({1, 1, 3})); + } + { + // QSet internally needs special inserter + const QSet<QString> strings({"1", "3", "132"}); + const QSet<int> i1 = Utils::transform(strings, [](const QString &s) { return s.toInt(); }); + QCOMPARE(i1, QSet<int>({1, 3, 132})); + const QSet<int> i2 = Utils::transform(strings, stringToInt); + QCOMPARE(i2, QSet<int>({1, 3, 132})); + const QSet<int> i3 = Utils::transform(strings, &QString::size); + QCOMPARE(i3, QSet<int>({1, 3})); + } + + // different container types + { + // QList to QSet + const QList<QString> strings({"1", "3", "132"}); + const QSet<int> i1 = Utils::transform<QSet>(strings, [](const QString &s) { return s.toInt(); }); + QCOMPARE(i1, QSet<int>({1, 3, 132})); + const QSet<int> i2 = Utils::transform<QSet>(strings, stringToInt); + QCOMPARE(i2, QSet<int>({1, 3, 132})); + const QSet<int> i3 = Utils::transform<QSet>(strings, &QString::size); + QCOMPARE(i3, QSet<int>({1, 3})); + } + { + // QStringList to QSet + const QStringList strings({"1", "3", "132"}); + const QSet<int> i1 = Utils::transform<QSet>(strings, [](const QString &s) { return s.toInt(); }); + QCOMPARE(i1, QSet<int>({1, 3, 132})); + const QSet<int> i2 = Utils::transform<QSet>(strings, stringToInt); + QCOMPARE(i2, QSet<int>({1, 3, 132})); + const QSet<int> i3 = Utils::transform<QSet>(strings, &QString::size); + QCOMPARE(i3, QSet<int>({1, 3})); + } + { + // QSet to QList + const QSet<QString> strings({"1", "3", "132"}); + QList<int> i1 = Utils::transform<QList>(strings, [](const QString &s) { return s.toInt(); }); + qSort(i1); + QCOMPARE(i1, QList<int>({1, 3, 132})); + QList<int> i2 = Utils::transform<QList>(strings, stringToInt); + qSort(i2); + QCOMPARE(i2, QList<int>({1, 3, 132})); + QList<int> i3 = Utils::transform<QList>(strings, &QString::size); + qSort(i3); + QCOMPARE(i3, QList<int>({1, 1, 3})); + } +} + +QTEST_MAIN(tst_Algorithm) + +#include "tst_algorithm.moc" diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 1612ea7f63a..af26b3319dc 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,6 +1,7 @@ TEMPLATE = subdirs SUBDIRS += \ + algorithm \ aggregation \ changeset \ clangstaticanalyzer \ diff --git a/tests/system/objects.map b/tests/system/objects.map index 29b6fcbe8da..9c78f4ec13e 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -3,17 +3,17 @@ :*Qt Creator.Cancel Build_QToolButton {text='Cancel Build' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Clear_QToolButton {text='Clear' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:*Qt Creator.Continue_Core::Internal::FancyToolButton {text='Continue' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:*Qt Creator.Continue_Core::Internal::FancyToolButton {toolTip?='Continue *' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.DoubleTabWidget_ProjectExplorer::Internal::DoubleTabWidget {name='ProjectExplorer__Internal__DoubleTabWidget' type='ProjectExplorer::Internal::DoubleTabWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='DoubleTabWidget'} :*Qt Creator.Events_QDockWidget {name='QmlProfilerStatisticsViewDockWidget' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Events_QTabBar {aboveWidget=':*Qt Creator.Events_QDockWidget' type='QTabBar' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Find_Find::Internal::FindToolBar {name='Core__Internal__FindWidget' type='Core::Internal::FindToolBar' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Find'} :*Qt Creator.FormEditorStack_Designer::Internal::FormEditorStack {name='FormEditorStack' type='Designer::Internal::FormEditorStack' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:*Qt Creator.Interrupt_Core::Internal::FancyToolButton {text='Interrupt' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:*Qt Creator.Interrupt_Core::Internal::FancyToolButton {toolTip='Interrupt' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.JavaScript_QDockWidget {name='QmlProfilerV8ProfileViewDockWidget' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='V8'} :*Qt Creator.JavaScript_QTabBar {aboveWidget=':*Qt Creator.JavaScript_QDockWidget' type='QTabBar' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Run_Core::Internal::FancyToolButton {text='Run' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:*Qt Creator.Start Debugging_Core::Internal::FancyToolButton {text='Start Debugging' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:*Qt Creator.Start Debugging_Core::Internal::FancyToolButton {toolTip?='Start Debugging *' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Timeline_QDockWidget {name='QML ProfilerDockWidget' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Timeline'} :*Qt Creator.Timeline_QTabBar {aboveWidget=':*Qt Creator.Timeline_QDockWidget' type='QTabBar' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Widget Box_QDockWidget {name='WidgetBoxDockWidget' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Widget Box'} @@ -61,7 +61,7 @@ :DebugModeWidget.Toolbar_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Toolbar' type='QDockWidget' visible='1'} :DebugModeWidget_Debugger::Internal::ConsoleView {container=':Qt Creator.DebugModeWidget_QSplitter' type='Debugger::Internal::ConsoleView' unnamed='1' visible='1'} :DebugModeWidget_QComboBox {container=':Qt Creator.DebugModeWidget_QSplitter' occurrence='2' type='QComboBox' unnamed='1' visible='1'} -:Debugger Toolbar.Continue_QToolButton {container=':DebugModeWidget.Toolbar_QDockWidget' text='Continue' type='QToolButton' unnamed='1' visible='1'} +:Debugger Toolbar.Continue_QToolButton {container=':DebugModeWidget.Toolbar_QDockWidget' toolTip?='Continue *' type='QToolButton' unnamed='1' visible='1'} :Debugger Toolbar.Exit Debugger_QToolButton {container=':DebugModeWidget.Toolbar_QDockWidget' text='Stop Debugger' type='QToolButton' unnamed='1' visible='1'} :Debugger Toolbar.StatusText_Utils::StatusLabel {container=':DebugModeWidget.Toolbar_QDockWidget' type='Utils::StatusLabel' unnamed='1'} :Debugger.Docks.BreakDockWidget.Debugger.Docks.Break_QFrame {container=':DebugModeWidget.Debugger.Docks.BreakDockWidget_QDockWidget' name='Debugger.Docks.Break' type='QFrame' visible='1'} diff --git a/tests/system/suite_SCOM/tst_SCOM04/test.py b/tests/system/suite_SCOM/tst_SCOM04/test.py index 33a6870e299..5698cae8eb7 100644 --- a/tests/system/suite_SCOM/tst_SCOM04/test.py +++ b/tests/system/suite_SCOM/tst_SCOM04/test.py @@ -30,6 +30,7 @@ source("../../shared/suites_qtta.py") def main(): # expected error texts - for different compilers expectedErrorAlternatives = ["'SyntaxError' was not declared in this scope", + "\xe2\x80\x98SyntaxError\xe2\x80\x99 was not declared in this scope", "'SyntaxError' : undeclared identifier", "use of undeclared identifier 'SyntaxError'", "unknown type name 'SyntaxError'"] |