diff --git a/scripts/deployqtHelper_mac.sh b/scripts/deployqtHelper_mac.sh index 867fa5c6988..97cefee46bf 100755 --- a/scripts/deployqtHelper_mac.sh +++ b/scripts/deployqtHelper_mac.sh @@ -67,6 +67,18 @@ if [ -d "$assetimporterSrcDir" ]; then fi fi +# workaround for Qt 6.2: +# - QTBUG-94796 macdeployqt does not deploy /Contents/PlugIns/sqldrivers/libqsqlite.dylib anymore +sqldriversDestDir="$app_path/Contents/PlugIns/sqldrivers" +sqldriversSrcDir="$plugin_src/sqldrivers" +if [ -d "$sqldriversSrcDir" ]; then + if [ ! -d "$sqldriversDestDir" ]; then + echo "- Copying sqlitedriver plugin" + mkdir -p "$sqldriversDestDir" + cp "$sqldriversSrcDir/libqsqlite.dylib" "$sqldriversDestDir/libqsqlite.dylib" + fi +fi + # copy Qt Quick 2 imports imports2Dir="$app_path/Contents/Imports/qtquick2" if [ -d "$quick2_src" ]; then diff --git a/src/libs/tracing/CMakeLists.txt b/src/libs/tracing/CMakeLists.txt index cb46eb21b03..e44c9dc57b3 100644 --- a/src/libs/tracing/CMakeLists.txt +++ b/src/libs/tracing/CMakeLists.txt @@ -32,17 +32,13 @@ set(TRACING_CPP_SOURCES tracing_global.h ) -add_qtc_library(Tracing - FEATURE_INFO - DEPENDS Utils Qt5::Qml Qt5::Quick - PUBLIC_DEPENDS Qt5::Widgets - SOURCES - ${TEST_SOURCES} -) - if(${Qt5_VERSION} VERSION_LESS "6.2.0") - extend_qtc_library(Tracing + add_qtc_library(Tracing + FEATURE_INFO + DEPENDS Utils Qt5::Qml Qt5::Quick + PUBLIC_DEPENDS Qt5::Widgets SOURCES + ${TEST_SOURCES} ${TRACING_CPP_SOURCES} qml/tracing.qrc ) @@ -51,6 +47,14 @@ else() # < Qt 6.2 return() endif() + add_qtc_library(Tracing + FEATURE_INFO + DEPENDS Utils Qt5::Qml Qt5::Quick + PUBLIC_DEPENDS Qt5::Widgets + SOURCES + ${TEST_SOURCES} + ) + set(TRACING_QML_FILES qml/ButtonsBar.qml qml/CategoryLabel.qml diff --git a/src/libs/tracing/qml/CategoryLabel.qml b/src/libs/tracing/qml/CategoryLabel.qml index cfd98c9a31f..e70dba108c8 100644 --- a/src/libs/tracing/qml/CategoryLabel.qml +++ b/src/libs/tracing/qml/CategoryLabel.qml @@ -72,7 +72,7 @@ Item { DropArea { id: dropArea - onPositionChanged: { + onPositionChanged: (drag) => { var sourceIndex = drag.source.visualIndex; if (drag.source.y === 0) { // special case for first position: Always swap, no matter if upper border touched. @@ -129,7 +129,7 @@ Item { labelContainer.selectNextBySelectionId(label.id); } } - onSetRowHeight: { + onSetRowHeight: (newHeight) => { labelsArea.parentModel.setExpandedRowHeight(index + 1, newHeight); loader.height = labelsArea.parentModel.rowHeight(index + 1); } diff --git a/src/libs/tracing/qml/MainView.qml b/src/libs/tracing/qml/MainView.qml index 0bdf9346ec7..17a6a29e3c0 100644 --- a/src/libs/tracing/qml/MainView.qml +++ b/src/libs/tracing/qml/MainView.qml @@ -151,8 +151,12 @@ Rectangle { zoomer: zoomControl reverseSelect: shiftPressed - onMoveCategories: content.moveCategories(sourceIndex, targetIndex) - onSelectItem: content.select(modelIndex, eventIndex) + onMoveCategories: (sourceIndex, targetIndex) => { + content.moveCategories(sourceIndex, targetIndex) + } + onSelectItem: (modelIndex, eventIndex) => { + content.select(modelIndex, eventIndex) + } } TimeDisplay { @@ -206,7 +210,7 @@ Rectangle { onWidthChanged: selectionRange.update(); - onPropagateSelection: { + onPropagateSelection: (newModel, newItem) => { if (lockItemSelection || (newModel === selectedModel && newItem === selectedItem)) return; diff --git a/src/libs/tracing/qml/Overview.qml b/src/libs/tracing/qml/Overview.qml index d2b3eb29417..5152e4bc965 100644 --- a/src/libs/tracing/qml/Overview.qml +++ b/src/libs/tracing/qml/Overview.qml @@ -168,10 +168,10 @@ Rectangle { } } - onPressed: { + onPressed: (mouse) => { jumpTo(mouse.x); } - onPositionChanged: { + onPositionChanged: (mouse) => { jumpTo(mouse.x); } } diff --git a/src/libs/tracing/qml/TimelineLabels.qml b/src/libs/tracing/qml/TimelineLabels.qml index c675ce1b6d9..88fadfa6342 100644 --- a/src/libs/tracing/qml/TimelineLabels.qml +++ b/src/libs/tracing/qml/TimelineLabels.qml @@ -115,14 +115,14 @@ Flickable { categories.selectItem(index, eventId) } - onSelectNextBySelectionId: { + onSelectNextBySelectionId: (selectionId) => { categories.selectItem(index, modelData.nextItemBySelectionId( selectionId, zoomer.rangeStart, categories.selectedModel === index ? categories.selectedItem : -1)); } - onSelectPrevBySelectionId: { + onSelectPrevBySelectionId: (selectionId) => { categories.selectItem(index, modelData.prevItemBySelectionId( selectionId, zoomer.rangeStart, categories.selectedModel === index ? categories.selectedItem : diff --git a/src/libs/tracing/qml/TimelineRulers.qml b/src/libs/tracing/qml/TimelineRulers.qml index 0e052e716ff..99c9d533a37 100644 --- a/src/libs/tracing/qml/TimelineRulers.qml +++ b/src/libs/tracing/qml/TimelineRulers.qml @@ -44,7 +44,7 @@ Item { anchors.right: parent.right height: scaleHeight - onClicked: { + onClicked: (mouse) => { rulersModel.append({ timestamp: (mouse.x + contentX) * viewTimePerPixel + windowStart }); diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 41eed8d531f..9035f01b11d 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -71,6 +71,7 @@ add_qtc_library(Utils htmldocextractor.cpp htmldocextractor.h icon.cpp icon.h id.cpp id.h + indexedcontainerproxyconstiterator.h infobar.cpp infobar.h infolabel.cpp infolabel.h itemviews.cpp itemviews.h diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 9f8c7f67d5a..22589c9ed34 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -390,7 +390,9 @@ FilePath FilePath::resolvePath(const QString &fileName) const { if (FileUtils::isAbsolutePath(fileName)) return FilePath::fromString(QDir::cleanPath(fileName)); - return FilePath::fromString(QDir::cleanPath(toString() + QLatin1Char('/') + fileName)); + FilePath result = *this; + result.setPath(QDir::cleanPath(m_data + '/' + fileName)); + return result; } FilePath FilePath::cleanPath() const diff --git a/src/libs/utils/indexedcontainerproxyconstiterator.h b/src/libs/utils/indexedcontainerproxyconstiterator.h new file mode 100644 index 00000000000..7e9dd4c82a6 --- /dev/null +++ b/src/libs/utils/indexedcontainerproxyconstiterator.h @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + +#pragma once + +#include "utils_global.h" + +#include + +#include + +namespace Utils { + +/// A class useful for the implementation of the -> operator of proxy iterators. +template +struct ArrowProxy { + Reference r; + Reference *operator->() { + return &r; + } +}; + +/// Random-access const iterator over elements of a container providing an overloaded operator[] +/// (which may return a proxy object, like std::vector, rather than a reference). +template +class IndexedContainerProxyConstIterator +{ +public: + typedef std::random_access_iterator_tag iterator_category; + typedef typename std::make_signed::type difference_type; + typedef typename Container::value_type value_type; + typedef value_type reference; + typedef ArrowProxy pointer; + typedef typename Container::size_type size_type; + + IndexedContainerProxyConstIterator() + : m_container(nullptr), m_index(0) + {} + + IndexedContainerProxyConstIterator(const Container &container, size_type index) + : m_container(&container), m_index(index) + {} + + reference operator*() const + { + Q_ASSERT(m_container); + return (*m_container)[m_index]; + } + + pointer operator->() const + { + Q_ASSERT(m_container); + return pointer{(*m_container)[m_index]}; + } + + reference operator[](difference_type j) const + { + Q_ASSERT(m_container); + return (*m_container)[m_index + j]; + } + + bool operator==(const IndexedContainerProxyConstIterator &other) const + { + Q_ASSERT(m_container == other.m_container); + return m_index == other.m_index; + } + + bool operator!=(const IndexedContainerProxyConstIterator &other) const + { + Q_ASSERT(m_container == other.m_container); + return m_index != other.m_index; + } + + bool operator<(const IndexedContainerProxyConstIterator &other) const + { + Q_ASSERT(m_container == other.m_container); + return m_index < other.m_index; + } + + bool operator<=(const IndexedContainerProxyConstIterator &other) const + { + Q_ASSERT(m_container == other.m_container); + return m_index <= other.m_index; + } + + bool operator>(const IndexedContainerProxyConstIterator &other) const + { + Q_ASSERT(m_container == other.m_container); + return m_index > other.m_index; + } + + bool operator>=(const IndexedContainerProxyConstIterator &other) const + { + Q_ASSERT(m_container == other.m_container); + return m_index >= other.m_index; + } + + IndexedContainerProxyConstIterator &operator++() + { + ++m_index; + return *this; + } + + IndexedContainerProxyConstIterator operator++(int) + { + IndexedContainerProxyConstIterator copy(*this); + ++m_index; + return copy; + } + + IndexedContainerProxyConstIterator &operator--() + { + --m_index; + return *this; + } + + IndexedContainerProxyConstIterator operator--(int) + { + IndexedContainerProxyConstIterator copy(*this); + --m_index; + return copy; + } + + IndexedContainerProxyConstIterator &operator+=(difference_type j) + { + m_index += j; + return *this; + } + + IndexedContainerProxyConstIterator &operator-=(difference_type j) + { + m_index -= j; + return *this; + } + + IndexedContainerProxyConstIterator operator+(difference_type j) const + { + IndexedContainerProxyConstIterator result(*this); + result += j; + return result; + } + + IndexedContainerProxyConstIterator operator-(difference_type j) const + { + IndexedContainerProxyConstIterator result(*this); + result -= j; + return result; + } + + friend IndexedContainerProxyConstIterator operator+( + difference_type j, const IndexedContainerProxyConstIterator &other) + { + return other + j; + } + + difference_type operator-(const IndexedContainerProxyConstIterator &other) const + { + return static_cast(m_index) - static_cast(other.m_index); + } + +private: + const Container *m_container; + size_type m_index; +}; + +} // namespace Utils diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h index 53a6a3900ea..7240d8d6b6b 100644 --- a/src/libs/utils/treemodel.h +++ b/src/libs/utils/treemodel.h @@ -26,6 +26,7 @@ #pragma once #include "utils_global.h" +#include "indexedcontainerproxyconstiterator.h" #include @@ -119,6 +120,15 @@ public: }); } + using value_type = ChildType *; + using const_iterator = IndexedContainerProxyConstIterator; + using size_type = int; + + ChildType *operator[](int index) const { return childAt(index); } + int size() const { return childCount(); } + const_iterator begin() const { return const_iterator(*this, 0); } + const_iterator end() const { return const_iterator(*this, size()); } + template void forAllChildren(const Predicate &pred) const { const auto pred0 = [pred](TreeItem *treeItem) { pred(static_cast(treeItem)); }; diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index a8b8ccd5852..d9a2633deaa 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -153,6 +153,7 @@ HEADERS += \ $$PWD/environmentfwd.h \ $$PWD/genericconstants.h \ $$PWD/globalfilechangeblocker.h \ + $$PWD/indexedcontainerproxyconstiterator.h \ $$PWD/benchmarker.h \ $$PWD/displayname.h \ $$PWD/environment.h \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index b2c6bfe57f8..fdc625c2412 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -149,6 +149,7 @@ Project { "icon.h", "id.cpp", "id.h", + "indexedcontainerproxyconstiterator.h", "infobar.cpp", "infobar.h", "infolabel.cpp", diff --git a/src/plugins/coreplugin/menubarfilter.cpp b/src/plugins/coreplugin/menubarfilter.cpp index 354a0e7b367..207959f2d74 100644 --- a/src/plugins/coreplugin/menubarfilter.cpp +++ b/src/plugins/coreplugin/menubarfilter.cpp @@ -101,7 +101,9 @@ QList MenuBarFilter::matchesForAction(QAction *action, QList entries; if (!m_enabledActions.contains(action)) return entries; - const QString text = Utils::stripAccelerator(action->text()); + const QString whatsThis = action->whatsThis(); + const QString text = Utils::stripAccelerator(action->text()) + + (whatsThis.isEmpty() ? QString() : QString(" (" + whatsThis + ")")); if (QMenu *menu = action->menu()) { if (processedMenus.contains(menu)) return entries; diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index fd0bfd91178..55d7833761c 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -432,8 +432,7 @@ void DebuggerItemConfigWidget::binaryPathHasChanged() return; DebuggerItem tmp; - QFileInfo fi = QFileInfo(m_binaryChooser->filePath().toString()); - if (fi.isExecutable()) { + if (m_binaryChooser->filePath().isExecutableFile()) { tmp = item(); tmp.reinitializeFromFile(); } @@ -800,7 +799,7 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePath &de const QString name = detectionSource.isEmpty() ? tr("System %1 at %2") : tr("Detected %1 at %2"); item.setUnexpandedDisplayName(name.arg(item.engineTypeName()).arg(command.toUserOutput())); m_model->addDebugger(item); - logMessages.append(tr("Found: \"%1\"").arg(name)); + logMessages.append(tr("Found: \"%1\"").arg(command.toUserOutput())); } if (logMessage) *logMessage = logMessages.join('\n'); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index b533c67d335..b355eb5d9b3 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,7 @@ #include #include #include +#include #include #ifdef Q_OS_UNIX @@ -312,6 +314,14 @@ public: QFileSystemWatcher m_mergedDirWatcher; Environment m_cachedEnviroment; + + enum LocalAccessState + { + NotEvaluated, + NoDaemon, + Accessible, + NotAccessible + } m_accessible = NotEvaluated; }; class DockerDeviceWidget final : public IDeviceWidget @@ -337,6 +347,17 @@ public: m_repoLineEdit->setText(data.repo); m_repoLineEdit->setEnabled(false); + auto daemonStateLabel = new QLabel(tr("Daemon state:")); + m_daemonReset = new QToolButton; + m_daemonReset->setIcon(Icons::INFO.icon()); + m_daemonReset->setToolTip(tr("Daemon state not evaluated.")); + + connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] { + dockerDevice->resetDaemonState(); + m_daemonReset->setIcon(Icons::INFO.icon()); + m_daemonReset->setToolTip(tr("Daemon state not evaluated.")); + }); + m_runAsOutsideUser = new QCheckBox(tr("Run as outside user")); m_runAsOutsideUser->setToolTip(tr("Use user ID and group ID of the user running Qt Creator " "in the Docker container.")); @@ -369,6 +390,16 @@ public: logView->clear(); dockerDevice->tryCreateLocalFileAccess(); m_kitItemDetector.autoDetect(id); + + if (!dockerDevice->isDaemonRunning()) { + logView->append(tr("Docker daemon appears to be not running.")); + m_daemonReset->setToolTip(tr("Daemon not running. Push to reset the state.")); + m_daemonReset->setIcon(Icons::CRITICAL.icon()); + } else { + m_daemonReset->setToolTip(tr("Docker daemon running.")); + m_daemonReset->setIcon(Icons::OK.icon()); + + } }); connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, id = data.id()] { @@ -381,6 +412,7 @@ public: Form { idLabel, m_idLineEdit, Break(), repoLabel, m_repoLineEdit, Break(), + daemonStateLabel, m_daemonReset, Break(), m_runAsOutsideUser, Break(), tr("Paths to mount:"), m_pathsLineEdit, Break(), Column { @@ -397,6 +429,7 @@ public: private: QLineEdit *m_idLineEdit; QLineEdit *m_repoLineEdit; + QToolButton *m_daemonReset; QCheckBox *m_runAsOutsideUser; QLineEdit *m_pathsLineEdit; @@ -648,7 +681,7 @@ void DockerDevice::tryCreateLocalFileAccess() const void DockerDevicePrivate::stopCurrentContainer() { - if (m_container.isEmpty()) + if (m_container.isEmpty() || m_accessible == NoDaemon) return; QtcProcess proc; @@ -662,7 +695,7 @@ void DockerDevicePrivate::stopCurrentContainer() void DockerDevicePrivate::tryCreateLocalFileAccess() { - if (!m_container.isEmpty()) + if (!m_container.isEmpty() || m_accessible == NoDaemon) return; QString tempFileName; @@ -701,6 +734,14 @@ void DockerDevicePrivate::tryCreateLocalFileAccess() LOG("RES: " << m_shell->result() << " STDOUT: " << m_shell->readAllStandardOutput() << " STDERR: " << m_shell->readAllStandardError()); + if (m_shell->exitCode() != 0) { + m_accessible = NoDaemon; + LOG("DOCKER DAEMON NOT RUNNING?"); + MessageManager::writeFlashing(tr("Docker Daemon appears to be not running. " + "Verify daemon is up and running and reset the " + "docker daemon on the docker device settings page " + "or restart Qt Creator.")); + } } m_container.clear(); }); @@ -723,10 +764,11 @@ void DockerDevicePrivate::tryCreateLocalFileAccess() break; } } - if (i == 20) { + if (i == 20 || m_accessible == NoDaemon) { qWarning("Docker cid file empty."); return; // No } + qApp->processEvents(); // FIXME turn this for-loop into QEventLoop QThread::msleep(100); } @@ -753,11 +795,13 @@ void DockerDevicePrivate::tryCreateLocalFileAccess() // of using wsl or a named pipe. // TODO investigate how to make it possible nevertheless. m_mergedDir.clear(); + m_accessible = NotAccessible; MessageManager::writeSilently(tr("This is expected on Windows.")); return; } } + m_accessible = Accessible; m_mergedDirWatcher.addPath(m_mergedDir); } @@ -766,6 +810,24 @@ bool DockerDevice::hasLocalFileAccess() const return !d->m_mergedDir.isEmpty(); } +bool DockerDevice::isDaemonRunning() const +{ + switch (d->m_accessible) { + case DockerDevicePrivate::NoDaemon: + return false; + case DockerDevicePrivate::NotEvaluated: // FIXME? + case DockerDevicePrivate::Accessible: + case DockerDevicePrivate::NotAccessible: + return true; + } + return false; +} + +void DockerDevice::resetDaemonState() +{ + d->m_accessible = DockerDevicePrivate::NotEvaluated; +} + void DockerDevice::setMounts(const QStringList &mounts) const { d->m_data.mounts = mounts; @@ -1183,7 +1245,7 @@ bool DockerDevice::writeFileContents(const Utils::FilePath &filePath, const QByt void DockerDevice::runProcess(QtcProcess &process) const { tryCreateLocalFileAccess(); - if (d->m_container.isEmpty()) { + if (d->m_container.isEmpty() || d->m_accessible == DockerDevicePrivate::NoDaemon) { LOG("No container set to run " << process.commandLine().toUserOutput()); QTC_CHECK(false); process.setResult(QtcProcess::StartFailed); @@ -1237,6 +1299,8 @@ void DockerDevicePrivate::fetchSystemEnviroment() int DockerDevicePrivate::runSynchronously(const CommandLine &cmd) const { + if (m_accessible == NoDaemon) + return -1; CommandLine dcmd{"docker", {"exec", m_container}}; dcmd.addArgs(cmd); diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 35ba3f1c87f..0c3eb5cb654 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -107,6 +107,8 @@ public: void tryCreateLocalFileAccess() const; bool hasLocalFileAccess() const; + bool isDaemonRunning() const; + void resetDaemonState(); void setMounts(const QStringList &mounts) const; Utils::FilePath mapToLocalAccess(const Utils::FilePath &filePath) const; diff --git a/src/plugins/perfprofiler/CMakeLists.txt b/src/plugins/perfprofiler/CMakeLists.txt index f7f6c91aa04..d83e9e65523 100644 --- a/src/plugins/perfprofiler/CMakeLists.txt +++ b/src/plugins/perfprofiler/CMakeLists.txt @@ -38,16 +38,12 @@ set(PERFPROFILER_CPP_SOURCES perftracepointdialog.cpp perftracepointdialog.h perftracepointdialog.ui ) -add_qtc_plugin(PerfProfiler - DEPENDS Tracing Qt5::QuickWidgets - PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport - SOURCES - ${TEST_SOURCES} -) - if(${Qt5_VERSION} VERSION_LESS "6.2.0") - extend_qtc_plugin(PerfProfiler + add_qtc_plugin(PerfProfiler + DEPENDS Tracing Qt5::QuickWidgets + PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport SOURCES + ${TEST_SOURCES} ${PERFPROFILER_CPP_SOURCES} perfprofiler.qrc ) @@ -56,6 +52,13 @@ else() # < Qt 6.2 return() endif() + add_qtc_plugin(PerfProfiler + DEPENDS Tracing Qt5::QuickWidgets + PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport + SOURCES + ${TEST_SOURCES} + ) + qt_add_resources(PerfProfiler perfprofiler PREFIX "/perfprofiler" tracepoints.sh diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index d7f12d4a7ca..cc637f17fe1 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1861,7 +1861,10 @@ static void detectCppBuildTools2015(QList *list) QList MsvcToolChainFactory::autoDetect(const QList &alreadyKnown, const IDevice::Ptr &device) { - Q_UNUSED(device) + if (!device.isNull()) { + // FIXME currently no support for msvc toolchains on a device + return {}; + } QList results; @@ -1969,8 +1972,10 @@ QList ClangClToolChainFactory::autoDetect(const QList const IDevice::Ptr &device) { Q_UNUSED(alreadyKnown) - Q_UNUSED(device) // FIXME: Use it. - + if (!device.isNull()) { + // FIXME currently no support for msvc toolchains on a device + return {}; + } #ifdef Q_OS_WIN64 const char registryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM"; #else diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 0ec4647ad9c..b48149ec7a1 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1140,36 +1140,48 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er // deploy session dd->m_deploySessionAction = new QAction(tr("Deploy"), this); + dd->m_deploySessionAction->setWhatsThis(tr("Deploy All Projects")); cmd = ActionManager::registerAction(dd->m_deploySessionAction, Constants::DEPLOYSESSION); + cmd->setDescription(dd->m_deploySessionAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS); msessionContextMenu->addAction(cmd, Constants::G_SESSION_BUILD); // rebuild session action dd->m_rebuildSessionAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"), this); + dd->m_rebuildSessionAction->setWhatsThis(tr("Rebuild All Projects")); cmd = ActionManager::registerAction(dd->m_rebuildSessionAction, Constants::REBUILDSESSION); + cmd->setDescription(dd->m_rebuildSessionAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS); msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD); dd->m_rebuildSessionForAllConfigsAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"), this); + dd->m_rebuildSessionForAllConfigsAction->setWhatsThis( + tr("Rebuild All Projects for All Configurations")); cmd = ActionManager::registerAction(dd->m_rebuildSessionForAllConfigsAction, Constants::REBUILDSESSIONALLCONFIGS); + cmd->setDescription(dd->m_rebuildSessionForAllConfigsAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS); msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD); // clean session dd->m_cleanSessionAction = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this); + dd->m_cleanSessionAction->setWhatsThis(tr("Clean All Projects")); cmd = ActionManager::registerAction(dd->m_cleanSessionAction, Constants::CLEANSESSION); + cmd->setDescription(dd->m_cleanSessionAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS); msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD); dd->m_cleanSessionForAllConfigsAction = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this); + dd->m_cleanSessionForAllConfigsAction->setWhatsThis( + tr("Clean All Projects for All Configurations")); cmd = ActionManager::registerAction(dd->m_cleanSessionForAllConfigsAction, Constants::CLEANSESSIONALLCONFIGS); + cmd->setDescription(dd->m_cleanSessionForAllConfigsAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS); msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD); @@ -1215,39 +1227,45 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er // deploy action dd->m_deployAction = new QAction(tr("Deploy"), this); + dd->m_deployAction->setWhatsThis(tr("Deploy Project")); cmd = ActionManager::registerAction(dd->m_deployAction, Constants::DEPLOY); cmd->setAttribute(Command::CA_UpdateText); - cmd->setDescription(dd->m_deployAction->text()); + cmd->setDescription(dd->m_deployAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_PROJECT); // rebuild action dd->m_rebuildAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"), this); + dd->m_rebuildAction->setWhatsThis(tr("Rebuild Project")); cmd = ActionManager::registerAction(dd->m_rebuildAction, Constants::REBUILD); cmd->setAttribute(Command::CA_UpdateText); - cmd->setDescription(dd->m_rebuildAction->text()); + cmd->setDescription(dd->m_rebuildAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_PROJECT); dd->m_rebuildProjectForAllConfigsAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"), this); + dd->m_rebuildProjectForAllConfigsAction->setWhatsThis( + tr("Rebuild Project for All Configurations")); cmd = ActionManager::registerAction(dd->m_rebuildProjectForAllConfigsAction, Constants::REBUILDALLCONFIGS); cmd->setAttribute(Command::CA_UpdateText); - cmd->setDescription(dd->m_rebuildProjectForAllConfigsAction->text()); + cmd->setDescription(dd->m_rebuildProjectForAllConfigsAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_PROJECT_ALLCONFIGURATIONS); // clean action dd->m_cleanAction = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this); + dd->m_cleanAction->setWhatsThis(tr("Clean Project")); cmd = ActionManager::registerAction(dd->m_cleanAction, Constants::CLEAN); cmd->setAttribute(Command::CA_UpdateText); - cmd->setDescription(dd->m_cleanAction->text()); + cmd->setDescription(dd->m_cleanAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_PROJECT); dd->m_cleanProjectForAllConfigsAction = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this); + dd->m_cleanProjectForAllConfigsAction->setWhatsThis(tr("Clean Project for All Configurations")); cmd = ActionManager::registerAction(dd->m_cleanProjectForAllConfigsAction, Constants::CLEANALLCONFIGS); cmd->setAttribute(Command::CA_UpdateText); - cmd->setDescription(dd->m_cleanProjectForAllConfigsAction->text()); + cmd->setDescription(dd->m_cleanProjectForAllConfigsAction->whatsThis()); mbuild->addAction(cmd, Constants::G_BUILD_PROJECT_ALLCONFIGURATIONS); // cancel build action diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 1ba9625ecf2..0565edcc523 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -61,6 +61,7 @@ #include #include +#include #include #include @@ -69,6 +70,28 @@ using namespace Utils; namespace ProjectExplorer { namespace Internal { +/// An output iterator whose assignment operator appends a clone of the operand to the list of +/// children of the WrapperNode passed to the constructor. +class Appender : public std::iterator +{ +public: + explicit Appender(WrapperNode *parent) : m_parent(parent) {} + + Appender &operator=(const WrapperNode *node) + { + if (node) + m_parent->appendClone(*node); + return *this; + } + + Appender &operator*() { return *this; } + Appender &operator++() { return *this; } + Appender &operator++(int) { return *this; } + +private: + WrapperNode *m_parent; +}; + bool compareNodes(const Node *n1, const Node *n2) { if (n1->priority() > n2->priority()) @@ -82,9 +105,7 @@ bool compareNodes(const Node *n1, const Node *n2) const int filePathResult = caseFriendlyCompare(n1->filePath().toString(), n2->filePath().toString()); - if (filePathResult != 0) - return filePathResult < 0; - return n1 < n2; // sort by pointer value + return filePathResult < 0; } static bool sortWrapperNodes(const WrapperNode *w1, const WrapperNode *w2) @@ -92,6 +113,71 @@ static bool sortWrapperNodes(const WrapperNode *w1, const WrapperNode *w2) return compareNodes(w1->m_node, w2->m_node); } +/// Appends to `dest` clones of children of `first` and `second`, removing duplicates (recursively). +/// +/// \param first, second +/// Nodes with children sorted by sortWrapperNodes. +/// \param dest +/// Node to which to append clones of children of `first` and `second`, with duplicates removed. +static void appendMergedChildren(const WrapperNode *first, const WrapperNode *second, WrapperNode *dest) +{ + setUnionMerge(first->begin(), first->end(), + second->begin(), second->end(), + Appender(dest), + [dest](const WrapperNode *childOfFirst, const WrapperNode *childOfSecond) + -> const WrapperNode * { + if (childOfSecond->hasChildren()) { + if (childOfFirst->hasChildren()) { + WrapperNode *mergeResult = new WrapperNode(childOfFirst->m_node); + dest->appendChild(mergeResult); + appendMergedChildren(childOfFirst, childOfSecond, mergeResult); + // mergeResult has already been appended to the parent's list of + // children -- there's no need for the Appender to do it again. + // That's why we return a null pointer. + return nullptr; + } else { + return childOfSecond; + } + } else { + return childOfFirst; + } + }, + sortWrapperNodes); +} + +/// Given a node `parent` with children sorted by the criteria defined in sortWrapperNodes(), merge +/// any children that are equal according to those criteria. +static void mergeDuplicates(WrapperNode *parent) +{ + // We assume all descendants of 'parent' are sorted + int childIndex = 0; + while (childIndex + 1 < parent->childCount()) { + const WrapperNode *child = parent->childAt(childIndex); + const WrapperNode *nextChild = parent->childAt(childIndex + 1); + Q_ASSERT_X(!sortWrapperNodes(nextChild, child), __func__, "Children are not sorted"); + if (!sortWrapperNodes(child, nextChild)) { + // child and nextChild must have the same priorities, display names and folder paths. + // Replace them by a single node 'mergeResult` containing the union of their children. + auto mergeResult = new WrapperNode(child->m_node); + parent->insertChild(childIndex, mergeResult); + appendMergedChildren(child, nextChild, mergeResult); + // Now we can remove the original children + parent->removeChildAt(childIndex + 2); + parent->removeChildAt(childIndex + 1); + } else { + ++childIndex; + } + } +} + +void WrapperNode::appendClone(const WrapperNode &node) +{ + WrapperNode *clone = new WrapperNode(node.m_node); + appendChild(clone); + for (const WrapperNode *child : node) + clone->appendClone(*child); +} + FlatModel::FlatModel(QObject *parent) : TreeModel(new WrapperNode(nullptr), parent) { @@ -393,6 +479,8 @@ void FlatModel::saveExpandData() void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet *seen) { + bool hasHiddenSourcesOrHeaders = false; + for (Node *node : folderNode->nodes()) { if (m_filterGeneratedFiles && node->isGenerated()) continue; @@ -403,8 +491,10 @@ void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet< if (!m_showSourceGroups) { if (subFolderNode->isVirtualFolderType()) { auto vnode = static_cast(subFolderNode); - if (vnode->isSourcesOrHeaders()) + if (vnode->isSourcesOrHeaders()) { isHidden = true; + hasHiddenSourcesOrHeaders = true; + } } } if (!isHidden && !seen->contains(subFolderNode)) { @@ -423,6 +513,11 @@ void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet< } } } + + if (hasHiddenSourcesOrHeaders) { + parent->sortChildren(&sortWrapperNodes); + mergeDuplicates(parent); + } } bool FlatModel::trimEmptyDirectories(WrapperNode *parent) diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h index 4c7b4012706..2da85b1a858 100644 --- a/src/plugins/projectexplorer/projectmodels.h +++ b/src/plugins/projectexplorer/projectmodels.h @@ -52,6 +52,8 @@ class WrapperNode : public Utils::TypedTreeItem public: explicit WrapperNode(Node *node) : m_node(node) {} Node *m_node = nullptr; + + void appendClone(const WrapperNode &node); }; class FlatModel : public Utils::TreeModel diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index bba13fe5f15..b739a93f1ca 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -361,7 +361,7 @@ public: void setIsSourcesOrHeaders(bool on) { m_isSourcesOrHeaders = on; } private: - bool m_isSourcesOrHeaders; // "Sources" or "Headers" + bool m_isSourcesOrHeaders = false; // "Sources" or "Headers" }; // Documentation inside. diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index 992047bb1fa..f96a86656eb 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -190,9 +190,11 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString * this, &QbsProjectManagerPlugin::cleanProductContextMenu); m_cleanProduct = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this); + m_cleanProduct->setWhatsThis(tr("Clean Product")); command = Core::ActionManager::registerAction(m_cleanProduct, Constants::ACTION_CLEAN_PRODUCT); command->setAttribute(Core::Command::CA_Hide); command->setAttribute(Core::Command::CA_UpdateText); + command->setDescription(m_cleanProduct->whatsThis()); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_PRODUCT); connect(m_cleanProduct, &QAction::triggered, this, &QbsProjectManagerPlugin::cleanProduct); @@ -205,10 +207,12 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString * this, &QbsProjectManagerPlugin::rebuildProductContextMenu); m_rebuildProduct = new QAction(ProjectExplorer::Icons::REBUILD.icon(), tr("Rebuild"), this); + m_rebuildProduct->setWhatsThis(tr("Rebuild Product")); command = Core::ActionManager::registerAction(m_rebuildProduct, Constants::ACTION_REBUILD_PRODUCT); command->setAttribute(Core::Command::CA_Hide); command->setAttribute(Core::Command::CA_UpdateText); + command->setDescription(m_rebuildProduct->whatsThis()); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_PRODUCT); connect(m_rebuildProduct, &QAction::triggered, this, &QbsProjectManagerPlugin::rebuildProduct); diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 5063d88ae74..da1f89f4eee 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -377,11 +377,9 @@ QVariant QmakeProFileNode::data(Utils::Id role) const if (role == Android::Constants::AndroidSoLibPath) { TargetInformation info = targetInformation(); QStringList res = {info.buildDir.toString()}; - Utils::FilePath destDir = info.destDir; + FilePath destDir = info.destDir; if (!destDir.isEmpty()) { - if (destDir.toFileInfo().isRelative()) - destDir = Utils::FilePath::fromString(QDir::cleanPath(info.buildDir.toString() - + '/' + destDir.toString())); + destDir = info.buildDir.resolvePath(destDir.path()); res.append(destDir.toString()); } res.removeDuplicates(); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index 01da9cad48f..603f683f304 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -246,19 +246,21 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString d->m_rebuildSubProjectAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"), this); + d->m_rebuildSubProjectAction->setWhatsThis(tr("Rebuild Subproject")); command = ActionManager::registerAction(d->m_rebuildSubProjectAction, Constants::REBUILDSUBDIR, projectContext); command->setAttribute(Command::CA_Hide); command->setAttribute(Command::CA_UpdateText); - command->setDescription(d->m_rebuildSubProjectAction->text()); + command->setDescription(d->m_rebuildSubProjectAction->whatsThis()); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_SUBPROJECT); connect(d->m_rebuildSubProjectAction, &QAction::triggered, d, &QmakeProjectManagerPluginPrivate::rebuildSubDirContextMenu); d->m_cleanSubProjectAction = new QAction(Utils::Icons::CLEAN.icon(),tr("Clean"), this); + d->m_cleanSubProjectAction->setWhatsThis(tr("Clean Subproject")); command = ActionManager::registerAction(d->m_cleanSubProjectAction, Constants::CLEANSUBDIR, projectContext); command->setAttribute(Command::CA_Hide); command->setAttribute(Command::CA_UpdateText); - command->setDescription(d->m_cleanSubProjectAction->text()); + command->setDescription(d->m_cleanSubProjectAction->whatsThis()); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_SUBPROJECT); connect(d->m_cleanSubProjectAction, &QAction::triggered, d, &QmakeProjectManagerPluginPrivate::cleanSubDirContextMenu); diff --git a/src/plugins/qmlprofiler/CMakeLists.txt b/src/plugins/qmlprofiler/CMakeLists.txt index 295bc3d0bb9..c5fa5399f86 100644 --- a/src/plugins/qmlprofiler/CMakeLists.txt +++ b/src/plugins/qmlprofiler/CMakeLists.txt @@ -69,16 +69,12 @@ set(QMLPROFILER_CPP_SOURCES scenegraphtimelinemodel.cpp scenegraphtimelinemodel.h ) -add_qtc_plugin(QmlProfiler - DEPENDS QmlDebug QmlJS Tracing Qt5::QuickWidgets - PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport TextEditor - SOURCES - ${TEST_SOURCES} -) - if(${Qt5_VERSION} VERSION_LESS "6.2.0") - extend_qtc_plugin(QmlProfiler + add_qtc_plugin(QmlProfiler + DEPENDS QmlDebug QmlJS Tracing Qt5::QuickWidgets + PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport TextEditor SOURCES + ${TEST_SOURCES} ${QMLPROFILER_CPP_SOURCES} qml/qmlprofiler.qrc ) @@ -87,6 +83,13 @@ else() # < Qt 6.2 return() endif() + add_qtc_plugin(QmlProfiler + DEPENDS QmlDebug QmlJS Tracing Qt5::QuickWidgets + PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport TextEditor + SOURCES + ${TEST_SOURCES} + ) + set(QMLPROFILER_QML_FILES qml/QmlProfilerFlameGraphView.qml ) diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index b3633ff614a..c512b372cd0 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -272,14 +272,14 @@ void tst_TestCore::loadEmptyCoreModel() QVERIFY(compareTree(testRewriterView1->rootModelNode(), testRewriterView2->rootModelNode())); } -void tst_TestCore::testRewriterView() +void tst_TestCore::testRewriterView2() { try { QPlainTextEdit textEdit; - textEdit.setPlainText("import QtQuick 2.15;\n\nItem {\n}\n"); + textEdit.setPlainText("import QtQuick 2.15;\n\nRectangle {\n}\n"); NotIndentingTextEditModifier textModifier(&textEdit); - QScopedPointer model(Model::create("QtQuick.Item")); + QScopedPointer model(Model::create("QtQuick.Rectangle", 2, 1)); QVERIFY(model.data()); QScopedPointer view(new TestView(model.data())); @@ -292,15 +292,20 @@ void tst_TestCore::testRewriterView() testRewriterView->setTextModifier(&textModifier); model->attachView(testRewriterView.data()); - ModelNode childNode(addNodeListChild(rootModelNode, "QtQuick.Rectangle", 1, 0, "data")); + while (testRewriterView->hasIncompleteTypeInformation()) { + QApplication::processEvents(QEventLoop::AllEvents, 1000); + } + + ModelNode childNode(addNodeListChild(rootModelNode, "QtQuick.Rectangle", 2, 11, "data")); + QVERIFY(childNode.isValid()); childNode.setIdWithoutRefactoring("childNode"); - ModelNode childNode2(addNodeListChild(childNode, "QtQuick.Rectangle", 1, 0, "data")); + ModelNode childNode2(addNodeListChild(childNode, "QtQuick.Rectangle", 2, 11, "data")); childNode2.setIdWithoutRefactoring("childNode2"); - ModelNode childNode3(addNodeListChild(childNode2, "QtQuick.Rectangle", 1, 0, "data")); + ModelNode childNode3(addNodeListChild(childNode2, "QtQuick.Rectangle", 2, 11, "data")); childNode3.setIdWithoutRefactoring("childNode3"); - ModelNode childNode4(addNodeListChild(childNode3, "QtQuick.Rectangle", 1, 0, "data")); + ModelNode childNode4(addNodeListChild(childNode3, "QtQuick.Rectangle", 2, 11, "data")); childNode4.setIdWithoutRefactoring("childNode4"); QVERIFY(childNode.isValid()); @@ -326,7 +331,7 @@ void tst_TestCore::testRewriterView() testRewriterView->modelToTextMerger()->applyChanges(); - childNode = addNodeListChild(rootModelNode, "QtQuick.Rectangle", 2, 0, "data"); + childNode = addNodeListChild(rootModelNode, "QtQuick.Rectangle", 2, 11, "data"); QVERIFY(testRewriterView->modelToTextMerger()->isNodeScheduledForAddition(childNode)); testRewriterView->modelToTextMerger()->applyChanges(); @@ -334,6 +339,93 @@ void tst_TestCore::testRewriterView() childNode.variantProperty("x").setValue(70); childNode.variantProperty("y").setValue(90); + QCOMPARE(testRewriterView->modelToTextMerger() + ->findAddedVariantProperty(childNode.variantProperty("x")) + .value(), + QVariant(70)); + QCOMPARE(testRewriterView->modelToTextMerger() + ->findAddedVariantProperty(childNode.variantProperty("y")) + .value(), + QVariant(90)); + + model->detachView(testRewriterView.data()); + } catch (Exception &e) { + QFAIL(qPrintable(e.description())); + } +} + +void tst_TestCore::testRewriterView() +{ + try { + const QLatin1String qmlString("import QtQuick 2.15\n" + "Rectangle {\n" + "}\n"); + + QPlainTextEdit textEdit; + textEdit.setPlainText(qmlString); + NotIndentingTextEditModifier textModifier(&textEdit); + + QScopedPointer model(Model::create("QtQuick.Item", 2, 15)); + QVERIFY(model.data()); + + QScopedPointer testRewriterView(new TestRewriterView()); + testRewriterView->setTextModifier(&textModifier); + testRewriterView->setCheckSemanticErrors(true); + model->attachView(testRewriterView.data()); + + while (testRewriterView->hasIncompleteTypeInformation()) { + QApplication::processEvents(QEventLoop::AllEvents, 1000); + } + + textEdit.setPlainText(qmlString); + + ModelNode rootModelNode = testRewriterView->rootModelNode(); + + ModelNode childNode(addNodeListChild(rootModelNode, "QtQuick.Rectangle", 2, 11, "data")); + + QVERIFY(childNode.isValid()); + childNode.setIdWithoutRefactoring("childNode"); + + ModelNode childNode2(addNodeListChild(childNode, "QtQuick.Rectangle", 2, 11, "data")); + childNode2.setIdWithoutRefactoring("childNode2"); + ModelNode childNode3(addNodeListChild(childNode2, "QtQuick.Rectangle", 2, 11, "data")); + childNode3.setIdWithoutRefactoring("childNode3"); + ModelNode childNode4(addNodeListChild(childNode3, "QtQuick.Rectangle", 2, 11, "data")); + childNode4.setIdWithoutRefactoring("childNode4"); + + QVERIFY(childNode.isValid()); + QVERIFY(childNode2.isValid()); + QVERIFY(childNode3.isValid()); + QVERIFY(childNode4.isValid()); + + testRewriterView->setModificationGroupActive(true); + + childNode.destroy(); + + QVERIFY(!childNode.isValid()); + QVERIFY(!childNode2.isValid()); + QVERIFY(!childNode3.isValid()); + QVERIFY(!childNode4.isValid()); + + QVERIFY(testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode)); + QVERIFY(!testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode2)); + QVERIFY(!testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode3)); + QVERIFY(!testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode4)); + + QVERIFY(!rootModelNode.hasProperty("data")); + + testRewriterView->modelToTextMerger()->applyChanges(); + + childNode = addNodeListChild(rootModelNode, "QtQuick.Rectangle", 2, 11, "data"); + QVERIFY(testRewriterView->modelToTextMerger()->isNodeScheduledForAddition(childNode)); + QVERIFY(childNode.isValid()); + + testRewriterView->modelToTextMerger()->applyChanges(); + + QVERIFY(childNode.isValid()); + childNode.variantProperty("x").setValue(70); + childNode.variantProperty("y").setValue(90); + QCOMPARE(testRewriterView->modelToTextMerger()->findAddedVariantProperty(childNode.variantProperty("x")).value(), QVariant(70)); QCOMPARE(testRewriterView->modelToTextMerger()->findAddedVariantProperty(childNode.variantProperty("y")).value(), QVariant(90)); diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h index 51bd8f496d6..d052bf950e5 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h @@ -95,6 +95,7 @@ private slots: // unit tests Rewriter // void testRewriterView(); + void testRewriterView2(); void testRewriterErrors(); void testRewriterChangeId(); void testRewriterRemoveId(); diff --git a/tests/auto/tracing/flamegraphview/CMakeLists.txt b/tests/auto/tracing/flamegraphview/CMakeLists.txt index f64a90d4d3b..a1e900b7288 100644 --- a/tests/auto/tracing/flamegraphview/CMakeLists.txt +++ b/tests/auto/tracing/flamegraphview/CMakeLists.txt @@ -1,19 +1,20 @@ -add_qtc_test(tst_tracing_flamegraphview - DEPENDS Tracing Qt5::QuickWidgets Qt5::Quick Utils -) - set(TSTFLAMEGRAPHVIEW_CPP_SOURCES testflamegraphmodel.h tst_flamegraphview.cpp ) if(${Qt5_VERSION} VERSION_LESS "6.2.0") - extend_qtc_test(tst_tracing_flamegraphview + add_qtc_test(tst_tracing_flamegraphview + DEPENDS Tracing Qt5::QuickWidgets Qt5::Quick Utils SOURCES ${TSTFLAMEGRAPHVIEW_CPP_SOURCES} flamegraphview.qrc ) else() # < Qt 6.2 + add_qtc_test(tst_tracing_flamegraphview + DEPENDS Tracing Qt5::QuickWidgets Qt5::Quick Utils + ) + qt_add_qml_module(tst_tracing_flamegraphview URI "QtCreator.TstTracingFlameGraphView" VERSION "1.0" diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index 4b341d6b3c1..63eb475063b 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(ansiescapecodehandler) add_subdirectory(fileutils) add_subdirectory(fuzzymatcher) +add_subdirectory(indexedcontainerproxyconstiterator) add_subdirectory(persistentsettings) add_subdirectory(qtcprocess) add_subdirectory(settings) diff --git a/tests/auto/utils/indexedcontainerproxyconstiterator/CMakeLists.txt b/tests/auto/utils/indexedcontainerproxyconstiterator/CMakeLists.txt new file mode 100644 index 00000000000..00a6adb4ed9 --- /dev/null +++ b/tests/auto/utils/indexedcontainerproxyconstiterator/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_utils_indexedcontainerproxyconstiterator + DEPENDS Utils + SOURCES tst_indexedcontainerproxyconstiterator.cpp +) diff --git a/tests/auto/utils/indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.pro b/tests/auto/utils/indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.pro new file mode 100644 index 00000000000..b0f9d7cc7e3 --- /dev/null +++ b/tests/auto/utils/indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.pro @@ -0,0 +1,4 @@ +QTC_LIB_DEPENDS += utils +include(../../qttest.pri) + +SOURCES += tst_indexedcontainerproxyconstiterator.cpp diff --git a/tests/auto/utils/indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.qbs b/tests/auto/utils/indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.qbs new file mode 100644 index 00000000000..461c89e4866 --- /dev/null +++ b/tests/auto/utils/indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.qbs @@ -0,0 +1,7 @@ +import qbs + +QtcAutotest { + name: "IndexedContainerProxyConstIterator autotest" + Depends { name: "Utils" } + files: "tst_indexedcontainerproxyconstiterator.cpp" +} diff --git a/tests/auto/utils/indexedcontainerproxyconstiterator/tst_indexedcontainerproxyconstiterator.cpp b/tests/auto/utils/indexedcontainerproxyconstiterator/tst_indexedcontainerproxyconstiterator.cpp new file mode 100644 index 00000000000..f0dceb0eb24 --- /dev/null +++ b/tests/auto/utils/indexedcontainerproxyconstiterator/tst_indexedcontainerproxyconstiterator.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 + +#include + +#include +#include + +using namespace Utils; + +class tst_IndexedContainerProxyConstIterator : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void testConstruction(); + void testDereference(); + void testIndexing(); + void testComparisons(); + void testIncrement(); + void testDecrement(); + void testPlus(); + void testMinus(); + void testIteration(); + +private: + using StringContainer = std::vector; + using StringIterator = IndexedContainerProxyConstIterator; + StringContainer strings; + + using BoolContainer = std::vector; + using BoolIterator = IndexedContainerProxyConstIterator; + BoolContainer bools; +}; + +void tst_IndexedContainerProxyConstIterator::initTestCase() +{ + strings = {"abc", "defgh", "ijk"}; + bools = {false, true, false}; +} + +void tst_IndexedContainerProxyConstIterator::testConstruction() +{ + StringIterator strIt(strings, 0); + QCOMPARE(*strIt, "abc"); + + StringIterator strIt2(strings, 1); + QCOMPARE(*strIt2, "defgh"); + + BoolIterator boolIt(bools, 0); + QCOMPARE(*boolIt, false); + + BoolIterator boolIt2(bools, 1); + QCOMPARE(*boolIt2, true); +} + +void tst_IndexedContainerProxyConstIterator::testDereference() +{ + StringIterator strIt(strings, 0); + QCOMPARE(*strIt, "abc"); + QCOMPARE(strIt->length(), 3); + + BoolIterator boolIt(bools, 0); + QCOMPARE(*boolIt, false); +} + +void tst_IndexedContainerProxyConstIterator::testIndexing() +{ + StringIterator strIt(strings, 0); + QCOMPARE(strIt[2], "ijk"); + + BoolIterator boolIt(bools, 0); + QCOMPARE(boolIt[2], false); +} + +void tst_IndexedContainerProxyConstIterator::testComparisons() +{ + StringIterator strIt(strings, 0); + StringIterator strIt2(strings, 0); + StringIterator strIt3(strings, 1); + + QVERIFY(strIt == strIt); + QVERIFY(!(strIt != strIt)); + QVERIFY(!(strIt < strIt)); + QVERIFY(strIt <= strIt); + QVERIFY(!(strIt > strIt)); + QVERIFY(strIt >= strIt); + + QVERIFY(strIt == strIt2); + QVERIFY(!(strIt != strIt2)); + QVERIFY(!(strIt < strIt2)); + QVERIFY(strIt <= strIt2); + QVERIFY(!(strIt > strIt2)); + QVERIFY(strIt >= strIt2); + + QVERIFY(!(strIt == strIt3)); + QVERIFY(strIt != strIt3); + QVERIFY(strIt < strIt3); + QVERIFY(strIt <= strIt3); + QVERIFY(!(strIt > strIt3)); + QVERIFY(!(strIt >= strIt3)); + + QVERIFY(!(strIt3 == strIt)); + QVERIFY(strIt3 != strIt); + QVERIFY(!(strIt3 < strIt)); + QVERIFY(!(strIt3 <= strIt)); + QVERIFY(strIt3 > strIt); + QVERIFY(strIt3 >= strIt); +} + +void tst_IndexedContainerProxyConstIterator::testIncrement() +{ + StringIterator strIt(strings, 0); + QCOMPARE(*(++strIt), "defgh"); + QCOMPARE(*(strIt++), "defgh"); + QCOMPARE(*strIt, "ijk"); + + BoolIterator boolIt(bools, 0); + QCOMPARE(*(++boolIt), true); + QCOMPARE(*(boolIt++), true); + QCOMPARE(*boolIt, false); +} + +void tst_IndexedContainerProxyConstIterator::testDecrement() +{ + StringIterator strIt(strings, 3); + QCOMPARE(*(--strIt), "ijk"); + QCOMPARE(*(strIt--), "ijk"); + QCOMPARE(*strIt, "defgh"); + + BoolIterator boolIt(bools, 3); + QCOMPARE(*(--boolIt), false); + QCOMPARE(*(boolIt--), false); + QCOMPARE(*boolIt, true); +} + +void tst_IndexedContainerProxyConstIterator::testPlus() +{ + StringIterator strIt(strings, 1); + QCOMPARE(*(strIt + 1), "ijk"); + QCOMPARE(*(1 + strIt), "ijk"); + strIt += 1; + QCOMPARE(*strIt, "ijk"); + + BoolIterator boolIt(bools, 1); + QCOMPARE(*(boolIt + 1), false); + QCOMPARE(*(1 + boolIt), false); + boolIt += 1; + QCOMPARE(*boolIt, false); +} + +void tst_IndexedContainerProxyConstIterator::testMinus() +{ + StringIterator strIt(strings, 1); + QCOMPARE(*(strIt - 1), "abc"); + strIt -= 1; + QCOMPARE(*strIt, "abc"); + + BoolIterator boolIt(bools, 1); + QCOMPARE(*(boolIt - 1), false); + boolIt -= 1; + QCOMPARE(*boolIt, false); +} + +void tst_IndexedContainerProxyConstIterator::testIteration() +{ + StringIterator strBegin(strings, 0); + StringIterator strEnd(strings, strings.size()); + StringContainer stringsCopy; + for (StringIterator it = strBegin; it != strEnd; ++it) + stringsCopy.push_back(*it); + QCOMPARE(stringsCopy, strings); + + BoolIterator boolBegin(bools, 0); + BoolIterator boolEnd(bools, bools.size()); + BoolContainer boolsCopy; + for (BoolIterator it = boolBegin; it != boolEnd; ++it) + boolsCopy.push_back(*it); + QCOMPARE(boolsCopy, bools); +} + +QTEST_MAIN(tst_IndexedContainerProxyConstIterator) + +#include "tst_indexedcontainerproxyconstiterator.moc" diff --git a/tests/auto/utils/utils.pro b/tests/auto/utils/utils.pro index 2e15c4379ed..e0f630ad2b5 100644 --- a/tests/auto/utils/utils.pro +++ b/tests/auto/utils/utils.pro @@ -4,6 +4,7 @@ SUBDIRS = \ fileutils \ ansiescapecodehandler \ fuzzymatcher \ + indexedcontainerproxyconstiterator \ persistentsettings \ qtcprocess \ settings \ diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index 5b11f46e7bc..b9a4f9a6116 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -6,6 +6,7 @@ Project { "fileutils/fileutils.qbs", "ansiescapecodehandler/ansiescapecodehandler.qbs", "fuzzymatcher/fuzzymatcher.qbs", + "indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.qbs", "persistentsettings/persistentsettings.qbs", "qtcprocess/qtcprocess.qbs", "settings/settings.qbs",