diff options
141 files changed, 1378 insertions, 771 deletions
diff --git a/dist/changelog/changes-17.0.1.md b/dist/changelog/changes-17.0.1.md index 88f899450be..a426cef4cf9 100644 --- a/dist/changelog/changes-17.0.1.md +++ b/dist/changelog/changes-17.0.1.md @@ -28,6 +28,7 @@ Help Editing ------- +* Improved the performance of painting annotations * Fixed a crash when closing an editor while the completion popup is shown ([QTCREATORBUG-33079](https://bugreports.qt.io/browse/QTCREATORBUG-33079)) * Fixed a crash when trying to open a file from history that has vanished @@ -48,6 +49,11 @@ Editing * Fixed that selecting a file from the toolbar did not jump to the file in the diff +### FakeVim + +* Fixed that `Cmd+S` could act as `S` on macOS + ([QTCREATORBUG-13392](https://bugreports.qt.io/browse/QTCREATORBUG-13392)) + ### EmacsKeys * Fixed that the added text editor based actions no longer worked @@ -67,11 +73,24 @@ Projects ### CMake +* Improved the order of targets in the `cm` locator filter + ([QTCREATORBUG-33210](https://bugreports.qt.io/browse/QTCREATORBUG-33210)) * Fixed that too many files were filtered out of the project files list ([QTCREATORBUG-32095](https://bugreports.qt.io/browse/QTCREATORBUG-32095), [QTCREATORBUG-33152](https://bugreports.qt.io/browse/QTCREATORBUG-33152), [QTCREATORBUG-33163](https://bugreports.qt.io/browse/QTCREATORBUG-33163), [QTCREATORBUG-33180](https://bugreports.qt.io/browse/QTCREATORBUG-33180)) +* Fixed that setting a non-existing toolchain file resulted in a successful + configuration instead of the expected error + ([QTCREATORBUG-33290](https://bugreports.qt.io/browse/QTCREATORBUG-33290)) +* Fixed adding the new file to the project after + `Move Component into Separate File` + ([QTCREATORBUG-33298](https://bugreports.qt.io/browse/QTCREATORBUG-33298)) + +### qmake + +* Fixed that it was not possible to provide an absolute path for the `mkspec` + ([QTCREATORBUG-33155](https://bugreports.qt.io/browse/QTCREATORBUG-33155)) Debugging --------- @@ -90,6 +109,7 @@ Analyzer * Fixed the display of freshly fetched issues from a local dashboard ([QTCREATORBUG-33012](https://bugreports.qt.io/browse/QTCREATORBUG-33012)) * Fixed the handling of path mappings +* Fixed that starting a local build was not possible in some configurations Platforms --------- @@ -122,6 +142,9 @@ Platforms * Improved the error message when device tests fail ([QTCREATORBUG-32933](https://bugreports.qt.io/browse/QTCREATORBUG-32933)) +* Fixed an issue with deployed files becoming corrupted + ([QTCREATORBUG-33317](https://bugreports.qt.io/browse/QTCREATORBUG-33317)) +* Fixed that the command bridge could be killed when operations take a long time Credits for these changes go to: -------------------------------- @@ -133,10 +156,12 @@ Cristian Adam David Schulz Eike Ziller Jaroslaw Kobus +Krzysztof Chrusciel Leena Miettinen Lukasz Papierkowski Marc Mutz Marcus Tillmanns Nicholas Bennett Orgad Shaneh +Prashant Vaibhav Sami Shalayel diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 13d3dc2dedf..0ac05d69512 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -2309,6 +2309,18 @@ bool Bind::visit(AsmDefinitionAST *ast) return false; } +bool Bind::visit(ConceptDeclarationAST *ast) +{ + if (!ast->name) + return false; + + const Name *name = this->name(ast->name); + Declaration *decl = control()->newDeclaration(ast->name->firstToken(), name); + _scope->addMember(decl); + + return false; +} + bool Bind::visit(ExceptionDeclarationAST *ast) { FullySpecifiedType type; diff --git a/src/libs/3rdparty/cplusplus/Bind.h b/src/libs/3rdparty/cplusplus/Bind.h index 867ed7baaa8..b8f2b6ca6f0 100644 --- a/src/libs/3rdparty/cplusplus/Bind.h +++ b/src/libs/3rdparty/cplusplus/Bind.h @@ -220,6 +220,7 @@ protected: bool visit(QtInterfacesDeclarationAST *ast) override; bool visit(AliasDeclarationAST *ast) override; bool visit(AsmDefinitionAST *ast) override; + bool visit(ConceptDeclarationAST *ast) override; bool visit(ExceptionDeclarationAST *ast) override; bool visit(FunctionDefinitionAST *ast) override; bool visit(LinkageBodyAST *ast) override; diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp index 7c13bb2daba..2a5c30fb748 100644 --- a/src/libs/3rdparty/cplusplus/Control.cpp +++ b/src/libs/3rdparty/cplusplus/Control.cpp @@ -574,8 +574,12 @@ TranslationUnit *Control::switchTranslationUnit(TranslationUnit *unit) DiagnosticClient *Control::diagnosticClient() const { return d->diagnosticClient; } -void Control::setDiagnosticClient(DiagnosticClient *diagnosticClient) -{ d->diagnosticClient = diagnosticClient; } +void Control::setDiagnosticClient(DiagnosticClient *diagnosticClient, bool deleteExisting) +{ + if (deleteExisting) + delete d->diagnosticClient; + d->diagnosticClient = diagnosticClient; +} const AnonymousNameId *Control::anonymousNameId(unsigned classTokenIndex) { return d->findOrInsertAnonymousNameId(classTokenIndex); } diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h index 8ef7c3586b6..68cdef19bea 100644 --- a/src/libs/3rdparty/cplusplus/Control.h +++ b/src/libs/3rdparty/cplusplus/Control.h @@ -46,7 +46,7 @@ public: void setTopLevelDeclarationProcessor(TopLevelDeclarationProcessor *processor); DiagnosticClient *diagnosticClient() const; - void setDiagnosticClient(DiagnosticClient *diagnosticClient); + void setDiagnosticClient(DiagnosticClient *diagnosticClient, bool deleteExisting); /// Returns the canonical anonymous name id const AnonymousNameId *anonymousNameId(unsigned classTokenIndex); diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 837ff04e641..b8514068599 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -259,7 +259,7 @@ Document::Document(const FilePath &filePath) { _control = new Control(); - _control->setDiagnosticClient(new DocumentDiagnosticClient(this, &_diagnosticMessages)); + _control->setDiagnosticClient(new DocumentDiagnosticClient(this, &_diagnosticMessages), true); const QByteArray localFileName = filePath.path().toUtf8(); const StringLiteral *fileId = _control->stringLiteral(localFileName.constData(), diff --git a/src/libs/gocmdbridge/client/bridgedfileaccess.cpp b/src/libs/gocmdbridge/client/bridgedfileaccess.cpp index 56d46f97cf5..0c0444b361e 100644 --- a/src/libs/gocmdbridge/client/bridgedfileaccess.cpp +++ b/src/libs/gocmdbridge/client/bridgedfileaccess.cpp @@ -7,7 +7,6 @@ #include "cmdbridgetr.h" #include <QElapsedTimer> -#include <QFutureWatcher> #include <QLoggingCategory> Q_LOGGING_CATEGORY(faLog, "qtc.cmdbridge.fileaccess", QtWarningMsg); diff --git a/src/libs/gocmdbridge/client/bridgedfileaccess.h b/src/libs/gocmdbridge/client/bridgedfileaccess.h index 3f892a8fe08..ec850cb7c38 100644 --- a/src/libs/gocmdbridge/client/bridgedfileaccess.h +++ b/src/libs/gocmdbridge/client/bridgedfileaccess.h @@ -11,8 +11,6 @@ #include <utils/processinterface.h> #include <utils/qtcprocess.h> -#include <QFuture> - class tst_CmdBridge; namespace CmdBridge { diff --git a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp index 61a6f3f5ee2..156e6483620 100644 --- a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp +++ b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp @@ -320,7 +320,7 @@ Result<> Client::start(bool deleteOnExit) auto stateMachine = [markerOffset = 0, state = int(0), packetSize(0), packetData = QByteArray(), this]( - QByteArray &buffer) mutable { + QByteArray &buffer) mutable -> bool { static const QByteArray MagicCode{GOBRIDGE_MAGIC_PACKET_MARKER}; if (state == 0) { @@ -332,7 +332,7 @@ Result<> Client::start(bool deleteOnExit) // Partial magic marker? markerOffset += buffer.size(); buffer.clear(); - return; + return false; } // Broken package, search for next magic marker qCWarning(clientLog) @@ -347,6 +347,8 @@ Result<> Client::start(bool deleteOnExit) } if (state == 1) { + if (buffer.size() < 4) + return false; // wait for more data QDataStream ds(buffer); ds >> packetSize; // TODO: Enforce max size in bridge. @@ -376,6 +378,7 @@ Result<> Client::start(bool deleteOnExit) QTC_CHECK_RESULT(result); } } + return !buffer.isEmpty(); }; connect( @@ -384,8 +387,7 @@ Result<> Client::start(bool deleteOnExit) d->process, [this, buffer = QByteArray(), stateMachine]() mutable { buffer.append(d->process->readAllRawStandardError()); - while (!buffer.isEmpty()) - stateMachine(buffer); + while (stateMachine(buffer)) {} }); connect(d->process, &Process::readyReadStandardOutput, d->process, [this] { diff --git a/src/libs/gocmdbridge/server/cmdbridge.go b/src/libs/gocmdbridge/server/cmdbridge.go index 15f84e1b250..cdad4665b98 100644 --- a/src/libs/gocmdbridge/server/cmdbridge.go +++ b/src/libs/gocmdbridge/server/cmdbridge.go @@ -465,15 +465,12 @@ func exit(exitCode int, deleteOnExit bool) { os.Exit(0) } -func processCommand(watcher *WatcherHandler, watchDogChannel chan struct{} ,cmd command, out chan<- []byte, deleteOnExit bool) { +func processCommand(watcher *WatcherHandler, cmd command, out chan<- []byte, deleteOnExit bool) { defer globalWaitGroup.Done() switch cmd.Type { case "ping": - select { - case watchDogChannel <- struct{}{}: - default: - } + // just a keepalive case "copyfile": processCopyFile(cmd, out) case "createsymlink": @@ -538,10 +535,10 @@ func processCommand(watcher *WatcherHandler, watchDogChannel chan struct{} ,cmd } } -func executor(watcher *WatcherHandler, watchDogChannel chan struct {}, commands <-chan command, out chan<- []byte, deleteOnExit bool) { +func executor(watcher *WatcherHandler, commands <-chan command, out chan<- []byte, deleteOnExit bool) { for cmd := range commands { globalWaitGroup.Add(1) - go processCommand(watcher, watchDogChannel, cmd, out, deleteOnExit) + go processCommand(watcher, cmd, out, deleteOnExit) } } @@ -611,14 +608,18 @@ func writeMain(out *bufio.Writer) { out.Flush() } -func watchDogLoop(channel chan struct {}, deleteOnExit bool) { - watchDogTimeOut := 60 * time.Minute +func watchDogLoop(channel chan bool, deleteOnExit bool) { + watchDogTimeOut := 60 * time.Second timer := time.NewTimer(watchDogTimeOut) for { select { - case <-channel: - timer.Reset(watchDogTimeOut) + case turnOn := <-channel: + if turnOn { + timer.Reset(watchDogTimeOut) + } else { + timer.Stop() + } case <-timer.C: // If we don't get a signal for one minute, we assume that the connection is dead. fmt.Println("Watchdog timeout, exiting.") @@ -631,7 +632,7 @@ func readMain(test bool, deleteOnExit bool) { commandChannel := make(chan command) outputChannel := make(chan []byte) - watchDogChannel := make(chan struct {}, 1) + watchDogChannel := make(chan bool) go watchDogLoop(watchDogChannel, deleteOnExit) watcher := NewWatcherHandler() @@ -650,7 +651,7 @@ func readMain(test bool, deleteOnExit bool) { globalWaitGroup.Add(1) go func() { defer globalWaitGroup.Done() - executor(watcher, watchDogChannel, commandChannel, outputChannel, deleteOnExit) + executor(watcher, commandChannel, outputChannel, deleteOnExit) }() globalWaitGroup.Add(1) @@ -672,8 +673,14 @@ func readMain(test bool, deleteOnExit bool) { } decoder := cbor.NewDecoder(in) for { + _, err := in.Peek(1) + if err == io.EOF { + time.Sleep(50*time.Millisecond) + continue + } + // disable watchdog while we are busy processing data + watchDogChannel <- false cmd, err := readPacket(decoder) - if err == io.EOF { close(commandChannel) break @@ -682,6 +689,8 @@ func readMain(test bool, deleteOnExit bool) { } else { commandChannel <- *cmd } + // reset watchdog timer + watchDogChannel <- true } globalWaitGroup.Wait() diff --git a/src/libs/modelinglib/qmt/infrastructure/handle.h b/src/libs/modelinglib/qmt/infrastructure/handle.h index 283e3d28180..7f95cfa2cb2 100644 --- a/src/libs/modelinglib/qmt/infrastructure/handle.h +++ b/src/libs/modelinglib/qmt/infrastructure/handle.h @@ -46,7 +46,7 @@ public: void clearTarget() { m_target = nullptr; } - friend auto qHash(const Handle<T> &handle) { return qHash(handle.uid()); } + friend size_t qHash(const Handle<T> &handle) { return qHash(handle.uid()); } private: Uid m_uid; diff --git a/src/libs/modelinglib/qmt/infrastructure/uid.h b/src/libs/modelinglib/qmt/infrastructure/uid.h index 02886728ab2..2eebc3575a6 100644 --- a/src/libs/modelinglib/qmt/infrastructure/uid.h +++ b/src/libs/modelinglib/qmt/infrastructure/uid.h @@ -29,7 +29,7 @@ public: QString toString() const { return m_uuid.toString(); } void fromString(const QString &s) { m_uuid = QUuid(s); } - friend auto qHash(const Uid &uid) { return qHash(uid.get()); } + friend size_t qHash(const Uid &uid) { return qHash(uid.get()); } friend bool operator==(const Uid &lhs, const Uid &rhs) { return lhs.get() == rhs.get(); } friend bool operator!=(const Uid &lhs, const Uid &rhs) { return !operator==(lhs, rhs); } diff --git a/src/libs/modelinglib/qmt/stereotype/customrelation.h b/src/libs/modelinglib/qmt/stereotype/customrelation.h index dd32c542c0c..9c19109a77b 100644 --- a/src/libs/modelinglib/qmt/stereotype/customrelation.h +++ b/src/libs/modelinglib/qmt/stereotype/customrelation.h @@ -119,15 +119,15 @@ public: bool emphasized() const { return m_emphasized; } void setEmphasized(bool emphasized); - friend auto qHash(CustomRelation::Relationship relationship) { + friend size_t qHash(CustomRelation::Relationship relationship) { return ::qHash(static_cast<int>(relationship)); } - friend auto qHash(CustomRelation::ShaftPattern pattern) { + friend size_t qHash(CustomRelation::ShaftPattern pattern) { return ::qHash(static_cast<int>(pattern)); } - friend auto qHash(CustomRelation::Head head) { + friend size_t qHash(CustomRelation::Head head) { return ::qHash(static_cast<int>(head)); } diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp index 2f679df1177..fc8356b853b 100644 --- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp +++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp @@ -50,7 +50,7 @@ struct IconKey { && lhs.m_lineWidth == rhs.m_lineWidth; } - friend auto qHash(const IconKey &key) { + friend size_t qHash(const IconKey &key) { return ::qHash(key.m_element) + qHash(key.m_stereotypes) + qHash(key.m_defaultIconPath) + qHash(key.m_styleUid) + ::qHash(key.m_size.width()) + ::qHash(key.m_size.height()); } diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt index b74fb48b96e..297da2d33bb 100644 --- a/src/libs/qtcreatorcdbext/CMakeLists.txt +++ b/src/libs/qtcreatorcdbext/CMakeLists.txt @@ -28,27 +28,20 @@ if (NOT QT_CREATOR_API_DEFINED) include(QtCreatorSbom) qtc_handle_compiler_cache_support() - # Need to look for Qt6 optionally, so that we can use the SBOM feature, even though the + # Need to look for Qt6, so that we can use the SBOM feature, even though the # project doesn't link to Qt. - find_package(Qt6 - COMPONENTS Core - ) + # Explicitly disable the version checks, because when configuring for an architecture that + # is not compatible with the found Qt, we'd fail to find the package. We don't care about + # binary compatibility here, we only want the SBOM feature. + if(QT_GENERATE_SBOM) + set(QT_NO_PACKAGE_VERSION_CHECK ON) + set(QT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING ON) + find_package(Qt6 REQUIRED) + unset(QT_NO_PACKAGE_VERSION_CHECK) + unset(QT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING) + endif() set(QT_CREATOR_CDB_EXT_STANDALONE_BUILD TRUE) - qtc_setup_sbom() - qtc_sbom_compute_cpe(project_cpe - VENDOR "qt" - PRODUCT "${PROJECT_NAME}" - VERSION "${IDE_VERSION}" - ) - set(QT_SBOM_LICENSE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../../LICENSES") - qtc_sbom_begin_project( - SBOM_PROJECT_NAME "${PROJECT_NAME}-${ArchSuffix}" - QT_REPO_PROJECT_NAME "${PROJECT_NAME}-${ArchSuffix}" - PURL_NAMESPACE "qt" - PURL_NAME "${PROJECT_NAME}" - CPE "${project_cpe}" - ) # Compile for x86, x64 and arm64 if (NOT ${PROJECT_NAME}-MultiBuild AND NOT MINGW) @@ -61,6 +54,16 @@ if (NOT QT_CREATOR_API_DEFINED) string(REPLACE ";" "|" CMAKE_PREFIX_PATH_ALT_SEP "${CMAKE_PREFIX_PATH}") + set(extra_cmake_args "") + set(extra_install_commands "") + if(QT_GENERATE_SBOM) + list(APPEND extra_cmake_args -DQT_GENERATE_SBOM=${QT_GENERATE_SBOM}) + list(APPEND extra_install_commands + && ${CMAKE_COMMAND} --install . --config ${CMAKE_BUILD_TYPE} + --prefix "${CMAKE_BINARY_DIR}" --component sbom + ) + endif() + macro (setup_library arch install_llvm) ExternalProject_Add(${arch}-bld SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" @@ -73,11 +76,14 @@ if (NOT QT_CREATOR_API_DEFINED) -DPython3_ROOT_DIR=${Python3_ROOT_DIR} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH_ALT_SEP} -DQTCREATORCDBEXT_INSTALL_LLVM=${install_llvm} + -DCMAKE_CONFIGURATION_TYPES=${CMAKE_BUILD_TYPE} + ${extra_cmake_args} BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} INSTALL_COMMAND ${CMAKE_COMMAND} --install . --config ${CMAKE_BUILD_TYPE} --prefix "${CMAKE_BINARY_DIR}" --component qtcreatorcdbext + ${extra_install_commands} ) endmacro() @@ -104,6 +110,17 @@ if (NOT QT_CREATOR_API_DEFINED) endif()" COMPONENT qtcreatorcdbext ) + if(QT_GENERATE_SBOM) + qtc_sbom_get_sbom_install_path(sbom_install_path) + # Because we are installing a dir, the destination should be the same without the dir + # name. + get_filename_component(sbom_install_dest "${sbom_install_path}" DIRECTORY) + install( + DIRECTORY "${CMAKE_BINARY_DIR}/${sbom_install_path}" + DESTINATION "${sbom_install_dest}" + COMPONENT qtcreatorcdbext + ) + endif() endif() return() @@ -118,6 +135,23 @@ if (NOT EXISTS "${CMAKE_BINARY_DIR}/lib/qtcreatorcdbext${ArchSuffix}") file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/lib/qtcreatorcdbext${ArchSuffix}") endif() +if(QT_CREATOR_CDB_EXT_STANDALONE_BUILD AND QT_GENERATE_SBOM) + qtc_setup_sbom() + qtc_sbom_compute_cpe(project_cpe + VENDOR "qt" + PRODUCT "${PROJECT_NAME}" + VERSION "${IDE_VERSION}" + ) + set(QT_SBOM_LICENSE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../../LICENSES") + qtc_sbom_begin_project( + SBOM_PROJECT_NAME "${PROJECT_NAME}-${ArchSuffix}" + QT_REPO_PROJECT_NAME "${PROJECT_NAME}-${ArchSuffix}" + PURL_NAMESPACE "qt" + PURL_NAME "${PROJECT_NAME}" + CPE "${project_cpe}" + ) +endif() + add_qtc_library(qtcreatorcdbext SHARED COMPONENT qtcreatorcdbext DEPENDS dbgeng @@ -329,6 +363,6 @@ if (_library_enabled) endif() -if(QT_CREATOR_CDB_EXT_STANDALONE_BUILD) +if(QT_CREATOR_CDB_EXT_STANDALONE_BUILD AND QT_GENERATE_SBOM) qtc_sbom_end_project() endif() diff --git a/src/libs/solutions/tasking/tasktreerunner.h b/src/libs/solutions/tasking/tasktreerunner.h index 7520aa4e7f4..9beb744a0db 100644 --- a/src/libs/solutions/tasking/tasktreerunner.h +++ b/src/libs/solutions/tasking/tasktreerunner.h @@ -42,8 +42,10 @@ protected: template <typename Handler> static TreeSetupHandler wrapTreeSetupHandler(Handler &&handler) { - if constexpr (std::is_same_v<std::decay_t<Handler>, TreeSetupHandler>) - return {}; // When user passed {} for the setup handler. + if constexpr (std::is_same_v<std::decay_t<Handler>, TreeSetupHandler>) { + if (!handler) + return {}; // When user passed {} for the setup handler. + } // V, T stands for: [V]oid, [T]askTree static constexpr bool isVT = isInvocable<void, Handler, TaskTree &>(); static constexpr bool isV = isInvocable<void, Handler>(); @@ -60,8 +62,10 @@ protected: template <typename Handler> static TreeDoneHandler wrapTreeDoneHandler(Handler &&handler) { - if constexpr (std::is_same_v<std::decay_t<Handler>, TreeDoneHandler>) - return {}; // User passed {} for the done handler. + if constexpr (std::is_same_v<std::decay_t<Handler>, TreeDoneHandler>) { + if (!handler) + return {}; // User passed {} for the done handler. + } // V, T, D stands for: [V]oid, [T]askTree, [D]oneWith static constexpr bool isVTD = isInvocable<void, Handler, const TaskTree &, DoneWith>(); static constexpr bool isVT = isInvocable<void, Handler, const TaskTree &>(); diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index d52b345528d..81002e98413 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1538,6 +1538,7 @@ public: bool m_autoApplyOnEditingFinished = false; bool m_allowPathFromDevice = true; bool m_validatePlaceHolder = false; + FilePaths m_valueAlternatives; Guard m_editFinishedGuard; }; @@ -1725,6 +1726,7 @@ void FilePathAspect::addToLayoutImpl(Layouting::Layout &parent) d->m_pathChooserDisplay->setAllowPathFromDevice(d->m_allowPathFromDevice); d->m_pathChooserDisplay->setReadOnly(isReadOnly()); d->m_pathChooserDisplay->lineEdit()->setValidatePlaceHolder(d->m_validatePlaceHolder); + d->m_pathChooserDisplay->setValueAlternatives(d->m_valueAlternatives); if (defaultValue() == value()) d->m_pathChooserDisplay->setDefaultValue(defaultValue()); else @@ -1824,6 +1826,13 @@ void FilePathAspect::setAutoApplyOnEditingFinished(bool applyOnEditingFinished) d->m_autoApplyOnEditingFinished = applyOnEditingFinished; } +void FilePathAspect::setValueAlternatives(const FilePaths &candidates) +{ + d->m_valueAlternatives = candidates; + if (d->m_pathChooserDisplay) + d->m_pathChooserDisplay->setValueAlternatives(candidates); +} + /*! Sets \a expectedKind as expected kind for path chooser displays. diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 802562a71b4..2343933e0af 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -8,7 +8,6 @@ #include "id.h" #include "infolabel.h" #include "pathchooser.h" -#include "qtcsettings.h" #include "store.h" #include <functional> @@ -715,6 +714,7 @@ public: QString value() const; void setValue(const FilePath &filePath, Announcement howToAnnounce = DoEmit); void setValue(const QString &filePath, Announcement howToAnnounce = DoEmit); + void setValueAlternatives(const FilePaths &candidate); void setDefaultValue(const QString &filePath); void setDefaultPathValue(const FilePath &filePath); diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp index d8cea641f0a..9477c39e721 100644 --- a/src/libs/utils/fancylineedit.cpp +++ b/src/libs/utils/fancylineedit.cpp @@ -404,6 +404,12 @@ void FancyLineEdit::setCompletionShortcut(const QKeySequence &shortcut) completionShortcut()->setKeySequence(shortcut); } +void FancyLineEdit::setValueAlternatives(const QStringList &values) +{ + for (const QString &value : values) + d->m_historyCompleter->addEntry(value); +} + void FancyLineEdit::setSpecialCompleter(QCompleter *completer) { QTC_ASSERT(!d->m_historyCompleter, return); diff --git a/src/libs/utils/fancylineedit.h b/src/libs/utils/fancylineedit.h index 873d4b04b70..b222ae88f37 100644 --- a/src/libs/utils/fancylineedit.h +++ b/src/libs/utils/fancylineedit.h @@ -129,6 +129,8 @@ public: static void setCamelCaseNavigationEnabled(bool enabled); static void setCompletionShortcut(const QKeySequence &shortcut); + void setValueAlternatives(const QStringList &values); + protected: // Custom behaviour can be added here. virtual void handleChanged(const QString &) {} diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp index 216f238a0f7..0016af2f9d7 100644 --- a/src/libs/utils/fsengine/fsenginehandler.cpp +++ b/src/libs/utils/fsengine/fsenginehandler.cpp @@ -51,7 +51,6 @@ public: bool setSize(qint64 size) final; bool caseSensitive() const final; bool isRelativePath() const final; - QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const final; FileFlags fileFlags(FileFlags type) const final; bool setPermissions(uint perms) final; QByteArray id() const final; @@ -278,22 +277,6 @@ bool FSEngineImpl::isRelativePath() const return false; } -QStringList FSEngineImpl::entryList(QDir::Filters filters, const QStringList &filterNames) const -{ - QStringList result; - m_filePath.iterateDirectory( - [&result](const FilePath &p, const FilePathInfo &fi) { - result.append(p.toFSPathString()); - g_filePathInfoCache - .cache(p, - new FilePathInfoCache::CachedData{fi, - QDateTime::currentDateTime().addSecs(60)}); - return IterationPolicy::Continue; - }, - {filterNames, filters}); - return result; -} - QAbstractFileEngine::FileFlags FSEngineImpl::fileFlags(FileFlags type) const { Q_UNUSED(type) diff --git a/src/libs/utils/id.cpp b/src/libs/utils/id.cpp index 0ff3fd2ed84..cae28ecd4f4 100644 --- a/src/libs/utils/id.cpp +++ b/src/libs/utils/id.cpp @@ -51,7 +51,7 @@ public: } } - friend auto qHash(const StringHolder &sh) + friend size_t qHash(const StringHolder &sh) { return QT_PREPEND_NAMESPACE(qHash)(sh.h, 0); } diff --git a/src/libs/utils/markdownbrowser.cpp b/src/libs/utils/markdownbrowser.cpp index 373275fec2c..aa1bbd2b914 100644 --- a/src/libs/utils/markdownbrowser.cpp +++ b/src/libs/utils/markdownbrowser.cpp @@ -297,13 +297,10 @@ public: return std::make_shared<Entry>(data); } - virtual QSizeF intrinsicSize( - QTextDocument *doc, int posInDocument, const QTextFormat &format) override + QSize getImageSize(const QTextImageFormat &format) { - Q_UNUSED(doc) - Q_UNUSED(posInDocument) QSize result = Utils::Icons::UNKNOWN_FILE.icon().actualSize(QSize(16, 16)); - QString name = format.toImageFormat().name(); + QString name = format.name(); Entry::Pointer *entryPtr = m_entries.object(name); if (!entryPtr) { @@ -322,6 +319,26 @@ public: return result; } + QSize getSize(QTextDocument *doc, const QTextImageFormat &format) + { + QSize size = getImageSize(format); + int effectiveMaxWidth = (doc->pageSize().width() - 2 * doc->documentMargin()); + + if (size.width() > effectiveMaxWidth) { + // image is bigger than effectiveMaxWidth, scale it down + size.setHeight(effectiveMaxWidth * (size.height() / qreal(size.width()))); + size.setWidth(effectiveMaxWidth); + } + + return size; + } + + QSizeF intrinsicSize(QTextDocument *doc, int pos, const QTextFormat &format) override + { + Q_UNUSED(pos); + return getSize(doc, format.toImageFormat()); + } + void drawObject( QPainter *painter, const QRectF &rect, @@ -335,6 +352,8 @@ public: const QString name = format.toImageFormat().name(); Entry::Pointer *entryPtr = m_entries.object(name); + painter->setRenderHints(QPainter::SmoothPixmapTransform); + if (!entryPtr) { constexpr QStringView themeScheme(u"theme://"); constexpr QStringView iconScheme(u"icon://"); diff --git a/src/libs/utils/multitextcursor.cpp b/src/libs/utils/multitextcursor.cpp index bb323302453..2ddef5222f8 100644 --- a/src/libs/utils/multitextcursor.cpp +++ b/src/libs/utils/multitextcursor.cpp @@ -452,13 +452,6 @@ bool MultiTextCursor::handleMoveKeyEvent( } else if (e == QKeySequence::SelectNextLine) { op = QTextCursor::Down; mode = QTextCursor::KeepAnchor; - { - QTextBlock block = cursor.block(); - QTextLine line = currentTextLine(cursor); - if (!block.next().isValid() && line.isValid() - && line.lineNumber() == block.layout()->lineCount() - 1) - op = QTextCursor::End; - } } else if (e == QKeySequence::MoveToNextWord) { op = QTextCursor::WordRight; } else if (e == QKeySequence::MoveToPreviousWord) { diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 2fadadbb9e5..4d349aa7b4d 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -17,10 +17,9 @@ #include "utilstr.h" #include <QFileDialog> -#include <QFuture> #include <QGuiApplication> -#include <QHelpEvent> #include <QHBoxLayout> +#include <QHelpEvent> #include <QMenu> #include <QPushButton> #include <QStandardPaths> @@ -184,6 +183,7 @@ public: QMenu *m_contextMenu = nullptr; OptionPushButton *m_browseButton = nullptr; + QPushButton *m_alternativesButton = nullptr; Guard m_callGuard; }; @@ -735,6 +735,36 @@ void PathChooser::setHistoryCompleter(const Key &historyKey, bool restoreLastIte d->m_lineEdit->setHistoryCompleter(historyKey, restoreLastItemFromHistory); } +void PathChooser::setValueAlternatives(const FilePaths &candidates) +{ + // FIXME: Think about UI. For now: + + // 1. put the alternatives in the line edit's history + d->m_lineEdit->setValueAlternatives(Utils::transform(candidates, &FilePath::toUserOutput)); + + // 2. add them to a (temporary) button next to the line edit for better visibility. + if (candidates.size() <= 1) { + delete d->m_alternativesButton; + d->m_alternativesButton = nullptr; + return; + } + + if (!d->m_alternativesButton) + d->m_alternativesButton = new QPushButton(Tr::tr("Alternatives"), this); + + auto menu = new QMenu; + for (const FilePath &candidate : candidates) { + QAction *action = menu->addAction(candidate.toUserOutput()); + connect(action, &QAction::triggered, this, [this, candidate] { + setFilePath(candidate); + }); + } + delete d->m_alternativesButton->menu(); + d->m_alternativesButton->setMenu(menu); + + d->m_hLayout->insertWidget(1, d->m_alternativesButton); +} + void PathChooser::setMacroExpander(const MacroExpander *macroExpander) { d->m_macroExpander = macroExpander; diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h index 48eff78588d..343b3733028 100644 --- a/src/libs/utils/pathchooser.h +++ b/src/libs/utils/pathchooser.h @@ -134,6 +134,8 @@ public: void setAllowPathFromDevice(bool allow); bool allowPathFromDevice() const; + void setValueAlternatives(const FilePaths &candidates); + public slots: void setPath(const QString &); void setFilePath(const FilePath &); diff --git a/src/libs/utils/plaintextedit/texteditorlayout.cpp b/src/libs/utils/plaintextedit/texteditorlayout.cpp index 79e3b965d1a..b7d10bd4237 100644 --- a/src/libs/utils/plaintextedit/texteditorlayout.cpp +++ b/src/libs/utils/plaintextedit/texteditorlayout.cpp @@ -358,38 +358,35 @@ bool TextEditorLayout::moveCursorImpl(QTextCursor &cursor, QTextCursor::MoveOper cursor.setPosition(newPosition, mode); return true; } - case QTextCursor::MoveOperation::Up: { - int i = line.lineNumber() - 1; - if (i == -1) { - block = block.previous(); - if (!block.isValid()) - return false; - ensureBlockLayout(block); - layout = blockLayout(block); - QTC_ASSERT(layout, return false); - i = layout->lineCount() - 1; - } - int x = line.cursorToX(cursor.positionInBlock()); - line = layout->lineAt(i); - QTC_ASSERT(line.isValid(), return false); - cursor.setPosition(line.xToCursor(x) + block.position(), mode); - return true; - } + case QTextCursor::MoveOperation::Up: case QTextCursor::MoveOperation::Down: { - int i = line.lineNumber() + 1; - if (i >= layout->lineCount()) { - block = block.next(); - if (!block.isValid()) - return false; + const bool down = operation == QTextCursor::MoveOperation::Down; + int lineNumber = down ? line.lineNumber() + 1 : line.lineNumber() - 1; + + if (lineNumber >= layout->lineCount() || lineNumber == -1) { + block = down ? block.next() : block.previous(); + + if (!block.isValid()) { + if (mode == QTextCursor::KeepAnchor) + cursor.movePosition(down ? QTextCursor::End : QTextCursor::Start, mode); + else if (cursor.hasSelection()) + cursor.clearSelection(); + + return true; + } ensureBlockLayout(block); layout = blockLayout(block); QTC_ASSERT(layout, return false); - i = 0; + lineNumber = down ? 0 : layout->lineCount() - 1; } - int x = line.cursorToX(cursor.positionInBlock()); - line = layout->lineAt(i); + + int x = cursor.verticalMovementX(); + if (x < 0) + x = line.cursorToX(cursor.positionInBlock()); + line = layout->lineAt(lineNumber); QTC_ASSERT(line.isValid(), return false); cursor.setPosition(line.xToCursor(x) + block.position(), mode); + cursor.setVerticalMovementX(x); return true; } default: diff --git a/src/libs/utils/qtcwidgets.cpp b/src/libs/utils/qtcwidgets.cpp index 1d24ab7ec49..77d451d8c8f 100644 --- a/src/libs/utils/qtcwidgets.cpp +++ b/src/libs/utils/qtcwidgets.cpp @@ -208,7 +208,8 @@ void QtcButton::paintEvent(QPaintEvent *event) break; } case SmallList: { - if (isChecked() || hovered) { + const bool filled = hovered || isDown() || isChecked(); + if (filled) { const QBrush fill(creatorColor(isChecked() ? Theme::Token_Foreground_Muted : Theme::Token_Foreground_Subtle)); StyleHelper::drawCardBg(&p, bgR, fill, QPen(Qt::NoPen), brRectRounding); @@ -218,8 +219,9 @@ void QtcButton::paintEvent(QPaintEvent *event) case SmallLink: break; case Tag: { - const QBrush fill(hovered ? creatorColor(Theme::Token_Foreground_Subtle) - : QBrush(Qt::NoBrush)); + const bool filled = hovered || isDown() || isChecked(); + const QBrush fill(filled ? creatorColor(Theme::Token_Foreground_Subtle) + : QBrush(Qt::NoBrush)); const QPen outline(hovered ? QPen(Qt::NoPen) : creatorColor(Theme::Token_Stroke_Subtle)); StyleHelper::drawCardBg(&p, bgR, fill, outline, brRectRounding); break; diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp index 8a07592d3fe..436c30d4a56 100644 --- a/src/libs/utils/reloadpromptutils.cpp +++ b/src/libs/utils/reloadpromptutils.cpp @@ -3,23 +3,21 @@ #include "reloadpromptutils.h" -#include "fileutils.h" +#include "filepath.h" +#include "guiutils.h" #include "hostosinfo.h" #include "utilstr.h" -#include <QDir> #include <QGuiApplication> #include <QMessageBox> #include <QPushButton> namespace Utils { -QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FilePath &fileName, - bool modified, - bool enableDiffOption, - QWidget *parent) +ReloadPromptAnswer reloadPrompt(const FilePath &fileName, + bool modified, + bool enableDiffOption) { - const QString title = Tr::tr("File Changed"); QString msg; @@ -38,16 +36,15 @@ QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FilePath &fileName, msg += Tr::tr("The default behavior can be set in Edit > Preferences > Environment > System."); } msg += "</p>"; - return reloadPrompt(title, msg, fileName.toUserOutput(), enableDiffOption, parent); + return reloadPrompt(title, msg, fileName.toUserOutput(), enableDiffOption); } -QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, - const QString &prompt, - const QString &details, - bool enableDiffOption, - QWidget *parent) +ReloadPromptAnswer reloadPrompt(const QString &title, + const QString &prompt, + const QString &details, + bool enableDiffOption) { - QMessageBox msg(parent); + QMessageBox msg(dialogParent()); msg.setStandardButtons(QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::Close | QMessageBox::No | QMessageBox::NoToAll); msg.setDefaultButton(QMessageBox::YesToAll); @@ -81,14 +78,13 @@ QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, return ReloadNone; } -QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer - fileDeletedPrompt(const QString &fileName, QWidget *parent) +FileDeletedPromptAnswer fileDeletedPrompt(const FilePath &filePath) { const QString title = Tr::tr("File Has Been Removed"); const QString msg = Tr::tr("The file %1 has been removed from disk. " "Do you want to save it under a different name, or close " - "the editor?").arg(QDir::toNativeSeparators(fileName)); - QMessageBox box(QMessageBox::Question, title, msg, QMessageBox::NoButton, parent); + "the editor?").arg(filePath.toUserOutput()); + QMessageBox box(QMessageBox::Question, title, msg, QMessageBox::NoButton, dialogParent()); QPushButton *saveas = box.addButton(Tr::tr("Save &as..."), QMessageBox::ActionRole); QPushButton *close = box.addButton(Tr::tr("&Close"), QMessageBox::RejectRole); QPushButton *closeAll = @@ -100,11 +96,11 @@ QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer QAbstractButton *clickedbutton = box.clickedButton(); if (clickedbutton == close) return FileDeletedClose; - else if (clickedbutton == closeAll) + if (clickedbutton == closeAll) return FileDeletedCloseAll; - else if (clickedbutton == saveas) + if (clickedbutton == saveas) return FileDeletedSaveAs; - else if (clickedbutton == save) + if (clickedbutton == save) return FileDeletedSave; return FileDeletedClose; } diff --git a/src/libs/utils/reloadpromptutils.h b/src/libs/utils/reloadpromptutils.h index 1232b70b2ff..5794a2b51f8 100644 --- a/src/libs/utils/reloadpromptutils.h +++ b/src/libs/utils/reloadpromptutils.h @@ -7,10 +7,10 @@ QT_BEGIN_NAMESPACE class QString; -class QWidget; QT_END_NAMESPACE namespace Utils { + class FilePath; enum ReloadPromptAnswer { @@ -24,13 +24,11 @@ enum ReloadPromptAnswer { QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FilePath &fileName, bool modified, - bool enableDiffOption, - QWidget *parent); + bool enableDiffOption); QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, const QString &prompt, const QString &details, - bool enableDiffOption, - QWidget *parent); + bool enableDiffOption); enum FileDeletedPromptAnswer { FileDeletedClose, @@ -39,7 +37,6 @@ enum FileDeletedPromptAnswer { FileDeletedSave }; -QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer fileDeletedPrompt(const QString &fileName, - QWidget *parent); +QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer fileDeletedPrompt(const FilePath &filePath); } // namespace Utils diff --git a/src/libs/utils/result.h b/src/libs/utils/result.h index bb11a290710..80e5cc793bc 100644 --- a/src/libs/utils/result.h +++ b/src/libs/utils/result.h @@ -27,8 +27,16 @@ template<typename T = void> class Continuation { public: + Continuation() = default; + + Continuation(const std::function<void(const Result<T> &)> &callback) + : m_unguarded(true), m_callback(callback) + { + QTC_CHECK(callback); + } + Continuation(QObject *guard, const std::function<void(const Result<T> &)> &callback) - : m_guard(guard), m_callback(callback) + : m_guarded(true), m_guard(guard), m_callback(callback) { QTC_CHECK(guard); QTC_CHECK(callback); @@ -36,8 +44,10 @@ public: void operator()(const Result<T> &result) const { - if (m_guard) + if (m_unguarded || (m_guarded && m_guard)) { + QTC_ASSERT(m_callback, return); m_callback(result); + } } QObject *guard() const @@ -46,6 +56,8 @@ public: } private: + bool m_guarded = false; + bool m_unguarded = false; QPointer<QObject> m_guard; std::function<void(const Result<T> &)> m_callback; }; diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index f68c2d01d4e..ad3d4086a3c 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1386,10 +1386,8 @@ void AndroidConfigurations::updateAutomaticKitList() const QList<Kit *> existingKits = Utils::filtered(KitManager::kits(), [](Kit *k) { Id deviceTypeId = RunDeviceTypeKitAspect::deviceTypeId(k); - if (k->detectionSource().isAutoDetected() && !k->detectionSource().isSdkProvided() - && deviceTypeId == Constants::ANDROID_DEVICE_TYPE) { + if (!k->detectionSource().isSdkProvided() && deviceTypeId == Constants::ANDROID_DEVICE_TYPE) return true; - } return false; }); @@ -1431,7 +1429,9 @@ void AndroidConfigurations::updateAutomaticKitList() }); const auto initializeKit = [&bundle, qt](Kit *k) { - k->setDetectionSource({DetectionSource::FromSystem, "AndroidConfiguration"}); + const auto source = qt->detectionSource().isAutoDetected() ? + DetectionSource::FromSystem : DetectionSource::Manual; + k->setDetectionSource({source, "AndroidConfiguration"}); RunDeviceTypeKitAspect::setDeviceTypeId(k, Constants::ANDROID_DEVICE_TYPE); ToolchainKitAspect::setBundle(k, bundle); QtKitAspect::setQtVersion(k, qt); diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 5541a18f0d3..1acebb1a256 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -136,7 +136,7 @@ class AndroidPlugin final : public ExtensionSystem::IPlugin void askUserAboutAndroidSetup() { NANOTRACE_SCOPE("Android", "AndroidPlugin::askUserAboutAndroidSetup"); - Utils::InfoBar *infoBar = Core::ICore::infoBar(); + Utils::InfoBar *infoBar = Core::ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(kSetupAndroidSetting)) return; diff --git a/src/plugins/autotest/testresult.h b/src/plugins/autotest/testresult.h index 51959deb426..76abd29dcab 100644 --- a/src/plugins/autotest/testresult.h +++ b/src/plugins/autotest/testresult.h @@ -57,9 +57,9 @@ static inline bool isTestMessage(const ResultType &result) return result >= ResultType::MessageDebug && result <= ResultType::MessageError; } -inline auto qHash(const ResultType &result) +inline size_t qHash(const ResultType &result) { - return QT_PREPEND_NAMESPACE(qHash(int(result))); + return QT_PREPEND_NAMESPACE(qHash)(int(result)); } class TestResult; diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index 5a7690fa918..9ae8651d24d 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -434,10 +434,7 @@ IssuesWidget::IssuesWidget(QWidget *parent) localLayout->addWidget(m_localBuild); localLayout->addWidget(m_localDashBoard); connect(&settings(), &AxivionSettings::suitePathValidated, this, [this] { - const auto info = settings().versionInfo(); - const bool enable = info && !info->versionNumber.isEmpty() - && !hasRunningLocalBuild(m_currentProject); - m_localBuild->setEnabled(enable); + m_localBuild->setEnabled(!hasRunningLocalBuild(m_currentProject)); checkForLocalBuildAndUpdate(); }); connect(m_localDashBoard, &QToolButton::clicked, this, &IssuesWidget::switchDashboard); @@ -1066,8 +1063,7 @@ void IssuesWidget::updateBasicProjectInfo(const std::optional<Dto::ProjectInfoDt updateVersionsFromProjectInfo(info); m_showFilterHelp->setEnabled(info->issueFilterHelp.has_value()); std::optional<AxivionVersionInfo> suiteVersionInfo = settings().versionInfo(); - m_localBuild->setEnabled(!m_currentProject.isEmpty() - && suiteVersionInfo && !suiteVersionInfo->versionNumber.isEmpty()); + m_localBuild->setEnabled(!hasRunningLocalBuild(m_currentProject)); checkForLocalBuildAndUpdate(); } @@ -1362,7 +1358,7 @@ void IssuesWidget::openFilterHelp() void IssuesWidget::checkForLocalBuildAndUpdate() { checkForLocalBuildResults(m_currentProject, [this] { - m_localBuild->setEnabled(true); + m_localBuild->setEnabled(!hasRunningLocalBuild(m_currentProject)); m_localDashBoard->setEnabled(true); }); } diff --git a/src/plugins/axivion/localbuild.cpp b/src/plugins/axivion/localbuild.cpp index 9202bac423b..02cf07f8535 100644 --- a/src/plugins/axivion/localbuild.cpp +++ b/src/plugins/axivion/localbuild.cpp @@ -428,20 +428,14 @@ public: layout->addWidget(widget); layout->addWidget(buttons); - const auto updateOkButton = [this, okButton] { - bool enable = bauhausSuite().pathAppended("bin/axivion_suite_info") - .withExecutableSuffix().exists(); - enable &= !fileOrCommand().isEmpty(); - okButton->setEnabled(enable); - }; - connect(&bauhausSuite, &FilePathAspect::changed, this, updateOkButton); - connect(&fileOrCommand, &FilePathAspect::changed, this, updateOkButton); + connect(&fileOrCommand, &FilePathAspect::changed, + this, [this, okButton] { okButton->setEnabled(!fileOrCommand().isEmpty()); }); connect(okButton, &QPushButton::clicked, this, &QDialog::accept); connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QDialog::reject); setWindowTitle(Tr::tr("Local Build Command: %1").arg(projectName)); - updateOkButton(); + okButton->setEnabled(!fileOrCommand().isEmpty()); } FilePathAspect bauhausSuite; @@ -547,6 +541,8 @@ bool LocalBuild::startLocalBuildFor(const QString &projectName) if (ExtensionSystem::PluginManager::isShuttingDown()) return false; + QTC_ASSERT(!projectName.isEmpty(), return false); + LocalBuildDialog dia(projectName); if (dia.exec() != QDialog::Accepted) return false; diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index b87caba57d1..a4ddaa4ea00 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -15,7 +15,7 @@ #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/messagemanager.h> -#include <coreplugin/progressmanager/progressmanager.h> +#include <coreplugin/progressmanager/taskprogress.h> #include <cppeditor/clangdiagnosticconfig.h> #include <cppeditor/cppeditorconstants.h> @@ -32,17 +32,18 @@ #include <projectexplorer/target.h> #include <projectexplorer/taskhub.h> +#include <solutions/tasking/tasktreerunner.h> + #include <texteditor/textmark.h> #include <utils/action.h> #include <utils/async.h> #include <utils/temporarydirectory.h> -#include <QFutureWatcher> - using namespace Core; using namespace CppEditor; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace ClangCodeModel::Internal { @@ -53,7 +54,6 @@ class ClangCodeModelPlugin final: public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangCodeModel.json") public: - ~ClangCodeModelPlugin() final; void initialize() final; private: @@ -62,15 +62,9 @@ private: Utils::Action *m_generateCompilationDBAction = nullptr; Task m_generateCompilationDBError; - QFutureWatcher<GenerateCompilationDbResult> m_generatorWatcher; + SingleTaskTreeRunner m_taskTreeRunner; }; -ClangCodeModelPlugin::~ClangCodeModelPlugin() -{ - m_generatorWatcher.cancel(); - m_generatorWatcher.waitForFinished(); -} - void ClangCodeModelPlugin::initialize() { TaskHub::addCategory({Constants::TASK_CATEGORY_DIAGNOSTICS, @@ -101,7 +95,7 @@ void ClangCodeModelPlugin::initialize() void ClangCodeModelPlugin::generateCompilationDB() { - Project * project = ProjectManager::startupProject(); + Project *project = ProjectManager::startupProject(); if (!project || !project->activeKit()) return; @@ -112,14 +106,39 @@ void ClangCodeModelPlugin::generateCompilationDB() if (baseDir == project->projectDirectory()) baseDir = TemporaryDirectory::masterDirectoryFilePath(); - QFuture<GenerateCompilationDbResult> task - = Utils::asyncRun(&Internal::generateCompilationDB, ProjectInfoList{projectInfo}, - baseDir, CompilationDbPurpose::Project, - warningsConfigForProject(project), - globalClangOptions(), - FilePath()); - ProgressManager::addTask(task, Tr::tr("Generating Compilation DB"), "generate compilation db"); - m_generatorWatcher.setFuture(task); + const auto onSetup = [projectInfo, baseDir, project]( + Async<GenerateCompilationDbResult> &task) { + task.setConcurrentCallData(&Internal::generateCompilationDB, + ProjectInfoList{projectInfo}, baseDir, + CompilationDbPurpose::Project, + warningsConfigForProject(project), + globalClangOptions(), FilePath()); + }; + const auto onDone = [this](const Async<GenerateCompilationDbResult> &task) { + QString message; + if (task.isResultAvailable()) { + const GenerateCompilationDbResult result = task.result(); + if (result) { + message = Tr::tr("Clang compilation database generated at \"%1\".") + .arg(result->toUserOutput()); + } else { + message = Tr::tr("Generating Clang compilation database failed: %1") + .arg(result.error()); + } + } else { + message = Tr::tr("Generating Clang compilation database canceled."); + } + MessageManager::writeFlashing(message); + m_generateCompilationDBAction->setEnabled(true); + }; + + const auto onTreeSetup = [](TaskTree &taskTree) { + auto progress = new TaskProgress(&taskTree); + progress->setDisplayName(Tr::tr("Generating Compilation DB")); + progress->setId("generate compilation db"); + }; + m_taskTreeRunner.start( + {AsyncTask<GenerateCompilationDbResult>(onSetup, onDone)}, onTreeSetup); } void ClangCodeModelPlugin::createCompilationDBAction() @@ -137,24 +156,6 @@ void ClangCodeModelPlugin::createCompilationDBAction() if (Project *startupProject = ProjectManager::startupProject()) m_generateCompilationDBAction->setParameter(startupProject->displayName()); - connect(&m_generatorWatcher, &QFutureWatcher<GenerateCompilationDbResult>::finished, - this, [this] { - QString message; - if (m_generatorWatcher.future().resultCount()) { - const GenerateCompilationDbResult result = m_generatorWatcher.result(); - if (result) { - message = Tr::tr("Clang compilation database generated at \"%1\".") - .arg(result->toUserOutput()); - } else { - message - = Tr::tr("Generating Clang compilation database failed: %1").arg(result.error()); - } - } else { - message = Tr::tr("Generating Clang compilation database canceled."); - } - MessageManager::writeFlashing(message); - m_generateCompilationDBAction->setEnabled(true); - }); connect(m_generateCompilationDBAction, &QAction::triggered, this, [this] { TaskHub::clearAndRemoveTask(m_generateCompilationDBError); const auto setError = [this](const QString &reason) { diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index ae106dbb357..f53f10af084 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -192,7 +192,7 @@ static void checkSystemForClangdSuitability() [] { ClangdSettings::setUseClangdAndSave(true); }, {}, InfoBarEntry::ButtonAction::Hide); - ICore::infoBar()->addInfo(info); + ICore::popupInfoBar()->addInfo(info); } static void updateParserConfig(ClangdClient *client) @@ -540,18 +540,27 @@ void ClangModelManagerSupport::updateLanguageClient(Project *project) const FilePath jsonDbDir = getJsonDbDir(project); if (jsonDbDir.isEmpty()) return; - const auto generatorWatcher = new QFutureWatcher<GenerateCompilationDbResult>; - connect(generatorWatcher, &QFutureWatcher<GenerateCompilationDbResult>::finished, - this, [this, project, projectInfo, jsonDbDir, generatorWatcher] { - generatorWatcher->deleteLater(); + + const FilePath includeDir = settings.clangdIncludePath(); + const auto onSetup = [this, projectInfo, jsonDbDir, project, includeDir]( + Async<GenerateCompilationDbResult> &task) { + task.setFutureSynchronizer(&m_generatorSynchronizer); + task.setConcurrentCallData(&Internal::generateCompilationDB, projectInfo, + jsonDbDir, CompilationDbPurpose::CodeModel, + warningsConfigForProject(project), + globalClangOptions(), includeDir); + }; + + const auto onDone = [this, project, projectInfo, jsonDbDir]( + const Async<GenerateCompilationDbResult> &task) { if (!isProjectDataUpToDate(project, projectInfo, jsonDbDir)) return; - if (generatorWatcher->future().resultCount() == 0) { + if (!task.isResultAvailable()) { MessageManager::writeDisrupting( Tr::tr("Cannot use clangd: Generating compilation database canceled.")); return; } - const GenerateCompilationDbResult result = generatorWatcher->result(); + const GenerateCompilationDbResult result = task.result(); if (!result) { MessageManager::writeDisrupting(Tr::tr("Cannot use clangd: " "Failed to generate compilation database:\n%1").arg(result.error())); @@ -652,15 +661,10 @@ void ClangModelManagerSupport::updateLanguageClient(Project *project) client->openExtraFile(cxxNode->filePath()); client->closeExtraFile(cxxNode->filePath()); }); - + }; + m_taskTreeRunner.start({ + AsyncTask<GenerateCompilationDbResult>(onSetup, onDone) }); - const FilePath includeDir = settings.clangdIncludePath(); - auto future = Utils::asyncRun(&Internal::generateCompilationDB, projectInfo, - jsonDbDir, CompilationDbPurpose::CodeModel, - warningsConfigForProject(project), - globalClangOptions(), includeDir); - generatorWatcher->setFuture(future); - m_generatorSynchronizer.addFuture(future); } QList<Client *> ClangModelManagerSupport::clientsForOpenProjects() diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index a7faa2da822..2d6225a7d0a 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -6,6 +6,8 @@ #include <cppeditor/cppmodelmanagersupport.h> #include <cppeditor/projectinfo.h> +#include <solutions/tasking/tasktreerunner.h> + #include <utils/filepath.h> #include <utils/futuresynchronizer.h> #include <utils/id.h> @@ -100,7 +102,8 @@ private: QList<QPointer<ClangdClient>> m_clientsToRestart; QTimer * const m_clientRestartTimer; QHash<Utils::FilePath, QString> m_potentialShadowDocuments; - Utils::FutureSynchronizer m_generatorSynchronizer; // Keep me last + Utils::FutureSynchronizer m_generatorSynchronizer; // Sync after task tree. + Tasking::ParallelTaskTreeRunner m_taskTreeRunner; }; } // namespace Internal diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 2473c3affa9..1cdce902c46 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -39,7 +39,10 @@ clang::format::FormatStyle calculateQtcStyle() style.Language = FormatStyle::LK_Cpp; style.AccessModifierOffset = -4; style.AlignAfterOpenBracket = FormatStyle::BAS_Align; -#if LLVM_VERSION_MAJOR >= 18 +#if LLVM_VERSION_MAJOR >= 20 + style.AlignConsecutiveAssignments = {false, false, false, false, false, false, false}; + style.AlignConsecutiveDeclarations = {false, false, false, false, false, false, false}; +#elif LLVM_VERSION_MAJOR >= 18 style.AlignConsecutiveAssignments = {false, false, false, false, false, false}; style.AlignConsecutiveDeclarations = {false, false, false, false, false, false}; #elif LLVM_VERSION_MAJOR >= 15 diff --git a/src/plugins/clangtools/clangtoolscompilationdb.cpp b/src/plugins/clangtools/clangtoolscompilationdb.cpp index 446fc3eec3e..62b4fbddfe2 100644 --- a/src/plugins/clangtools/clangtoolscompilationdb.cpp +++ b/src/plugins/clangtools/clangtoolscompilationdb.cpp @@ -13,18 +13,22 @@ #include <cppeditor/clangdiagnosticconfigsmodel.h> #include <cppeditor/compilationdb.h> #include <cppeditor/cppmodelmanager.h> + #include <projectexplorer/buildconfiguration.h> + +#include <solutions/tasking/tasktreerunner.h> + #include <utils/async.h> #include <utils/futuresynchronizer.h> #include <utils/temporarydirectory.h> -#include <QFutureWatcher> #include <QHash> #include <utility> using namespace CppEditor; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace ClangTools::Internal { @@ -43,9 +47,9 @@ public: ClangToolsCompilationDb * const q; const ClangToolType toolType; TemporaryDirectory dir{toolName() + "XXXXXX"}; - QFutureWatcher<GenerateCompilationDbResult> generatorWatcher; - FutureSynchronizer generatorSynchronizer; bool readyAndUpToDate = false; + FutureSynchronizer generatorSynchronizer; + SingleTaskTreeRunner taskTreeRunner; }; ClangToolsCompilationDb::ClangToolsCompilationDb(ClangToolType toolType, BuildConfiguration *bc) @@ -54,25 +58,6 @@ ClangToolsCompilationDb::ClangToolsCompilationDb(ClangToolType toolType, BuildCo connect(bc, &BuildConfiguration::destroyed, [bc, toolType] { dbs.remove(std::make_pair(toolType, bc)); }); - - connect(&d->generatorWatcher, &QFutureWatcher<GenerateCompilationDbResult>::finished, - this, [this] { - const auto result = d->generatorWatcher.result(); - const bool success = result.has_value(); - QTC_CHECK(!d->readyAndUpToDate); - d->readyAndUpToDate = success; - if (success) { - Core::MessageManager::writeSilently( - Tr::tr("Compilation database for %1 successfully generated at \"%2\".") - .arg(d->toolName(), d->dir.path().toUserOutput())); - } else { - Core::MessageManager::writeDisrupting( - Tr::tr("Generating compilation database for %1 failed: %2") - .arg(d->toolName(), result.error())); - } - emit generated(success); - }); - connect(ClangToolsProjectSettings::getSettings(bc->project()).get(), &ClangToolsProjectSettings::changed, this, &ClangToolsCompilationDb::invalidate); @@ -112,9 +97,6 @@ void ClangToolsCompilationDb::Private::generate() { QTC_CHECK(!readyAndUpToDate); - if (generatorWatcher.isRunning()) - generatorWatcher.cancel(); - Core::MessageManager::writeSilently( Tr::tr("Generating compilation database for %1 at \"%2\" ...") .arg(clangToolName(toolType), dir.path().toUserOutput())); @@ -154,15 +136,36 @@ void ClangToolsCompilationDb::Private::generate() return optionsBuilder; }; - generatorWatcher.setFuture( - Utils::asyncRun( + const auto onSetup = [this, bc, getCompilerOptionsBuilder]( + Async<GenerateCompilationDbResult> &task) { + task.setFutureSynchronizer(&generatorSynchronizer); + task.setConcurrentCallData( &generateCompilationDB, QList<ProjectInfo::ConstPtr>{CppModelManager::projectInfo(bc->project())}, dir.path(), CompilationDbPurpose::Analysis, ClangDiagnosticConfigsModel::globalDiagnosticOptions(), - getCompilerOptionsBuilder)); - generatorSynchronizer.addFuture(generatorWatcher.future()); + getCompilerOptionsBuilder); + }; + const auto onDone = [this](const Async<GenerateCompilationDbResult> &task) { + const auto result = task.result(); + const bool success = result.has_value(); + QTC_CHECK(!readyAndUpToDate); + readyAndUpToDate = success; + if (success) { + Core::MessageManager::writeSilently( + Tr::tr("Compilation database for %1 successfully generated at \"%2\".") + .arg(toolName(), dir.path().toUserOutput())); + } else { + Core::MessageManager::writeDisrupting( + Tr::tr("Generating compilation database for %1 failed: %2") + .arg(toolName(), result.error())); + } + emit q->generated(success); + }; + taskTreeRunner.start({ + AsyncTask<GenerateCompilationDbResult>(onSetup, onDone) + }); } } // namespace ClangTools::Internal diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp index fa58fe48894..e279bfc5c73 100644 --- a/src/plugins/clangtools/clangtoolslogfilereader.cpp +++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp @@ -10,8 +10,6 @@ #include <utils/fileutils.h> #include <utils/textutils.h> -#include <QFuture> - #include <yaml-cpp/yaml.h> using namespace Utils; diff --git a/src/plugins/classview/classviewsymbolinformation.h b/src/plugins/classview/classviewsymbolinformation.h index 9aa12b3a6b4..453b4c795f9 100644 --- a/src/plugins/classview/classviewsymbolinformation.h +++ b/src/plugins/classview/classviewsymbolinformation.h @@ -8,8 +8,7 @@ #include <limits.h> -namespace ClassView { -namespace Internal { +namespace ClassView::Internal { class SymbolInformation { @@ -31,16 +30,15 @@ public: int iconTypeSortOrder() const; - friend auto qHash(const SymbolInformation &information) { return information.hash(); } + friend size_t qHash(const SymbolInformation &information) { return information.hash(); } private: const int m_iconType; - const size_t m_hash; // precalculated hash value - to speed up qHash - const QString m_name; // symbol name (e.g. SymbolInformation) - const QString m_type; // symbol type (e.g. (int char)) + const size_t m_hash; // precalculated hash value - to speed up qHash + const QString m_name; // symbol name (e.g. SymbolInformation) + const QString m_type; // symbol type (e.g. (int char)) }; -} // namespace Internal -} // namespace ClassView +} // namespace ClassView::Internal Q_DECLARE_METATYPE(ClassView::Internal::SymbolInformation) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 50f82577798..0f3321b0cd1 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -143,6 +143,8 @@ Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakeP result.vendor = cmakeUserPresetsData.vendor; } + result.hasValidPresets = cmakePresetsData.hasValidPresets && cmakeUserPresetsData.hasValidPresets; + auto combinePresetsInternal = [](auto &presetsHash, auto &presets, auto &userPresets, @@ -239,6 +241,7 @@ void CMakeProject::setupBuildPresets(Internal::PresetsData &presetsData) Task::TaskType::DisruptingError, Tr::tr("Build preset %1 is missing a corresponding configure preset.") .arg(buildPreset.name)); + presetsData.hasValidPresets = false; } const QString &configurePresetName = buildPreset.configurePreset.value_or(QString()); @@ -305,16 +308,11 @@ void CMakeProject::readPresets() QString errorMessage; int errorLine = -1; - if (presetFile.exists()) { - if (parser.parse(presetFile, errorMessage, errorLine)) { - data = parser.presetsData(); - } else { - TaskHub::addTask<BuildSystemTask>( - Task::TaskType::DisruptingError, - Tr::tr("Failed to load %1: %2").arg(presetFile.fileName()).arg(errorMessage), - presetFile, - errorLine); - } + if (parser.parse(presetFile, errorMessage, errorLine)) { + data = parser.presetsData(); + } else { + TaskHub::addTask<BuildSystemTask>( + Task::TaskType::DisruptingError, errorMessage, presetFile, errorLine); } return data; }; @@ -345,6 +343,7 @@ void CMakeProject::readPresets() presetData.configurePresets = includeData.configurePresets + presetData.configurePresets; presetData.buildPresets = includeData.buildPresets + presetData.buildPresets; + presetData.hasValidPresets = includeData.hasValidPresets && presetData.hasValidPresets; includeStack << includePath; } @@ -354,8 +353,13 @@ void CMakeProject::readPresets() const Utils::FilePath cmakePresetsJson = projectDirectory().pathAppended("CMakePresets.json"); const Utils::FilePath cmakeUserPresetsJson = projectDirectory().pathAppended("CMakeUserPresets.json"); + if (!cmakePresetsJson.exists()) + return; + Internal::PresetsData cmakePresetsData = parsePreset(cmakePresetsJson); - Internal::PresetsData cmakeUserPresetsData = parsePreset(cmakeUserPresetsJson); + Internal::PresetsData cmakeUserPresetsData; + if (cmakeUserPresetsJson.exists()) + cmakeUserPresetsData = parsePreset(cmakeUserPresetsJson); // resolve the include Utils::FilePaths includeStack = {cmakePresetsJson}; @@ -367,6 +371,11 @@ void CMakeProject::readPresets() m_presetsData = combinePresets(cmakePresetsData, cmakeUserPresetsData); setupBuildPresets(m_presetsData); + if (!m_presetsData.hasValidPresets) { + m_presetsData = {}; + return; + } + for (const auto &configPreset : std::as_const(m_presetsData.configurePresets)) { if (configPreset.hidden) continue; diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 6b45491ce20..862d5b9a56a 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -39,6 +39,9 @@ public: Internal::CMakeSpecificSettings &settings(); static QString projectDisplayName(const Utils::FilePath &projectFilePath); +signals: + void cmakePresetsUpdated(); + private: ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; void configureAsExampleProject(ProjectExplorer::Kit *kit) override; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index c3e734c2d70..7f080ca96e2 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -490,7 +490,7 @@ void CMakeManager::reloadCMakePresets() project->setOldPresetKits(oldKits); - emit project->projectImporter()->cmakePresetsUpdated(); + emit project->cmakePresetsUpdated(); Core::ModeManager::activateMode(ProjectExplorer::Constants::MODE_SESSION); Core::ModeManager::setFocusToCurrentMode(); diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index d670fe938a8..3e810a9ff7e 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -125,13 +125,15 @@ CMakeSpecificSettings::CMakeSpecificSettings(Project *p, bool autoApply) // Re-read the settings. Reading in constructor is too early connect(project, &Project::settingsLoaded, this, [this] { readSettings(); }); - connect(project->projectImporter(), &ProjectImporter::cmakePresetsUpdated, this, [this] { - // clear settings first - Store data; - project->setNamedSettings(Constants::Settings::GENERAL_ID, variantFromStore(data)); + if (CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project)) { + connect(cmakeProject, &CMakeProject::cmakePresetsUpdated, this, [this] { + // clear settings first + Store data; + project->setNamedSettings(Constants::Settings::GENERAL_ID, variantFromStore(data)); - readSettings(); - }); + readSettings(); + }); + } } } diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index e27d8af5158..56997e06801 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -41,7 +41,6 @@ const char CMAKE_INFORMATION_QCH_FILE_PATH[] = "QchFile"; const char CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY[] = "AutoCreateBuildDirectory"; const char CMAKE_INFORMATION_AUTODETECTED[] = "AutoDetected"; const char CMAKE_INFORMATION_DETECTIONSOURCE[] = "DetectionSource"; -const char CMAKE_INFORMATION_READERTYPE[] = "ReaderType"; bool CMakeTool::Generator::matches(const QString &n) const { @@ -50,26 +49,6 @@ bool CMakeTool::Generator::matches(const QString &n) const namespace Internal { -const char READER_TYPE_FILEAPI[] = "fileapi"; - -static std::optional<CMakeTool::ReaderType> readerTypeFromString(const QString &input) -{ - // Do not try to be clever here, just use whatever is in the string! - if (input == READER_TYPE_FILEAPI) - return CMakeTool::FileApi; - return {}; -} - -static QString readerTypeToString(const CMakeTool::ReaderType &type) -{ - switch (type) { - case CMakeTool::FileApi: - return QString(READER_TYPE_FILEAPI); - default: - return QString(); - } -} - // -------------------------------------------------------------------- // CMakeIntrospectionData: // -------------------------------------------------------------------- @@ -114,8 +93,6 @@ CMakeTool::CMakeTool(const Store &map, bool fromSdk) { m_displayName = map.value(CMAKE_INFORMATION_DISPLAYNAME).toString(); m_autoCreateBuildDirectory = map.value(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, false).toBool(); - m_readerType = Internal::readerTypeFromString( - map.value(CMAKE_INFORMATION_READERTYPE).toString()); const DetectionSource::DetectionType type = [&] { if (fromSdk) @@ -190,8 +167,6 @@ Store CMakeTool::toMap() const data.insert(CMAKE_INFORMATION_COMMAND, m_executable.toSettings()); data.insert(CMAKE_INFORMATION_QCH_FILE_PATH, m_qchFilePath.toSettings()); data.insert(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, m_autoCreateBuildDirectory); - if (m_readerType) - data.insert(CMAKE_INFORMATION_READERTYPE, Internal::readerTypeToString(*m_readerType)); data.insert(CMAKE_INFORMATION_AUTODETECTED, m_detectionSource.isAutoDetected()); data.insert(CMAKE_INFORMATION_DETECTIONSOURCE, m_detectionSource.id); return data; @@ -380,17 +355,6 @@ CMakeTool::PathMapper CMakeTool::pathMapper() const return [](const FilePath &fn) { return fn; }; } -std::optional<CMakeTool::ReaderType> CMakeTool::readerType() const -{ - if (m_readerType) - return m_readerType; // Allow overriding the auto-detected value via .user files - - // Find best possible reader type: - if (hasFileApi()) - return FileApi; - return {}; -} - FilePath CMakeTool::searchQchFile(const FilePath &executable) { if (executable.isEmpty() || !executable.isLocal()) // do not register docs from devices diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h index 17ef86404f7..a6782d9dd32 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.h +++ b/src/plugins/cmakeprojectmanager/cmaketool.h @@ -46,8 +46,6 @@ public: AutoDetection }; - enum ReaderType { FileApi }; - struct Version { int major = 0; @@ -107,8 +105,6 @@ public: void setPathMapper(const PathMapper &includePathMapper); PathMapper pathMapper() const; - std::optional<ReaderType> readerType() const; - static Utils::FilePath searchQchFile(const Utils::FilePath &executable); [[deprecated("Use setDetectionSource(DetectionSource) instead")]] void setDetectionSource( @@ -142,8 +138,6 @@ private: ProjectExplorer::DetectionSource m_detectionSource; bool m_autoCreateBuildDirectory = false; - std::optional<ReaderType> m_readerType; - std::unique_ptr<Internal::IntrospectionData> m_introspection; PathMapper m_pathMapper; diff --git a/src/plugins/cmakeprojectmanager/presetsparser.h b/src/plugins/cmakeprojectmanager/presetsparser.h index 17a779a8c7d..a0e743f833a 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.h +++ b/src/plugins/cmakeprojectmanager/presetsparser.h @@ -141,6 +141,7 @@ class PresetsData public: int version = 0; bool havePresets = false; + bool hasValidPresets = true; QVersionNumber cmakeMinimimRequired; std::optional<QVariantMap> vendor; std::optional<QStringList> include; diff --git a/src/plugins/compilerexplorer/api/compiler.cpp b/src/plugins/compilerexplorer/api/compiler.cpp index 6b9223d8681..93778f25dea 100644 --- a/src/plugins/compilerexplorer/api/compiler.cpp +++ b/src/plugins/compilerexplorer/api/compiler.cpp @@ -5,7 +5,6 @@ #include "request.h" -#include <QFutureWatcher> #include <QUrlQuery> namespace CompilerExplorer::Api { diff --git a/src/plugins/compilerexplorer/compilerexploreraspects.cpp b/src/plugins/compilerexplorer/compilerexploreraspects.cpp index ac75bffcf9e..52c776a65a6 100644 --- a/src/plugins/compilerexplorer/compilerexploreraspects.cpp +++ b/src/plugins/compilerexplorer/compilerexploreraspects.cpp @@ -11,7 +11,6 @@ #include <QComboBox> #include <QCompleter> -#include <QFutureWatcher> #include <QPushButton> #include <QStackedWidget> diff --git a/src/plugins/compilerexplorer/compilerexploreroptions.cpp b/src/plugins/compilerexplorer/compilerexploreroptions.cpp index 64ed6513f45..d8819ca1ff1 100644 --- a/src/plugins/compilerexplorer/compilerexploreroptions.cpp +++ b/src/plugins/compilerexplorer/compilerexploreroptions.cpp @@ -7,7 +7,6 @@ #include <utils/layoutbuilder.h> -#include <QFutureWatcher> #include <QScrollArea> #include <QStandardItemModel> diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 23227574016..2ca70adede3 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -544,7 +544,7 @@ void CorePlugin::checkSettings() void CorePlugin::warnAboutCrashReporing() { - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(kWarnCrashReportingSetting)) return; diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index df824715138..54aa65f5b6b 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -716,7 +716,7 @@ bool DocumentManager::saveDocument(IDocument *document, if (const Result<> res = document->save(savePath, false); !res) { if (isReadOnly) { - QFile ofi(savePath.toUrlishString()); + QFile ofi(savePath.toFSPathString()); // Check whether the existing file is writable if (!ofi.open(QIODevice::ReadWrite) && ofi.open(QIODevice::ReadOnly)) { *isReadOnly = true; @@ -1230,8 +1230,7 @@ void DocumentManager::checkForReload() } else { // Ask about content change previousReloadAnswer = reloadPrompt(document->filePath(), document->isModified(), - DiffService::instance(), - ICore::dialogParent()); + DiffService::instance()); switch (previousReloadAnswer) { case ReloadAll: case ReloadCurrent: @@ -1255,11 +1254,9 @@ void DocumentManager::checkForReload() // Ask about removed file bool unhandled = true; while (unhandled) { - if (previousDeletedAnswer != FileDeletedCloseAll) { - previousDeletedAnswer = - fileDeletedPrompt(document->filePath().toUrlishString(), - ICore::dialogParent()); - } + if (previousDeletedAnswer != FileDeletedCloseAll) + previousDeletedAnswer = fileDeletedPrompt(document->filePath()); + switch (previousDeletedAnswer) { case FileDeletedSave: documentsToSave.insert(document, document->filePath()); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 4ee13fe78c9..5a2f6a197fa 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -690,24 +690,6 @@ void EditorManagerPrivate::init() gotoNextSplit.addToContainer(Constants::M_WINDOW, Constants::G_WINDOW_SPLIT); gotoNextSplit.addOnTriggered(this, &EditorManagerPrivate::gotoNextSplit); - ActionContainer *medit = ActionManager::actionContainer(Constants::M_EDIT); - ActionContainer *advancedMenu = ActionManager::createMenu(Constants::M_EDIT_ADVANCED); - medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED); - advancedMenu->menu()->setTitle(::Core::Tr::tr("Ad&vanced")); - advancedMenu->appendGroup(Constants::G_EDIT_FORMAT); - advancedMenu->appendGroup(Constants::G_EDIT_TEXT); - advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING); - advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS); - advancedMenu->appendGroup(Constants::G_EDIT_FONT); - advancedMenu->appendGroup(Constants::G_EDIT_EDITOR); - - // Advanced menu separators - advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_TEXT); - advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_COLLAPSING); - advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_BLOCKS); - advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_FONT); - advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_EDITOR); - // other setup auto mainEditorArea = new EditorArea(); // assign parent to avoid failing updates (e.g. windowTitle) before it is displayed first time @@ -1753,7 +1735,7 @@ void EditorManagerPrivate::tabClosed(DocumentModel::Entry *entry) })) { return; } - DocumentModelPrivate::removeEntry(entry); + EditorManager::closeDocuments({entry->document}); } // Collects all tabs from the given viewsToClose for which no other tab is shown anywhere. diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 96a82a63fc2..b1c0bca7646 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -1705,6 +1705,23 @@ void ICorePrivate::registerDefaultContainers() medit->appendGroup(Constants::G_EDIT_FIND); medit->appendGroup(Constants::G_EDIT_OTHER); + ActionContainer *advancedMenu = ActionManager::createMenu(Constants::M_EDIT_ADVANCED); + medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED); + advancedMenu->menu()->setTitle(::Core::Tr::tr("Ad&vanced")); + advancedMenu->appendGroup(Constants::G_EDIT_FORMAT); + advancedMenu->appendGroup(Constants::G_EDIT_TEXT); + advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING); + advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS); + advancedMenu->appendGroup(Constants::G_EDIT_FONT); + advancedMenu->appendGroup(Constants::G_EDIT_EDITOR); + + advancedMenu->addSeparator(Constants::G_EDIT_TEXT); + advancedMenu->addSeparator(Constants::G_EDIT_COLLAPSING); + advancedMenu->addSeparator(Constants::G_EDIT_BLOCKS); + advancedMenu->addSeparator(Constants::G_EDIT_FONT); + advancedMenu->addSeparator(Constants::G_EDIT_EDITOR); + + // View Menu ActionContainer *mview = ActionManager::createMenu(Constants::M_VIEW); menubar->addMenu(mview, Constants::G_VIEW); mview->menu()->setTitle(Tr::tr("&View")); @@ -1953,6 +1970,7 @@ void ICorePrivate::registerDefaultActions() zoomInAction.setText(Tr::tr("Zoom In")); zoomInAction.setIcon(Icon::fromTheme("zoom-in")); zoomInAction.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl++"))); + zoomInAction.addToContainer(Constants::M_EDIT_ADVANCED, Constants::G_EDIT_FONT); zoomInAction.setEnabled(false); // Zoom Out Action @@ -1963,6 +1981,7 @@ void ICorePrivate::registerDefaultActions() zoomOutAction.setDefaultKeySequences({QKeySequence(Tr::tr("Ctrl+-")), QKeySequence(Tr::tr("Ctrl+Shift+-"))}); else zoomOutAction.setDefaultKeySequence(Tr::tr("Ctrl+-")); + zoomOutAction.addToContainer(Constants::M_EDIT_ADVANCED, Constants::G_EDIT_FONT); zoomOutAction.setEnabled(false); // Zoom Reset Action @@ -1970,6 +1989,7 @@ void ICorePrivate::registerDefaultActions() zoomOriginalAction.setText(Tr::tr("Original Size")); zoomOriginalAction.setIcon(Icon::fromTheme("zoom-original")); zoomOriginalAction.setDefaultKeySequence(Tr::tr("Meta+0"), Tr::tr("Ctrl+0")); + zoomOriginalAction.addToContainer(Constants::M_EDIT_ADVANCED, Constants::G_EDIT_FONT); zoomOriginalAction.setEnabled(false); // Debug Qt Creator menu diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 720e01af468..016d0726f0b 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -15,7 +15,6 @@ #include <QCheckBox> #include <QDialog> #include <QDialogButtonBox> -#include <QFutureWatcher> #include <QJsonDocument> #include <QJsonObject> #include <QLabel> diff --git a/src/plugins/coreplugin/secretaspect.cpp b/src/plugins/coreplugin/secretaspect.cpp index 49d1a8b5399..37fbcc9a0ce 100644 --- a/src/plugins/coreplugin/secretaspect.cpp +++ b/src/plugins/coreplugin/secretaspect.cpp @@ -15,6 +15,7 @@ #include <utils/hostosinfo.h> #include <utils/layoutbuilder.h> #include <utils/passworddialog.h> +#include <utils/qtcsettings.h> #include <utils/utilsicons.h> #include <QIcon> diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index 07bb150e2e1..aa299c4e5e5 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -212,7 +212,7 @@ static void askForDisabledVcsPlugins(const FilePath &inputDirectory) return; const Id vcsSuggestion = Id("VcsManager.Suggestion.").withSuffix(spec->id()); - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(vcsSuggestion)) return; diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 9ee55bc50d8..06ec60d2efc 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -156,9 +156,12 @@ public: ClangdToolFactory() { setToolId(Constants::CLANGD_TOOL_ID); + setToolType(DeviceToolAspect::SourceTool); setFilePattern({"clangd"}); setLabelText(Tr::tr("Clangd executable:")); - setChecker(&checkClangdVersion); + setChecker([](const IDevicePtr &, const FilePath &candidate) { + return checkClangdVersion(candidate); + }); } }; diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 88f79a3db83..f22ff773816 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -789,7 +789,7 @@ void CppEditorWidget::showRenameWarningIfFileIsGenerated(const Utils::FilePath & {}, InfoBarEntry::ButtonAction::Hide); } - ICore::infoBar()->addInfo(info); + ICore::popupInfoBar()->addInfo(info); return; } } diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index 587b1b40279..e9844950b58 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -25,7 +25,6 @@ #include <texteditor/texteditorconstants.h> #include <utils/async.h> -#include <utils/futuresynchronizer.h> #include <utils/proxyaction.h> #include <utils/qtcassert.h> #include <utils/textutils.h> @@ -35,32 +34,16 @@ #include <QVarLengthArray> using namespace CPlusPlus; +using namespace Tasking; using namespace TextEditor; using namespace Utils; -namespace CppEditor { -namespace Internal { +namespace CppEditor::Internal { FunctionDeclDefLinkFinder::FunctionDeclDefLinkFinder(QObject *parent) : QObject(parent) {} -void FunctionDeclDefLinkFinder::onFutureDone() -{ - std::shared_ptr<FunctionDeclDefLink> link = m_watcher->result(); - m_watcher.release()->deleteLater(); - if (link) { - link->linkSelection = m_scannedSelection; - link->nameSelection = m_nameSelection; - if (m_nameSelection.selectedText() != link->nameInitial) - link.reset(); - } - m_scannedSelection = {}; - m_nameSelection = {}; - if (link) - emit foundLink(link); -} - QTextCursor FunctionDeclDefLinkFinder::scannedSelection() const { return m_scannedSelection; @@ -225,8 +208,9 @@ void FunctionDeclDefLinkFinder::startFindLinkAt( m_nameSelection.setPosition(sourceFile->startOf(declId), QTextCursor::KeepAnchor); m_nameSelection.setKeepPositionOnInsert(true); + using ResultType = std::shared_ptr<FunctionDeclDefLink>; // set up a base result - std::shared_ptr<FunctionDeclDefLink> result(new FunctionDeclDefLink); + ResultType result(new FunctionDeclDefLink); result->nameInitial = m_nameSelection.selectedText(); result->sourceDocument = doc; result->sourceFunction = funcDecl->symbol; @@ -234,10 +218,25 @@ void FunctionDeclDefLinkFinder::startFindLinkAt( result->sourceFunctionDeclarator = funcDecl; // handle the rest in a thread - m_watcher.reset(new QFutureWatcher<std::shared_ptr<FunctionDeclDefLink> >()); - connect(m_watcher.get(), &QFutureWatcherBase::finished, this, &FunctionDeclDefLinkFinder::onFutureDone); - m_watcher->setFuture(Utils::asyncRun(findLinkHelper, result, refactoringChanges)); - Utils::futureSynchronizer()->addFuture(m_watcher->future()); + const auto onSetup = [result, refactoringChanges](Async<ResultType> &task) { + task.setConcurrentCallData(findLinkHelper, result, refactoringChanges); + }; + const auto onDone = [this](const Async<ResultType> &task) { + ResultType link = task.result(); + if (link) { + link->linkSelection = m_scannedSelection; + link->nameSelection = m_nameSelection; + if (m_nameSelection.selectedText() != link->nameInitial) + link.reset(); + } + m_scannedSelection = {}; + m_nameSelection = {}; + if (link) + emit foundLink(link); + }; + m_taskTreeRunner.start({ + AsyncTask<ResultType>(onSetup, onDone, CallDone::OnSuccess) + }); } bool FunctionDeclDefLink::isValid() const @@ -1046,5 +1045,4 @@ QString FunctionDeclDefLink::normalizedInitialName() const return n; } -} // namespace Internal -} // namespace CppEditor +} // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.h b/src/plugins/cppeditor/cppfunctiondecldeflink.h index 8fe6219e339..e3d4e4b299c 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.h +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.h @@ -5,9 +5,9 @@ #include "cpprefactoringchanges.h" +#include <solutions/tasking/tasktreerunner.h> + #include <QString> -#include <QCoreApplication> -#include <QFutureWatcher> #include <QTextCursor> namespace CppEditor { @@ -32,11 +32,9 @@ signals: void foundLink(std::shared_ptr<FunctionDeclDefLink> link); private: - void onFutureDone(); - QTextCursor m_scannedSelection; QTextCursor m_nameSelection; - std::unique_ptr<QFutureWatcher<std::shared_ptr<FunctionDeclDefLink>>> m_watcher; + Tasking::SingleTaskTreeRunner m_taskTreeRunner; }; class FunctionDeclDefLink diff --git a/src/plugins/cppeditor/cppmodelmanager_test.cpp b/src/plugins/cppeditor/cppmodelmanager_test.cpp index a3048b01597..68c9921f56a 100644 --- a/src/plugins/cppeditor/cppmodelmanager_test.cpp +++ b/src/plugins/cppeditor/cppmodelmanager_test.cpp @@ -61,23 +61,22 @@ class MyTestDataDir : public Core::Tests::TestDataDir { public: explicit MyTestDataDir(const QString &dir) - : TestDataDir(_(SRCDIR "/../../../tests/cppmodelmanager/") + dir) + : TestDataDir(SRCDIR "/../../../tests/cppmodelmanager/" + dir) {} FilePath includeDir(bool cleaned = true) const - { return FilePath::fromUserInput(directory(_("include"), cleaned)); } + { + return directoryPath("include", cleaned); + } FilePath frameworksDir(bool cleaned = true) const - { return FilePath::fromUserInput(directory(_("frameworks"), cleaned)); } - - FilePath fileFromSourcesDir(const QString &fileName) const { - return FilePath::fromString(directory(_("sources"))).pathAppended(fileName); + return directoryPath("frameworks", cleaned); } - FilePath filePath(const QString &p) const + FilePath fileFromSourcesDir(const QString &fileName) const { - return FilePath::fromString(TestDataDir::file(p)); + return directoryPath("sources").pathAppended(fileName); } }; diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 4d0f37b07c5..7c41a8ecc72 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -1331,6 +1331,9 @@ void FollowSymbolTest::testFollowSymbol_data() QTest::newRow("baseClassViaDecltype") << _("struct Foo { static const int $_foo = 0; };\n" "struct Bar : public decltype(Foo()) { static const int _bar = @_foo; };\n"); + QTest::newRow("concept") + << _("namespace N { template<typename T> concept $C1 = true; }\n" + "static void func(N::@C1 auto p);\n"); } void FollowSymbolTest::testFollowSymbol() diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 0132e2bcaf6..83c2da6df9c 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -199,9 +199,9 @@ using SubBreakpoints = const QList<SubBreakpoint>; using BreakHandlerModel = Utils::TreeModel<Utils::TypedTreeItem<BreakpointItem>, BreakpointItem, SubBreakpointItem>; using BreakpointManagerModel = Utils::TreeModel<Utils::TypedTreeItem<GlobalBreakpointItem>, GlobalBreakpointItem>; -inline auto qHash(const Debugger::Internal::SubBreakpoint &b) { return qHash(b.data()); } -inline auto qHash(const Debugger::Internal::Breakpoint &b) { return qHash(b.data()); } -inline auto qHash(const Debugger::Internal::GlobalBreakpoint &b) { return qHash(b.data()); } +inline size_t qHash(const Debugger::Internal::SubBreakpoint &b) { return qHash(b.data()); } +inline size_t qHash(const Debugger::Internal::Breakpoint &b) { return qHash(b.data()); } +inline size_t qHash(const Debugger::Internal::GlobalBreakpoint &b) { return qHash(b.data()); } class BreakHandler : public BreakHandlerModel { diff --git a/src/plugins/debugger/dap/pydapengine.cpp b/src/plugins/debugger/dap/pydapengine.cpp index 034a94977a4..13459825ebe 100644 --- a/src/plugins/debugger/dap/pydapengine.cpp +++ b/src/plugins/debugger/dap/pydapengine.cpp @@ -252,7 +252,7 @@ void PyDapEngine::setupEngine() }, {}, InfoBarEntry::ButtonAction::SuppressPersistently); - Core::ICore::infoBar()->addInfo(info); + Core::ICore::popupInfoBar()->addInfo(info); notifyEngineSetupFailed(); return; diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 9757c8e00d1..26b5581087f 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -9,12 +9,16 @@ #include <coreplugin/dialogs/ioptionspage.h> #include <coreplugin/icore.h> +#include <nanotrace/nanotrace.h> + #include <projectexplorer/devicesupport/devicemanager.h> #include <projectexplorer/kitaspect.h> #include <projectexplorer/kitoptionspage.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorericons.h> +#include <solutions/tasking/tasktreerunner.h> + #include <utils/algorithm.h> #include <utils/async.h> #include <utils/detailswidget.h> @@ -29,13 +33,10 @@ #include <utils/qtcassert.h> #include <utils/winutils.h> -#include <nanotrace/nanotrace.h> - #include <QDebug> #include <QDir> #include <QFileInfo> #include <QFormLayout> -#include <QFutureWatcher> #include <QHeaderView> #include <QLabel> #include <QLineEdit> @@ -46,10 +47,11 @@ #include <QTreeView> #include <QWidget> +using namespace Core; using namespace Debugger; using namespace Debugger::Internal; -using namespace Core; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; static DebuggerItem makeAutoDetectedDebuggerItem( @@ -131,7 +133,7 @@ private: QLabel *m_type; PathChooser *m_workingDirectoryChooser; - QFutureWatcher<DebuggerItem> m_updateWatcher; + SingleTaskTreeRunner m_taskTreeRunner; }; // -------------------------------------------------------------------------- @@ -404,16 +406,6 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget() connect(m_displayNameLineEdit, &QLineEdit::textChanged, this, &DebuggerItemConfigWidget::store); - connect(&m_updateWatcher, &QFutureWatcher<DebuggerItem>::finished, this, [this] { - if (m_updateWatcher.future().resultCount() > 0) { - DebuggerItem tmp = m_updateWatcher.result(); - setAbis(tmp.abiNames()); - m_version->setText(tmp.version()); - m_engineType = tmp.engineType(); - m_type->setText(tmp.engineTypeName()); - } - }); - // clang-format off using namespace Layouting; Form { @@ -516,14 +508,26 @@ void DebuggerItemConfigWidget::binaryPathHasChanged() return; if (m_detectionSource != DebuggerItem::genericDetectionSource) { - m_updateWatcher.cancel(); + m_taskTreeRunner.reset(); if (m_binaryChooser->filePath().isExecutableFile()) { - m_updateWatcher.setFuture(Utils::asyncRun([tmp = item()]() mutable { - tmp.reinitializeFromFile(); - return tmp; - })); - Utils::futureSynchronizer()->addFuture(m_updateWatcher.future()); + const auto onSetup = [this](Async<DebuggerItem> &task) { + task.setConcurrentCallData([tmp = item()]() mutable { + tmp.reinitializeFromFile(); + return tmp; + }); + }; + const auto onDone = [this](const Async<DebuggerItem> &task) { + if (!task.isResultAvailable()) + return; + + const DebuggerItem tmp = task.result(); + setAbis(tmp.abiNames()); + m_version->setText(tmp.version()); + m_engineType = tmp.engineType(); + m_type->setText(tmp.engineTypeName()); + }; + m_taskTreeRunner.start({AsyncTask<DebuggerItem>(onSetup, onDone)}); } else { const DebuggerItem tmp; setAbis(tmp.abiNames()); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index c5a5ef08e38..449a0aaaa8e 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -565,6 +565,7 @@ public: DebugServerToolFactory() { setToolId(Constants::DEBUGSERVER_TOOL_ID); + setToolType(DeviceToolAspect::RunTool); setFilePattern({"gdbserver"}); setLabelText(Tr::tr("GDB server executable:")); setToolTip(Tr::tr("The GDB server executable to use on the device.")); diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index e254fb0311f..dd07ae4bb91 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -13,8 +13,9 @@ #include <utils/hostosinfo.h> #include <utils/layoutbuilder.h> #include <utils/pathchooser.h> -#include <utils/qtcprocess.h> #include <utils/qtcassert.h> +#include <utils/qtcprocess.h> +#include <utils/qtcsettings.h> #include <utils/variablechooser.h> #include <QFileDialog> diff --git a/src/plugins/devcontainer/devcontainerdevice.cpp b/src/plugins/devcontainer/devcontainerdevice.cpp index 62fda15d256..0259dd8f08a 100644 --- a/src/plugins/devcontainer/devcontainerdevice.cpp +++ b/src/plugins/devcontainer/devcontainerdevice.cpp @@ -30,8 +30,9 @@ Q_LOGGING_CATEGORY(devContainerDeviceLog, "qtc.devcontainer.device", QtWarningMsg) -using namespace Utils; using namespace ProjectExplorer; +using namespace Tasking; +using namespace Utils; namespace DevContainer { @@ -42,7 +43,7 @@ Device::Device() setupId(IDevice::AutoDetected, Id::generate()); setType(Constants::DEVCONTAINER_DEVICE_TYPE); setMachineType(IDevice::Hardware); - setFileAccessFactory([this]() { return m_fileAccess.get(); }); + setFileAccessFactory([this] { return m_fileAccess.get(); }); } Device::~Device() {} // Necessary for forward declared unique_ptr @@ -73,20 +74,19 @@ public: } }; - ProgressPromise(Tasking::TaskTree &tree, const QString title, Utils::Id id) + ProgressPromise(TaskTree &tree, const QString title, Id id) { Core::FutureProgress *futureProgress = Core::ProgressManager::addTask(future(), title, id); QObject::connect( - futureProgress, &Core::FutureProgress::canceled, &tree, &Tasking::TaskTree::cancel); - QObject::connect(&tree, &Tasking::TaskTree::destroyed, &tree, [this]() { delete this; }); + futureProgress, &Core::FutureProgress::canceled, &tree, &TaskTree::cancel); addSource(tree); start(); } - void addSource(Tasking::TaskTree &taskTree) + void addSource(TaskTree &taskTree) { - sources = [tt = QPointer<Tasking::TaskTree>(&taskTree), + sources = [tt = QPointer<TaskTree>(&taskTree), max = taskTree.progressMaximum(), lastSource = sources]() -> Progress { Progress last = lastSource(); @@ -95,7 +95,7 @@ public: return last + Progress{max, max}; }; update(); - QObject::connect(&taskTree, &Tasking::TaskTree::progressValueChanged, &taskTree, [this]() { + QObject::connect(&taskTree, &TaskTree::progressValueChanged, &taskTree, [this] { update(); }); } @@ -137,6 +137,20 @@ private: const FilePath m_workspaceFolderMountPoint; }; +using ProgressPtr = std::unique_ptr<ProgressPromise>; + +static auto setupProgress(const Storage<ProgressPtr> &progressStorage, const QString &title, Id id) +{ + return [progressStorage, title, id](TaskTree &taskTree) { + taskTree.onStorageSetup(progressStorage, [&taskTree, title, id](ProgressPtr &promise) { + promise.reset(new ProgressPromise(taskTree, title, id)); + }); + taskTree.onStorageDone(progressStorage, [](const ProgressPtr &promise) { + promise->finish(); + }); + }; +} + Result<> Device::up( const FilePath &path, InstanceConfig instanceConfig, std::function<void(Result<>)> callback) { @@ -146,24 +160,6 @@ Result<> Device::up( m_systemEnvironment.reset(); m_downRecipe.reset(); - using namespace Tasking; - - TaskTree *tree = new TaskTree(this); - ProgressPromise *progress - = new ProgressPromise(*tree, Tr::tr("Starting DevContainer"), "DevContainer.Startup"); - - connect(tree, &TaskTree::done, this, [progress, callback](DoneWith doneWith) { - progress->finish(); - if (doneWith == DoneWith::Error) { - callback(ResultError( - Tr::tr("Failed to start DevContainer, check General Messages for details"))); - } else { - callback(ResultOk); - } - }); - - connect(tree, &TaskTree::done, tree, &TaskTree::deleteLater); - struct Options { bool mountLibExec = true; @@ -174,8 +170,9 @@ Result<> Device::up( bool autoDetectKits = true; }; - Storage<std::shared_ptr<Instance>> instance; - Storage<Options> options; + const Storage<std::shared_ptr<Instance>> instance; + const Storage<Options> options; + const Storage<ProgressPtr> progressStorage; auto runningInstance = std::make_shared<DevContainer::RunningInstanceData>(); @@ -244,7 +241,7 @@ Result<> Device::up( return DoneResult::Success; }; - const auto setupProcessInterfaceCreator = [this, instance, runningInstance]() { + const auto setupProcessInterfaceCreator = [this, instance, runningInstance] { m_processInterfaceCreator = [inst = *instance, runningInstance] { return inst->createProcessInterface(runningInstance); }; @@ -293,15 +290,15 @@ Result<> Device::up( }; const auto startDeviceTree = - [instance, instanceConfig, runningInstance, progress](TaskTree &taskTree) -> SetupResult { - const Result<Tasking::Group> devcontainerRecipe = (*instance)->upRecipe(runningInstance); + [instance, instanceConfig, runningInstance, progressStorage](TaskTree &taskTree) -> SetupResult { + const Result<Group> devcontainerRecipe = (*instance)->upRecipe(runningInstance); if (!devcontainerRecipe) { instanceConfig.logFunction( Tr::tr("Failed to create DevContainer recipe: %1").arg(devcontainerRecipe.error())); return SetupResult::StopWithError; } taskTree.setRecipe(std::move(*devcontainerRecipe)); - progress->addSource(taskTree); + progressStorage->get()->addSource(taskTree); return SetupResult::Continue; }; @@ -349,7 +346,7 @@ Result<> Device::up( const auto factory = Utils::findOrDefault( KitAspectFactory::kitAspectFactories(), - Utils::equal(&KitAspectFactory::id, Utils::Id::fromString(it.key()))); + Utils::equal(&KitAspectFactory::id, Id::fromString(it.key()))); if (!factory) { instanceConfig.logFunction( @@ -382,8 +379,9 @@ Result<> Device::up( const auto autoDetectKitsEnabled = [options] { return options->autoDetectKits; }; // clang-format off - Group recipe { + const Group recipe { instance, options, + progressStorage, Sync(loadConfig), TaskTreeTask(startDeviceTree, onDeviceStarted), Sync(setupProcessInterfaceCreator), @@ -391,12 +389,18 @@ Result<> Device::up( TaskTreeTask(setupManualKits), If (autoDetectKitsEnabled) >> Then { kitDetectionRecipe(shared_from_this(), DetectionSource::Temporary, instanceConfig.logFunction) - }, + } }; // clang-format on - tree->setRecipe(recipe); - tree->start(); + const auto onDone = [callback](DoneWith doneWith) { + const Result<> result = (doneWith != DoneWith::Error) ? ResultOk + : ResultError(Tr::tr("Failed to start DevContainer, check General Messages for details")); + callback(result); + }; + + m_taskTreeRunner.start(recipe, setupProgress(progressStorage, Tr::tr("Starting DevContainer"), + "DevContainer.Startup"), onDone); return ResultOk; } @@ -409,28 +413,18 @@ Result<> Device::down() m_fileAccess.reset(); m_systemEnvironment.reset(); - using namespace Tasking; - - TaskTree *tree = new TaskTree(this); - ProgressPromise *progress - = new ProgressPromise(*tree, Tr::tr("Stopping DevContainer"), "DevContainer.Shutdown"); - - connect(tree, &TaskTree::done, this, [progress](DoneWith /*doneWith*/) { - progress->finish(); - }); - - connect(tree, &TaskTree::done, tree, &TaskTree::deleteLater); + const Storage<ProgressPtr> progressStorage; // clang-format off - Group recipe { + const Group recipe { + progressStorage, removeDetectedKitsRecipe(shared_from_this(), m_instanceConfig.logFunction), *m_downRecipe }; // clang-format on - tree->setRecipe(recipe); - tree->start(); - + m_taskTreeRunner.start(recipe, setupProgress(progressStorage, Tr::tr("Stopping DevContainer"), + "DevContainer.Shutdown")); return ResultOk; } diff --git a/src/plugins/devcontainer/devcontainerdevice.h b/src/plugins/devcontainer/devcontainerdevice.h index b974d75f83a..488fcad5f34 100644 --- a/src/plugins/devcontainer/devcontainerdevice.h +++ b/src/plugins/devcontainer/devcontainerdevice.h @@ -5,6 +5,8 @@ #include <devcontainer/devcontainer.h> +#include <solutions/tasking/tasktreerunner.h> + #include <utils/qtcprocess.h> namespace CmdBridge { @@ -45,6 +47,7 @@ private: std::unique_ptr<CmdBridge::FileAccess> m_fileAccess; std::optional<Utils::Environment> m_systemEnvironment; std::optional<Tasking::ExecutableItem> m_downRecipe; + Tasking::ParallelTaskTreeRunner m_taskTreeRunner; }; } // namespace DevContainer diff --git a/src/plugins/devcontainer/devcontainerplugin.cpp b/src/plugins/devcontainer/devcontainerplugin.cpp index b5e873b7164..5c8c01a2dd1 100644 --- a/src/plugins/devcontainer/devcontainerplugin.cpp +++ b/src/plugins/devcontainer/devcontainerplugin.cpp @@ -130,17 +130,18 @@ void DevContainerPlugin::onProjectAdded(Project *project) Tr::tr("Found devcontainers in project, would you like to start them?"), InfoBarEntry::GlobalSuppression::Enabled); + InfoBar *infoBar = Core::ICore::popupInfoBar(); entry.setTitle(Tr::tr("Configure devcontainer?")); entry.setInfoType(InfoLabel::Information); entry.addCustomButton( Tr::tr("Yes"), - [this, project, path, instanceConfig, infoBarId] { - Core::ICore::infoBar()->removeInfo(infoBarId); + [this, project, path, instanceConfig, infoBarId, infoBar] { + infoBar->removeInfo(infoBarId); startDeviceForProject(path, project, instanceConfig); }, Tr::tr("Start DevContainer")); - Core::ICore::infoBar()->addInfo(entry); + infoBar->addInfo(entry); }; } diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index 6a5c579a7c1..7ca8f6d5287 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -6,7 +6,6 @@ #include <utils/algorithm.h> #include <utils/differ.h> -#include <QFuture> #include <QPromise> #include <QRegularExpression> #include <QStringList> diff --git a/src/plugins/docker/dockerdevicewidget.cpp b/src/plugins/docker/dockerdevicewidget.cpp index d2ad5ee308c..4622e802c32 100644 --- a/src/plugins/docker/dockerdevicewidget.cpp +++ b/src/plugins/docker/dockerdevicewidget.cpp @@ -128,14 +128,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device) return; } - const FilePath clangdPath - = dockerDevice->filePath("clangd") - .searchInPath({}, FilePath::AppendToPath, [](const FilePath &clangd) { - return Utils::checkClangdVersion(clangd).has_value(); - }); - - if (!clangdPath.isEmpty()) - dockerDevice->setDeviceToolPath(CppEditor::Constants::CLANGD_TOOL_ID, clangdPath); + DeviceToolAspectFactory::autoDetectAll(dockerDevice, searchPaths()); const auto log = [logView](const QString &msg) { logView->append(msg); }; // clang-format off @@ -203,7 +196,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device) dockerDevice->keepEntryPoint, br, dockerDevice->enableLldbFlags, br, dockerDevice->mountCmdBridge, br, - dockerDevice->deviceToolAspects(), br, + dockerDevice->deviceToolAspects(DeviceToolAspect::AllTools), br, dockerDevice->network, br, dockerDevice->extraArgs, br, dockerDevice->environment, br, diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index b3ab6b9a3f8..580f52d368c 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -102,7 +102,7 @@ const char kRestartSetting[] = "RestartAfterPluginEnabledChanged"; static void requestRestart() { - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (infoBar->canInfoBeAdded(kRestartSetting)) { Utils::InfoBarEntry info(kRestartSetting, Core::Tr::tr("Plugin changes will take effect after restart.")); diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index ca4052529e6..690949fc82b 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -72,6 +72,7 @@ using PlainTextEdit = QPlainTextEdit; #else #include <utils/plaintextedit/plaintextedit.h> #endif +#include <utils/hostosinfo.h> //#define DEBUG_KEY 1 #if DEBUG_KEY @@ -112,12 +113,6 @@ namespace Internal { #define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit ? m_plaintextedit->s : m_qcPlainTextEdit->s) -#ifdef Q_OS_DARWIN -#define ControlModifier Qt::MetaModifier -#else -#define ControlModifier Qt::ControlModifier -#endif - /* Clipboard MIME types used by Vim. */ static const QString vimMimeText = "_VIM_TEXT"; static const QString vimMimeTextEncoded = "_VIMENC_TEXT"; @@ -934,12 +929,18 @@ static const QMap<QString, int> &vimKeyNames() static bool isOnlyControlModifier(const Qt::KeyboardModifiers &mods) { - return (mods ^ ControlModifier) == Qt::NoModifier; + return (mods ^ Utils::HostOsInfo::controlModifier()) == Qt::NoModifier; } static bool isAcceptableModifier(const Qt::KeyboardModifiers &mods) { - if (mods & ControlModifier) { + if (Utils::HostOsInfo::isMacHost() && (mods & Qt::ControlModifier)) { + // We want to have Cmd+S as save and not as 's' action + // See QTCREATORBUG-13392 + return false; + } + + if (mods & Utils::HostOsInfo::controlModifier()) { // Generally, CTRL is not fine, except in combination with ALT. // See QTCREATORBUG-24673 return mods & AltModifier; @@ -1044,7 +1045,7 @@ public: } // Set text only if input is ascii key without control modifier. - if (m_text.isEmpty() && k >= 0 && k <= 0x7f && (m & ControlModifier) == 0) { + if (m_text.isEmpty() && k >= 0 && k <= 0x7f && (m & Utils::HostOsInfo::controlModifier()) == 0) { QChar c = QChar(k); if (c.isLetter()) m_text = isShift() ? c.toUpper() : c; @@ -1214,7 +1215,7 @@ public: << quoteUnprintable(m_text); } - friend auto qHash(const Input &i) + friend size_t qHash(const Input &i) { return ::qHash(i.m_key); } @@ -1341,7 +1342,7 @@ static Input parseVimKeyName(const QString &keyName) if (key == "S") mods |= Qt::ShiftModifier; else if (key == "C") - mods |= ControlModifier; + mods |= Utils::HostOsInfo::controlModifier(); else return Input(); } diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 1a79429d6f2..b8f08e843f5 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -11,7 +11,7 @@ #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/fileutils.h> #include <coreplugin/iversioncontrol.h> -#include <coreplugin/progressmanager/progressmanager.h> +#include <coreplugin/progressmanager/taskprogress.h> #include <utils/async.h> #include <utils/environment.h> @@ -29,6 +29,8 @@ #include <QStringList> #include <QTimer> +using namespace Core; +using namespace Tasking; using namespace Utils; using namespace VcsBase; @@ -71,7 +73,7 @@ private: } }; -Result<CommitData> fetchCommitData(CommitType commitType, const FilePath &workingDirectory) +static Result<CommitData> fetchCommitData(CommitType commitType, const FilePath &workingDirectory) { return gitClient().getCommitData(commitType, workingDirectory); } @@ -89,10 +91,8 @@ GitSubmitEditor::GitSubmitEditor() : connect(submitEditorWidget(), &GitSubmitEditorWidget::logRequested, this, &GitSubmitEditor::showLog); connect(submitEditorWidget(), &GitSubmitEditorWidget::fileActionRequested, this, &GitSubmitEditor::performFileAction); - connect(versionControl(), &Core::IVersionControl::repositoryChanged, + connect(versionControl(), &IVersionControl::repositoryChanged, this, &GitSubmitEditor::forceUpdateFileModel); - connect(&m_fetchWatcher, &QFutureWatcher<Result<CommitData>>::finished, - this, &GitSubmitEditor::commitDataRetrieved); } GitSubmitEditor::~GitSubmitEditor() = default; @@ -109,7 +109,7 @@ const GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget() const void GitSubmitEditor::setCommitData(const CommitData &d) { - using IVCF = Core::IVersionControl::FileState; + using IVCF = IVersionControl::FileState; m_commitEncoding = d.commitEncoding; m_workingDirectory = d.panelInfo.repository; @@ -184,7 +184,7 @@ void GitSubmitEditor::slotDiffSelected(const QList<int> &rows) } stagedFiles.push_back(fileName); } else if (state == UntrackedFile) { - Core::EditorManager::openEditor(m_workingDirectory.pathAppended(fileName)); + EditorManager::openEditor(m_workingDirectory.pathAppended(fileName)); } else { unstagedFiles.push_back(fileName); } @@ -292,7 +292,7 @@ void GitSubmitEditor::performFileAction(const Utils::FilePath &filePath, FileAct break; case FileOpenEditor: - Core::EditorManager::openEditor(fullPath); + EditorManager::openEditor(fullPath); break; case FileStage: @@ -352,13 +352,36 @@ void GitSubmitEditor::updateFileModel() if (w->updateInProgress() || m_workingDirectory.isEmpty()) return; w->setUpdateInProgress(true); - // TODO: Check if fetch works OK from separate thread, refactor otherwise - m_fetchWatcher.setFuture(Utils::asyncRun(&fetchCommitData, - m_commitType, m_workingDirectory)); - Core::ProgressManager::addTask(m_fetchWatcher.future(), Tr::tr("Refreshing Commit Data"), - TASK_UPDATE_COMMIT); - Utils::futureSynchronizer()->addFuture(m_fetchWatcher.future()); + using ResultType = Result<CommitData>; + // TODO: Check if fetch works OK from separate thread, refactor otherwise + const auto onSetup = [this](Async<ResultType> &task) { + task.setConcurrentCallData(&fetchCommitData,m_commitType, + m_workingDirectory); + }; + const auto onDone = [this](const Async<ResultType> &task) { + const ResultType result = task.result(); + GitSubmitEditorWidget *w = submitEditorWidget(); + if (result) { + setCommitData(result.value()); + w->refreshLog(m_workingDirectory); + w->setEnabled(true); + } else { + // Nothing to commit left! + VcsOutputWindow::appendError(m_workingDirectory, result.error()); + m_model->clear(); + w->setEnabled(false); + } + w->setUpdateInProgress(false); + }; + const auto onTreeSetup = [](TaskTree &taskTree) { + auto progress = new TaskProgress(&taskTree); + progress->setDisplayName(Tr::tr("Refreshing Commit Data")); + progress->setId(TASK_UPDATE_COMMIT); + }; + m_taskTreeRunner.start( + {AsyncTask<ResultType>(onSetup, onDone, CallDone::OnSuccess)}, + onTreeSetup); } void GitSubmitEditor::forceUpdateFileModel() @@ -370,23 +393,6 @@ void GitSubmitEditor::forceUpdateFileModel() updateFileModel(); } -void GitSubmitEditor::commitDataRetrieved() -{ - const Result<CommitData> result = m_fetchWatcher.result(); - GitSubmitEditorWidget *w = submitEditorWidget(); - if (result) { - setCommitData(result.value()); - w->refreshLog(m_workingDirectory); - w->setEnabled(true); - } else { - // Nothing to commit left! - VcsOutputWindow::appendError(m_workingDirectory, result.error()); - m_model->clear(); - w->setEnabled(false); - } - w->setUpdateInProgress(false); -} - GitSubmitEditorPanelData GitSubmitEditor::panelData() const { return submitEditorWidget()->panelData(); diff --git a/src/plugins/git/gitsubmiteditor.h b/src/plugins/git/gitsubmiteditor.h index fac9d42fc12..5c49f6a953a 100644 --- a/src/plugins/git/gitsubmiteditor.h +++ b/src/plugins/git/gitsubmiteditor.h @@ -5,11 +5,12 @@ #include "commitdata.h" +#include <solutions/tasking/tasktreerunner.h> + #include <utils/filepath.h> #include <vcsbase/vcsbasesubmiteditor.h> -#include <QFutureWatcher> #include <QStringList> namespace VcsBase { class SubmitFileModel; } @@ -42,7 +43,6 @@ private: void showCommit(const QString &commit); void showLog(const QStringList &range); void performFileAction(const Utils::FilePath &filePath, FileAction action); - void commitDataRetrieved(); void addToGitignore(const Utils::FilePath &relativePath); inline GitSubmitEditorWidget *submitEditorWidget(); @@ -54,7 +54,7 @@ private: QString m_amenHash; Utils::FilePath m_workingDirectory; bool m_firstUpdate = true; - QFutureWatcher<Utils::Result<CommitData>> m_fetchWatcher; + Tasking::SingleTaskTreeRunner m_taskTreeRunner; }; } // Git::Internal diff --git a/src/plugins/help/helpwidget.cpp b/src/plugins/help/helpwidget.cpp index 08f6605d348..59fbc9e5464 100644 --- a/src/plugins/help/helpwidget.cpp +++ b/src/plugins/help/helpwidget.cpp @@ -414,20 +414,17 @@ HelpWidget::HelpWidget(const Core::Context &context, WidgetStyle style, QWidget if (QTC_GUARD(advancedMenu)) { // reuse TextEditor constants to avoid a second pair of menu actions m_scaleUp = new QAction(Tr::tr("Increase Font Size"), this); - cmd = Core::ActionManager::registerAction(m_scaleUp, TextEditor::Constants::INCREASE_FONT_SIZE, - context); + cmd = Core::ActionManager::registerAction(m_scaleUp, Core::Constants::ZOOM_IN, context); connect(m_scaleUp, &QAction::triggered, this, &HelpWidget::scaleUp); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); m_scaleDown = new QAction(Tr::tr("Decrease Font Size"), this); - cmd = Core::ActionManager::registerAction(m_scaleDown, TextEditor::Constants::DECREASE_FONT_SIZE, - context); + cmd = Core::ActionManager::registerAction(m_scaleDown, Core::Constants::ZOOM_OUT, context); connect(m_scaleDown, &QAction::triggered, this, &HelpWidget::scaleDown); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); m_resetScale = new QAction(Tr::tr("Reset Font Size"), this); - cmd = Core::ActionManager::registerAction(m_resetScale, TextEditor::Constants::RESET_FONT_SIZE, - context); + cmd = Core::ActionManager::registerAction(m_resetScale, Core::Constants::ZOOM_RESET, context); connect(m_resetScale, &QAction::triggered, this, &HelpWidget::resetScale); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); } @@ -544,11 +541,11 @@ HelpWidget::~HelpWidget() Core::ActionManager::unregisterAction(m_backAction, Constants::HELP_PREVIOUS); Core::ActionManager::unregisterAction(m_addBookmarkAction, Constants::HELP_ADDBOOKMARK); if (m_scaleUp) - Core::ActionManager::unregisterAction(m_scaleUp, TextEditor::Constants::INCREASE_FONT_SIZE); + Core::ActionManager::unregisterAction(m_scaleUp, Core::Constants::ZOOM_IN); if (m_scaleDown) - Core::ActionManager::unregisterAction(m_scaleDown, TextEditor::Constants::DECREASE_FONT_SIZE); + Core::ActionManager::unregisterAction(m_scaleDown, Core::Constants::ZOOM_OUT); if (m_resetScale) - Core::ActionManager::unregisterAction(m_resetScale, TextEditor::Constants::RESET_FONT_SIZE); + Core::ActionManager::unregisterAction(m_resetScale, Core::Constants::ZOOM_RESET); delete m_openPagesManager; } diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 2a56dd07eec..d5059cbc470 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -587,6 +587,15 @@ QWidget *BaseSettings::createSettingsWidget(QWidget *parent) const return new BaseSettingsWidget(this, parent); } +BaseSettings *BaseSettings::copy() const +{ + BaseSettings *other = create(); + Store store; + toMap(store); + other->fromMap(store); + return other; +} + bool BaseSettings::isValid() const { return !m_name.isEmpty(); diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index a13127e63f5..b753c7412b0 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -85,7 +85,8 @@ public: virtual bool applyFromSettingsWidget(QWidget *widget); virtual QWidget *createSettingsWidget(QWidget *parent = nullptr) const; - virtual BaseSettings *copy() const = 0; + virtual BaseSettings *copy() const; + virtual BaseSettings *create() const = 0; virtual bool isValid() const; virtual bool isValidOnBuildConfiguration(ProjectExplorer::BuildConfiguration *bc) const; Client *createClient() const; @@ -116,7 +117,7 @@ public: bool applyFromSettingsWidget(QWidget *widget) override; QWidget *createSettingsWidget(QWidget *parent = nullptr) const override; - BaseSettings *copy() const override { return new StdIOSettings(*this); } + BaseSettings *create() const override { return new StdIOSettings; } bool isValid() const override; void toMap(Utils::Store &map) const override; void fromMap(const Utils::Store &map) override; diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp index d3fa7633bf2..0b7f47ebf8e 100644 --- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp +++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp @@ -181,11 +181,8 @@ class LuaClientWrapper; class LuaClientSettings : public BaseSettings { - std::weak_ptr<LuaClientWrapper> m_wrapper; - QObject guard; - public: - LuaClientSettings(const LuaClientSettings &wrapper); + LuaClientSettings() {} LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrapper); ~LuaClientSettings() override = default; @@ -196,13 +193,19 @@ public: QWidget *createSettingsWidget(QWidget *parent = nullptr) const override; - BaseSettings *copy() const override { return new LuaClientSettings(*this); } + BaseSettings *create() const override { return new LuaClientSettings; } + BaseSettings *copy() const override; protected: Client *createClient(BaseClientInterface *interface) const final; BaseClientInterface *createInterface(ProjectExplorer::BuildConfiguration *bc) const override; + +private: + std::weak_ptr<LuaClientWrapper> m_wrapper; + QObject guard; }; + enum class TransportType { StdIO, LocalSocket }; class LuaClientWrapper : public QObject @@ -622,16 +625,19 @@ signals: void optionsChanged(); }; -LuaClientSettings::LuaClientSettings(const LuaClientSettings &other) - : BaseSettings::BaseSettings(other) - , m_wrapper(other.m_wrapper) +BaseSettings *LuaClientSettings::copy() const { - if (auto w = m_wrapper.lock()) { - QObject::connect(w.get(), &LuaClientWrapper::optionsChanged, &guard, [this] { - if (auto w = m_wrapper.lock()) - m_initializationOptions = w->m_initializationOptions; + auto other = static_cast<LuaClientSettings *>(BaseSettings::copy()); + + other->m_wrapper = m_wrapper; + if (auto w = other->m_wrapper.lock()) { + QObject::connect(w.get(), &LuaClientWrapper::optionsChanged, &other->guard, [other] { + if (auto w = other->m_wrapper.lock()) + other->m_initializationOptions = w->m_initializationOptions; }); } + + return other; } LuaClientSettings::LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrapper) diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index 0cb490b5562..086e3a5333c 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -507,7 +507,7 @@ static void askUserAboutMcuSupportKitsUpgrade(const SettingsHandler::Ptr &settin { const char upgradeMcuSupportKits[] = "UpgradeMcuSupportKits"; - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(upgradeMcuSupportKits)) return; diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 8f93b841d35..4fba92c896a 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -261,7 +261,7 @@ void McuSupportOptions::displayKitCreationMessages(const MessagesList messages, if (messages.isEmpty() || !qtMCUsPackage->isValidStatus()) return; static const char mcuKitCreationErrorInfoId[] = "ErrorWhileCreatingMCUKits"; - InfoBar *infoBar = Core::ICore::infoBar(); + InfoBar *infoBar = Core::ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(mcuKitCreationErrorInfoId)) return; diff --git a/src/plugins/mcusupport/mcusupportplugin.cpp b/src/plugins/mcusupport/mcusupportplugin.cpp index c40a2797e03..c3eaeb45783 100644 --- a/src/plugins/mcusupport/mcusupportplugin.cpp +++ b/src/plugins/mcusupport/mcusupportplugin.cpp @@ -123,7 +123,7 @@ static bool isQtMCUsProject(ProjectExplorer::Project *p) static void askUserAboutMcuSupportKitsSetup() { - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(setupMcuSupportKits) || dd->m_options.qulDirFromSettings().isEmpty() || !McuKitManager::existingKits(nullptr).isEmpty()) @@ -147,7 +147,7 @@ static void askUserAboutRemovingUninstalledTargetsKits() const char removeUninstalledKits[] = "RemoveUninstalledKits"; QList<Kit *> uninstalledTargetsKits; - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(removeUninstalledKits) || (uninstalledTargetsKits = McuKitManager::findUninstalledTargetsKits()).isEmpty()) return; @@ -243,7 +243,7 @@ void McuSupportPlugin::initialize() connect(ProjectManager::instance(), &ProjectManager::projectFinishedParsing, [&](ProjectExplorer::Project *p) { - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (!isQtMCUsProject(p) || !infoBar->canInfoBeAdded(qdsMcuDocInfoEntry)) return; Utils::InfoBarEntry docInfo( diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index c0e76267b62..e75dc0058ff 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -168,7 +168,7 @@ public: static Abi hostAbi(); static Abis abisOfBinary(const Utils::FilePath &path); - friend auto qHash(const ProjectExplorer::Abi &abi) + friend size_t qHash(const ProjectExplorer::Abi &abi) { int h = abi.architecture() + (abi.os() << 3) diff --git a/src/plugins/projectexplorer/buildtargetinfo.h b/src/plugins/projectexplorer/buildtargetinfo.h index c99dec64308..ab07b51d98a 100644 --- a/src/plugins/projectexplorer/buildtargetinfo.h +++ b/src/plugins/projectexplorer/buildtargetinfo.h @@ -53,7 +53,7 @@ public: return !(ti1 == ti2); } - friend auto qHash(const BuildTargetInfo &ti) + friend size_t qHash(const BuildTargetInfo &ti) { return qHash(ti.displayName) ^ qHash(ti.buildKey); } diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 31b6a89d54c..1e20a870484 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -10,6 +10,8 @@ #include <coreplugin/fileutils.h> +#include <solutions/tasking/tasktreerunner.h> + #include <utils/async.h> #include <utils/devicefileaccess.h> #include <utils/environment.h> @@ -30,15 +32,19 @@ #endif using namespace ProjectExplorer::Constants; +using namespace Tasking; using namespace Utils; namespace ProjectExplorer { -class DesktopDevicePrivate : public QObject -{}; +class DesktopDevicePrivate +{ +public: + SingleTaskTreeRunner taskTreeRunner; +}; DesktopDevice::DesktopDevice() - : d(new DesktopDevicePrivate()) + : d(new DesktopDevicePrivate) { setFileAccess(DesktopDeviceFileAccess::instance()); @@ -96,12 +102,13 @@ DesktopDevice::DesktopDevice() }; if (HostOsInfo::isWindowsHost()) { - QFutureWatcher<DeployToolsAvailability> *w = new QFutureWatcher<DeployToolsAvailability>(this); - connect(w, &QFutureWatcher<DeployToolsAvailability>::finished, this, [w, updateExtraData]() { - updateExtraData(w->result()); - w->deleteLater(); - }); - w->setFuture(Utils::asyncRun([]() { return hostDeployTools(); })); + const auto onSetup = [](Async<DeployToolsAvailability> &task) { + task.setConcurrentCallData(hostDeployTools); + }; + const auto onDone = [updateExtraData](const Async<DeployToolsAvailability> &task) { + updateExtraData(task.result()); + }; + d->taskTreeRunner.start({AsyncTask<DeployToolsAvailability>(onSetup, onDone)}); } else { updateExtraData(hostDeployTools()); } diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h index 0bc04d75f08..2830e608164 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h @@ -7,8 +7,6 @@ #include "idevice.h" -#include <QApplication> - #include <memory> namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.cpp index d658d1fa2a0..b97d88e3243 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.cpp @@ -13,10 +13,10 @@ #include <utils/icon.h> #include <utils/qtcassert.h> +#include <QApplication> #include <QStyle> -namespace ProjectExplorer { -namespace Internal { +namespace ProjectExplorer::Internal { DesktopDeviceFactory::DesktopDeviceFactory() : IDeviceFactory(Constants::DESKTOP_DEVICE_TYPE) @@ -29,5 +29,4 @@ DesktopDeviceFactory::DesktopDeviceFactory() : QApplication::style()->standardIcon(QStyle::SP_ComputerIcon)); } -} // namespace Internal -} // namespace ProjectExplorer +} // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 42d65f003fe..cddaf235a5e 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -5,6 +5,7 @@ #include "devicekitaspects.h" #include "devicemanager.h" +#include "idevice.h" #include "idevicefactory.h" #include "sshparameters.h" @@ -13,6 +14,7 @@ #include "../projectexplorertr.h" #include "../target.h" +#include <utils/algorithm.h> #include <utils/async.h> #include <utils/commandline.h> #include <utils/devicefileaccess.h> @@ -156,6 +158,24 @@ public: } // namespace Internal +// DeviceToolAspect + +DeviceToolAspect::ToolType DeviceToolAspect::toolType() const +{ + return m_toolType; +} + +void DeviceToolAspect::setToolType(ToolType toolType) +{ + m_toolType = toolType; +} + +void DeviceToolAspect::addToLayoutImpl(Layouting::Layout &parent) +{ + FilePathAspect::addToLayoutImpl(parent); + parent.flush(); +} + // DeviceToolFactory static QList<DeviceToolAspectFactory *> theDeviceToolFactories; @@ -183,21 +203,23 @@ void DeviceToolAspectFactory::autoDetectAll(const IDevicePtr &device, const File void DeviceToolAspectFactory::autoDetect(const IDevicePtr &device, const FilePaths &searchPaths) { - FilePaths toolPaths; + FilePaths result; - for (const QString &filePattern : m_filePattern) - toolPaths.append(device->filePath(filePattern).searchInDirectories(searchPaths)); - - // FIXME: Make all values available somehow. - for (const FilePath &toolPath : std::as_const(toolPaths)) { - if (!m_checker || m_checker(toolPath)) { - device->setDeviceToolPath(m_toolId, toolPath); - break; + for (const QString &filePattern : m_filePattern) { + const FilePaths toolPaths = device->filePath(filePattern).searchAllInDirectories(searchPaths); + for (const FilePath &toolPath : toolPaths) { + if (!m_checker || m_checker(device, toolPath)) + result.append(toolPath); } } + + device->setDeviceToolPathAlternatives(m_toolId, result); + + if (!result.isEmpty()) + device->setDeviceToolPath(m_toolId, result.front()); } -DeviceToolAspect *DeviceToolAspectFactory::createAspect() const +DeviceToolAspect *DeviceToolAspectFactory::createAspect(const IDevicePtr &device) const { auto toolAspect = new DeviceToolAspect; toolAspect->setSettingsKey(m_toolId.name()); @@ -206,17 +228,18 @@ DeviceToolAspect *DeviceToolAspectFactory::createAspect() const toolAspect->setPlaceHolderText(Tr::tr("Leave empty to look up executable in $PATH")); toolAspect->setHistoryCompleter(m_toolId.name()); toolAspect->setValidationFunction( - [checker = m_checker](const QString &newValue) -> FancyLineEdit::AsyncValidationFuture { - return asyncRun([checker, newValue]() -> Result<QString> { + [device, checker = m_checker](const QString &newValue) -> FancyLineEdit::AsyncValidationFuture { + return asyncRun([device, checker, newValue]() -> Result<QString> { if (!checker) return newValue; FilePath path = FilePath::fromUserInput(newValue); - Result<> result = checker(path); + Result<> result = checker(device, path); return result ? newValue : result.error(); }); }); toolAspect->setAllowPathFromDevice(true); toolAspect->setExpectedKind(PathChooser::ExistingCommand); + toolAspect->setToolType(m_toolType); return toolAspect; } @@ -250,6 +273,11 @@ void DeviceToolAspectFactory::setFilePattern(const QStringList &filePattern) m_filePattern = filePattern; } +void DeviceToolAspectFactory::setToolType(DeviceToolAspect::ToolType toolType) +{ + m_toolType = toolType; +} + // DeviceTester DeviceTester::DeviceTester(const IDevice::Ptr &device, QObject *parent) @@ -338,13 +366,6 @@ IDevice::IDevice() return newValue; }); - for (const DeviceToolAspectFactory *factory : theDeviceToolFactories) { - DeviceToolAspect *toolAspect = factory->createAspect(); - registerAspect(toolAspect, true); - toolAspect->setBaseDirectory([this] { return rootPath(); }); - d->deviceToolAspects.insert(factory->toolId(), toolAspect); - } - freePortsAspect.setSettingsKey(PortsSpecKey); freePortsAspect.setLabelText(Tr::tr("Free ports:")); freePortsAspect.setToolTip( @@ -354,6 +375,17 @@ IDevice::IDevice() IDevice::~IDevice() = default; +void IDevice::init() +{ + // shared_from_this doesn't work in the ctor. + for (const DeviceToolAspectFactory *factory : theDeviceToolFactories) { + DeviceToolAspect *toolAspect = factory->createAspect(shared_from_this()); + registerAspect(toolAspect, true); + toolAspect->setBaseDirectory([this] { return rootPath(); }); + d->deviceToolAspects.insert(factory->toolId(), toolAspect); + } +} + void IDevice::setOpenTerminal(const IDevice::OpenTerminal &openTerminal) { d->openTerminal = openTerminal; @@ -820,13 +852,6 @@ void IDevice::setMachineType(MachineType machineType) d->machineType = machineType; } -void IDevice::setDeviceToolPath(Id toolId, const FilePath &filePath) -{ - DeviceToolAspect *toolAspect = d->deviceToolAspects.value(toolId); - QTC_ASSERT(toolAspect, return); - toolAspect->setValue(filePath); -} - FilePath IDevice::deviceToolPath(Id toolId) const { DeviceToolAspect *toolAspect = d->deviceToolAspects.value(toolId); @@ -839,15 +864,25 @@ FilePath IDevice::deviceToolPath(Id toolId) const return filePath; } -QList<DeviceToolAspect *> IDevice::deviceToolAspects() const +void IDevice::setDeviceToolPath(Id toolId, const FilePath &filePath) { - return d->deviceToolAspects.values(); + DeviceToolAspect *toolAspect = d->deviceToolAspects.value(toolId); + QTC_ASSERT(toolAspect, return); + toolAspect->setValue(filePath); } -void DeviceToolAspect::addToLayoutImpl(Layouting::Layout &parent) +void IDevice::setDeviceToolPathAlternatives(Id toolId, const FilePaths &candidates) { - FilePathAspect::addToLayoutImpl(parent); - parent.flush(); + DeviceToolAspect *toolAspect = d->deviceToolAspects.value(toolId); + QTC_ASSERT(toolAspect, return); + toolAspect->setValueAlternatives(candidates); +} + +QList<DeviceToolAspect *> IDevice::deviceToolAspects(DeviceToolAspect::ToolType supportType) const +{ + return Utils::filtered(d->deviceToolAspects.values(), [supportType](DeviceToolAspect *aspect) { + return aspect->toolType() & supportType; + }); } FilePath IDevice::rootPath() const diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 9456ad36e70..4c56b8bd24e 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -57,9 +57,22 @@ class DeviceTester; class PROJECTEXPLORER_EXPORT DeviceToolAspect : public Utils::FilePathAspect { public: + enum ToolType { + RunTool = 1, // Tool used in connection with project running (on target device) + BuildTool = 2, // Tool used in connection with project building (on build device) + SourceTool = 4, // Tool used on project sources (typically, but not necessarily build device) + AllTools = RunTool | BuildTool | SourceTool + }; + using Utils::FilePathAspect::FilePathAspect; void addToLayoutImpl(Layouting::Layout &parent) override; + + ToolType toolType() const; + void setToolType(ToolType toolType); + +public: + ToolType m_toolType = AllTools; }; class PROJECTEXPLORER_EXPORT DeviceToolAspectFactory @@ -70,18 +83,19 @@ public: Utils::Id toolId() const; - DeviceToolAspect *createAspect() const; + DeviceToolAspect *createAspect(const IDevicePtr &device) const; static void autoDetectAll(const IDevicePtr &device, const Utils::FilePaths &searchPaths); protected: - using Checker = std::function<Utils::Result<>(const Utils::FilePath &)>; + using Checker = std::function<Utils::Result<>(const IDevicePtr &device, const Utils::FilePath &)>; void setToolId(const Utils::Id &toolId); void setFilePattern(const QStringList &filePattern); void setLabelText(const QString &labelText); void setToolTip(const QString &toolTip); void setVariablePrefix(const QByteArray &variablePrefix); void setChecker(const Checker &checker); + void setToolType(DeviceToolAspect::ToolType toolType); private: void autoDetect(const IDevicePtr &device, const Utils::FilePaths &searchPaths); @@ -92,6 +106,7 @@ private: QStringList m_filePattern; QByteArray m_variablePrefix; Checker m_checker; + DeviceToolAspect::ToolType m_toolType = DeviceToolAspect::AllTools; }; class PROJECTEXPLORER_EXPORT DeviceProcessSignalOperation : public QObject @@ -222,7 +237,8 @@ public: Utils::FilePath deviceToolPath(Utils::Id toolId) const; void setDeviceToolPath(Utils::Id toolId, const Utils::FilePath &filePath); - QList<DeviceToolAspect *> deviceToolAspects() const; + void setDeviceToolPathAlternatives(Utils::Id toolId, const Utils::FilePaths &candidates); + QList<DeviceToolAspect *> deviceToolAspects(DeviceToolAspect::ToolType supportType) const; void setExtraData(Utils::Id kind, const QVariant &data); QVariant extraData(Utils::Id kind) const; @@ -290,11 +306,14 @@ private: IDevice(const IDevice &) = delete; IDevice &operator=(const IDevice &) = delete; + void init(); + int version() const; void setFromSdk(); const std::unique_ptr<Internal::IDevicePrivate> d; friend class DeviceManager; + friend class IDeviceFactory; }; class PROJECTEXPLORER_EXPORT DeviceConstRef diff --git a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp index b095bf33792..ceb0a7b0ee5 100644 --- a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp @@ -80,6 +80,7 @@ IDevice::Ptr IDeviceFactory::construct() const IDevice::Ptr device = m_constructor(); QTC_ASSERT(device, return {}); device->setDisplayName(displayName()); + device->init(); return device; } diff --git a/src/plugins/projectexplorer/headerpath.h b/src/plugins/projectexplorer/headerpath.h index 130341db755..b093553d577 100644 --- a/src/plugins/projectexplorer/headerpath.h +++ b/src/plugins/projectexplorer/headerpath.h @@ -56,9 +56,9 @@ public: return {fp, HeaderPathType::Framework}; } - friend auto qHash(const HeaderPath &key, uint seed = 0) + friend size_t qHash(const HeaderPath &key, size_t seed = 0) { - return ((qHash(key.path) << 2) | uint(key.type)) ^ seed; + return ((qHash(key.path) << 2) | size_t(key.type)) ^ seed; } Utils::FilePath path; diff --git a/src/plugins/projectexplorer/projectimporter.h b/src/plugins/projectexplorer/projectimporter.h index 540283a579f..487729569dc 100644 --- a/src/plugins/projectexplorer/projectimporter.h +++ b/src/plugins/projectexplorer/projectimporter.h @@ -46,9 +46,6 @@ public: void addProject(Kit *k) const; void removeProject(Kit *k) const; -signals: - void cmakePresetsUpdated(); - protected: class UpdateGuard { diff --git a/src/plugins/projectexplorer/projectmacro.h b/src/plugins/projectexplorer/projectmacro.h index 7083d1ad123..d18cc2cc666 100644 --- a/src/plugins/projectexplorer/projectmacro.h +++ b/src/plugins/projectexplorer/projectmacro.h @@ -46,7 +46,7 @@ public: static Macro fromKeyValue(const QByteArray &text); QByteArray toKeyValue(const QByteArray &prefix) const; - friend auto qHash(const Macro ¯o) + friend size_t qHash(const Macro ¯o) { using QT_PREPEND_NAMESPACE(qHash); return qHash(macro.key) ^ qHash(macro.value) ^ qHash(int(macro.type)); diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index a5e54bb44c3..8579a701af8 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -817,6 +817,17 @@ public: { m_kitWarningForProject = containsType(m_kitIssues, Task::TaskType::Warning); m_kitErrorsForProject = containsType(m_kitIssues, Task::TaskType::Error); + + QObject::connect( + project, + &ProjectExplorer::Project::removedTarget, + [this, t = target()](ProjectExplorer::Target *rt) { + if (t == rt) { + m_buildSettingsWidget.clear(); + m_deploySettingsWidget.clear(); + m_runSettingsWidget.clear(); + } + }); } ~TargetItem() diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index ded74be8ffc..540f6cc8606 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -250,22 +250,9 @@ void TargetSetupPage::setProjectImporter(ProjectImporter *importer) if (d->widgetsWereSetUp) d->reset(); // Reset before changing the importer! - if (d->importer) { - disconnect(d->importer, &ProjectImporter::cmakePresetsUpdated, - this, &TargetSetupPage::initializePage); - } - - d->importer = importer; d->importWidget->setVisible(d->importer); - if (d->importer) { - // FIXME: Needed for the refresh of CMake preset kits created by - // CMakeProjectImporter - connect(d->importer, &ProjectImporter::cmakePresetsUpdated, - this, &TargetSetupPage::initializePage); - } - if (d->widgetsWereSetUp) initializePage(); } diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index 65b84eefb0d..a0340dced8a 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -189,7 +189,7 @@ std::optional<SettingsAccessor::Issue> UserFileAccessor::writeFile( const FilePath userFileV1 = projectUserFileV1(); const FilePath userFileV2 = projectUserFileV2(); - if (path == userFileV2 && userFileV1.exists()) { + if (userFileV1 != userFileV2 && path == userFileV2 && userFileV1.exists()) { userFileV1.removeFile(); userFileV2.copyFile(userFileV1); } @@ -265,6 +265,12 @@ FilePath UserFileAccessor::projectUserFileV1() const FilePath UserFileAccessor::projectUserFileV2() const { const FilePath projectFile = m_project->projectFilePath(); + + // Don't nest the hidden subdirs; e.g. WorkspaceProject already puts its project file + // in there. + if (projectFile.parentDir().fileName() == ".qtcreator") + return projectUserFileV1(); + return projectFile.parentDir() .pathAppended(".qtcreator") .pathAppended(projectFile.fileName()) diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index 7e464fc6591..d96122e146a 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -68,6 +68,7 @@ public: QbsToolFactory() { setToolId(Constants::QBS_TOOL_ID); + setToolType(DeviceToolAspect::BuildTool); setFilePattern({"qbs"}); setLabelText(Tr::tr("Qbs executable:")); } diff --git a/src/plugins/qmldesigner/libs/designercore/include/abstractproperty.h b/src/plugins/qmldesigner/libs/designercore/include/abstractproperty.h index a94cd3a635f..cbc8df94a9e 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/abstractproperty.h +++ b/src/plugins/qmldesigner/libs/designercore/include/abstractproperty.h @@ -106,7 +106,7 @@ public: Model *model() const; AbstractView *view() const; - friend auto qHash(const AbstractProperty &property) + friend size_t qHash(const AbstractProperty &property) { return ::qHash(property.m_internalNode.get()) ^ ::qHash(property.m_propertyName); } diff --git a/src/plugins/qmldesigner/libs/designercore/include/modelnode.h b/src/plugins/qmldesigner/libs/designercore/include/modelnode.h index 1f894e976b5..a01bac3f442 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/modelnode.h +++ b/src/plugins/qmldesigner/libs/designercore/include/modelnode.h @@ -262,7 +262,7 @@ public: swap(first.m_view, second.m_view); } - friend auto qHash(const ModelNode &node) { return ::qHash(node.m_internalNode.get()); } + friend size_t qHash(const ModelNode &node) { return ::qHash(node.m_internalNode.get()); } friend bool operator==(const ModelNode &firstNode, const ModelNode &secondNode) { diff --git a/src/plugins/qmldesigner/libs/designercore/include/nodeabstractproperty.h b/src/plugins/qmldesigner/libs/designercore/include/nodeabstractproperty.h index 1790810f8b9..4c7e6c3a7dd 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/nodeabstractproperty.h +++ b/src/plugins/qmldesigner/libs/designercore/include/nodeabstractproperty.h @@ -33,7 +33,7 @@ public: QList<ModelNode> allSubNodes(); QList<ModelNode> directSubNodes() const; - friend auto qHash(const NodeAbstractProperty &property) { qHash(AbstractProperty(property)); } + friend size_t qHash(const NodeAbstractProperty &property) { return qHash(AbstractProperty(property)); } NodeAbstractProperty(PropertyNameView propertyName, const Internal::InternalNodePointer &internalNode, diff --git a/src/plugins/qmldesigner/qmltools/qml3dnode.h b/src/plugins/qmldesigner/qmltools/qml3dnode.h index df367a7098f..853e5781691 100644 --- a/src/plugins/qmldesigner/qmltools/qml3dnode.h +++ b/src/plugins/qmldesigner/qmltools/qml3dnode.h @@ -33,7 +33,7 @@ public: bool handleEulerRotation(PropertyNameView name); bool isBlocked(PropertyNameView propName) const; - friend auto qHash(const Qml3DNode &node) { return qHash(node.modelNode()); } + friend size_t qHash(const Qml3DNode &node) { return qHash(node.modelNode()); } private: void handleEulerRotationSet(); diff --git a/src/plugins/qmldesigner/qmltools/qmlitemnode.h b/src/plugins/qmldesigner/qmltools/qmlitemnode.h index f19a89902f0..9030bfe379d 100644 --- a/src/plugins/qmldesigner/qmltools/qmlitemnode.h +++ b/src/plugins/qmldesigner/qmltools/qmlitemnode.h @@ -143,7 +143,7 @@ public: bool isEffectItem() const; - friend auto qHash(const QmlItemNode &node) { return qHash(node.modelNode()); } + friend size_t qHash(const QmlItemNode &node) { return qHash(node.modelNode()); } }; class QmlFlowItemNode; diff --git a/src/plugins/qmldesigner/qmltools/qmlobjectnode.h b/src/plugins/qmldesigner/qmltools/qmlobjectnode.h index 8773591add9..c11d78f097b 100644 --- a/src/plugins/qmldesigner/qmltools/qmlobjectnode.h +++ b/src/plugins/qmldesigner/qmltools/qmlobjectnode.h @@ -113,7 +113,7 @@ public: QStringList allStateNames() const; - friend auto qHash(const QmlObjectNode &node) { return qHash(node.modelNode()); } + friend size_t qHash(const QmlObjectNode &node) { return qHash(node.modelNode()); } QList<QmlModelState> allDefinedStates() const; QList<QmlModelStateOperation> allInvalidStateOperations() const; diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp index 60fc563295a..f2b2f82bca6 100644 --- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp +++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp @@ -19,6 +19,7 @@ #include <qmljs/qmljsrewriter.h> #include <qmljstools/qmljsrefactoringchanges.h> #include <projectexplorer/project.h> +#include <projectexplorer/projectmanager.h> #include <projectexplorer/projectnodes.h> #include <projectexplorer/projecttree.h> @@ -171,12 +172,22 @@ public: if (path.toUrlishString() == currentFileName.toFileInfo().path()) { // hack for the common case, next version should use the wizard - ProjectExplorer::Node *oldFileNode = ProjectExplorer::ProjectTree::nodeForFile( - currentFileName); - if (oldFileNode) { - ProjectExplorer::FolderNode *containingFolder = oldFileNode->parentFolderNode(); - if (containingFolder) - containingFolder->addFiles({newFileName}); + using namespace ProjectExplorer; + bool fileAdded = false; + if (Project *const project = ProjectManager::projectForFile(currentFileName)) { + if (ProjectNode *const product = project->productNodeForFilePath(currentFileName)) { + if (product->addFiles({newFileName})) + fileAdded = true; + } + } + if (!fileAdded) { + ProjectExplorer::Node *oldFileNode = ProjectExplorer::ProjectTree::nodeForFile( + currentFileName); + if (oldFileNode) { + ProjectExplorer::FolderNode *containingFolder = oldFileNode->parentFolderNode(); + if (containingFolder) + containingFolder->addFiles({newFileName}); + } } } diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index ba786543011..52987435c37 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -7,6 +7,7 @@ #include "qmllsclient.h" #include <utils/mimeconstants.h> +#include <utils/qtcsettings.h> #include <coreplugin/messagemanager.h> @@ -20,12 +21,14 @@ #include <projectexplorer/projectmanager.h> #include <projectexplorer/target.h> -#include <QtWidgets/qcheckbox.h> #include <qmljs/qmljsmodelmanagerinterface.h> #include <qtsupport/qtkitaspect.h> #include <qtsupport/qtversionmanager.h> +#include <QCheckBox> +#include <QRadioButton> + using namespace LanguageClient; using namespace QtSupport; using namespace Utils; @@ -34,10 +37,12 @@ using namespace ProjectExplorer; namespace QmlJSEditor { constexpr char useLatestQmllsKey[] = "useLatestQmlls"; +constexpr char executableSelectionKey[] = "executableSelection"; constexpr char disableBuiltinCodemodelKey[] = "disableBuiltinCodemodel"; constexpr char generateQmllsIniFilesKey[] = "generateQmllsIniFiles"; constexpr char ignoreMinimumQmllsVersionKey[] = "ignoreMinimumQmllsVersion"; constexpr char useQmllsSemanticHighlightingKey[] = "enableQmllsSemanticHighlighting"; +constexpr char executableKey[] = "executable"; QmllsClientSettings *qmllsSettings() { @@ -102,14 +107,77 @@ static std::pair<FilePath, QVersionNumber> evaluateLatestQmlls() return std::make_pair(latestQmlls, latestVersion); } +static QVersionNumber mapStandaloneVersions(const QVersionNumber &standaloneVersion) +{ + // standalone qmlls 0.2 supports the same command line arguments as qmlls 6.10 + if (standaloneVersion >= QVersionNumber(0, 2)) { + return QVersionNumber(6, 10); + } + // fallback + return QVersionNumber(6, 9); +} + +static std::pair<FilePath, QVersionNumber> evaluateOverridenQmlls() +{ + if (!qmllsSettings()->m_executable.exists()) { + Core::MessageManager::writeFlashing( + Tr::tr("Custom qmlls executable \"%1\" does not exist and was disabled.") + .arg(qmllsSettings()->m_executable.path())); + return {}; + } + Process qmlls; + qmlls.setCommand({qmllsSettings()->m_executable, {"--version"}}); + qmlls.start(); + qmlls.waitForFinished(); + if (qmlls.exitStatus() != QProcess::NormalExit || qmlls.exitCode() != EXIT_SUCCESS) { + Core::MessageManager::writeFlashing( + Tr::tr( + "Custom qmlls executable \"%1\" exited abnormally and was disabled. Note that " + "qmlls versions < 6.10 are not supported this way. The custom executable output " + "was:\n %2") + .arg(qmllsSettings()->m_executable.path(), qmlls.readAllStandardError())); + return {}; + } + + const QString output = qmlls.readAllStandardOutput(); + + if (!output.contains("qmlls")) { + Core::MessageManager::writeFlashing( + Tr::tr( + "Custom qmlls executable \"%1\" does not seem to be a qmlls executable and was " + "disabled") + .arg(qmllsSettings()->m_executable.path())); + return {}; + } + + const bool isStandaloneQmlls = output.contains("(standalone)"); + const int versionBegin = isStandaloneQmlls + ? std::char_traits<char>::length("qmlls (standalone) ") + : std::char_traits<char>::length("qmlls "); + + std::pair<FilePath, QVersionNumber> result{ + qmllsSettings()->m_executable, + QVersionNumber::fromString(QStringView(output).sliced(versionBegin)), + }; + if (isStandaloneQmlls) + result.second = mapStandaloneVersions(result.second); + return result; +} + static std::pair<FilePath, QVersionNumber> evaluateQmlls(const QtVersion *qtVersion) { - return qmllsSettings()->m_useLatestQmlls - ? evaluateLatestQmlls() - : std::make_pair( - QmlJS::ModelManagerInterface::qmllsForBinPath( - qtVersion->hostBinPath(), qtVersion->qtVersion()), - qtVersion->qtVersion()); + switch (qmllsSettings()->m_executableSelection) { + case QmllsClientSettings::FromQtKit: + return std::make_pair( + QmlJS::ModelManagerInterface::qmllsForBinPath( + qtVersion->hostBinPath(), qtVersion->qtVersion()), + qtVersion->qtVersion()); + case QmllsClientSettings::FromLatestQtKit: + return evaluateLatestQmlls(); + case QmllsClientSettings::FromUser: + return evaluateOverridenQmlls(); + } + Q_UNREACHABLE_RETURN({}); } static CommandLine commandLineForQmlls(BuildConfiguration *bc) @@ -209,13 +277,21 @@ public: bool generateQmllsIniFiles() const; bool ignoreMinimumQmllsVersion() const; bool useQmllsSemanticHighlighting() const; + bool overrideExecutable() const; + Utils::FilePath executable() const; + QmllsClientSettings::ExecutableSelection executableSelection() const; private: - QCheckBox *m_useLatestQmlls; QCheckBox *m_disableBuiltinCodemodel; QCheckBox *m_generateQmllsIniFiles; QCheckBox *m_ignoreMinimumQmllsVersion; QCheckBox *m_useQmllsSemanticHighlighting; + + QRadioButton *m_useDefaultQmlls; + QRadioButton *m_useLatestQmlls; + QRadioButton *m_overrideExecutable; + + Utils::PathChooser *m_executable; }; QWidget *QmllsClientSettings::createSettingsWidget(QWidget *parent) const @@ -223,6 +299,18 @@ QWidget *QmllsClientSettings::createSettingsWidget(QWidget *parent) const return new QmllsClientSettingsWidget(this, parent); } +QmllsClientSettings::ExecutableSelection QmllsClientSettingsWidget::executableSelection() const +{ + if (m_useDefaultQmlls->isChecked()) + return QmllsClientSettings::FromQtKit; + if (m_useLatestQmlls->isChecked()) + return QmllsClientSettings::FromLatestQtKit; + if (m_overrideExecutable->isChecked()) + return QmllsClientSettings::FromUser; + + QTC_ASSERT(false, return QmllsClientSettings::FromQtKit); +} + bool QmllsClientSettings::applyFromSettingsWidget(QWidget *widget) { bool changed = BaseSettings::applyFromSettingsWidget(widget); @@ -231,8 +319,8 @@ bool QmllsClientSettings::applyFromSettingsWidget(QWidget *widget) if (!qmllsWidget) return changed; - if (m_useLatestQmlls != qmllsWidget->useLatestQmlls()) { - m_useLatestQmlls = qmllsWidget->useLatestQmlls(); + if (m_executableSelection != qmllsWidget->executableSelection()) { + m_executableSelection = qmllsWidget->executableSelection(); changed = true; } @@ -256,6 +344,11 @@ bool QmllsClientSettings::applyFromSettingsWidget(QWidget *widget) changed = true; } + if (m_executable != qmllsWidget->executable()) { + m_executable = qmllsWidget->executable(); + changed = true; + } + return changed; } @@ -263,11 +356,12 @@ void QmllsClientSettings::toMap(Store &map) const { BaseSettings::toMap(map); - map.insert(useLatestQmllsKey, m_useLatestQmlls); + map.insert(executableSelectionKey, static_cast<int>(m_executableSelection)); map.insert(disableBuiltinCodemodelKey, m_disableBuiltinCodemodel); map.insert(generateQmllsIniFilesKey, m_generateQmllsIniFiles); map.insert(ignoreMinimumQmllsVersionKey, m_ignoreMinimumQmllsVersion); map.insert(useQmllsSemanticHighlightingKey, m_useQmllsSemanticHighlighting); + map.insert(executableKey, m_executable.toSettings()); } void QmllsClientSettings::fromMap(const Store &map) @@ -275,11 +369,20 @@ void QmllsClientSettings::fromMap(const Store &map) BaseSettings::fromMap(map); m_languageFilter.mimeTypes = supportedMimeTypes(); - m_useLatestQmlls = map[useLatestQmllsKey].toBool(); + // port from previous settings + if (map.contains(useLatestQmllsKey)) + m_executableSelection = map[useLatestQmllsKey].toBool() ? FromLatestQtKit : FromQtKit; + + // don't overwrite ported settings if the new key is not in use yet. + if (map.contains(executableSelectionKey)) + m_executableSelection = static_cast<ExecutableSelection>( + map[executableSelectionKey].toInt()); + m_disableBuiltinCodemodel = map[disableBuiltinCodemodelKey].toBool(); m_generateQmllsIniFiles = map[generateQmllsIniFilesKey].toBool(); m_ignoreMinimumQmllsVersion = map[ignoreMinimumQmllsVersionKey].toBool(); m_useQmllsSemanticHighlighting = map[useQmllsSemanticHighlightingKey].toBool(); + m_executable = Utils::FilePath::fromSettings(map[executableKey]); } bool QmllsClientSettings::isEnabledOnProjectFile(const Utils::FilePath &file) const @@ -319,7 +422,8 @@ static void portFromOldSettings(QmllsClientSettings* qmllsClientSettings) = "QmlJSEditor.EnableQmllsSemanticHighlighting"; portSetting(baseKey + USE_QMLLS, &qmllsClientSettings->m_enabled); - portSetting(baseKey + USE_LATEST_QMLLS, &qmllsClientSettings->m_useLatestQmlls); + if (settings->contains(baseKey + USE_LATEST_QMLLS)) + qmllsClientSettings->m_executableSelection = QmllsClientSettings::FromLatestQtKit; portSetting(baseKey + DISABLE_BUILTIN_CODEMODEL, &qmllsClientSettings->m_disableBuiltinCodemodel); portSetting(baseKey + GENERATE_QMLLS_INI_FILES, &qmllsClientSettings->m_generateQmllsIniFiles); portSetting(baseKey + IGNORE_MINIMUM_QMLLS_VERSION, &qmllsClientSettings->m_ignoreMinimumQmllsVersion); @@ -350,7 +454,6 @@ void setupQmllsClient() QmllsClientSettingsWidget::QmllsClientSettingsWidget( const QmllsClientSettings *settings, QWidget *parent) : QWidget(parent) - , m_useLatestQmlls(new QCheckBox(Tr::tr("Use from latest Qt version"), this)) , m_disableBuiltinCodemodel(new QCheckBox( Tr::tr("Use advanced features (renaming, find usages, and so on) (experimental)"), this)) , m_generateQmllsIniFiles( @@ -361,21 +464,53 @@ QmllsClientSettingsWidget::QmllsClientSettingsWidget( this)) , m_useQmllsSemanticHighlighting( new QCheckBox(Tr::tr("Enable semantic highlighting (experimental)"), this)) + , m_useDefaultQmlls(new QRadioButton(Tr::tr("Use qmlls from project Qt kit"), this)) + , m_useLatestQmlls(new QRadioButton( + Tr::tr("Use qmlls from latest Qt kit (located at %1)") + .arg(evaluateLatestQmlls().first.path()), + this)) + , m_overrideExecutable(new QRadioButton(Tr::tr("Use custom qmlls executable:"), this)) + , m_executable(new Utils::PathChooser(this)) { - m_useLatestQmlls->setChecked(settings->m_useLatestQmlls); + m_useDefaultQmlls->setChecked(settings->m_executableSelection == QmllsClientSettings::FromQtKit); + m_useLatestQmlls->setChecked( + settings->m_executableSelection == QmllsClientSettings::FromLatestQtKit); + m_overrideExecutable->setChecked( + settings->m_executableSelection == QmllsClientSettings::FromUser); + m_disableBuiltinCodemodel->setChecked(settings->m_disableBuiltinCodemodel); m_generateQmllsIniFiles->setChecked(settings->m_generateQmllsIniFiles); m_ignoreMinimumQmllsVersion->setChecked(settings->m_ignoreMinimumQmllsVersion); m_useQmllsSemanticHighlighting->setChecked(settings->m_useQmllsSemanticHighlighting); + QObject::connect(m_overrideExecutable, &QCheckBox::toggled, m_executable, [this](bool checked) { + m_executable->setEnabled(checked); + }); + + m_executable->setFilePath(settings->m_executable); + m_executable->setExpectedKind(Utils::PathChooser::File); + m_executable->setEnabled(m_overrideExecutable->isChecked()); + using namespace Layouting; // clang-format off - auto form = Form { - m_ignoreMinimumQmllsVersion, br, - m_disableBuiltinCodemodel, br, - m_useQmllsSemanticHighlighting, br, - m_useLatestQmlls, br, - m_generateQmllsIniFiles, br, + auto form = Column { + Group { + title(Tr::tr("Options")), + Form { + m_ignoreMinimumQmllsVersion, br, + m_disableBuiltinCodemodel, br, + m_useQmllsSemanticHighlighting, br, + m_generateQmllsIniFiles, br, + } + }, + Group { + title(Tr::tr("Executable selection for qmlls")), + Column { + Row { m_useDefaultQmlls }, + Row { m_useLatestQmlls }, + Row { m_overrideExecutable, m_executable }, + } + }, }; // clang-format on @@ -402,6 +537,16 @@ bool QmllsClientSettingsWidget::useQmllsSemanticHighlighting() const return m_useQmllsSemanticHighlighting->isChecked(); } +bool QmllsClientSettingsWidget::overrideExecutable() const +{ + return m_overrideExecutable->isChecked(); +} + +Utils::FilePath QmllsClientSettingsWidget::executable() const +{ + return m_executable->filePath(); +} + } // namespace QmlJSEditor #include "qmllsclientsettings.moc" diff --git a/src/plugins/qmljseditor/qmllsclientsettings.h b/src/plugins/qmljseditor/qmllsclientsettings.h index 79b0a23b73e..267dba407c6 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.h +++ b/src/plugins/qmljseditor/qmllsclientsettings.h @@ -13,10 +13,11 @@ namespace QmlJSEditor { class QmllsClientSettings : public LanguageClient::BaseSettings { public: + enum ExecutableSelection { FromQtKit, FromLatestQtKit, FromUser }; static const inline QVersionNumber mininumQmllsVersion = QVersionNumber(6, 8); QmllsClientSettings(); - BaseSettings *copy() const override { return new QmllsClientSettings(*this); } + BaseSettings *create() const override { return new QmllsClientSettings; } QWidget *createSettingsWidget(QWidget *parent = nullptr) const override; bool applyFromSettingsWidget(QWidget *widget) override; @@ -31,11 +32,13 @@ public: bool useQmllsWithBuiltinCodemodelOnProject(ProjectExplorer::Project *project, const Utils::FilePath &file) const; + ExecutableSelection m_executableSelection = FromQtKit; bool m_useLatestQmlls = false; bool m_ignoreMinimumQmllsVersion = false; bool m_useQmllsSemanticHighlighting = false; bool m_disableBuiltinCodemodel = false; bool m_generateQmllsIniFiles = false; + Utils::FilePath m_executable = {}; protected: LanguageClient::BaseClientInterface *createInterface( diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp index d22101ca73f..5c23cbc6224 100644 --- a/src/plugins/qmljstools/qmljstoolsplugin.cpp +++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp @@ -36,6 +36,7 @@ public: QmlRuntimeToolFactory() { setToolId(Constants::QML_TOOL_ID); + setToolType(DeviceToolAspect::RunTool); setFilePattern({"qml"}); setLabelText(Tr::tr("QML runtime executable:")); setToolTip(Tr::tr("The QML runtime executable to use on the device.")); diff --git a/src/plugins/qmlprofiler/qmleventlocation.h b/src/plugins/qmlprofiler/qmleventlocation.h index b8922ce3949..8763a0db805 100644 --- a/src/plugins/qmlprofiler/qmleventlocation.h +++ b/src/plugins/qmlprofiler/qmleventlocation.h @@ -45,7 +45,7 @@ public: return !(location1 == location2); } - friend auto qHash(const QmlEventLocation &location) + friend size_t qHash(const QmlEventLocation &location) { return qHash(location.filename()) ^ ((location.line() & 0xfff) // 12 bits of line number diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index c73c73f079f..93a6cbdc591 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -16,7 +16,7 @@ namespace QmlProfiler { -inline auto qHash(const QmlEventType &type) +inline size_t qHash(const QmlEventType &type) { return qHash(type.location()) ^ qHash(type.data()) ^ (((type.message() << 12) & 0xf000) // 4 bits of message diff --git a/src/plugins/qnx/qnxconstants.h b/src/plugins/qnx/qnxconstants.h index 3b8bdd26996..dd6cbe7a8f1 100644 --- a/src/plugins/qnx/qnxconstants.h +++ b/src/plugins/qnx/qnxconstants.h @@ -15,6 +15,8 @@ const char QNX_QNX_OS_TYPE[] = "QnxOsType"; // Also used for device type. const char QNX_TOOLCHAIN_ID[] = "Qnx.QccToolChain"; const char QNX_TMP_DIR[] = "/tmp"; // /var/run is root:root drwxr-xr-x -const char QNX_DIRECT_UPLOAD_STEP_ID[] ="Qnx.DirectUploadStep"; +const char QNX_DIRECT_UPLOAD_STEP_ID[] = "Qnx.DirectUploadStep"; + +const char QNX_SDPENVFILE_TOOL_ID[] = "Qnx.SdpEnvFileTool"; } // Qnx::Constants diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index 82f40c8ba06..2f396d5ec7b 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -23,6 +23,7 @@ #include <projectexplorer/buildstep.h> #include <projectexplorer/deployconfiguration.h> #include <projectexplorer/devicesupport/devicekitaspects.h> +#include <projectexplorer/devicesupport/idevice.h> #include <projectexplorer/kitmanager.h> #include <projectexplorer/project.h> #include <projectexplorer/projectexplorerconstants.h> @@ -35,13 +36,14 @@ using namespace Core; using namespace ProjectExplorer; +using namespace Utils; namespace Qnx::Internal { class QnxDeployStepFactory : public BuildStepFactory { public: - QnxDeployStepFactory(Utils::Id existingStepId, Utils::Id overrideId = {}) + QnxDeployStepFactory(Id existingStepId, Id overrideId = {}) { cloneStepCreator(existingStepId, overrideId); setSupportedConfiguration(Constants::QNX_QNX_DEPLOYCONFIGURATION_ID); @@ -77,6 +79,32 @@ void setupQnxDeployment() static QnxDeployStepFactory makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId}; } +class QnxSdpEnvFileToolAspectFactory : public DeviceToolAspectFactory +{ +public: + QnxSdpEnvFileToolAspectFactory() + { + setToolId(Constants::QNX_SDPENVFILE_TOOL_ID); + setToolType(DeviceToolAspect::BuildTool); + setFilePattern({"/opt/qnx710/qnxsdp-env.sh", "/opt/qnx710/qnxsdp-env.bat", + "/opt/qnx800/qnxsdp-env.sh", "/opt/qnx800/qnxsdp-env.bat"}); + setLabelText(Tr::tr("QNX sdpenv.sh:")); + setToolTip(Tr::tr("QNX Software Development Platform environment file.")); + setChecker([](const IDevicePtr &device, const FilePath &candidate) -> Result<> { + if (device->osType() == OsTypeWindows && candidate.suffix() == "bat") + return ResultOk; + if (device->osType() != OsTypeWindows && candidate.suffix() == "sh") + return ResultOk; + return ResultError(Tr::tr("File suffix does not match OS type.")); + }); + } +}; + +void setupQnxSdpEnvFileToolAspect() +{ + static QnxSdpEnvFileToolAspectFactory theQnxSdpEnvFileToolAspectFactory; +} + class QnxPlugin final : public ExtensionSystem::IPlugin { Q_OBJECT @@ -91,6 +119,7 @@ class QnxPlugin final : public ExtensionSystem::IPlugin setupQnxRunnning(); setupQnxDebugging(); setupQnxQmlProfiler(); + setupQnxSdpEnvFileToolAspect(); setupQnxSettingsPage(this); } diff --git a/src/plugins/qtsupport/qtsupportconstants.h b/src/plugins/qtsupport/qtsupportconstants.h index 27851ed695f..a5e73a3a215 100644 --- a/src/plugins/qtsupport/qtsupportconstants.h +++ b/src/plugins/qtsupport/qtsupportconstants.h @@ -3,8 +3,7 @@ #pragma once -namespace QtSupport { -namespace Constants { +namespace QtSupport::Constants { // Qt settings pages const char QTVERSION_SETTINGS_PAGE_ID[] = "H.Qt Versions"; @@ -40,5 +39,6 @@ const char KIT_QML_IMPORT_PATH[] = "QtSupport.KitQmlImportPath"; const char KIT_HAS_MERGED_HEADER_PATHS_WITH_QML_IMPORT_PATHS[] = "QtSupport.KitHasMergedHeaderPathsWithQmlImportPaths"; -} // namepsace Constants -} // namepsace QtSupport +const char QMAKE_TOOL_ID[] = "QMakeTool"; + +} // namepsace QtSupport::Constants diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 0b1e5b19e60..3317e4d4262 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -11,6 +11,7 @@ #include "qtoutputformatter.h" #include "qtparser.h" #include "qtprojectimporter.h" +#include "qtsupportconstants.h" #include "qtsupporttr.h" #include "qttestparser.h" #include "qtversionmanager.h" @@ -23,9 +24,10 @@ #include <extensionsystem/iplugin.h> -#include <projectexplorer/jsonwizard/jsonwizardfactory.h> #include <projectexplorer/buildpropertiessettings.h> #include <projectexplorer/buildsystem.h> +#include <projectexplorer/devicesupport/idevice.h> +#include <projectexplorer/jsonwizard/jsonwizardfactory.h> #include <projectexplorer/project.h> #include <projectexplorer/projectmanager.h> #include <projectexplorer/projecttree.h> @@ -66,6 +68,23 @@ static void processRunnerCallback(ProcessData *data) data->stdOut = proc.rawStdOut(); } +class QmakeToolFactory : public DeviceToolAspectFactory +{ +public: + QmakeToolFactory() + { + setToolId(Constants::QMAKE_TOOL_ID); + setToolType(DeviceToolAspect::BuildTool); + setFilePattern({"qmake"}); + setLabelText(Tr::tr("qmake executable:")); + } +}; + +void setupQmakeToolFactory() +{ + static QmakeToolFactory theQmakeToolFactory; +} + class QtSupportPlugin final : public ExtensionSystem::IPlugin { Q_OBJECT @@ -87,6 +106,7 @@ void QtSupportPlugin::initialize() #endif setupQtVersionManager(this); + setupQmakeToolFactory(); setupDesktopQtVersion(); setupEmbeddedLinuxQtVersion(); @@ -155,7 +175,7 @@ const char kLinkWithQtInstallationSetting[] = "LinkWithQtInstallation"; static void askAboutQtInstallation() { - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); // if the install settings exist, the Qt Creator installation is (probably) already linked to // a Qt installation, so don't ask if (!LinkWithQtSupport::canLinkWithQt() || LinkWithQtSupport::isLinkedWithQt() diff --git a/src/plugins/remotelinux/deploymenttimeinfo.cpp b/src/plugins/remotelinux/deploymenttimeinfo.cpp index 9395c87e1a9..3f8f3ebad4c 100644 --- a/src/plugins/remotelinux/deploymenttimeinfo.cpp +++ b/src/plugins/remotelinux/deploymenttimeinfo.cpp @@ -32,7 +32,7 @@ public: bool operator==(const DeployParameters &other) const { return file == other.file && host == other.host && sysroot == other.sysroot; } - friend auto qHash(const DeployParameters &p) { + friend size_t qHash(const DeployParameters &p) { return qHash(qMakePair(qMakePair(p.file, p.host), p.sysroot)); } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 496e4426b6a..01e96821511 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -27,6 +27,8 @@ #include <projectexplorer/devicesupport/sshsettings.h> #include <projectexplorer/projectexplorerconstants.h> +#include <tasking/tasktreerunner.h> + #include <utils/algorithm.h> #include <utils/async.h> #include <utils/devicefileaccess.h> @@ -65,7 +67,9 @@ #include <QRegularExpression> #include <QSpacerItem> #include <QSpinBox> +#include <QStackedWidget> #include <QTemporaryDir> +#include <QTextBrowser> #include <QThread> #include <QTimer> @@ -289,6 +293,8 @@ public: private: void createNewKey(); void updateDeviceFromUi() override {} + + Tasking::SingleTaskTreeRunner m_detectionRunner; }; LinuxDeviceConfigurationWidget::LinuxDeviceConfigurationWidget( @@ -314,9 +320,27 @@ LinuxDeviceConfigurationWidget::LinuxDeviceConfigurationWidget( updatePortWarningLabel(); - // clang-format off connect(&device->freePortsAspect, &PortListAspect::volatileValueChanged, this, updatePortWarningLabel); + auto autoDetectButton = new QPushButton(Tr::tr("Run auto-detection now")); + + connect(&m_detectionRunner, &Tasking::SingleTaskTreeRunner::aboutToStart, [=] { + autoDetectButton->setEnabled(false); + }); + connect(&m_detectionRunner, &Tasking::SingleTaskTreeRunner::done, [=] { + autoDetectButton->setEnabled(true); + }); + + connect(autoDetectButton, &QPushButton::clicked, this, [linuxDevice, autoDetectButton] { + autoDetectButton->setEnabled(false); + linuxDevice->tryToConnect({linuxDevice.get(), [linuxDevice, autoDetectButton](const Result<> &res) { + if (res) + DeviceToolAspectFactory::autoDetectAll(linuxDevice, linuxDevice->autoDetectionPaths()); + autoDetectButton->setEnabled(true); + }}); + }); + + // clang-format off Form { Tr::tr("Machine type:"), machineType, st, br, device->sshParametersAspectContainer().host, device->sshParametersAspectContainer().port, @@ -327,9 +351,31 @@ LinuxDeviceConfigurationWidget::LinuxDeviceConfigurationWidget( device->sshParametersAspectContainer().privateKeyFile, createKeyButton, br, linuxDevice->autoConnectOnStartup, br, linuxDevice->sourceProfile, br, - device->deviceToolAspects(), br, device->sshForwardDebugServerPort, br, device->linkDevice, br, + Column { Space(20) }, br, + Group { + title(Tr::tr("Auto-detection")), + Grid { + linuxDevice->autoDetectInPath, br, + linuxDevice->autoDetectInQtInstallation, linuxDevice->autoDetectQtInstallation, br, + linuxDevice->autoDetectInDirectories, linuxDevice->autoDetectDirectories, br, + autoDetectButton, + } + }, br, + Group { + title(Tr::tr("Run tools on this device")), + Form { + device->deviceToolAspects(DeviceToolAspect::RunTool) + } + }, br, + Group { + title(Tr::tr("Source and build tools on this device")), + Form { + device->deviceToolAspects(DeviceToolAspect::ToolType( + DeviceToolAspect::SourceTool | DeviceToolAspect::BuildTool)) + } + } }.attachTo(this); // clang-format on @@ -1132,6 +1178,35 @@ LinuxDevice::LinuxDevice() autoConnectOnStartup.setLabelText(Tr::tr("Auto-connect on startup")); autoConnectOnStartup.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); + autoDetectInPath.setSettingsKey("AutoDetectInPath"); + autoDetectInPath.setDefaultValue(true); + autoDetectInPath.setLabelText(Tr::tr("Search in PATH")); + autoDetectInPath.setLabelPlacement(BoolAspect::LabelPlacement::Compact); + + autoDetectInQtInstallation.setSettingsKey("AutoDetectInQtInstallation"); + autoDetectInQtInstallation.setDefaultValue(true); + autoDetectInQtInstallation.setLabelText(Tr::tr("Search in Qt Installation")); + autoDetectInQtInstallation.setLabelPlacement(BoolAspect::LabelPlacement::Compact); + + autoDetectQtInstallation.setSettingsKey("AutoDetectQtInstallation"); + autoDetectQtInstallation.setHistoryCompleter("QtInstallation"); + autoDetectQtInstallation.setPlaceHolderText("Leave empty to search in $HOME/Qt"); + autoDetectQtInstallation.setExpectedKind(PathChooser::ExistingDirectory); + autoDetectQtInstallation.setEnabler(&autoDetectInQtInstallation); + + autoDetectInDirectories.setSettingsKey("AutoDetectInDirectories"); + autoDetectInDirectories.setDefaultValue(false); + autoDetectInDirectories.setLabelText(Tr::tr("Search in Directories")); + autoDetectInDirectories.setLabelPlacement(BoolAspect::LabelPlacement::Compact); + + autoDetectDirectories.setSettingsKey("AutoDetectDirectories"); + autoDetectDirectories.setDisplayStyle(StringAspect::LineEditDisplay); + autoDetectDirectories.setPlaceHolderText(Tr::tr("Semicolon-separated list of directories")); + autoDetectDirectories.setToolTip( + Tr::tr("Select the paths on the device that should be scanned for binaries.")); + autoDetectDirectories.setHistoryCompleter("Directories"); + autoDetectDirectories.setEnabler(&autoDetectInDirectories); + addDeviceAction({ Tr::tr("Deploy Public Key..."), [](const IDevice::Ptr &device) { @@ -1374,7 +1449,7 @@ void LinuxDevicePrivate::announceConnectionAttempt() InfoBarEntry info(announceId(), message); info.setTitle(Tr::tr("Establishing a Connection")); info.setInfoType(InfoLabel::Ok); - Core::ICore::infoBar()->addInfo(info); + Core::ICore::popupInfoBar()->addInfo(info); Core::MessageManager::writeSilently(message); } @@ -1406,10 +1481,11 @@ void LinuxDevicePrivate::unannounceConnectionAttempt() InfoBarEntry info(announceId(), message); info.setTitle(Tr::tr("Connection Attempt Finished")); info.setInfoType(infoType); - Core::ICore::infoBar()->addInfo(info); + InfoBar *infoBar = Core::ICore::popupInfoBar(); + infoBar->addInfo(info); Core::MessageManager::writeSilently(message); - QTimer::singleShot(5000, q, [id=announceId()] { Core::ICore::infoBar()->removeInfo(id); }); + QTimer::singleShot(5000, q, [id=announceId(), infoBar] { infoBar->removeInfo(id); }); } bool LinuxDevicePrivate::checkDisconnectedWithWarning() @@ -1417,7 +1493,7 @@ bool LinuxDevicePrivate::checkDisconnectedWithWarning() if (m_deviceState != IDevice::DeviceDisconnected) return false; - InfoBar *infoBar = Core::ICore::infoBar(); + InfoBar *infoBar = Core::ICore::popupInfoBar(); QMetaObject::invokeMethod(infoBar, [id = q->id(), name = q->displayName(), infoBar] { const Id errorId = id.withPrefix("error_"); if (!infoBar->canInfoBeAdded(errorId)) @@ -1604,11 +1680,59 @@ void LinuxDevice::postLoad() InfoBarEntry info(d->announceId(), message); info.setTitle(Tr::tr("Establishing a Connection")); info.setInfoType(InfoLabel::Warning); - Core::ICore::infoBar()->addInfo(info); + Core::ICore::popupInfoBar()->addInfo(info); Core::MessageManager::writeSilently(message); }}); } +FilePaths LinuxDevice::autoDetectionPaths() const +{ + FilePaths paths; + if (autoDetectInPath.volatileValue()) + paths += systemEnvironment().path(); + + if (autoDetectInQtInstallation.volatileValue()) { + QString qtPath = autoDetectQtInstallation.volatileValue(); + if (qtPath.isEmpty()) + qtPath = systemEnvironment().value("HOME") + "/Qt"; + + using VersionAndPath = QPair<QVersionNumber, FilePath>; + QList<VersionAndPath> qtBinPaths; + + // We are looking for something like ~/Qt/6.6.3/gcc_64/bin/ + const FilePath qtInstallation = filePath(qtPath); + for (const FilePath &qtVersion : qtInstallation.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (qtVersion.fileName().count(".") == 2) { + const QVersionNumber qtVersionNumber = QVersionNumber::fromString(qtVersion.fileName()); + for (const FilePath &qtArch : qtVersion.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot)) { + const FilePath qtBinPath = qtArch.pathAppended("bin"); + if (qtBinPath.exists()) + qtBinPaths += std::make_pair(qtVersionNumber, qtBinPath); + } + } + } + + // Prefer higher Qt versions. + Utils::sort(qtBinPaths, [](const VersionAndPath &a, const VersionAndPath &b) { + return a.first > b.first; + }); + + for (const VersionAndPath &vp : qtBinPaths) + paths += vp.second; + } + + if (autoDetectInDirectories.volatileValue()) { + for (const QString &path : autoDetectDirectories.volatileValue().split(';')) + paths.append(FilePath::fromString(path.trimmed())); + } + + paths = Utils::transform(paths, [this](const FilePath &path) { + return filePath(path.path()); + }); + + return paths; +} + } // namespace RemoteLinux #include "linuxdevice.moc" diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index dd665d9df10..0c9a41ce346 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -79,9 +79,16 @@ public: void toMap(Utils::Store &map) const override; void postLoad() override; + Utils::FilePaths autoDetectionPaths() const; + public: Utils::BoolAspect sourceProfile{this}; Utils::BoolAspect autoConnectOnStartup{this}; + Utils::BoolAspect autoDetectInPath{this}; + Utils::BoolAspect autoDetectInQtInstallation{this}; + Utils::FilePathAspect autoDetectQtInstallation{this}; + Utils::BoolAspect autoDetectInDirectories{this}; + Utils::StringAspect autoDetectDirectories{this}; protected: LinuxDevice(); diff --git a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp index 73f0829d091..a743606eabb 100644 --- a/src/plugins/texteditor/codeassist/genericproposalmodel.cpp +++ b/src/plugins/texteditor/codeassist/genericproposalmodel.cpp @@ -19,7 +19,7 @@ using namespace TextEditor; QT_BEGIN_NAMESPACE -auto qHash(const AssistProposalItem &item) +size_t qHash(const AssistProposalItem &item) { return qHash(item.text()); } diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp index cc56ef71ae8..67b7e99fb4c 100644 --- a/src/plugins/texteditor/fontsettings.cpp +++ b/src/plugins/texteditor/fontsettings.cpp @@ -129,7 +129,7 @@ bool FontSettings::equals(const FontSettings &f) const && m_scheme == f.m_scheme; } -auto qHash(const TextStyle &textStyle) +size_t qHash(const TextStyle &textStyle) { return ::qHash(quint8(textStyle)); } @@ -185,7 +185,7 @@ QTextCharFormat FontSettings::toTextCharFormat(TextStyle category) const return tf; } -auto qHash(TextStyles textStyles) +size_t qHash(TextStyles textStyles) { return ::qHash(reinterpret_cast<quint64&>(textStyles)); } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 59a959d916f..a262e212536 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1093,6 +1093,8 @@ public: void insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion); void updateSuggestion(); void clearCurrentSuggestion(); + void updateSuggestionActions(); + QTextBlock m_suggestionBlock; int m_numEmbeddedWidgets = 0; @@ -1120,6 +1122,7 @@ public: QAction *m_jumpToFileAction = nullptr; QAction *m_jumpToFileInNextSplitAction = nullptr; QList<QAction *> m_modifyingActions; + QList<QAction *> m_suggestionActions; bool m_updatePasteActionScheduled = false; }; @@ -2015,6 +2018,7 @@ void TextEditorWidgetPrivate::insertSuggestion(std::unique_ptr<TextSuggestion> & m_document->updateLayout(); forceUpdateScrollbarSize(); + updateSuggestionActions(); } void TextEditorWidgetPrivate::updateSuggestion() @@ -2046,6 +2050,15 @@ void TextEditorWidgetPrivate::clearCurrentSuggestion() TextBlockUserData::clearSuggestion(m_suggestionBlock); m_document->updateLayout(); m_suggestionBlock = QTextBlock(); + + updateSuggestionActions(); +} + +void TextEditorWidgetPrivate::updateSuggestionActions() +{ + const bool hasSuggestion = m_suggestionBlock.isValid(); + for (QAction *action : m_suggestionActions) + action->setEnabled(hasSuggestion); } void TextEditorWidget::selectEncoding() @@ -3053,21 +3066,6 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) const bool inOverwriteMode = overwriteMode(); const bool hasMultipleCursors = cursor.hasMultipleCursors(); - if (TextSuggestion *suggestion = TextBlockUserData::suggestion(d->m_suggestionBlock)) { - if (e->matches(QKeySequence::MoveToNextWord)) { - e->accept(); - if (suggestion->applyWord(this)) - d->clearCurrentSuggestion(); - return; - } else if (e->modifiers() == Qt::NoModifier - && (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab)) { - e->accept(); - if (suggestion->apply()) - d->clearCurrentSuggestion(); - return; - } - } - if (!ro && (e == QKeySequence::InsertParagraphSeparator || (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))) { @@ -4609,15 +4607,15 @@ void TextEditorWidgetPrivate::registerActions() .addOnTriggered([this] { q->toggleFoldAll(); }) .setScriptable(true) .contextAction(); - ActionBuilder(this, INCREASE_FONT_SIZE).setContext(m_editorContext).addOnTriggered([this] { + ActionBuilder(this, Core::Constants::ZOOM_IN).setContext(m_editorContext).addOnTriggered([this] { q->increaseFontZoom(); }); - ActionBuilder(this, DECREASE_FONT_SIZE).setContext(m_editorContext).addOnTriggered([this] { + ActionBuilder(this, Core::Constants::ZOOM_OUT).setContext(m_editorContext).addOnTriggered([this] { q->decreaseFontZoom(); }); - ActionBuilder(this, RESET_FONT_SIZE).setContext(m_editorContext).addOnTriggered([this] { - q->zoomReset(); - }); + ActionBuilder(this, Core::Constants::ZOOM_RESET) + .setContext(m_editorContext) + .addOnTriggered([this] { q->zoomReset(); }); ActionBuilder(this, GOTO_BLOCK_START) .setContext(m_editorContext) .addOnTriggered([this] { q->gotoBlockStart(); }) @@ -4733,6 +4731,49 @@ void TextEditorWidgetPrivate::registerActions() .addOnTriggered([this] { q->gotoNextWordCamelCaseWithSelection(); }) .setScriptable(true); + m_suggestionActions << + ActionBuilder(this, SUGGESTION_APPLY) + .setContext(m_editorContext) + .setText(Tr::tr("Apply")) + .setToolTip(Tr::tr("Apply the current suggestion")) + .addOnTriggered([this] { + if (TextSuggestion *s = q->currentSuggestion()) + s->apply(); + }) + .setScriptable(true) + .setDefaultKeySequence(QKeySequence(Qt::Key_Tab)) + .setEnabled(false) + .contextAction(); + + m_suggestionActions << + ActionBuilder(this, SUGGESTION_APPLY_WORD) + .setContext(m_editorContext) + .setText(Tr::tr("Apply one Word")) + .setToolTip(Tr::tr("Apply one word of the current suggestion")) + .addOnTriggered([this] { + if (TextSuggestion *s = q->currentSuggestion()) + s->applyWord(q); + }) + .setScriptable(true) + .setDefaultKeySequence(QKeySequence(QKeySequence::MoveToNextWord)) + .setEnabled(false) + .contextAction(); + + m_suggestionActions << + ActionBuilder(this, SUGGESTION_APPLY_LINE) + .setContext(m_editorContext) + .setText(Tr::tr("Apply Line")) + .setToolTip(Tr::tr("Apply one line of the current suggestion")) + .addOnTriggered([this] { + if (TextSuggestion *s = q->currentSuggestion()) + s->applyLine(q); + }) + .setScriptable(true) + .setDefaultKeySequence( + QKeyCombination(Qt::ShiftModifier, Qt::Key_Tab)) + .setEnabled(false) + .contextAction(); + // Collect additional modifying actions so we can check for them inside a readonly file // and disable them m_modifyingActions << m_autoIndentAction; diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index b60c448a424..efe77951c80 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -139,9 +139,6 @@ const char UNFOLD_ALL[] = "TextEditor.UnFoldAll"; const char AUTO_INDENT_SELECTION[] = "TextEditor.AutoIndentSelection"; const char AUTO_FORMAT_SELECTION[] = "TextEditor.AutoFormatSelection"; const char REFORMAT_FILE[] = "TextEditor.ReformatFile"; -const char INCREASE_FONT_SIZE[] = "TextEditor.IncreaseFontSize"; -const char DECREASE_FONT_SIZE[] = "TextEditor.DecreaseFontSize"; -const char RESET_FONT_SIZE[] = "TextEditor.ResetFontSize"; const char GOTO_BLOCK_START[] = "TextEditor.GotoBlockStart"; const char GOTO_BLOCK_START_WITH_SELECTION[] = "TextEditor.GotoBlockStartWithSelection"; const char GOTO_BLOCK_END[] = "TextEditor.GotoBlockEnd"; @@ -202,6 +199,9 @@ const char GOTO_PREVIOUS_WORD_WITH_SELECTION[] = "TextEditor.GotoPreviousWordWit const char GOTO_NEXT_WORD_WITH_SELECTION[] = "TextEditor.GotoNextWordWithSelection"; const char GOTO_PREVIOUS_WORD_CAMEL_CASE_WITH_SELECTION[] = "TextEditor.GotoPreviousWordCamelCaseWithSelection"; const char GOTO_NEXT_WORD_CAMEL_CASE_WITH_SELECTION[] = "TextEditor.GotoNextWordCamelCaseWithSelection"; +const char SUGGESTION_APPLY[] = "TextEditor.Suggestion.Apply"; +const char SUGGESTION_APPLY_WORD[] = "TextEditor.Suggestion.ApplyWord"; +const char SUGGESTION_APPLY_LINE[] = "TextEditor.Suggestion.ApplyLine"; const char C_TEXTEDITOR_MIMETYPE_TEXT[] = "text/plain"; const char INFO_MISSING_SYNTAX_DEFINITION[] = "TextEditor.InfoSyntaxDefinition"; const char INFO_MULTIPLE_SYNTAX_DEFINITIONS[] = "TextEditor.InfoMultipleSyntaxDefinitions"; diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index 384c2603f3b..0ef7f8c1525 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -540,18 +540,6 @@ void TextEditorPlugin::createEditorCommands() TextActionBuilder(this, UNFOLD_ALL) .setText(Tr::tr("Toggle &Fold All")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_COLLAPSING); - TextActionBuilder(this, INCREASE_FONT_SIZE) - .setText(Tr::tr("Increase Font Size")) - .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl++"))) - .addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT); - TextActionBuilder(this, DECREASE_FONT_SIZE) - .setText(Tr::tr("Decrease Font Size")) - .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+-"))) - .addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT); - TextActionBuilder(this, RESET_FONT_SIZE) - .setText(Tr::tr("Reset Font Size")) - .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+0"))) - .addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT); TextActionBuilder(this, GOTO_BLOCK_START) .setText(Tr::tr("Go to Block Start")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+["))) diff --git a/src/plugins/texteditor/textsuggestion.cpp b/src/plugins/texteditor/textsuggestion.cpp index b41d3b6c7fd..e49c9158554 100644 --- a/src/plugins/texteditor/textsuggestion.cpp +++ b/src/plugins/texteditor/textsuggestion.cpp @@ -5,8 +5,11 @@ #include "textdocumentlayout.h" #include "texteditor.h" +#include "texteditorconstants.h" #include "texteditortr.h" +#include <coreplugin/actionmanager/actionmanager.h> + #include <QToolBar> #include <utils/qtcassert.h> #include <utils/stringutils.h> @@ -151,14 +154,10 @@ public: connect(m_next, &QAction::triggered, this, &SuggestionToolTip::selectNext); } - auto apply = addAction(Tr::tr("Apply (%1)").arg(QKeySequence(Qt::Key_Tab).toString())); - auto applyWord = addAction( - Tr::tr("Apply Word (%1)").arg(QKeySequence(QKeySequence::MoveToNextWord).toString())); - auto applyLine = addAction(Tr::tr("Apply Line")); + addAction(Core::ActionManager::command(Constants::SUGGESTION_APPLY)->action()); + addAction(Core::ActionManager::command(Constants::SUGGESTION_APPLY_WORD)->action()); + addAction(Core::ActionManager::command(Constants::SUGGESTION_APPLY_LINE)->action()); - connect(apply, &QAction::triggered, this, &SuggestionToolTip::apply); - connect(applyWord, &QAction::triggered, this, &SuggestionToolTip::applyWord); - connect(applyLine, &QAction::triggered, this, &SuggestionToolTip::applyLine); connect(editor->document(), &QTextDocument::contentsChange, this, &SuggestionToolTip::contentsChanged); updateSuggestionSelector(); diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index 07dd0c083fd..426e6a552aa 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -456,7 +456,7 @@ static void showUpdateInfo(const QList<Update> &updates, return scrollArea; }); } - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); infoBar->removeInfo(InstallUpdates); // remove any existing notifications infoBar->unsuppressInfo(InstallUpdates); infoBar->addInfo(info); diff --git a/src/plugins/webassembly/webassemblydevice.cpp b/src/plugins/webassembly/webassemblydevice.cpp index d72043d2f10..babc21df5b6 100644 --- a/src/plugins/webassembly/webassemblydevice.cpp +++ b/src/plugins/webassembly/webassemblydevice.cpp @@ -53,7 +53,7 @@ static void askUserAboutEmSdkSetup() { const char setupWebAssemblyEmSdk[] = "SetupWebAssemblyEmSdk"; - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); if (!infoBar->canInfoBeAdded(setupWebAssemblyEmSdk) || !WebAssemblyQtVersion::isQtVersionInstalled() || areToolChainsRegistered()) diff --git a/src/plugins/welcome/introductionwidget.cpp b/src/plugins/welcome/introductionwidget.cpp index 03f3ba1040c..180a4dd80f8 100644 --- a/src/plugins/welcome/introductionwidget.cpp +++ b/src/plugins/welcome/introductionwidget.cpp @@ -417,7 +417,7 @@ void runUiTour() void askUserAboutIntroduction() { - InfoBar *infoBar = ICore::infoBar(); + InfoBar *infoBar = ICore::popupInfoBar(); // CheckableMessageBox for compatibility with Qt Creator < 4.11 if (!CheckableDecider(Key(kTakeTourSetting)).shouldAskAgain() diff --git a/src/shared/qbs b/src/shared/qbs -Subproject c2e3d70decbce47ff94c7efe0262448decc9692 +Subproject a0dfa99c6071fede3be6522102818839a7f8365 diff --git a/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp b/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp index 7d4198a39a7..cb8b91d6716 100644 --- a/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp +++ b/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp @@ -428,7 +428,7 @@ static Document::Ptr parse(const QString &fileName, const QByteArray &source, std::cout << "Parsing as " << qPrintable(parseModeToString(parseMode)) << "..."; Document::Ptr doc = Document::create(Utils::FilePath::fromUserInput(fileName)); - doc->control()->setDiagnosticClient(errorHandler); + doc->control()->setDiagnosticClient(errorHandler, true); doc->setUtf8Source(source); const bool parsed = doc->parse(parseMode); if (parsed && errorHandler->m_errorCount == 0) { diff --git a/src/tools/cplusplus-frontend/cplusplus-frontend.cpp b/src/tools/cplusplus-frontend/cplusplus-frontend.cpp index 467bb8ffa11..ad2cff7c5a2 100644 --- a/src/tools/cplusplus-frontend/cplusplus-frontend.cpp +++ b/src/tools/cplusplus-frontend/cplusplus-frontend.cpp @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) file.close(); Document::Ptr doc = Document::create(Utils::FilePath::fromString(fileName)); - doc->control()->setDiagnosticClient(0); + doc->control()->setDiagnosticClient(0, true); doc->setUtf8Source(source); doc->parse(); } diff --git a/src/tools/wininterrupt/CMakeLists.txt b/src/tools/wininterrupt/CMakeLists.txt index 903e9b5f0e2..c7903c3c41a 100644 --- a/src/tools/wininterrupt/CMakeLists.txt +++ b/src/tools/wininterrupt/CMakeLists.txt @@ -24,27 +24,20 @@ if (NOT QT_CREATOR_API_DEFINED) include(QtCreatorSbom) qtc_handle_compiler_cache_support() - # Need to look for Qt6 optionally, so that we can use the SBOM feature, even though the + # Need to look for Qt6, so that we can use the SBOM feature, even though the # project doesn't link to Qt. - find_package(Qt6 - COMPONENTS Core - ) + # Explicitly disable the version checks, because when configuring for an architecture that + # is not compatible with the found Qt, we'd fail to find the package. We don't care about + # binary compatibility here, we only want the SBOM feature. + if(QT_GENERATE_SBOM) + set(QT_NO_PACKAGE_VERSION_CHECK ON) + set(QT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING ON) + find_package(Qt6 REQUIRED) + unset(QT_NO_PACKAGE_VERSION_CHECK) + unset(QT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING) + endif() set(QT_WIN_INTERRUPT_STANDALONE_BUILD TRUE) - qtc_setup_sbom() - qtc_sbom_compute_cpe(project_cpe - VENDOR "qt" - PRODUCT "${PROJECT_NAME}" - VERSION "${IDE_VERSION}" - ) - set(QT_SBOM_LICENSE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../../LICENSES") - qtc_sbom_begin_project( - SBOM_PROJECT_NAME "${PROJECT_NAME}-${Arch}" - QT_REPO_PROJECT_NAME "${PROJECT_NAME}-${Arch}" - PURL_NAMESPACE "qt" - PURL_NAME "${PROJECT_NAME}" - CPE "${project_cpe}" - ) # Compile for x86, x64 and arm64 if (NOT ${PROJECT_NAME}-MultiBuild AND NOT MINGW) @@ -57,19 +50,33 @@ if (NOT QT_CREATOR_API_DEFINED) string(REPLACE ";" "|" CMAKE_PREFIX_PATH_ALT_SEP "${CMAKE_PREFIX_PATH}") + set(extra_cmake_args "") + set(extra_install_commands "") + if(QT_GENERATE_SBOM) + list(APPEND extra_cmake_args -DQT_GENERATE_SBOM=${QT_GENERATE_SBOM}) + list(APPEND extra_install_commands + && ${CMAKE_COMMAND} --install . --config ${CMAKE_BUILD_TYPE} + --prefix "${CMAKE_BINARY_DIR}" --component sbom + ) + endif() + macro (setup_executable arch) ExternalProject_Add(${arch}-bld SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CMAKE_GENERATOR "${generator}" CMAKE_GENERATOR_PLATFORM "${arch}" + LIST_SEPARATOR | CMAKE_ARGS -D${PROJECT_NAME}-MultiBuild=ON -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH_ALT_SEP} + -DCMAKE_CONFIGURATION_TYPES=${CMAKE_BUILD_TYPE} + ${extra_cmake_args} BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} INSTALL_COMMAND ${CMAKE_COMMAND} --install . --config ${CMAKE_BUILD_TYPE} --prefix "${CMAKE_BINARY_DIR}" --component wininterrupt + ${extra_install_commands} ) endmacro() @@ -87,6 +94,17 @@ if (NOT QT_CREATOR_API_DEFINED) DESTINATION . COMPONENT wininterrupt ) + if(QT_GENERATE_SBOM) + qtc_sbom_get_sbom_install_path(sbom_install_path) + # Because we are installing a dir, the destination should be the same without the dir + # name. + get_filename_component(sbom_install_dest "${sbom_install_path}" DIRECTORY) + install( + DIRECTORY "${CMAKE_BINARY_DIR}/${sbom_install_path}" + DESTINATION "${sbom_install_dest}" + COMPONENT wininterrupt + ) + endif() endif() return() @@ -97,11 +115,28 @@ if (NOT WIN32) return() endif() +if(QT_WIN_INTERRUPT_STANDALONE_BUILD AND QT_GENERATE_SBOM) + qtc_setup_sbom() + qtc_sbom_compute_cpe(project_cpe + VENDOR "qt" + PRODUCT "${PROJECT_NAME}" + VERSION "${IDE_VERSION}" + ) + set(QT_SBOM_LICENSE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../../LICENSES") + qtc_sbom_begin_project( + SBOM_PROJECT_NAME "${PROJECT_NAME}-${Arch}" + QT_REPO_PROJECT_NAME "${PROJECT_NAME}-${Arch}" + PURL_NAMESPACE "qt" + PURL_NAME "${PROJECT_NAME}" + CPE "${project_cpe}" + ) +endif() + add_qtc_executable(win${Arch}interrupt COMPONENT wininterrupt SOURCES wininterrupt.c ) -if(QT_WIN_INTERRUPT_STANDALONE_BUILD) +if(QT_WIN_INTERRUPT_STANDALONE_BUILD AND QT_GENERATE_SBOM) qtc_sbom_end_project() endif() diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index 220bd9ed031..48539336c8b 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -2082,7 +2082,7 @@ void tst_AST::placementNewWithEmptyConstructorArgs() void tst_AST::initTestCase() { - control.setDiagnosticClient(&diag); + control.setDiagnosticClient(&diag, true); } void tst_AST::cleanup() diff --git a/tests/auto/cplusplus/c99/tst_c99.cpp b/tests/auto/cplusplus/c99/tst_c99.cpp index b6fe64a8774..cd8bfa6bee3 100644 --- a/tests/auto/cplusplus/c99/tst_c99.cpp +++ b/tests/auto/cplusplus/c99/tst_c99.cpp @@ -79,11 +79,11 @@ class tst_c99: public QObject LanguageFeatures features; features.c99Enabled = true; Client client(errors); - doc->control()->setDiagnosticClient(&client); + doc->control()->setDiagnosticClient(&client, true); doc->setUtf8Source(QTextStream(&file).readAll().toUtf8()); doc->translationUnit()->setLanguageFeatures(features); doc->check(); - doc->control()->setDiagnosticClient(0); + doc->control()->setDiagnosticClient(0, false); } else { qWarning() << "could not read file" << fileName; } diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index 90bbb927eed..6b41435fe68 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -105,11 +105,11 @@ class tst_cxx11: public QObject LanguageFeatures languageFeatures, QByteArray *errors) { Client client(errors); - doc->control()->setDiagnosticClient(&client); + doc->control()->setDiagnosticClient(&client, true); doc->setUtf8Source(source); doc->translationUnit()->setLanguageFeatures(languageFeatures); doc->check(); - doc->control()->setDiagnosticClient(0); + doc->control()->setDiagnosticClient(0, false); } Document::Ptr document(const QString &fileName, QByteArray *errors = 0, bool c99Enabled = false) diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp index 93f4665d4a0..15fc5dafee4 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -40,7 +40,7 @@ class tst_Semantic: public QObject public: tst_Semantic() : control(new Control) - { control->setDiagnosticClient(&diag); } + { control->setDiagnosticClient(&diag, true); } TranslationUnit *parse(const QByteArray &source, TranslationUnit::ParseMode mode, diff --git a/tests/auto/cplusplus/translationunit/tst_translationunit.cpp b/tests/auto/cplusplus/translationunit/tst_translationunit.cpp index b0e23013234..a0fcb719389 100644 --- a/tests/auto/cplusplus/translationunit/tst_translationunit.cpp +++ b/tests/auto/cplusplus/translationunit/tst_translationunit.cpp @@ -73,7 +73,7 @@ private: Document() : m_translationUnit(&m_control, m_control.stringLiteral("testFile")) { - m_control.setDiagnosticClient(&m_diagnosticClient); + m_control.setDiagnosticClient(&m_diagnosticClient, true); } TranslationUnit *translationUnit() diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index f0de8cf8f9a..2fbb388475e 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -4841,24 +4841,40 @@ void tst_Tasking::validConditionalConstructs() void tst_Tasking::exactHandlers() { - bool calledSetup = false; - bool calledDone = false; + bool taskSetupCalled = false; + bool taskDoneCalled = false; + bool treeSetupCalled = false; + bool treeDoneCalled = false; - const TestTask::TaskSetupHandler setup = [&calledSetup](TaskObject &) { - calledSetup = true; + const TestTask::TaskSetupHandler onTaskSetup = [&taskSetupCalled](TaskObject &) { + taskSetupCalled = true; return SetupResult::Continue; }; - const TestTask::TaskDoneHandler done = [&calledDone](const TaskObject &, DoneWith) { - calledDone = true; + const TestTask::TaskDoneHandler onTaskDone = [&taskDoneCalled](const TaskObject &, DoneWith) { + taskDoneCalled = true; return DoneResult::Success; }; - TaskTree taskTree({TestTask(setup, done)}); - taskTree.runBlocking(); + const AbstractTaskTreeRunner::TreeSetupHandler onTreeSetup = [&treeSetupCalled](TaskTree &) { + treeSetupCalled = true; + }; + + const AbstractTaskTreeRunner::TreeDoneHandler onTreeDone + = [&treeDoneCalled](const TaskTree &, DoneWith) { + treeDoneCalled = true; + }; + + SingleTaskTreeRunner taskTreeRunner; + QSignalSpy doneSpy(&taskTreeRunner, &AbstractTaskTreeRunner::done); + taskTreeRunner.start({TestTask(onTaskSetup, onTaskDone)}, onTreeSetup, onTreeDone); + + QVERIFY(doneSpy.wait(1000)); - QVERIFY(calledSetup); - QVERIFY(calledDone); + QVERIFY(taskSetupCalled); + QVERIFY(taskDoneCalled); + QVERIFY(treeSetupCalled); + QVERIFY(treeDoneCalled); } QTEST_GUILESS_MAIN(tst_Tasking) diff --git a/tests/manual/docker/Dockerfile-qt-6-ubuntu-24.04-build b/tests/manual/docker/Dockerfile-qt-6-ubuntu-24.04-build index 0e4fbfe73de..5d6c2252fe8 100644 --- a/tests/manual/docker/Dockerfile-qt-6-ubuntu-24.04-build +++ b/tests/manual/docker/Dockerfile-qt-6-ubuntu-24.04-build @@ -10,6 +10,7 @@ RUN apt-get update \ qt6-base-dev \ qt6-5compat-dev \ gdb \ + gdbserver \ linux-tools-common \ valgrind \ x11-apps \ |