From 2971138cb72ed162e7ea6197a3c17e12d1e9ed47 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Fri, 7 Jun 2024 15:20:01 +0200 Subject: [PATCH 01/73] Debugger: Fix hitting unexisting breakpoints Set UseFullPath only for BP from the opened projects. Fixes: QTCREATORBUG-3750 Change-Id: I343c68ca341f9bfb57e352b9b28df333eb1c16c3 Reviewed-by: David Schulz --- src/plugins/debugger/gdb/gdbengine.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index ab173cc0eab..b31ee7130e4 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -30,7 +30,9 @@ #include #include +#include #include +#include #include #include @@ -2074,8 +2076,10 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data) return addressSpec(data.address); BreakpointPathUsage usage = data.pathUsage; - if (usage == BreakpointPathUsageEngineDefault) - usage = BreakpointUseShortPath; + if (usage == BreakpointPathUsageEngineDefault) { + ProjectExplorer::Project *project = ProjectManager::projectForFile(data.fileName); + usage = project ? BreakpointUseFullPath : BreakpointUseShortPath; + } const QString fileName = usage == BreakpointUseFullPath ? data.fileName.path() : breakLocation(data.fileName); @@ -2088,8 +2092,10 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data) QString GdbEngine::breakpointLocation2(const BreakpointParameters &data) { BreakpointPathUsage usage = data.pathUsage; - if (usage == BreakpointPathUsageEngineDefault) - usage = BreakpointUseShortPath; + if (usage == BreakpointPathUsageEngineDefault) { + ProjectExplorer::Project *project = ProjectManager::projectForFile(data.fileName); + usage = project ? BreakpointUseFullPath : BreakpointUseShortPath; + } const QString fileName = usage == BreakpointUseFullPath ? data.fileName.path() : breakLocation(data.fileName); From 107a783452aff4f1bd3636d7ee183b0ec939203f Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 21 Jun 2024 13:30:50 +0200 Subject: [PATCH 02/73] Doc: Describe File > Open Workspace ...which opens a directory as a project and creates a .json project file. Task-number: QTCREATORBUG-30604 Change-Id: Ieadcddb298cbf50f25353d344dce0cd1820095e8 Reviewed-by: David Schulz --- .../creator-only/creator-projects-opening.qdoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc index 67fc416ee7a..b71064f96e0 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc @@ -14,6 +14,7 @@ \ingroup creator-how-to-projects-configure \ingroup creator-how-to-manage-kits + \ingroup creator-how-to-projects \title Open projects @@ -49,6 +50,15 @@ \endlist \endlist + \section1 Open directories as projects + + To open a directory as a project, go to \uicontrol File > + \uicontrol {Open Workspace}. + + \QC generates the \e .qtcreator/project.json project file in the directory + for setting a project name and file exclusion filters. You can open either + the JSON file or the workspace to open the project the next time. + \section1 Re-configure projects \QC stores information that it needs to build projects in a .user file. If From 739b4fc5f40c613fa5b04b5005f2a19b4157f582 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 21 Jun 2024 15:18:23 +0200 Subject: [PATCH 03/73] CMakePM: Fix crash on non-cmake projects when viewing project's settings Amends 1a5f61adcabb934bd8fe96030cc6b20fd842a29d Change-Id: Ife8eac40365d06e06a9177eb7a1886eb65a84095 Reviewed-by: Alessandro Portale --- src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index eeab46f946d..a56a66c533b 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -142,8 +142,9 @@ void CMakeSpecificSettings::readSettings() } else { Store data = storeFromVariant(project->namedSettings(Constants::Settings::GENERAL_ID)); if (data.isEmpty()) { - CMakeProject *cmakeProject = static_cast(project); - if (cmakeProject->presetsData().havePresets && cmakeProject->presetsData().vendor) { + CMakeProject *cmakeProject = qobject_cast(project); + if (cmakeProject && cmakeProject->presetsData().havePresets + && cmakeProject->presetsData().vendor) { useGlobalSettings = false; data = storeFromMap(cmakeProject->presetsData().vendor.value()); fromMap(data); From 92761ad2932c494e027c6ef54d3597b7da312485 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 21 Jun 2024 11:27:53 +0200 Subject: [PATCH 04/73] PE: Allow candidate renaming with sub directories This would allow renaming of: myclass.h myclass.cpp -> my/class.h my/class.cpp Fixes: QTCREATORBUG-30830 Change-Id: Ic7f277e52a52dfe6745023f550072a935295bcac Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectmodels.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 5f5aa0150e1..b7be5e1546b 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -284,8 +284,9 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol QTC_ASSERT(node, return false); std::vector> toRename; - const Utils::FilePath orgFilePath = node->filePath(); - const Utils::FilePath newFilePath = orgFilePath.parentDir().pathAppended(value.toString()); + const FilePath orgFilePath = node->filePath(); + const FilePath newFilePath = orgFilePath.parentDir().pathAppended(value.toString()); + const FilePath valuePath = FilePath::fromString(value.toString()); const QFileInfo orgFileInfo = orgFilePath.toFileInfo(); toRename.emplace_back(std::make_tuple(node, orgFilePath, newFilePath)); @@ -309,12 +310,13 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol case QMessageBox::Yes: for (Node * const n : candidateNodes) { QString targetFilePath = orgFileInfo.absolutePath() + '/' - + newFilePath.completeBaseName(); + + valuePath.parentDir().path() + '/' + + valuePath.completeBaseName(); const QString suffix = n->filePath().suffix(); if (!suffix.isEmpty()) targetFilePath.append('.').append(suffix); toRename.emplace_back(std::make_tuple(n, n->filePath(), - FilePath::fromString(targetFilePath))); + FilePath::fromString(targetFilePath).cleanPath())); } break; case QMessageBox::Cancel: From b4f798d002bebc62a308dcc73bddc695e37ce03d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 19 Jun 2024 11:55:03 +0200 Subject: [PATCH 05/73] CodingStyle: Fix Utils::QtcProcess -> Utils::Process rename Change-Id: Iabcfcdea47bf6372904b5a0f89c568790df90023 Reviewed-by: Eike Ziller --- doc/qtcreatordev/src/coding-style.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/qtcreatordev/src/coding-style.qdoc b/doc/qtcreatordev/src/coding-style.qdoc index 49e99a8e8bc..33a2189aaf6 100644 --- a/doc/qtcreatordev/src/coding-style.qdoc +++ b/doc/qtcreatordev/src/coding-style.qdoc @@ -637,8 +637,8 @@ \li Use Utils::FilePath for any QString that semantically is a file or directory, see also \l{Passing File Names}. \li Prefer using Utils::FilePath over any use of QDir and QFileInfo. - \li Prefer using Utils::QtcProcess over QProcess. - \li If Utils::FilePath or Utils::QtcProcess functionality is not sufficient + \li Prefer using Utils::Process over QProcess. + \li If Utils::FilePath or Utils::Process functionality is not sufficient for your purpose, prefer enhancing them over falling back to QString or QProcess. \li Avoid platform #ifdefs unless they are absolutely needed for locally From 99acc4440a66dbf25ed2dd38fc26a1e3d7c82f24 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 20 Jun 2024 10:52:21 +0200 Subject: [PATCH 06/73] Android: Provide more info when createAvd failed Fixes: QTCREATORBUG-30852 Change-Id: I9334a25c6e15a615dbf52736c9369821ba0ff8b9 Reviewed-by: Alessandro Portale --- src/plugins/android/androiddevice.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 7e6e715dc86..4972c653c9d 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -974,8 +974,12 @@ expected_str createAvd(const CreateAvdInfo &info, bool force) GuardLocker locker(s_instance->m_avdPathGuard); process.runBlocking(); - if (process.result() != ProcessResult::FinishedWithSuccess) - return Utils::make_unexpected(process.exitMessage()); + if (process.result() != ProcessResult::FinishedWithSuccess) { + const QString stdErr = process.stdErr(); + const QString errorMessage = stdErr.isEmpty() ? process.exitMessage() + : process.exitMessage() + "\n\n" + stdErr; + return Utils::make_unexpected(errorMessage); + } return {}; } From d8fa27cfbbdeb2980c75cdbe7e4da92593f81bad Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 21 Jun 2024 15:45:20 +0200 Subject: [PATCH 07/73] LanguageClient: Fix and export DynamicCapabilities This is useful to explicitly disable specific functionality from code in the case were the server reports capabilities we know are not stable or not usable. Change-Id: Iba1701c59258da6f30f32c33b477f3a650387491 Reviewed-by: Fabian Kosmale Reviewed-by: Semih Yavuz --- src/plugins/languageclient/client.cpp | 5 +++++ src/plugins/languageclient/client.h | 1 + src/plugins/languageclient/dynamiccapabilities.h | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 2ec4d41dbf3..412430171dc 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -1789,6 +1789,11 @@ const DynamicCapabilities &Client::dynamicCapabilities() const return d->m_dynamicCapabilities; } +DynamicCapabilities &Client::dynamicCapabilities() +{ + return d->m_dynamicCapabilities; +} + DocumentSymbolCache *Client::documentSymbolCache() { return &d->m_documentSymbolCache; diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index c80e458a472..28360c71a6f 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -97,6 +97,7 @@ public: QString serverName() const; QString serverVersion() const; const DynamicCapabilities &dynamicCapabilities() const; + DynamicCapabilities &dynamicCapabilities(); void registerCapabilities(const QList ®istrations); void unregisterCapabilities(const QList &unregistrations); diff --git a/src/plugins/languageclient/dynamiccapabilities.h b/src/plugins/languageclient/dynamiccapabilities.h index 076d578d8f3..13f8be74a6f 100644 --- a/src/plugins/languageclient/dynamiccapabilities.h +++ b/src/plugins/languageclient/dynamiccapabilities.h @@ -3,6 +3,8 @@ #pragma once +#include "languageclient_global.h" + #include namespace LanguageClient { @@ -21,7 +23,7 @@ public: void disable() { - m_enabled = true; + m_enabled = false; m_id.clear(); m_options = QJsonValue(); } @@ -37,7 +39,7 @@ private: }; -class DynamicCapabilities +class LANGUAGECLIENT_EXPORT DynamicCapabilities { public: DynamicCapabilities() = default; From df2e55d92a78e2e571f714fb2fc25478da5e0525 Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Thu, 20 Jun 2024 15:36:23 +0200 Subject: [PATCH 08/73] Opt out qmlls semantic highlighting Apperantly, qmlls semantic highlighting is not as powerful as the embedded code model's highlighter. Disable lsp based highlighting until qmlls semantic highlighting reaches the feature parity with the QtC highlighter. This is tracked by QTBUG-126550. Task-number: QTBUG-126550 Fixes: QTCREATORBUG-31083 Change-Id: I6cab94d4ba1d1cde50b62ce03a6b1cc5b6d7d27b Reviewed-by: Sami Shalayel Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmljseditordocument.cpp | 9 +++++---- src/plugins/qmljseditor/qmllsclient.cpp | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index 3dfb9b8f137..2d537422daf 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -728,10 +728,11 @@ void QmlJSEditorDocumentPrivate::setSourcesWithCapabilities( setSemanticWarningSource(QmllsStatus::Source::Qmlls); else setSemanticWarningSource(QmllsStatus::Source::EmbeddedCodeModel); - if (cap.semanticTokensProvider()) - setSemanticHighlightSource(QmllsStatus::Source::Qmlls); - else - setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel); + // TODO: uncomment when qmlls semantic tokens reach a stable state + // if (cap.semanticTokensProvider()) + // setSemanticHighlightSource(QmllsStatus::Source::Qmlls); + // else + setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel); } static Utils::FilePath qmllsForFile(const Utils::FilePath &file, diff --git a/src/plugins/qmljseditor/qmllsclient.cpp b/src/plugins/qmljseditor/qmllsclient.cpp index 6ec46774f30..9fe50a5af7e 100644 --- a/src/plugins/qmljseditor/qmllsclient.cpp +++ b/src/plugins/qmljseditor/qmllsclient.cpp @@ -66,6 +66,10 @@ QmllsClient *QmllsClient::clientForQmlls(const FilePath &qmlls) QmllsClient::QmllsClient(StdIOClientInterface *interface) : Client(interface) { + LanguageServerProtocol::Unregistration unregister; + unregister.setMethod("textDocument/semanticTokens"); + unregister.setId({}); + dynamicCapabilities().unregisterCapability({unregister}); } QmllsClient::~QmllsClient() From 03e35aac14c8ee2d9531297b658b4106b11c303b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 20 Jun 2024 10:01:18 +0200 Subject: [PATCH 09/73] Core: Fix selecting recent document with arrow keys The editor actions are defined in the editor since the removal of the TextEditorActionHandler. So we potentially capture the ctrl+up/down in the editor. Fix this by overwriting the shortcuts in the event handler of the open editor widget. Fixes: QTCREATORBUG-31072 Change-Id: I45217962bcb2ef3ae8ebed7c4a6d0412bcc0216b Reviewed-by: Eike Ziller --- .../coreplugin/editormanager/openeditorswindow.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp index d59f49bf803..606f6b0f683 100644 --- a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp +++ b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp @@ -161,6 +161,17 @@ void OpenEditorsWindow::setVisible(bool visible) bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e) { if (obj == m_editorView) { + if (e->type() == QEvent::ShortcutOverride) { + auto ke = static_cast(e); + if (ke->key() == Qt::Key_Up) { + selectPreviousEditor(); + return true; + } + if (ke->key() == Qt::Key_Down) { + selectNextEditor(); + return true; + } + } if (e->type() == QEvent::KeyPress) { auto ke = static_cast(e); if (ke->key() == Qt::Key_Escape) { From e6299f510d44b5b57913026da3625ded316d848b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 21 Jun 2024 14:19:37 +0200 Subject: [PATCH 10/73] Core: allow selecting recent documents with Ctrl+N/P This is more in line with other list popups like the locator or the completion widgets. Task-number: QTCREATORBUG-31072 Change-Id: Ic3c8a7de2791473c693bd21c661e3e5b85ff21a7 Reviewed-by: Eike Ziller --- .../editormanager/openeditorswindow.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp index 606f6b0f683..0967fb16e6e 100644 --- a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp +++ b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp @@ -163,13 +163,23 @@ bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e) if (obj == m_editorView) { if (e->type() == QEvent::ShortcutOverride) { auto ke = static_cast(e); - if (ke->key() == Qt::Key_Up) { + switch (ke->key()) { + case Qt::Key_Up: selectPreviousEditor(); return true; - } - if (ke->key() == Qt::Key_Down) { + case Qt::Key_Down: selectNextEditor(); return true; + case Qt::Key_P: + case Qt::Key_N: + if (ke->modifiers() == Qt::KeyboardModifiers(HostOsInfo::controlModifier())) { + if (ke->key() == Qt::Key_P) + selectPreviousEditor(); + else + selectNextEditor(); + return true; + } + break; } } if (e->type() == QEvent::KeyPress) { From 322679db16f01c21a3a0f388de0d216af11bfe0e Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Wed, 12 Jun 2024 16:07:27 +0200 Subject: [PATCH 11/73] CppEditor: Fix folding after comment Fixes: QTCREATORBUG-5110 Change-Id: I65e0245d68ed41ab0cfc85cedbee21584b6fa90f Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cpphighlighter.cpp | 41 ++++++++++++++++--- src/plugins/cppeditor/cpphighlighter.h | 2 + .../testcases/highlightingtestcase.cpp | 21 ++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 952d74707a2..ff8ebc53d3b 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -81,8 +81,6 @@ void CppHighlighter::highlightBlock(const QString &text) return; } - const int firstNonSpace = tokens.first().utf16charsBegin(); - // Keep "semantic parentheses". Parentheses parentheses; if (TextBlockUserData *userData = TextDocumentLayout::textUserData(currentBlock())) { @@ -121,9 +119,16 @@ void CppHighlighter::highlightBlock(const QString &text) if (tk.is(T_LBRACE)) { ++braceDepth; - // if a folding block opens at the beginning of a line, treat the entire line - // as if it were inside the folding block - if (tk.utf16charsBegin() == firstNonSpace) { + // if a folding block opens at the beginning of a line, treat the line before + // as if it were inside the folding block except if it is a comment or the line does + // end with ; + const int firstNonSpace = tokens.first().utf16charsBegin(); + const QString prevBlockText = currentBlock().previous().isValid() + ? currentBlock().previous().text().trimmed() + : QString(); + if (!prevBlockText.isEmpty() && !prevBlockText.startsWith("//") + && !prevBlockText.endsWith("*/") && !prevBlockText.endsWith(";") + && tk.utf16charsBegin() == firstNonSpace) { ++foldingIndent; TextDocumentLayout::userData(currentBlock())->setFoldingStartIncluded(true); } @@ -653,6 +658,32 @@ void CppHighlighterTest::testParentheses() QCOMPARE(TextDocumentLayout::parentheses(block).count(), expectedParenCount); } +void CppHighlighterTest::testFoldingIndent_data() +{ + QTest::addColumn("line"); + QTest::addColumn("expectedFoldingIndent"); + QTest::addColumn("expectedFoldingIndentNextLine"); + + QTest::newRow("braces after one line comment") << 52 << 0 << 1; + QTest::newRow("braces after multiline comment") << 59 << 0 << 1; + QTest::newRow("braces after completed line") << 67 << 1 << 2; +} + +void CppHighlighterTest::testFoldingIndent() +{ + QFETCH(int, line); + QFETCH(int, expectedFoldingIndent); + QFETCH(int, expectedFoldingIndentNextLine); + + QTextBlock block = m_doc.findBlockByNumber(line - 1); + QVERIFY(block.isValid()); + QCOMPARE(TextDocumentLayout::foldingIndent(block), expectedFoldingIndent); + + QTextBlock nextBlock = m_doc.findBlockByNumber(line); + QVERIFY(nextBlock.isValid()); + QCOMPARE(TextDocumentLayout::foldingIndent(nextBlock), expectedFoldingIndentNextLine); +} + } // namespace Internal #endif // WITH_TESTS diff --git a/src/plugins/cppeditor/cpphighlighter.h b/src/plugins/cppeditor/cpphighlighter.h index 5a6af63adaf..70fe8525c2c 100644 --- a/src/plugins/cppeditor/cpphighlighter.h +++ b/src/plugins/cppeditor/cpphighlighter.h @@ -54,6 +54,8 @@ private slots: void test(); void testParentheses_data(); void testParentheses(); + void testFoldingIndent_data(); + void testFoldingIndent(); private: QTextDocument m_doc; diff --git a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp index a9102ce4578..92b4e21a260 100644 --- a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp +++ b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp @@ -47,3 +47,24 @@ static void parenTest() const char* s7 = R"( ))"; + +// comment +{ + +} + +/* + * + */ +{ + +} + +static void parenTest2() +{ + + parenTest(); + { + + } +} From 6cfcd62c9d5a299e2b47e63f6dd0e8fbfdd05713 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 24 Jun 2024 10:50:57 +0200 Subject: [PATCH 12/73] GitHub Actions: Fix beta/rc tag handling and update versions The beta/rc tag was not properly handled and all beta/rc releases were marked as final releases. The updated from actions/*@v3 to actions/*@v4 will get rid of the node.js update warnings. Lastly the macos-latest runner is actually 14 nowadays. Change-Id: Ia4483012195fcac938ed0eec59d9e9812f1f3c05 Reviewed-by: Eike Ziller --- .github/workflows/build_cmake.yml | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 6f0223b578b..7cbe1ce5b7f 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -49,13 +49,12 @@ jobs: } - { name: "macOS Latest Clang", artifact: "macos-universal", - # TODO: move back to macos-latest when macos-latest is 13 or higher - os: macos-13, + os: macos-latest, cc: "clang", cxx: "clang++" } steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Checkout submodules id: git shell: cmake -P {0} @@ -63,10 +62,10 @@ jobs: execute_process(COMMAND git submodule set-url -- perfparser https://code.qt.io/qt-creator/perfparser.git) execute_process(COMMAND git submodule update --init --recursive) file(MAKE_DIRECTORY release) - if (${{github.ref}} MATCHES "tags/v([0-9.]+)") + if (${{github.ref}} MATCHES "tags/v(([0-9.]+).*)") file(APPEND "$ENV{GITHUB_OUTPUT}" "tag=${CMAKE_MATCH_1}\n") - if (EXISTS "dist/changelog/changes-${CMAKE_MATCH_1}.md") - file(READ "dist/changelog/changes-${CMAKE_MATCH_1}.md" changelog_md) + if (EXISTS "dist/changelog/changes-${CMAKE_MATCH_2}.md") + file(READ "dist/changelog/changes-${CMAKE_MATCH_2}.md" changelog_md) endif() file(WRITE "release/changelog.md" "These packages are not officially supported, for official packages please check out https://download.qt.io/official_releases/qtcreator\n\n") file(APPEND "release/changelog.md" "${changelog_md}") @@ -695,41 +694,41 @@ jobs: endif() - name: Upload - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z name: qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z - name: Upload Devel - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}_dev.7z name: qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}_dev.7z - name: Upload wininterrupt if: runner.os == 'Windows' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/wininterrupt-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z name: wininterrupt-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z - name: Upload qtcreatorcdbext if: runner.os == 'Windows' && matrix.config.is_msvc - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/qtcreatorcdbext-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z name: qtcreatorcdbext-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z - name: Upload Debian package if: runner.os == 'Linux' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/build/qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.deb name: qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.deb - name: Upload disk image if: runner.os == 'macOS' && contains(github.ref, 'tags/v') - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: build/qt-creator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.dmg name: qt-creator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.dmg @@ -739,14 +738,14 @@ jobs: run: cmake -E tar cf ../${{ steps.ccache.outputs.archive_name }}.tar . - name: Upload ccache archive - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: ./${{ steps.ccache.outputs.archive_name }}.tar name: ${{ steps.ccache.outputs.archive_name }} - name: Upload Release Changelog if: contains(github.ref, 'tags/v') - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: ./release/changelog.md name: changelog.md @@ -758,7 +757,7 @@ jobs: steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: release-with-dirs @@ -770,7 +769,7 @@ jobs: - name: Create Release id: create_release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: From 595c2051d246a378292a7b090f32578b0d5ff770 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 24 Jun 2024 10:28:56 +0200 Subject: [PATCH 13/73] COIN: Fix the branch used for tqtc-qtsdk 'master' was changed to 'production' Change-Id: Iffbf6dad061e0a9a86d456410dcde55a9ff21fb9 Reviewed-by: Patrik Teivonen Reviewed-by: Eike Ziller --- coin/instructions/provision.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coin/instructions/provision.yaml b/coin/instructions/provision.yaml index 7b84c6e3baa..a5dad3955c6 100644 --- a/coin/instructions/provision.yaml +++ b/coin/instructions/provision.yaml @@ -20,7 +20,7 @@ instructions: maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 project: qtsdk/tqtc-qtsdk - ref: master + ref: production directory: "build/tqtc-qtsdk" userMessageOnFailure: "Failed to install tqtc-qtsdk, check logs" - type: Group From c3de8c7f318c90234bd109ec8cc6ab618eab5d52 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Jun 2024 09:17:32 +0200 Subject: [PATCH 14/73] SshParameters: Remove return value from setupSshEnvironment() Change-Id: I3e58454f23b5828991a5da1a88913f68d0f3ac9b Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/devicesupport/sshparameters.cpp | 4 +--- src/plugins/projectexplorer/devicesupport/sshparameters.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp index 2b2ebdabc00..c266055003c 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp @@ -75,12 +75,11 @@ QStringList SshParameters::connectionOptions(const FilePath &binary) const return args; } -bool SshParameters::setupSshEnvironment(Process *process) +void SshParameters::setupSshEnvironment(Process *process) { Environment env = process->controlEnvironment(); if (!env.hasChanges()) env = Environment::systemEnvironment(); - const bool hasDisplay = env.hasKey("DISPLAY") && (env.value("DISPLAY") != QString(":0")); if (SshSettings::askpassFilePath().exists()) { env.set("SSH_ASKPASS", SshSettings::askpassFilePath().toUserOutput()); env.set("SSH_ASKPASS_REQUIRE", "force"); @@ -93,7 +92,6 @@ bool SshParameters::setupSshEnvironment(Process *process) // Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly. process->setDisableUnixTerminal(); - return hasDisplay; } bool operator==(const SshParameters &p1, const SshParameters &p2) diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.h b/src/plugins/projectexplorer/devicesupport/sshparameters.h index 5a5f32da268..da57f2c5aa2 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.h +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.h @@ -46,7 +46,7 @@ public: AuthenticationType authenticationType = AuthenticationTypeAll; SshHostKeyCheckingMode hostKeyCheckingMode = SshHostKeyCheckingAllowNoMatch; - static bool setupSshEnvironment(Utils::Process *process); + static void setupSshEnvironment(Utils::Process *process); friend PROJECTEXPLORER_EXPORT bool operator==(const SshParameters &p1, const SshParameters &p2); friend bool operator!=(const SshParameters &p1, const SshParameters &p2) { return !(p1 == p2); } From a41c4de3df3cd120095da646e656597e10f6e3bf Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 21 Jun 2024 12:05:30 +0200 Subject: [PATCH 15/73] CMakePM: Do not hang on renaming files in parent directories This fixes renaming of "my/class.cpp my/class.h" via "../class.h" and resulting into "class.cpp class.h". "oldRelPathName" was not needed since it was saved in the "m_filesToBeRenamed" map and it was computed from the new filename. This was prone to error. Task-number: QTCREATORBUG-30830 Change-Id: I839fab3bd6a6172f5ebfbaf9a4b6501cd5693fa8 Reviewed-by: Alessandro Portale --- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index e0d2b6773fb..f1c3731d4f2 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -936,10 +936,6 @@ bool CMakeBuildSystem::renameFile(Node *context, const FilePath newRelPath = newFilePath.canonicalPath().relativePathFrom(projDir).cleanPath(); const QString newRelPathName = newRelPath.toString(); - // FilePath needs the file to exist on disk, the old file has already been renamed - const QString oldRelPathName - = newRelPath.parentDir().pathAppended(oldFilePath.fileName()).cleanPath().toString(); - const QString targetName = n->buildKey(); const QString key = QStringList{projDir.path(), targetName, oldFilePath.path(), newFilePath.path()}.join( @@ -984,7 +980,7 @@ bool CMakeBuildSystem::renameFile(Node *context, } // Try the next occurrence. This can happen if set_source_file_properties is used - fileToRename = projectFileArgumentPosition(targetName, oldRelPathName); + fileToRename = projectFileArgumentPosition(targetName, fileToRename->relativeFileName); } while (fileToRename && !fileToRename->fromGlobbing); return true; From 81163b431e68f281bd7c6cdd4e6c8ba279ff9155 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 6 Jun 2024 14:40:58 +0200 Subject: [PATCH 16/73] ExtensionManager: Implement Extension details design This implements the design for the "right side" of the extension manager. The introduced "header" shows the extension icon in a slightly bigger variant. The "Install..." button that starts downloading and installing of a plugin moved to the newly desigend "header". The previous HTML based prototype has been split up into separate items in order to achieve specialized sections like the images and tags. Images are loaded via TaskTree and displayed as static image or as animation. Change-Id: Ifaf4a46c0a4789e77e76f9a44c8a15ee74c5e8df Reviewed-by: Cristian Adam --- .../extensionmanager/extensionmanager.qrc | 4 + .../extensionmanager_test.qrc | 1 + .../extensionmanagerwidget.cpp | 649 +++++++++++++----- .../extensionmanager/extensionmanagerwidget.h | 1 + .../extensionmanager/extensionsbrowser.cpp | 78 ++- .../extensionmanager/extensionsbrowser.h | 11 + .../extensionmanager/images/extensionbig.png | Bin 0 -> 509 bytes .../images/extensionbig@2x.png | Bin 0 -> 1037 bytes .../extensionmanager/images/packbig.png | Bin 0 -> 455 bytes .../extensionmanager/images/packbig@2x.png | Bin 0 -> 785 bytes .../extensionmanager/testdata/varieddata.json | 76 ++ src/tools/icons/qtcreatoricons.svg | 33 + 12 files changed, 648 insertions(+), 205 deletions(-) create mode 100644 src/plugins/extensionmanager/images/extensionbig.png create mode 100644 src/plugins/extensionmanager/images/extensionbig@2x.png create mode 100644 src/plugins/extensionmanager/images/packbig.png create mode 100644 src/plugins/extensionmanager/images/packbig@2x.png create mode 100644 src/plugins/extensionmanager/testdata/varieddata.json diff --git a/src/plugins/extensionmanager/extensionmanager.qrc b/src/plugins/extensionmanager/extensionmanager.qrc index b6a3554cb1f..b552aaf7b59 100644 --- a/src/plugins/extensionmanager/extensionmanager.qrc +++ b/src/plugins/extensionmanager/extensionmanager.qrc @@ -2,10 +2,14 @@ images/download.png images/download@2x.png + images/extensionbig.png + images/extensionbig@2x.png images/extensionsmall.png images/extensionsmall@2x.png images/mode_extensionmanager_mask.png images/mode_extensionmanager_mask@2x.png + images/packbig.png + images/packbig@2x.png images/packsmall.png images/packsmall@2x.png diff --git a/src/plugins/extensionmanager/extensionmanager_test.qrc b/src/plugins/extensionmanager/extensionmanager_test.qrc index 4c4d59f002d..f8a11b4e084 100644 --- a/src/plugins/extensionmanager/extensionmanager_test.qrc +++ b/src/plugins/extensionmanager/extensionmanager_test.qrc @@ -2,5 +2,6 @@ testdata/defaultpacks.json testdata/thirdpartyplugins.json + testdata/varieddata.json diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 363b8cb90ee..dea2f9e806f 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -33,16 +33,56 @@ #include #include +#include +#include #include +#include +#include #include -#include +#include +#include #include +#include +#include using namespace Core; using namespace Utils; +using namespace StyleHelper; +using namespace WelcomePageHelpers; namespace ExtensionManager::Internal { +constexpr TextFormat h5TF + {Theme::Token_Text_Default, UiElement::UiElementH5}; +constexpr TextFormat h6TF + {h5TF.themeColor, UiElement::UiElementH6}; +constexpr TextFormat h6CapitalTF + {Theme::Token_Text_Muted, UiElement::UiElementH6Capital}; +constexpr TextFormat contentTF + {Theme::Token_Text_Default, UiElement::UiElementBody2}; + +static QLabel *sectionTitle(const TextFormat &tf, const QString &title) +{ + QLabel *label = tfLabel(tf, true); + label->setText(title); + return label; +}; + +static QWidget *toScrollableColumn(QWidget *widget) +{ + widget->setContentsMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl, + SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl); + widget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum); + + auto scrollArea = new QScrollArea; + scrollArea->setWidget(widget); + scrollArea->setWidgetResizable(true); + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setFrameStyle(QFrame::NoFrame); + + return scrollArea; +}; + class CollapsingWidget : public QWidget { public: @@ -68,6 +108,169 @@ private: int m_width = 100; }; +class HeadingWidget : public QWidget +{ + static constexpr QSize iconBgS{68, 68}; + static constexpr int dividerH = 16; + + Q_OBJECT + +public: + explicit HeadingWidget(QWidget *parent = nullptr) + : QWidget(parent) + { + m_icon = new QLabel; + m_icon->setFixedSize(iconBgS); + + static const TextFormat titleTF + {Theme::Token_Text_Default, UiElementH4}; + static const TextFormat vendorTF + {Theme::Token_Text_Accent, UiElementLabelMedium}; + static const TextFormat dlTF + {Theme::Token_Text_Muted, vendorTF.uiElement}; + static const TextFormat detailsTF + {Theme::Token_Text_Default, UiElementBody2}; + + m_title = tfLabel(titleTF); + m_vendor = new Button({}, Button::SmallLink); + m_vendor->setContentsMargins({}); + m_divider = new QLabel; + m_divider->setFixedSize(1, dividerH); + WelcomePageHelpers::setBackgroundColor(m_divider, dlTF.themeColor); + m_dlIcon = new QLabel; + const QPixmap dlIcon = Icon({{":/extensionmanager/images/download.png", dlTF.themeColor}}, + Icon::Tint).pixmap(); + m_dlIcon->setPixmap(dlIcon); + m_dlCount = tfLabel(dlTF); + m_dlCount->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + m_details = tfLabel(detailsTF); + installButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); + installButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + installButton->hide(); + + using namespace Layouting; + Row { + m_icon, + Column { + m_title, + st, + Row { + m_vendor, + Widget { + bindTo(&m_dlCountItems), + Row { + Space(SpacingTokens::HGapXs), + m_divider, + Space(SpacingTokens::HGapXs), + m_dlIcon, + Space(SpacingTokens::HGapXxs), + m_dlCount, + noMargin, spacing(0), + }, + }, + }, + st, + m_details, + spacing(0), + }, + Column { + installButton, + st, + }, + noMargin, spacing(SpacingTokens::ExPaddingGapL), + }.attachTo(this); + + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); + m_dlCountItems->setVisible(false); + + connect(installButton, &QAbstractButton::pressed, + this, &HeadingWidget::pluginInstallationRequested); + connect(m_vendor, &QAbstractButton::pressed, this, [this]() { + emit vendorClicked(m_currentVendor); + }); + + update({}); + } + + void update(const QModelIndex ¤t) + { + if (!current.isValid()) + return; + + m_icon->setPixmap(icon(current)); + + const QString name = current.data(RoleName).toString(); + m_title->setText(name); + + m_currentVendor = current.data(RoleVendor).toString(); + m_vendor->setText(m_currentVendor); + + const int dlCount = current.data(RoleDownloadCount).toInt(); + const bool showDlCount = dlCount > 0; + if (showDlCount) + m_dlCount->setText(QString::number(dlCount)); + m_dlCountItems->setVisible(showDlCount); + + const auto pluginData = current.data(RolePlugins).value(); + if (current.data(RoleItemType).toInt() == ItemTypePack) { + const int pluginsCount = pluginData.count(); + const QString details = Tr::tr("Pack contains %n plugins.", nullptr, pluginsCount); + m_details->setText(details); + } else { + m_details->setText({}); + } + + const ItemType itemType = current.data(RoleItemType).value(); + const bool isPack = itemType == ItemTypePack; + const bool isRemotePlugin = !(isPack || ExtensionsModel::pluginSpecForName(name)); + installButton->setVisible(isRemotePlugin && !pluginData.empty()); + if (installButton->isVisible()) + installButton->setToolTip(pluginData.constFirst().second); + } + +signals: + void pluginInstallationRequested(); + void vendorClicked(const QString &vendor); + +private: + static QPixmap icon(const QModelIndex &index) + { + const qreal dpr = qApp->devicePixelRatio(); + QPixmap pixmap(iconBgS * dpr); + pixmap.fill(Qt::transparent); + pixmap.setDevicePixelRatio(dpr); + const QRect bgR(QPoint(), pixmap.deviceIndependentSize().toSize()); + + QPainter p(&pixmap); + QLinearGradient gradient(bgR.topRight(), bgR.bottomLeft()); + gradient.setStops(iconGradientStops(index)); + constexpr int iconRectRounding = 4; + WelcomePageHelpers::drawCardBackground(&p, bgR, gradient, Qt::NoPen, iconRectRounding); + + // Icon + constexpr Theme::Color color = Theme::Token_Basic_White; + static const QIcon pack = Icon({{":/extensionmanager/images/packbig.png", color}}, + Icon::Tint).icon(); + static const QIcon extension = Icon({{":/extensionmanager/images/extensionbig.png", + color}}, Icon::Tint).icon(); + const ItemType itemType = index.data(RoleItemType).value(); + (itemType == ItemTypePack ? pack : extension).paint(&p, bgR); + + return pixmap; + } + + QLabel *m_icon; + QLabel *m_title; + Button *m_vendor; + QLabel *m_divider; + QLabel *m_dlIcon; + QLabel *m_dlCount; + QWidget *m_dlCountItems; + QLabel *m_details; + QAbstractButton *installButton; + QString m_currentVendor; +}; + class PluginStatusWidget : public QWidget { public: @@ -128,49 +331,149 @@ private: QString m_pluginName; }; +class TagList : public QWidget +{ + Q_OBJECT + +public: + explicit TagList(QWidget *parent = nullptr) + : QWidget(parent) + { + QHBoxLayout *layout = new QHBoxLayout(this); + setLayout(layout); + layout->setContentsMargins({}); + m_signalMapper = new QSignalMapper(this); + connect(m_signalMapper, &QSignalMapper::mappedString, this, &TagList::tagSelected); + } + + void setTags(const QStringList &tags) + { + if (m_container) { + delete m_container; + m_container = nullptr; + } + + if (!tags.empty()) { + m_container = new QWidget(this); + layout()->addWidget(m_container); + + using namespace Layouting; + Flow flow {}; + flow.setNoMargins(); + flow.setSpacing(SpacingTokens::HGapXs); + + for (const QString &tag : tags) { + QAbstractButton *tagButton = new Button(tag, Button::Tag); + connect(tagButton, &QAbstractButton::clicked, + m_signalMapper, qOverload<>(&QSignalMapper::map)); + m_signalMapper->setMapping(tagButton, tag); + flow.addItem(tagButton); + } + + flow.attachTo(m_container); + } + + updateGeometry(); + } + +signals: + void tagSelected(const QString &tag); + +private: + QWidget *m_container = nullptr; + QSignalMapper *m_signalMapper; +}; + class ExtensionManagerWidgetPrivate { public: QString currentItemName; - ExtensionsBrowser *leftColumn; + ExtensionsBrowser *extensionBrowser; CollapsingWidget *secondaryDescriptionWidget; - QTextBrowser *primaryDescription; - QTextBrowser *secondaryDescription; + HeadingWidget *headingWidget; + QWidget *primaryContent; + QWidget *secondaryContent; + QLabel *description; + QLabel *linksTitle; + QLabel *links; + QLabel *imageTitle; + QLabel *image; + QBuffer imageDataBuffer; + QMovie imageMovie; + QLabel *tagsTitle; + TagList *tags; + QLabel *platformsTitle; + QLabel *platforms; + QLabel *dependenciesTitle; + QLabel *dependencies; + QLabel *packExtensionsTitle; + QLabel *packExtensions; PluginStatusWidget *pluginStatus; - QAbstractButton *installButton; PluginsData currentItemPlugins; - Tasking::TaskTreeRunner taskTreeRunner; + Tasking::TaskTreeRunner dlTaskTreeRunner; + Tasking::TaskTreeRunner imgTaskTreeRunner; }; ExtensionManagerWidget::ExtensionManagerWidget(QWidget *parent) : ResizeSignallingWidget(parent) , d(new ExtensionManagerWidgetPrivate) { - d->leftColumn = new ExtensionsBrowser; - + d->extensionBrowser = new ExtensionsBrowser; auto descriptionColumns = new QWidget; - d->secondaryDescriptionWidget = new CollapsingWidget; - d->primaryDescription = new QTextBrowser; - d->primaryDescription->setOpenExternalLinks(true); - d->primaryDescription->setFrameStyle(QFrame::NoFrame); - - d->secondaryDescription = new QTextBrowser; - d->secondaryDescription->setFrameStyle(QFrame::NoFrame); - - d->pluginStatus = new PluginStatusWidget; - - d->installButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); - d->installButton->hide(); + d->headingWidget = new HeadingWidget; + d->description = tfLabel(contentTF, false); + d->description->setWordWrap(true); + d->linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information")); + d->links = tfLabel(contentTF, false); + d->imageTitle = sectionTitle(h6CapitalTF, {}); + d->image = new QLabel; + d->imageMovie.setDevice(&d->imageDataBuffer); using namespace Layouting; + auto primary = new QWidget; + const auto spL = spacing(SpacingTokens::VPaddingL); + Column { + d->description, + Column { d->linksTitle, d->links, spL }, + Column { d->imageTitle, d->image, spL }, + st, + noMargin, spacing(SpacingTokens::ExVPaddingGapXl), + }.attachTo(primary); + d->primaryContent = toScrollableColumn(primary); + + d->tagsTitle = sectionTitle(h6TF, Tr::tr("Tags")); + d->tags = new TagList; + d->platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms")); + d->platforms = tfLabel(contentTF, false); + d->dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies")); + d->dependencies = tfLabel(contentTF, false); + d->packExtensionsTitle = sectionTitle(h6TF, Tr::tr("Extensions in pack")); + d->packExtensions = tfLabel(contentTF, false); + d->pluginStatus = new PluginStatusWidget; + + auto secondary = new QWidget; + const auto spXxs = spacing(SpacingTokens::VPaddingXxs); + Column { + sectionTitle(h6CapitalTF, Tr::tr("Extension details")), + Column { + Column { d->tagsTitle, d->tags, spXxs }, + Column { d->platformsTitle, d->platforms, spXxs }, + Column { d->dependenciesTitle, d->dependencies, spXxs }, + Column { d->packExtensionsTitle, d->packExtensions, spXxs }, + spacing(SpacingTokens::VPaddingL), + }, + st, + noMargin, spacing(SpacingTokens::ExVPaddingGapXl), + }.attachTo(secondary); + d->secondaryContent = toScrollableColumn(secondary); + Row { WelcomePageHelpers::createRule(Qt::Vertical), Column { - d->secondaryDescription, + d->secondaryContent, d->pluginStatus, - d->installButton, }, noMargin, spacing(0), }.attachTo(d->secondaryDescriptionWidget); @@ -178,34 +481,44 @@ ExtensionManagerWidget::ExtensionManagerWidget(QWidget *parent) Row { WelcomePageHelpers::createRule(Qt::Vertical), Row { - d->primaryDescription, - noMargin, + Column { + Column { + d->headingWidget, + customMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl, + SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl), + }, + d->primaryContent, + }, }, d->secondaryDescriptionWidget, noMargin, spacing(0), }.attachTo(descriptionColumns); Row { - Space(StyleHelper::SpacingTokens::ExVPaddingGapXl), - d->leftColumn, + Space(SpacingTokens::ExVPaddingGapXl), + d->extensionBrowser, descriptionColumns, noMargin, spacing(0), }.attachTo(this); WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default); - connect(d->leftColumn, &ExtensionsBrowser::itemSelected, + connect(d->extensionBrowser, &ExtensionsBrowser::itemSelected, this, &ExtensionManagerWidget::updateView); connect(this, &ResizeSignallingWidget::resized, this, [this](const QSize &size) { - const int intendedLeftColumnWidth = size.width() - 580; - d->leftColumn->adjustToWidth(intendedLeftColumnWidth); + const int intendedBrowserColumnWidth = size.width() - 580; + d->extensionBrowser->adjustToWidth(intendedBrowserColumnWidth); const bool secondaryDescriptionVisible = size.width() > 970; const int secondaryDescriptionWidth = secondaryDescriptionVisible ? 264 : 0; d->secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth); }); - connect(d->installButton, &QAbstractButton::pressed, this, [this]() { + connect(d->headingWidget, &HeadingWidget::pluginInstallationRequested, this, [this](){ fetchAndInstallPlugin(QUrl::fromUserInput(d->currentItemPlugins.constFirst().second)); }); + connect(d->tags, &TagList::tagSelected, d->extensionBrowser, &ExtensionsBrowser::setFilter); + connect(d->headingWidget, &HeadingWidget::vendorClicked, + d->extensionBrowser, &ExtensionsBrowser::setFilter); + updateView({}); } @@ -216,199 +529,116 @@ ExtensionManagerWidget::~ExtensionManagerWidget() void ExtensionManagerWidget::updateView(const QModelIndex ¤t) { - const QString h5Css = - StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH5)) - + "; margin-top: 0px;"; - const QString h6Css = - StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH6)) - + "; margin-top: 28px;"; - const QString h6CapitalCss = - StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH6Capital)) - + QString::fromLatin1("; margin-top: 0px; color: %1;") - .arg(creatorColor(Theme::Token_Text_Muted).name()); - const QString bodyStyle = QString::fromLatin1("color: %1; background-color: %2; " - "margin-left: %3px; margin-right: %3px;") - .arg(creatorColor(Theme::Token_Text_Default).name()) - .arg(creatorColor(Theme::Token_Background_Muted).name()) - .arg(StyleHelper::SpacingTokens::ExVPaddingGapXl); - const QString htmlStart = QString(R"( - -
- )").arg(bodyStyle); - const QString htmlEnd = QString(R"( - - )"); + d->headingWidget->update(current); - if (!current.isValid()) { - const QString emptyHtml = htmlStart + htmlEnd; - d->primaryDescription->setText(emptyHtml); - d->secondaryDescription->setText(emptyHtml); + const bool showContent = current.isValid(); + d->primaryContent->setVisible(showContent); + d->secondaryContent->setVisible(showContent); + if (!showContent) return; - } d->currentItemName = current.data().toString(); const bool isPack = current.data(RoleItemType) == ItemTypePack; d->pluginStatus->setPluginName(isPack ? QString() : d->currentItemName); - const bool isRemotePlugin = !(isPack || ExtensionsModel::pluginSpecForName(d->currentItemName)); d->currentItemPlugins = current.data(RolePlugins).value(); - d->installButton->setVisible(isRemotePlugin && !d->currentItemPlugins.empty()); - if (!d->currentItemPlugins.empty()) - d->installButton->setToolTip(d->currentItemPlugins.constFirst().second); + + auto toContentParagraph = [](const QString &text) { + const QString pHtml = QString::fromLatin1("

%2

") + .arg(contentTF.lineHeight()).arg(text); + return pHtml; + }; { - QString description = htmlStart; - - QString descriptionHtml; - { - const TextData textData = current.data(RoleDescriptionText).value(); + const TextData textData = current.data(RoleDescriptionText).value(); + const bool hasDescription = !textData.isEmpty(); + if (hasDescription) { + const QString headerCssTemplate = + ";margin-top:%1;margin-bottom:%2;padding-top:0;padding-bottom:0;"; + const QString h4Css = fontToCssProperties(uiFont(UiElementH4)) + + headerCssTemplate.arg(0).arg(SpacingTokens::VGapL); + const QString h5Css = fontToCssProperties(uiFont(UiElementH5)) + + headerCssTemplate.arg(SpacingTokens::ExVPaddingGapXl) + .arg(SpacingTokens::VGapL); + QString descriptionHtml; for (const TextData::Type &text : textData) { if (text.second.isEmpty()) continue; const QString paragraph = - QString::fromLatin1("
%2

%3

") - .arg(descriptionHtml.isEmpty() ? h5Css : h6Css) + QString::fromLatin1("
%2
%3") + .arg(descriptionHtml.isEmpty() ? h4Css : h5Css) .arg(text.first) - .arg(text.second.join("
")); + .arg(toContentParagraph(text.second.join("
"))); descriptionHtml.append(paragraph); } + descriptionHtml.prepend(QString::fromLatin1("") + .arg(creatorColor(Theme::Token_Text_Default).name())); + descriptionHtml.append(""); + d->description->setText(descriptionHtml); } - description.append(descriptionHtml); + d->description->setVisible(hasDescription); - description.append(QString::fromLatin1("
%2
") - .arg(h6Css) - .arg(Tr::tr("More information"))); const LinksData linksData = current.data(RoleDescriptionLinks).value(); - if (!linksData.isEmpty()) { + const bool hasLinks = !linksData.isEmpty(); + if (hasLinks) { QString linksHtml; const QStringList links = transform(linksData, [](const LinksData::Type &link) { const QString anchor = link.first.isEmpty() ? link.second : link.first; - return QString::fromLatin1("%2 >") - .arg(link.second).arg(anchor); + return QString::fromLatin1(R"(%3 >)") + .arg(link.second) + .arg(creatorColor(Theme::Token_Text_Accent).name()) + .arg(anchor); }); linksHtml = links.join("
"); - description.append(QString::fromLatin1("

%1

").arg(linksHtml)); + d->links->setText(toContentParagraph(linksHtml)); } + d->linksTitle->setVisible(hasLinks); + d->links->setVisible(hasLinks); + d->imgTaskTreeRunner.reset(); + d->imageMovie.stop(); + d->imageDataBuffer.close(); + d->image->clear(); const ImagesData imagesData = current.data(RoleDescriptionImages).value(); - if (!imagesData.isEmpty()) { - const QString examplesBoxCss = - QString::fromLatin1("height: 168px; background-color: %1; ") - .arg(creatorColor(Theme::Token_Background_Default).name()); - description.append(QString(R"( -
-
%2
-

-




- TODO: Load imagea asynchronously, and show them in a QLabel. - Also Use QMovie for animated images. -




-

- )").arg(h6CapitalCss) - .arg(Tr::tr("Examples")) - .arg(examplesBoxCss)); + const bool hasImages = !imagesData.isEmpty(); + if (hasImages) { + const ImagesData::Type &image = imagesData.constFirst(); // Only show one image + d->imageTitle->setText(image.first); + fetchAndDisplayImage(image.second); } - - // Library details vanished from the Figma designs. The data is available, though. - const bool showDetails = false; - if (showDetails) { - const QString captionStrongCss = StyleHelper::fontToCssProperties( - StyleHelper::uiFont(StyleHelper::UiElementCaptionStrong)); - const QLocale locale; - const uint size = current.data(RoleSize).toUInt(); - const QString sizeFmt = locale.formattedDataSize(size); - const FilePath location = FilePath::fromVariant(current.data(RoleLocation)); - const QString version = current.data(RoleVersion).toString(); - description.append(QString(R"( -
%2
-

- - - - )").arg(h6Css) - .arg(Tr::tr("Extension library details")) - .arg(captionStrongCss) - .arg(Tr::tr("Size")) - .arg(sizeFmt) - .arg(Tr::tr("Version")) - .arg(version)); - if (!location.isEmpty()) { - const QString locationFmt = - HostOsInfo::isWindowsHost() ? location.toUserOutput() - : location.withTildeHomePath(); - description.append(QString(R"( - - )").arg(Tr::tr("Location")) - .arg(locationFmt)); - } - description.append(QString(R"( -
%4%5
%6%7
%1%2
-

- )")); - } - - description.append(htmlEnd); - d->primaryDescription->setText(description); + d->imageTitle->setVisible(hasImages); + d->image->setVisible(hasImages); } { - QString description = htmlStart; - - description.append(QString(R"( -

%2

- )").arg(h6CapitalCss) - .arg(Tr::tr("Extension details"))); - const QStringList tags = current.data(RoleTags).toStringList(); - if (!tags.isEmpty()) { - const QString tagTemplate = QString(R"( - %2 - )").arg(creatorColor(Theme::Token_Stroke_Subtle).name()); - const QStringList tagsFmt = transform(tags, [&tagTemplate](const QString &tag) { - return tagTemplate.arg(tag); - }); - description.append(QString(R"( -
%2
-

%3

- )").arg(h6Css) - .arg(Tr::tr("Related tags")) - .arg(tagsFmt.join(" "))); - } + d->tags->setTags(tags); + const bool hasTags = !tags.isEmpty(); + d->tagsTitle->setVisible(hasTags); + d->tags->setVisible(hasTags); const QStringList platforms = current.data(RolePlatforms).toStringList(); - if (!platforms.isEmpty()) { - description.append(QString(R"( -
%2
-

%3

- )").arg(h6Css) - .arg(Tr::tr("Platforms")) - .arg(platforms.join("
"))); - } + const bool hasPlatforms = !platforms.isEmpty(); + if (hasPlatforms) + d->platforms->setText(toContentParagraph(platforms.join("
"))); + d->platformsTitle->setVisible(hasPlatforms); + d->platforms->setVisible(hasPlatforms); const QStringList dependencies = current.data(RoleDependencies).toStringList(); - if (!dependencies.isEmpty()) { - const QString dependenciesFmt = dependencies.join("
"); - description.append(QString(R"( -
%2
-

%3

- )").arg(h6Css) - .arg(Tr::tr("Dependencies")) - .arg(dependenciesFmt)); - } + const bool hasDependencies = !dependencies.isEmpty(); + if (hasDependencies) + d->dependencies->setText(toContentParagraph(dependencies.join("
"))); + d->dependenciesTitle->setVisible(hasDependencies); + d->dependencies->setVisible(hasDependencies); - if (isPack) { - const PluginsData plugins = current.data(RolePlugins).value(); + const PluginsData plugins = current.data(RolePlugins).value(); + const bool hasExtensions = isPack && !plugins.isEmpty(); + if (hasExtensions) { const QStringList extensions = transform(plugins, &QPair::first); - const QString extensionsFmt = extensions.join("
"); - description.append(QString(R"( -
%2
-

%3

- )").arg(h6Css) - .arg(Tr::tr("Extensions in pack")) - .arg(extensionsFmt)); + d->packExtensions->setText(toContentParagraph(extensions.join("
"))); } - - description.append(htmlEnd); - d->secondaryDescription->setText(description); + d->packExtensionsTitle->setVisible(hasExtensions); + d->packExtensions->setVisible(hasExtensions); } } @@ -469,7 +699,56 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url) onGroupDone(onPluginInstallation), }; - d->taskTreeRunner.start(group); + d->dlTaskTreeRunner.start(group); +} + +void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url) +{ + using namespace Tasking; + + struct StorageStruct + { + QByteArray imageData; + QUrl url; + }; + Storage storage; + + const auto onFetchSetup = [url, storage](NetworkQuery &query) { + storage->url = url; + query.setRequest(QNetworkRequest(url)); + query.setNetworkAccessManager(NetworkAccessManager::instance()); + }; + const auto onFetchDone = [storage](const NetworkQuery &query, DoneWith result) { + if (result == DoneWith::Success) + storage->imageData = query.reply()->readAll(); + }; + + const auto onShowImage = [storage, this]() { + if (storage->imageData.isEmpty()) + return; + d->imageDataBuffer.setData(storage->imageData); + if (!d->imageDataBuffer.open(QIODevice::ReadOnly)) + return; + QImageReader reader(&d->imageDataBuffer); + const bool animated = reader.supportsAnimation(); + if (animated) { + d->image->setMovie(&d->imageMovie); + d->imageMovie.start(); + } else { + const QPixmap pixmap = QPixmap::fromImage(reader.read()); + d->image->setPixmap(pixmap); + } + }; + + Group group{ + storage, + NetworkQueryTask{onFetchSetup, onFetchDone}, + onGroupDone(onShowImage), + }; + + d->imgTaskTreeRunner.start(group); } } // ExtensionManager::Internal + +#include "extensionmanagerwidget.moc" diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.h b/src/plugins/extensionmanager/extensionmanagerwidget.h index aeaad3db07c..dbc02daeca8 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.h +++ b/src/plugins/extensionmanager/extensionmanagerwidget.h @@ -14,6 +14,7 @@ public: private: void updateView(const QModelIndex ¤t); void fetchAndInstallPlugin(const QUrl &url); + void fetchAndDisplayImage(const QUrl &url); class ExtensionManagerWidgetPrivate *d = nullptr; }; diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index ccf814cd7c8..330c2395920 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -141,10 +142,7 @@ public: } { QLinearGradient gradient(iconBgR.topRight(), iconBgR.bottomLeft()); - const QColor startColor = creatorColor(Utils::Theme::Token_Gradient01_Start); - const QColor endColor = creatorColor(Utils::Theme::Token_Gradient01_End); - gradient.setColorAt(0, startColor); - gradient.setColorAt(1, endColor); + gradient.setStops(iconGradientStops(index)); constexpr int iconRectRounding = 4; drawCardBackground(painter, iconBgR, gradient, Qt::NoPen, iconRectRounding); @@ -267,11 +265,13 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) { setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); - auto manageLabel = new QLabel(Tr::tr("Manage Extensions")); - manageLabel->setFont(uiFont(UiElementH1)); + static const TextFormat titleTF + {Theme::Token_Text_Default, UiElementH2}; + QLabel *titleLabel = tfLabel(titleTF); + titleLabel->setText(Tr::tr("Manage Extensions")); d->searchBox = new SearchBox; - d->searchBox->setFixedWidth(itemWidth); + d->searchBox->setPlaceholderText(Tr::tr("Search")); d->updateButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); d->model = new ExtensionsModel(this); @@ -294,11 +294,17 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) using namespace Layouting; Column { - Space(15), - manageLabel, - Space(15), - Row { d->searchBox, st, d->updateButton, Space(extraListViewWidth() + gapSize) }, - Space(gapSize), + Column { + titleLabel, + customMargins(0, VPaddingM, 0, VPaddingM), + }, + Row { + d->searchBox, + d->updateButton, + spacing(gapSize), + customMargins(0, VPaddingM, extraListViewWidth() + gapSize, VPaddingM), + }, + Space(ExPaddingGapL), d->extensionsView, noMargin, spacing(0), }.attachTo(this); @@ -335,6 +341,11 @@ ExtensionsBrowser::~ExtensionsBrowser() delete d; } +void ExtensionsBrowser::setFilter(const QString &filter) +{ + d->searchBox->setText(filter); +} + void ExtensionsBrowser::adjustToWidth(const int width) { const int widthForItems = width - extraListViewWidth(); @@ -358,8 +369,6 @@ int ExtensionsBrowser::extraListViewWidth() const void ExtensionsBrowser::fetchExtensions() { - // d->model->setExtensionsJson(testData("thirdpartyplugins")); return; - using namespace Tasking; const auto onQuerySetup = [](NetworkQuery &query) { @@ -367,12 +376,11 @@ void ExtensionsBrowser::fetchExtensions() const QString url = "%1/api/v1/search?request="; const QString requestTemplate = R"({"version":"%1","host_os":"%2","host_os_version":"%3","host_architecture":"%4","page_size":200})"; - const QString request = url.arg(host) - + requestTemplate - .arg("2.2") // .arg(QCoreApplication::applicationVersion()) - .arg("macOS") // .arg(QSysInfo::productType()) - .arg("12") // .arg(QSysInfo::productVersion()) - .arg("arm64"); // .arg(QSysInfo::currentCpuArchitecture()); + const QString request = url.arg(host) + requestTemplate + .arg(QCoreApplication::applicationVersion()) + .arg(QSysInfo::productType()) + .arg(QSysInfo::productVersion()) + .arg(QSysInfo::currentCpuArchitecture()); query.setRequest(QNetworkRequest(QUrl::fromUserInput(request))); query.setNetworkAccessManager(NetworkAccessManager::instance()); @@ -380,6 +388,7 @@ void ExtensionsBrowser::fetchExtensions() const auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) { if (result != DoneWith::Success) { #ifdef WITH_TESTS + // Available test sets: "defaultpacks", "varieddata", "thirdpartyplugins" d->model->setExtensionsJson(testData("defaultpacks")); #endif // WITH_TESTS return; @@ -395,4 +404,33 @@ void ExtensionsBrowser::fetchExtensions() d->taskTreeRunner.start(group); } +QLabel *tfLabel(const TextFormat &tf, bool singleLine) +{ + QLabel *label = singleLine ? new Utils::ElidingLabel : new QLabel; + if (singleLine) + label->setFixedHeight(tf.lineHeight()); + label->setFont(tf.font()); + label->setAlignment(Qt::Alignment(tf.drawTextFlags)); + + QPalette pal = label->palette(); + pal.setColor(QPalette::WindowText, tf.color()); + label->setPalette(pal); + + return label; +} + +QGradientStops iconGradientStops(const QModelIndex &index) +{ + const bool isVendorExtension = index.data(RoleVendor).toString() == "The Qt Company Ltd"; + const QColor startColor = creatorColor(isVendorExtension ? Theme::Token_Gradient01_Start + : Theme::Token_Gradient02_Start); + const QColor endColor = creatorColor(isVendorExtension ? Theme::Token_Gradient01_End + : Theme::Token_Gradient02_End); + const QGradientStops gradient = { + {0, startColor}, + {1, endColor}, + }; + return gradient; +} + } // ExtensionManager::Internal diff --git a/src/plugins/extensionmanager/extensionsbrowser.h b/src/plugins/extensionmanager/extensionsbrowser.h index d0467aa2162..b49bcfaba12 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.h +++ b/src/plugins/extensionmanager/extensionsbrowser.h @@ -5,6 +5,12 @@ #include +QT_FORWARD_DECLARE_CLASS(QLabel) + +namespace Core::WelcomePageHelpers { +class TextFormat; +} + namespace ExtensionManager::Internal { class ExtensionsBrowser final : public QWidget @@ -15,6 +21,8 @@ public: ExtensionsBrowser(QWidget *parent = nullptr); ~ExtensionsBrowser(); + void setFilter(const QString &filter); + void adjustToWidth(const int width); QSize sizeHint() const override; @@ -29,4 +37,7 @@ private: class ExtensionsBrowserPrivate *d = nullptr; }; +QLabel *tfLabel(const Core::WelcomePageHelpers::TextFormat &tf, bool singleLine = true); +QGradientStops iconGradientStops(const QModelIndex &index); + } // ExtensionManager::Internal diff --git a/src/plugins/extensionmanager/images/extensionbig.png b/src/plugins/extensionmanager/images/extensionbig.png new file mode 100644 index 0000000000000000000000000000000000000000..6600ff9fb0627ed9f2ed72a4607b4d51be7be5d5 GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0y~yU{GXWU{K;0WlT6NfSC|TUc0b3AM7+(&%b#4qm~#%kAZ) z3C&6^mF?;0_m`jle6L!!R{kIVvewss*ZzIIFmr~*T;3JjY5u+mm)#~tALX5GP*%FI z+2Qt&=O4`y0`%AQBt9wFvp4nT+Xd+hSA~gJHRVo^zIB|xH(|%M>CA0sq?n3ovlm7z z)4O4ut-oNM&a;MdS1;7JuAb}QxI}Np>Y1UlxjR^t%$J>+r8KGjpD&Br?Zh($na8EA zy%#25u=^S8df?QbGdnL|*c-8V+YR2!^Uj|MU*mk>hQ`Eo=CLkrYj4*CRj5zXkhGT8 zD_U$(v+Qa=f5V;~)|;{qpDf|j@SXqS;}zSaq+_ZDE327VrH<%0xO;T$R^F|~kgKRT zO=Bj*9yM1MpC>1!Cn+(hsYR*(aqi-nQR>>oF(Xvjm8CD|R@KI*s+viBQS)jyE^Ovo ztx}XUbC)~&F$QgwQ%O56c|Tcdcz`?a>$;Ytl==k+)ce`)%W?de9g&!DpW~R{{@2$47l{Cg`V z{cv5Yz-wFLI;D%lk;U7xI_An53%qf>9k!<9_WS(FjVDUBt#r`gcqOTD!`REZ z=^UHO>1C$MVoIBJl$ED>WGh-d%D8*{?~X(78*rdpspqWun?XEMh-r!)a=x`%_fd?$7!fVbPzu^DZ3q zRI74a&*Eshto43**j@4T!;ddXt>kEu)ITy)zYiM! zmxO+ZS;df2vg7DMJ%xyG&q74lEt?DKZJI3?{jl6S@fB;^1UF@aEqQs{q!>aYF|Wfyhjqc1fHH}N>aJmSvSFvM{;K}L8@IJ7&pa^wnpDuw#Ff0+ zD_;M4?S1mFtMyI(ABpTMD!;v)nA5mOjr~Vn?$+hP*DTnM{M@bbNKumck?qeJy_@DJ zxwJ_&?O7@0BCtZyW1Xt=omEO4e0uIIA%dR_loj$GxuqyBOke-l?Z(6loB!<){HM2g zWA|lywLF(6GQKi}Q!O4D6|%_MH$}#@v|npwJ90y`^MGn#jM0&K*$xcB@At_hI-eBy z?JugR;)?D{>`J>9n zCEGK>fqnm8u_ISKT`Hb7gr8er(aY~$^GWaet%5T@Tsx9a);KSTI2?1zdWy8wiT0hR zA6_ti%2#RF;vOT%E2BNdbP0l+XkK1v}64 literal 0 HcmV?d00001 diff --git a/src/plugins/extensionmanager/images/packbig.png b/src/plugins/extensionmanager/images/packbig.png new file mode 100644 index 0000000000000000000000000000000000000000..b69acad9770c3ebb493d5d6df478bb03f4c2533e GIT binary patch literal 455 zcmeAS@N?(olHy`uVBq!ia0y~yU{GXWU{K;7j&aFaNyv z(3*FpyTP?Ly^i%$-I^lC&p$rDa|-!$_tnvsJfkaaYWfRSOa5bTG}S2I@A&cH?7Y+s z6#@aQCm1@<)*Bvr_&$wuf}w+`0KealmSqnvvvgcf)M|LAwX0vHet(C&7GGc>>o>0A z6M`%LOcY3)(BL5&bM(JFcj*DC9+3nay}~D!Ii+3)N9k~dUT~nmjOgmMCS7Px7M3mHQnUeEB`>t?u%B# zQ5o}ptxwvxGv_GS`QIwt(6#$1lY(CK3(h4nU-$U&%=yFI;KE>0+;P>`{q)rP&tDiR zG`yShKBDN`{=0DxQjQ&XvGuq7x=Rns`&Q(#HS* literal 0 HcmV?d00001 diff --git a/src/plugins/extensionmanager/images/packbig@2x.png b/src/plugins/extensionmanager/images/packbig@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7fb684a9c2a2b9a68da337cd506cc9920cca8f54 GIT binary patch literal 785 zcmeAS@N?(olHy`uVBq!ia0y~yU~pn!U~u7JU|?VnNZX^yz`%6F)5S3);_%xUz8=z! zBFEJOcW)C_-FiXn)}E)J1HpFVFcOmy~sqR6t&$)r8O`NSGl-?!6SzsYR0 zuVl8;SSKKFcJ6tp=tAA^Mv68<>l>8Sw(LC}#VPpG;k@OZiBt8Ty*ai)w5r^tt3&a^ z6+2;5uQM-vtR)OWTr{lS$7B?|)o^urx?DZ8tlOhXtJ$FGMp|+j!^TMIiHaPVGPg~c z-t?Is5|mNOuYI+$=FiGo$9HrKwA}gpSAbcl(S44wL&?E!(^hiuclc~|n6Jm@xIJ)E zaKzj*HPKZn(i6&8Kiz`yYI-0*nrwfFyiPkbF4 zui1K}qef`W;w52s-rH3LHkGZPGi7p2(}~-C-1{oJS@oo^^WDgL!r`_5XI`h-{jm4x zTOPht)cAW?o|*5ze%kG;?oXOGnQ<^SXW!9F>Ns)x_Q}^v_hqj$U!;73rRh?|N_{;$ z4qru|uU7?2U1UG*R}>4{su;xmXXBk`y))g9Xgi5;FJ1Q0wzy;OM>U-(3u2@r&Ppg6 zt!ADRb9m83yZINKRi3?Ny6Ca>s9#BjulxxC_RDK8Y%UI5&Gq7~U`0ukyOYw9ebOt} z{3~V+nyJ`y^k{d2l(OH3Q$cs$vmQNC_<(VmV0&oG3jc^pAB?B&>-fKL&4yc2t&>hQ z*>znr*p(V_&oD4ug{>mG%Jtd%2f~I2-u=(qb>*mbz@{Qz?z{=?ll~Y6ehc3mIOpgx xJ^3wD(^(HZcK9UpU3}-+&d#%UrruvPhjBTZs + + + + + + + + + Date: Sun, 23 Jun 2024 10:23:06 +0300 Subject: [PATCH 17/73] TextEditor: Fix context for editor actions Amends 411100b0378202dc617acaa236f4730eb4cc43b2. Fixes: QTCREATORBUG-30748 Change-Id: I6b54e7283df2523e26a6dd186de973a8378a9b2f Reviewed-by: David Schulz --- src/plugins/texteditor/texteditorplugin.cpp | 190 ++++++++++---------- 1 file changed, 100 insertions(+), 90 deletions(-) diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index 5db6a17e0d5..5df9de54701 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -304,12 +304,22 @@ void TextEditorPlugin::createStandardContextMenu() add(Constants::SWITCH_UTF8BOM, Constants::G_BOM); } +class TextActionBuilder : public ActionBuilder +{ +public: + TextActionBuilder(QObject *contextActionParent, const Utils::Id actionId) + : ActionBuilder(contextActionParent, actionId) + { + setContext(Context(Constants::C_TEXTEDITOR)); + } +}; + void TextEditorPlugin::createEditorCommands() { using namespace Core::Constants; // Add shortcut for invoking automatic completion Command *command = nullptr; - ActionBuilder(this, Constants::COMPLETE_THIS) + TextActionBuilder(this, Constants::COMPLETE_THIS) .setText(Tr::tr("Trigger Completion")) .bindCommand(&command) .setDefaultKeySequence(Tr::tr("Meta+Space"), Tr::tr("Ctrl+Space")); @@ -320,253 +330,253 @@ void TextEditorPlugin::createEditorCommands() FancyLineEdit::setCompletionShortcut(command->keySequence()); // Add shortcut for invoking function hint completion - ActionBuilder(this, Constants::FUNCTION_HINT) + TextActionBuilder(this, Constants::FUNCTION_HINT) .setText(Tr::tr("Display Function Hint")) .setDefaultKeySequence(Tr::tr("Meta+Shift+D"), Tr::tr("Ctrl+Shift+D")); // Add shortcut for invoking quick fix options - ActionBuilder(this, Constants::QUICKFIX_THIS) + TextActionBuilder(this, Constants::QUICKFIX_THIS) .setText(Tr::tr("Trigger Refactoring Action")) .setDefaultKeySequence(Tr::tr("Alt+Return")); - ActionBuilder(this, Constants::SHOWCONTEXTMENU) + TextActionBuilder(this, Constants::SHOWCONTEXTMENU) .setText(Tr::tr("Show Context Menu")); - ActionBuilder(this, DELETE_LINE).setText(Tr::tr("Delete &Line")); - ActionBuilder(this, DELETE_END_OF_LINE).setText(Tr::tr("Delete Line from Cursor On")); - ActionBuilder(this, DELETE_END_OF_WORD).setText(Tr::tr("Delete Word from Cursor On")); - ActionBuilder(this, DELETE_END_OF_WORD_CAMEL_CASE) + TextActionBuilder(this, DELETE_LINE).setText(Tr::tr("Delete &Line")); + TextActionBuilder(this, DELETE_END_OF_LINE).setText(Tr::tr("Delete Line from Cursor On")); + TextActionBuilder(this, DELETE_END_OF_WORD).setText(Tr::tr("Delete Word from Cursor On")); + TextActionBuilder(this, DELETE_END_OF_WORD_CAMEL_CASE) .setText(Tr::tr("Delete Word Camel Case from Cursor On")); - ActionBuilder(this, DELETE_START_OF_LINE) + TextActionBuilder(this, DELETE_START_OF_LINE) .setText(Tr::tr("Delete Line up to Cursor")) .setDefaultKeySequence(Tr::tr("Ctrl+Backspace"), {}); - ActionBuilder(this, DELETE_START_OF_WORD).setText(Tr::tr("Delete Word up to Cursor")); - ActionBuilder(this, DELETE_START_OF_WORD_CAMEL_CASE) + TextActionBuilder(this, DELETE_START_OF_WORD).setText(Tr::tr("Delete Word up to Cursor")); + TextActionBuilder(this, DELETE_START_OF_WORD_CAMEL_CASE) .setText(Tr::tr("Delete Word Camel Case up to Cursor")); - ActionBuilder(this, GOTO_BLOCK_START_WITH_SELECTION) + TextActionBuilder(this, GOTO_BLOCK_START_WITH_SELECTION) .setText(Tr::tr("Go to Block Start with Selection")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+{"))); - ActionBuilder(this, GOTO_BLOCK_END_WITH_SELECTION) + TextActionBuilder(this, GOTO_BLOCK_END_WITH_SELECTION) .setText(Tr::tr("Go to Block End with Selection")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+}"))); - ActionBuilder(this, MOVE_LINE_UP) + TextActionBuilder(this, MOVE_LINE_UP) .setText(Tr::tr("Move Line Up")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Up"))); - ActionBuilder(this, MOVE_LINE_DOWN) + TextActionBuilder(this, MOVE_LINE_DOWN) .setText(Tr::tr("Move Line Down")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Down"))); - ActionBuilder(this, COPY_LINE_UP) + TextActionBuilder(this, COPY_LINE_UP) .setText(Tr::tr("Copy Line Up")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Alt+Up"))); - ActionBuilder(this, COPY_LINE_DOWN) + TextActionBuilder(this, COPY_LINE_DOWN) .setText(Tr::tr("Copy Line Down")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Alt+Down"))); - ActionBuilder(this, JOIN_LINES) + TextActionBuilder(this, JOIN_LINES) .setText(Tr::tr("Join Lines")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+J"))); - ActionBuilder(this, INSERT_LINE_ABOVE) + TextActionBuilder(this, INSERT_LINE_ABOVE) .setText(Tr::tr("Insert Line Above Current Line")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Return"))); - ActionBuilder(this, INSERT_LINE_BELOW) + TextActionBuilder(this, INSERT_LINE_BELOW) .setText(Tr::tr("Insert Line Below Current Line")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Return"))); - ActionBuilder(this, SWITCH_UTF8BOM).setText(Tr::tr("Toggle UTF-8 BOM")); - ActionBuilder(this, INDENT).setText(Tr::tr("Indent")); - ActionBuilder(this, UNINDENT).setText(Tr::tr("Unindent")); - ActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR) + TextActionBuilder(this, SWITCH_UTF8BOM).setText(Tr::tr("Toggle UTF-8 BOM")); + TextActionBuilder(this, INDENT).setText(Tr::tr("Indent")); + TextActionBuilder(this, UNINDENT).setText(Tr::tr("Unindent")); + TextActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR) .setText(Tr::tr("Follow Symbol Under Cursor")) .setDefaultKeySequence(QKeySequence(Qt::Key_F2)); - ActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT) + TextActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT) .setText(Tr::tr("Follow Symbol Under Cursor in Next Split")) .setDefaultKeySequence(Tr::tr("Meta+E, F2"), Tr::tr("Ctrl+E, F2")); - ActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE) + TextActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE) .setText(Tr::tr("Follow Type Under Cursor")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+F2"))); - ActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT) + TextActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT) .setText(Tr::tr("Follow Type Under Cursor in Next Split")) .setDefaultKeySequence(Tr::tr("Meta+E, Shift+F2"), Tr::tr("Ctrl+E, Ctrl+Shift+F2")); - ActionBuilder(this, FIND_USAGES) + TextActionBuilder(this, FIND_USAGES) .setText(Tr::tr("Find References to Symbol Under Cursor")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+U"))); - ActionBuilder(this, RENAME_SYMBOL) + TextActionBuilder(this, RENAME_SYMBOL) .setText(Tr::tr("Rename Symbol Under Cursor")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+R"))); - ActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR) + TextActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR) .setText(Tr::tr("Jump to File Under Cursor")) .setDefaultKeySequence(QKeySequence(Qt::Key_F2)); - ActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT) + TextActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT) .setText(Tr::tr("Jump to File Under Cursor in Next Split")) .setDefaultKeySequence(Tr::tr("Meta+E, F2"), Tr::tr("Ctrl+E, F2")); - ActionBuilder(this, OPEN_CALL_HIERARCHY).setText(Tr::tr("Open Call Hierarchy")); - ActionBuilder(this, OPEN_TYPE_HIERARCHY) + TextActionBuilder(this, OPEN_CALL_HIERARCHY).setText(Tr::tr("Open Call Hierarchy")); + TextActionBuilder(this, OPEN_TYPE_HIERARCHY) .setText(Tr::tr("Open Type Hierarchy")) .setDefaultKeySequence(Tr::tr("Meta+Shift+T"), Tr::tr("Ctrl+Shift+T")); - ActionBuilder(this, VIEW_PAGE_UP) + TextActionBuilder(this, VIEW_PAGE_UP) .setText(Tr::tr("Move the View a Page Up and Keep the Cursor Position")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+PgUp"))); - ActionBuilder(this, VIEW_PAGE_DOWN) + TextActionBuilder(this, VIEW_PAGE_DOWN) .setText(Tr::tr("Move the View a Page Down and Keep the Cursor Position")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+PgDown"))); - ActionBuilder(this, VIEW_LINE_UP) + TextActionBuilder(this, VIEW_LINE_UP) .setText(Tr::tr("Move the View a Line Up and Keep the Cursor Position")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Up"))); - ActionBuilder(this, VIEW_LINE_DOWN) + TextActionBuilder(this, VIEW_LINE_DOWN) .setText(Tr::tr("Move the View a Line Down and Keep the Cursor Position")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Down"))); ActionManager::actionContainer(M_EDIT); - ActionBuilder(this, SELECT_ENCODING) + TextActionBuilder(this, SELECT_ENCODING) .setText(Tr::tr("Select Encoding...")) .addToContainer(M_EDIT, G_EDIT_OTHER); - ActionBuilder(this, CIRCULAR_PASTE) + TextActionBuilder(this, CIRCULAR_PASTE) .setText(Tr::tr("Paste from Clipboard History")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+V"))) .addToContainer(M_EDIT, G_EDIT_COPYPASTE); - ActionBuilder(this, NO_FORMAT_PASTE) + TextActionBuilder(this, NO_FORMAT_PASTE) .setText(Tr::tr("Paste Without Formatting")) .setDefaultKeySequence(Tr::tr("Ctrl+Alt+Shift+V"), QString()) .addToContainer(M_EDIT, G_EDIT_COPYPASTE); ActionManager::actionContainer(M_EDIT_ADVANCED); - ActionBuilder(this, AUTO_INDENT_SELECTION) + TextActionBuilder(this, AUTO_INDENT_SELECTION) .setText(Tr::tr("Auto-&indent Selection")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+I"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT); - ActionBuilder(this, AUTO_FORMAT_SELECTION) + TextActionBuilder(this, AUTO_FORMAT_SELECTION) .setText(Tr::tr("Auto-&format Selection")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+;"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT); - ActionBuilder(this, REWRAP_PARAGRAPH) + TextActionBuilder(this, REWRAP_PARAGRAPH) .setText(Tr::tr("&Rewrap Paragraph")) .setDefaultKeySequence(Tr::tr("Meta+E, R"), Tr::tr("Ctrl+E, R")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT); - ActionBuilder(this, VISUALIZE_WHITESPACE) + TextActionBuilder(this, VISUALIZE_WHITESPACE) .setText(Tr::tr("&Visualize Whitespace")) .setDefaultKeySequence(Tr::tr("Meta+E, Meta+V"), Tr::tr("Ctrl+E, Ctrl+V")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT); - ActionBuilder(this, CLEAN_WHITESPACE) + TextActionBuilder(this, CLEAN_WHITESPACE) .setText(Tr::tr("Clean Whitespace")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT); - ActionBuilder(this, TEXT_WRAPPING) + TextActionBuilder(this, TEXT_WRAPPING) .setText(Tr::tr("Enable Text &Wrapping")) .setDefaultKeySequence(Tr::tr("Meta+E, Meta+W"), Tr::tr("Ctrl+E, Ctrl+W")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT) .setCheckable(true); - ActionBuilder(this, UN_COMMENT_SELECTION) + TextActionBuilder(this, UN_COMMENT_SELECTION) .setText(Tr::tr("Toggle Comment &Selection")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+/"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT); - ActionBuilder(this, CUT_LINE) + TextActionBuilder(this, CUT_LINE) .setText(Tr::tr("Cut &Line")) .setDefaultKeySequence(QKeySequence(Tr::tr("Shift+Del"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, COPY_LINE) + TextActionBuilder(this, COPY_LINE) .setText(Tr::tr("Copy &Line")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Ins"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, COPY_WITH_HTML) + TextActionBuilder(this, COPY_WITH_HTML) .setText(Tr::tr("Copy With Highlighting")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, ADD_CURSORS_TO_LINE_ENDS) + TextActionBuilder(this, ADD_CURSORS_TO_LINE_ENDS) .setText(Tr::tr("Create Cursors at Selected Line Ends")) .setDefaultKeySequence(QKeySequence(Tr::tr("Alt+Shift+I"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, ADD_SELECT_NEXT_FIND_MATCH) + TextActionBuilder(this, ADD_SELECT_NEXT_FIND_MATCH) .setText(Tr::tr("Add Next Occurrence to Selection")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+D"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, DUPLICATE_SELECTION) + TextActionBuilder(this, DUPLICATE_SELECTION) .setText(Tr::tr("&Duplicate Selection")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, DUPLICATE_SELECTION_AND_COMMENT) + TextActionBuilder(this, DUPLICATE_SELECTION_AND_COMMENT) .setText(Tr::tr("&Duplicate Selection and Comment")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, UPPERCASE_SELECTION) + TextActionBuilder(this, UPPERCASE_SELECTION) .setText(Tr::tr("Uppercase Selection")) .setDefaultKeySequence(Tr::tr("Meta+Shift+U"), Tr::tr("Alt+Shift+U")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, LOWERCASE_SELECTION) + TextActionBuilder(this, LOWERCASE_SELECTION) .setText(Tr::tr("Lowercase Selection")) .setDefaultKeySequence(Tr::tr("Meta+U"), Tr::tr("Alt+U")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, SORT_LINES) + TextActionBuilder(this, SORT_LINES) .setText(Tr::tr("Sort Lines")) .setDefaultKeySequence(Tr::tr("Meta+Shift+S"), Tr::tr("Alt+Shift+S")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT); - ActionBuilder(this, FOLD) + TextActionBuilder(this, FOLD) .setText(Tr::tr("Fold")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+<"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_COLLAPSING); - ActionBuilder(this, UNFOLD) + TextActionBuilder(this, UNFOLD) .setText(Tr::tr("Unfold")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+>"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_COLLAPSING); - ActionBuilder(this, UNFOLD_ALL) + TextActionBuilder(this, UNFOLD_ALL) .setText(Tr::tr("Toggle &Fold All")) .addToContainer(M_EDIT_ADVANCED, G_EDIT_COLLAPSING); - ActionBuilder(this, INCREASE_FONT_SIZE) + TextActionBuilder(this, INCREASE_FONT_SIZE) .setText(Tr::tr("Increase Font Size")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl++"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT); - ActionBuilder(this, DECREASE_FONT_SIZE) + TextActionBuilder(this, DECREASE_FONT_SIZE) .setText(Tr::tr("Decrease Font Size")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+-"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT); - ActionBuilder(this, RESET_FONT_SIZE) + TextActionBuilder(this, RESET_FONT_SIZE) .setText(Tr::tr("Reset Font Size")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+0"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT); - ActionBuilder(this, GOTO_BLOCK_START) + TextActionBuilder(this, GOTO_BLOCK_START) .setText(Tr::tr("Go to Block Start")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+["))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS); - ActionBuilder(this, GOTO_BLOCK_END) + TextActionBuilder(this, GOTO_BLOCK_END) .setText(Tr::tr("Go to Block End")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+]"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS); - ActionBuilder(this, SELECT_BLOCK_UP) + TextActionBuilder(this, SELECT_BLOCK_UP) .setText(Tr::tr("Select Block Up")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+U"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS); - ActionBuilder(this, SELECT_BLOCK_DOWN) + TextActionBuilder(this, SELECT_BLOCK_DOWN) .setText(Tr::tr("Select Block Down")) .setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Alt+U"))) .addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS); - ActionBuilder(this, SELECT_WORD_UNDER_CURSOR).setText(Tr::tr("Select Word Under Cursor")); + TextActionBuilder(this, SELECT_WORD_UNDER_CURSOR).setText(Tr::tr("Select Word Under Cursor")); - ActionBuilder(this, GOTO_DOCUMENT_START).setText(Tr::tr("Go to Document Start")); - ActionBuilder(this, GOTO_DOCUMENT_END).setText(Tr::tr("Go to Document End")); - ActionBuilder(this, GOTO_LINE_START).setText(Tr::tr("Go to Line Start")); - ActionBuilder(this, GOTO_LINE_END).setText(Tr::tr("Go to Line End")); - ActionBuilder(this, GOTO_NEXT_LINE).setText(Tr::tr("Go to Next Line")); - ActionBuilder(this, GOTO_PREVIOUS_LINE).setText(Tr::tr("Go to Previous Line")); - ActionBuilder(this, GOTO_PREVIOUS_CHARACTER).setText(Tr::tr("Go to Previous Character")); - ActionBuilder(this, GOTO_NEXT_CHARACTER).setText(Tr::tr("Go to Next Character")); - ActionBuilder(this, GOTO_PREVIOUS_WORD).setText(Tr::tr("Go to Previous Word")); - ActionBuilder(this, GOTO_NEXT_WORD).setText(Tr::tr("Go to Next Word")); - ActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE) + TextActionBuilder(this, GOTO_DOCUMENT_START).setText(Tr::tr("Go to Document Start")); + TextActionBuilder(this, GOTO_DOCUMENT_END).setText(Tr::tr("Go to Document End")); + TextActionBuilder(this, GOTO_LINE_START).setText(Tr::tr("Go to Line Start")); + TextActionBuilder(this, GOTO_LINE_END).setText(Tr::tr("Go to Line End")); + TextActionBuilder(this, GOTO_NEXT_LINE).setText(Tr::tr("Go to Next Line")); + TextActionBuilder(this, GOTO_PREVIOUS_LINE).setText(Tr::tr("Go to Previous Line")); + TextActionBuilder(this, GOTO_PREVIOUS_CHARACTER).setText(Tr::tr("Go to Previous Character")); + TextActionBuilder(this, GOTO_NEXT_CHARACTER).setText(Tr::tr("Go to Next Character")); + TextActionBuilder(this, GOTO_PREVIOUS_WORD).setText(Tr::tr("Go to Previous Word")); + TextActionBuilder(this, GOTO_NEXT_WORD).setText(Tr::tr("Go to Next Word")); + TextActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE) .setText(Tr::tr("Go to Previous Word (Camel Case)")); - ActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE).setText(Tr::tr("Go to Next Word (Camel Case)")); + TextActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE).setText(Tr::tr("Go to Next Word (Camel Case)")); - ActionBuilder(this, GOTO_LINE_START_WITH_SELECTION) + TextActionBuilder(this, GOTO_LINE_START_WITH_SELECTION) .setText(Tr::tr("Go to Line Start with Selection")); - ActionBuilder(this, GOTO_LINE_END_WITH_SELECTION) + TextActionBuilder(this, GOTO_LINE_END_WITH_SELECTION) .setText(Tr::tr("Go to Line End with Selection")); - ActionBuilder(this, GOTO_NEXT_LINE_WITH_SELECTION) + TextActionBuilder(this, GOTO_NEXT_LINE_WITH_SELECTION) .setText(Tr::tr("Go to Next Line with Selection")); - ActionBuilder(this, GOTO_PREVIOUS_LINE_WITH_SELECTION) + TextActionBuilder(this, GOTO_PREVIOUS_LINE_WITH_SELECTION) .setText(Tr::tr("Go to Previous Line with Selection")); - ActionBuilder(this, GOTO_PREVIOUS_CHARACTER_WITH_SELECTION) + TextActionBuilder(this, GOTO_PREVIOUS_CHARACTER_WITH_SELECTION) .setText(Tr::tr("Go to Previous Character with Selection")); - ActionBuilder(this, GOTO_NEXT_CHARACTER_WITH_SELECTION) + TextActionBuilder(this, GOTO_NEXT_CHARACTER_WITH_SELECTION) .setText(Tr::tr("Go to Next Character with Selection")); - ActionBuilder(this, GOTO_PREVIOUS_WORD_WITH_SELECTION) + TextActionBuilder(this, GOTO_PREVIOUS_WORD_WITH_SELECTION) .setText(Tr::tr("Go to Previous Word with Selection")); - ActionBuilder(this, GOTO_NEXT_WORD_WITH_SELECTION) + TextActionBuilder(this, GOTO_NEXT_WORD_WITH_SELECTION) .setText(Tr::tr("Go to Next Word with Selection")); - ActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE_WITH_SELECTION) + TextActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE_WITH_SELECTION) .setText(Tr::tr("Go to Previous Word (Camel Case) with Selection")); - ActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE_WITH_SELECTION) + TextActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE_WITH_SELECTION) .setText(Tr::tr("Go to Next Word (Camel Case) with Selection")); } From 64a9da8114b265d5dbc966330b57db9a77b87612 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Jun 2024 15:02:43 +0200 Subject: [PATCH 18/73] COIN: Switch sdktool to Qt 6 Change-Id: I638c0b385a27e1e5b036102330b8f5a80899343c Reviewed-by: Eike Ziller --- coin/instructions/build.yaml | 6 +++--- coin/instructions/common_environment.yaml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coin/instructions/build.yaml b/coin/instructions/build.yaml index e4453c9e71b..23ec37b4d6c 100644 --- a/coin/instructions/build.yaml +++ b/coin/instructions/build.yaml @@ -42,7 +42,7 @@ instructions: - type: ChangeDirectory directory: "{{.AgentWorkingDir}}/build/tqtc-qtsdk/packaging_tools" - type: ExecuteCommand - command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command make" + command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command ninja" maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to build sdktool, check logs." @@ -79,7 +79,7 @@ instructions: variableName: MACOSX_DEPLOYMENT_TARGET variableValue: "{{.Env.SDKTOOL_MACOSX_DEPLOYMENT_TARGET}}" - type: ExecuteCommand - command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command make" + command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command ninja --universal" maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to build sdktool, check logs." @@ -128,7 +128,7 @@ instructions: - type: ChangeDirectory directory: "{{.AgentWorkingDir}}\\build\\tqtc-qtsdk\\packaging_tools" - type: ExecuteCommand - command: "python -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}\\build\\sdktool\\qt --src {{.AgentWorkingDir}}\\qt-creator\\qt-creator\\src\\tools\\sdktool --build {{.AgentWorkingDir}}\\build\\sdktool\\build --install {{.AgentWorkingDir}}\\build\\sdktool\\install --make-command nmake" + command: "python -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}\\build\\sdktool\\qt --src {{.AgentWorkingDir}}\\qt-creator\\qt-creator\\src\\tools\\sdktool --build {{.AgentWorkingDir}}\\build\\sdktool\\build --install {{.AgentWorkingDir}}\\build\\sdktool\\install --make-command ninja" maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to build sdktool, check logs." diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index bed851d11ed..22d53d03e2a 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -19,10 +19,10 @@ instructions: variableValue: 11.0 - type: EnvironmentVariable variableName: SDKTOOL_MACOSX_DEPLOYMENT_TARGET - variableValue: 10.14 + variableValue: 11.0 - type: EnvironmentVariable variableName: QTC_SDKTOOL_QT_BASE_URL - variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/5.15/5.15.2-final-released/latest/src/submodules/qtbase-everywhere-src-5.15.2" + variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.6/6.6.0-released/Qt/src/submodules/qtbase-everywhere-src-6.6.0" - type: Group instructions: - type: EnvironmentVariable From 4f1cc1ff310caf6296b7a4fc671157ffaaf7be1c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 24 Jun 2024 14:24:02 +0200 Subject: [PATCH 19/73] Core: fix direction of Ctrl+N/P/Up/Down Additionally accept the shortcut override events in order to block other potential shortcuts from interfering with the selection of the open document. amends e6299f510d44b5b57913026da3625ded316d848b amends 03e35aac14c8ee2d9531297b658b4106b11c303b Task-number: QTCREATORBUG-31072 Change-Id: Idfd65b92a84f5be39f9a01da68e8046ae5304733 Reviewed-by: Eike Ziller --- .../editormanager/openeditorswindow.cpp | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp index 0967fb16e6e..172b54570e1 100644 --- a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp +++ b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp @@ -165,34 +165,35 @@ bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e) auto ke = static_cast(e); switch (ke->key()) { case Qt::Key_Up: - selectPreviousEditor(); + case Qt::Key_P: + e->accept(); return true; case Qt::Key_Down: - selectNextEditor(); - return true; - case Qt::Key_P: case Qt::Key_N: - if (ke->modifiers() == Qt::KeyboardModifiers(HostOsInfo::controlModifier())) { - if (ke->key() == Qt::Key_P) - selectPreviousEditor(); - else - selectNextEditor(); - return true; - } - break; + e->accept(); + return true; } } if (e->type() == QEvent::KeyPress) { auto ke = static_cast(e); - if (ke->key() == Qt::Key_Escape) { + switch (ke->key()) { + case Qt::Key_Up: + case Qt::Key_P: + selectNextEditor(); + return true; + case Qt::Key_Down: + case Qt::Key_N: + selectPreviousEditor(); + return true; + case Qt::Key_Escape: setVisible(false); return true; - } - if (ke->key() == Qt::Key_Return - || ke->key() == Qt::Key_Enter) { + case Qt::Key_Return: + case Qt::Key_Enter: selectEditor(m_editorView->currentItem()); return true; } + } else if (e->type() == QEvent::KeyRelease) { auto ke = static_cast(e); if (ke->modifiers() == 0 From 38fc03cc3bf1a005180f7a8d6d9f6fedd0f86a65 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 24 Jun 2024 13:51:50 +0200 Subject: [PATCH 20/73] COIN: Do not specify full path to 7zip It is in the PATH, and the full path makes changing platforms/VMs harder (like updating to ARM Macs) Change-Id: I3b4a3208aa066e8000321d6a548b9559c249dc5e Reviewed-by: Eike Ziller --- coin/instructions/build.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/coin/instructions/build.yaml b/coin/instructions/build.yaml index 23ec37b4d6c..b98cfbafbcc 100644 --- a/coin/instructions/build.yaml +++ b/coin/instructions/build.yaml @@ -20,7 +20,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to download elfutils package, check logs." - type: ExecuteCommand - command: "/usr/bin/7z x -y {{.AgentWorkingDir}}/build/qt_temp/elfutils-release_0.175qt-linux-x86_64.7z -o{{.AgentWorkingDir}}/build/qt_temp/elfutils" + command: "7z x -y {{.AgentWorkingDir}}/build/qt_temp/elfutils-release_0.175qt-linux-x86_64.7z -o{{.AgentWorkingDir}}/build/qt_temp/elfutils" maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract elfutils package, check logs." @@ -30,7 +30,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to download LLVM package, check logs." - type: ExecuteCommand - command: "/usr/bin/7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/" + command: "7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/" maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract LLVM package, check logs." @@ -64,7 +64,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to download LLVM package, check logs." - type: ExecuteCommand - command: "/usr/local/bin/7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/" + command: "7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/" maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract LLVM package, check logs." @@ -96,7 +96,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to download elfutils package, check logs." - type: ExecuteCommand - command: "C:\\Utils\\sevenzip\\7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\elfutils-release_0.175qt-windows-x86_64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\elfutils" + command: "7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\elfutils-release_0.175qt-windows-x86_64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\elfutils" maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract elfutils package, check logs." @@ -106,7 +106,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to download python package, check logs." - type: ExecuteCommand - command: "C:\\Utils\\sevenzip\\7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\Python38-win-x64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\python" + command: "7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\Python38-win-x64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\python" maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract python package, check logs." @@ -116,7 +116,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to download LLVM package, check logs." - type: ExecuteCommand - command: "C:\\Utils\\sevenzip\\7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\libclang.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\" + command: "7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\libclang.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\" maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract LLVM package, check logs." From 7ffcbe541b87bc9977ba2cb14d6b48df717e7e11 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 19 Jun 2024 13:17:11 +0200 Subject: [PATCH 21/73] TreeScanner: Inline scanForFiles() method Make scanForFiles() a non-template method and hide it in treescanner.cpp. Inline scanForFilesRecursively(). Change-Id: I10e07f190e1a4a65cd7045c625a364350964afb9 Reviewed-by: David Schulz --- src/plugins/projectexplorer/CMakeLists.txt | 1 - .../projectexplorer/projectexplorer.qbs | 1 - .../projectexplorer/projectnodeshelper.h | 141 ------------------ src/plugins/projectexplorer/treescanner.cpp | 111 +++++++++++++- src/plugins/projectexplorer/treescanner.h | 2 +- 5 files changed, 107 insertions(+), 149 deletions(-) delete mode 100644 src/plugins/projectexplorer/projectnodeshelper.h diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index ea7a079d908..0c62d2177a1 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -140,7 +140,6 @@ add_qtc_plugin(ProjectExplorer projectmanager.cpp projectmanager.h projectmodels.cpp projectmodels.h projectnodes.cpp projectnodes.h - projectnodeshelper.h projectpanelfactory.cpp projectpanelfactory.h projectsettingswidget.cpp projectsettingswidget.h projecttree.cpp projecttree.h diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 19b9221de2b..bce24dc1361 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -115,7 +115,6 @@ QtcPlugin { "projectmanager.cpp", "projectmanager.h", "projectmodels.cpp", "projectmodels.h", "projectnodes.cpp", "projectnodes.h", - "projectnodeshelper.h", "projectpanelfactory.cpp", "projectpanelfactory.h", "projectsettingswidget.cpp", "projectsettingswidget.h", "projecttree.cpp", diff --git a/src/plugins/projectexplorer/projectnodeshelper.h b/src/plugins/projectexplorer/projectnodeshelper.h deleted file mode 100644 index 37b015ec321..00000000000 --- a/src/plugins/projectexplorer/projectnodeshelper.h +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "projectnodes.h" - -#include -#include - -#include - -#include -#include -#include -#include - -#include - -namespace ProjectExplorer { -namespace Internal { - -struct DirectoryScanResult -{ - QList nodes; - Utils::FilePaths subDirectories; -}; - -static DirectoryScanResult scanForFiles( - const QFuture &future, - const Utils::FilePath &directory, - QDir::Filters filter, - const std::function &factory, - const QList &versionControls) -{ - DirectoryScanResult result; - - const Utils::FilePaths entries = directory.dirEntries(filter); - for (const Utils::FilePath &entry : entries) { - if (future.isCanceled()) - return result; - - if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) { - return vc->isVcsFileOrDirectory(entry); - })) { - continue; - } - - if (entry.isDir()) - result.subDirectories.append(entry); - else if (FileNode *node = factory(entry)) - result.nodes.append(node); - } - return result; -} - -template -QList scanForFilesRecursively( - QPromise &promise, - int progressRange, - const Utils::FilePath &directory, - QDir::Filters filter, - const std::function &factory, - const QList &versionControls) -{ - const QFuture future(promise.future()); - - QSet visited; - const DirectoryScanResult result - = scanForFiles(future, directory, filter, factory, versionControls); - QList fileNodes = result.nodes; - const int progressIncrement = int( - progressRange / static_cast(fileNodes.count() + result.subDirectories.count())); - promise.setProgressValue(int(fileNodes.count() * progressIncrement)); - QList> subDirectories; - auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) { - for (const Utils::FilePath &subdir : subdirs) { - if (Utils::insert(visited, subdir.canonicalPath())) - subDirectories.append(qMakePair(subdir, progressIncrement)); - else - promise.setProgressValue(promise.future().progressValue() + progressIncrement); - } - }; - addSubDirectories(result.subDirectories, progressIncrement); - - while (!subDirectories.isEmpty()) { - using namespace Tasking; - const LoopList iterator(subDirectories); - subDirectories.clear(); - - auto onSetup = [&, iterator](Utils::Async &task) { - task.setConcurrentCallData( - scanForFiles, future, iterator->first, filter, factory, versionControls); - }; - - auto onDone = [&, iterator](const Utils::Async &task) { - const int progressRange = iterator->second; - const DirectoryScanResult result = task.result(); - fileNodes.append(result.nodes); - const qsizetype subDirCount = result.subDirectories.count(); - if (subDirCount == 0) { - promise.setProgressValue(promise.future().progressValue() + progressRange); - } else { - const qsizetype fileCount = result.nodes.count(); - const int increment = int( - progressRange / static_cast(fileCount + subDirCount)); - promise.setProgressValue( - promise.future().progressValue() + increment * fileCount); - addSubDirectories(result.subDirectories, increment); - } - }; - - const Group group{ - Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit, - iterator, - Utils::AsyncTask(onSetup, onDone) - }; - TaskTree::runBlocking(group); - } - return fileNodes; -} - -} // namespace Internal - -template -QList scanForFiles( - QPromise &promise, - const Utils::FilePath &directory, - QDir::Filters filter, - const std::function &factory) -{ - promise.setProgressRange(0, 1000000); - return Internal::scanForFilesRecursively(promise, - 1000000, - directory, - filter, - factory, - Core::VcsManager::versionControls()); -} - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp index 49680621ec2..4411184c923 100644 --- a/src/plugins/projectexplorer/treescanner.cpp +++ b/src/plugins/projectexplorer/treescanner.cpp @@ -3,15 +3,17 @@ #include "treescanner.h" -#include "projectnodeshelper.h" #include "projecttree.h" #include #include -#include -#include +#include + #include +#include +#include +#include #include @@ -146,14 +148,113 @@ static std::unique_ptr createFolderNode(const Utils::FilePath &direc return fileSystemNode; } +struct DirectoryScanResult +{ + QList nodes; + Utils::FilePaths subDirectories; +}; + +static DirectoryScanResult scanForFilesImpl( + const QFuture &future, + const Utils::FilePath &directory, + QDir::Filters filter, + const std::function &factory, + const QList &versionControls) +{ + DirectoryScanResult result; + + const Utils::FilePaths entries = directory.dirEntries(filter); + for (const Utils::FilePath &entry : entries) { + if (future.isCanceled()) + return result; + + if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) { + return vc->isVcsFileOrDirectory(entry); + })) { + continue; + } + + if (entry.isDir()) + result.subDirectories.append(entry); + else if (FileNode *node = factory(entry)) + result.nodes.append(node); + } + return result; +} + +static QList scanForFilesHelper( + TreeScanner::Promise &promise, + const Utils::FilePath &directory, + QDir::Filters filter, + const std::function &factory) +{ + const QFuture future(promise.future()); + + const int progressRange = 1000000; + const QList &versionControls = Core::VcsManager::versionControls(); + promise.setProgressRange(0, progressRange); + + QSet visited; + const DirectoryScanResult result = scanForFilesImpl(future, directory, filter, factory, versionControls); + QList fileNodes = result.nodes; + const int progressIncrement = int( + progressRange / static_cast(fileNodes.count() + result.subDirectories.count())); + promise.setProgressValue(int(fileNodes.count() * progressIncrement)); + QList> subDirectories; + auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) { + for (const Utils::FilePath &subdir : subdirs) { + if (Utils::insert(visited, subdir.canonicalPath())) + subDirectories.append(qMakePair(subdir, progressIncrement)); + else + promise.setProgressValue(future.progressValue() + progressIncrement); + } + }; + addSubDirectories(result.subDirectories, progressIncrement); + + while (!subDirectories.isEmpty()) { + using namespace Tasking; + const LoopList iterator(subDirectories); + subDirectories.clear(); + + auto onSetup = [&, iterator](Utils::Async &task) { + task.setConcurrentCallData( + scanForFilesImpl, future, iterator->first, filter, factory, versionControls); + }; + + auto onDone = [&, iterator](const Utils::Async &task) { + const int progressRange = iterator->second; + const DirectoryScanResult result = task.result(); + fileNodes.append(result.nodes); + const qsizetype subDirCount = result.subDirectories.count(); + if (subDirCount == 0) { + promise.setProgressValue(future.progressValue() + progressRange); + } else { + const qsizetype fileCount = result.nodes.count(); + const int increment = int( + progressRange / static_cast(fileCount + subDirCount)); + promise.setProgressValue(future.progressValue() + increment * fileCount); + addSubDirectories(result.subDirectories, increment); + } + }; + + const Group group{ + Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit, + iterator, + Utils::AsyncTask(onSetup, onDone) + }; + TaskTree::runBlocking(group); + } + return fileNodes; +} + void TreeScanner::scanForFiles( Promise &promise, const Utils::FilePath &directory, const FileFilter &filter, - const QDir::Filters &dirFilter, + QDir::Filters dirFilter, const FileTypeFactory &factory) { - QList nodes = ProjectExplorer::scanForFiles( + QList nodes = scanForFilesHelper( promise, directory, dirFilter, [&filter, &factory](const Utils::FilePath &fn) -> FileNode * { const Utils::MimeType mimeType = Utils::mimeTypesForFileName(fn.path()).value(0); diff --git a/src/plugins/projectexplorer/treescanner.h b/src/plugins/projectexplorer/treescanner.h index 6de26e399ad..bc4dbe0b069 100644 --- a/src/plugins/projectexplorer/treescanner.h +++ b/src/plugins/projectexplorer/treescanner.h @@ -75,7 +75,7 @@ private: static void scanForFiles(Promise &fi, const Utils::FilePath &directory, const FileFilter &filter, - const QDir::Filters &dirFilter, + QDir::Filters dirFilter, const FileTypeFactory &factory); private: From 1f0d028b092f8f8713b7c756c9be9a28c319dabe Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 24 Jun 2024 15:49:20 +0200 Subject: [PATCH 22/73] Update change log Change-Id: I966a24d9fc2b272c798bd413eaadaf6c8ef14a0f Reviewed-by: Leena Miettinen --- dist/changelog/changes-14.0.0.md | 40 ++++++++++++++++++++++++++++---- dist/changelog/template.md | 4 ++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/dist/changelog/changes-14.0.0.md b/dist/changelog/changes-14.0.0.md index 7d14123acae..8ef28236d6e 100644 --- a/dist/changelog/changes-14.0.0.md +++ b/dist/changelog/changes-14.0.0.md @@ -5,16 +5,16 @@ Qt Creator version 14 contains bug fixes and new features. The most important changes are listed in this document. For a complete list of changes, see the Git log for the Qt Creator sources that you can check out from -the public Git repository. For example: +the public Git repository or view online at - git clone git://code.qt.io/qt-creator/qt-creator.git - git log --cherry-pick --pretty=oneline origin/13.0..v14.0.0 +https://code.qt.io/cgit/qt-creator/qt-creator.git/log/?id=13.0..v14.0.0 General ------- * Started work on supporting Lua based plugins (registering language servers, actions, preferences, and wizards) + ([Documentation](https://doc-snapshots.qt.io/qtcreator-extending/lua-extensions.html)) * Added `Clear` and `Save Contents` to context menus of all output views * Locator * Added the option to show results relative to project root @@ -42,6 +42,8 @@ Editing ### C++ * Made C++ code model settings configurable per project +* Added a setting for the naming of include guards + ([QTCREATORBUG-25117](https://bugreports.qt.io/browse/QTCREATORBUG-25117)) * Fixed indentation after function calls with subscript operator ([QTCREATORBUG-29225](https://bugreports.qt.io/browse/QTCREATORBUG-29225)) * Refactoring @@ -58,6 +60,7 @@ Editing [Documentation](https://doc.qt.io/qtcreator/creator-reference-cpp-quick-fixes.html) * Clangd + * Updated the prebuilt binaries to LLVM 18.1.7 * Increased the minimum version to LLVM 17 * Added the `Per-project index location` and `Per-session index location` options in `Preferences` > `C++` > `Clangd` for setting the index location @@ -88,8 +91,10 @@ Editing ([QTCREATORBUG-19226](https://bugreports.qt.io/browse/QTCREATORBUG-19226)) * Added `Qt Design Studio` to `Open With` for `.ui.qml` files ([Documentation](https://doc.qt.io/qtcreator/creator-quick-ui-forms.html)) +* Fixed that the color preview did not work on named colors + ([QTCREATORBUG-30594](https://bugreports.qt.io/browse/QTCREATORBUG-30594)) * Language Server - * Switched on by default + * Switched on by default for Qt 6.8 and later * Added option for generating `qmlls.ini` files for CMake projects ([QTCREATORBUG-30394](https://bugreports.qt.io/browse/QTCREATORBUG-30394)) ([Qt Documentation](https://doc.qt.io/qt-6/cmake-variable-qt-qml-generate-qmlls-ini.html)) @@ -114,6 +119,10 @@ Editing `Compiler Explorer` [Documentation](https://doc.qt.io/qtcreator/creator-how-to-create-compiler-explorer-sessions.html) +### Markdown + +* Fixed the navigation history + ### Models * Added more visual attributes for relations @@ -135,6 +144,8 @@ Projects from the list in the `Projects` mode * Added support for user comments in the environment editor ([Documentation](https://doc-snapshots.qt.io/qtcreator-14.0/creator-how-to-edit-environment-settings.html)) +* Added the setting `Time to wait before force-stopping applications` + ([QTCREATORBUG-31025](https://bugreports.qt.io/browse/QTCREATORBUG-31025)) * Fixed the parsing of file links when color was used for the output ([QTCREATORBUG-30774](https://bugreports.qt.io/browse/QTCREATORBUG-30774)) * Fixed that the column information was not used when opening files from links @@ -151,12 +162,18 @@ Projects * Implemented `Open Online Documentation` for CMake documentation * Added `Clear CMake Configuration` to the context menu in the `Projects` view ([QTCREATORBUG-24658](https://bugreports.qt.io/browse/QTCREATORBUG-24658)) +* Added support for the `CROSSCOMPILING_EMULATOR` target property + ([QTCREATORBUG-29880](https://bugreports.qt.io/browse/QTCREATORBUG-29880)) + ([CMake Documentation](https://cmake.org/cmake/help/latest/prop_tgt/CROSSCOMPILING_EMULATOR.html#crosscompiling-emulator)) * Fixed that the package manager auto-setup files were not removed with `Clear CMake Configuration` ([QTCREATORBUG-30771](https://bugreports.qt.io/browse/QTCREATORBUG-30771)) * Fixed that files generated by the Qt QML CMake API were not filtered as generated files ([QTCREATORBUG-29631](https://bugreports.qt.io/browse/QTCREATORBUG-29631)) +* Fixed a crash when triggering `Follow Symbol` in a CMake file that does not + belong to a project + ([QTCREATORBUG-31077](https://bugreports.qt.io/browse/QTCREATORBUG-31077)) * Presets * Made CMake settings configurable ([QTCREATORBUG-25972](https://bugreports.qt.io/browse/QTCREATORBUG-25972), @@ -202,6 +219,12 @@ Analyzer * Made it possible to register multiple servers +### Cppcheck + +* Fixed that Cppcheck was not working until selecting `Apply` in the settings + ([QTCREATORBUG-28951](https://bugreports.qt.io/browse/QTCREATORBUG-28951), + [QTCREATORBUG-30615](https://bugreports.qt.io/browse/QTCREATORBUG-30615)) + Terminal -------- @@ -249,11 +272,15 @@ Platforms * Added support for creating `android-desktop` devices * Added support for `namespace` in `build.gradle` ([QTBUG-106907](https://bugreports.qt.io/browse/QTBUG-106907)) +* Fixed that errors when creating AVDs were not visible to the user + ([QTCREATORBUG-30852](https://bugreports.qt.io/browse/QTCREATORBUG-30852)) ### iOS * Removed Simulator management from the preferences. Use the `Devices and Simulators` window in Xcode instead. +* Fixed that starting the debugger could be slow for iOS < 17 + ([QTCREATORBUG-31044](https://bugreports.qt.io/browse/QTCREATORBUG-31044)) ### Remote Linux @@ -266,6 +293,11 @@ Platforms * Added support for the `perf` profiler +### Bare Metal + +* Fixed issues with Qbs and the IAR toolchain + ([QTCREATORBUG-24040](https://bugreports.qt.io/browse/QTCREATORBUG-24040)) + Credits for these changes go to: -------------------------------- Ahmad Samir diff --git a/dist/changelog/template.md b/dist/changelog/template.md index cfbdad4677f..66e94906aea 100644 --- a/dist/changelog/template.md +++ b/dist/changelog/template.md @@ -83,6 +83,8 @@ Analyzer ### CTF Visualizer +### Cppcheck + Terminal -------- @@ -127,5 +129,7 @@ Platforms ### QNX +### Bare Metal + Credits for these changes go to: -------------------------------- From 3babe8c73c7b0b5448543b34ae24b87d0bae01fb Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 20 Jun 2024 13:05:05 +0200 Subject: [PATCH 23/73] App: Set "windowsvista" style on Windows This will set the pre Qt 6.7 default style. Task-number: QTBUG-126515 Task-number: QTBUG-126548 Task-number: QTBUG-126549 Change-Id: I947bcbe859c91906f2a273a04f3142d8d42b7af1 Reviewed-by: Eike Ziller --- src/app/main.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 4ec11d5e896..43712c6836a 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -680,11 +680,18 @@ int main(int argc, char **argv) setPixmapCacheLimit(); loadFonts(); - // On 100% or 200% scaling we can use the default 'Vista' style on Windows - qreal tmp; - const bool fractionalDpi = !qFuzzyIsNull(std::modf(qApp->devicePixelRatio(), &tmp)); - if (Utils::HostOsInfo::isWindowsHost() && fractionalDpi && !hasStyleOption) - QApplication::setStyle(QLatin1String("fusion")); + if (Utils::HostOsInfo::isWindowsHost() && !hasStyleOption) { + // The Windows 11 default style (Qt 6.7) has major issues, therefore + // set the previous default style: "windowsvista" + // FIXME: check newer Qt Versions + QApplication::setStyle(QLatin1String("windowsvista")); + + // On scaling different than 100% or 200% use the "fusion" style + qreal tmp; + const bool fractionalDpi = !qFuzzyIsNull(std::modf(qApp->devicePixelRatio(), &tmp)); + if (fractionalDpi) + QApplication::setStyle(QLatin1String("fusion")); + } const int threadCount = QThreadPool::globalInstance()->maxThreadCount(); QThreadPool::globalInstance()->setMaxThreadCount(qMax(4, 2 * threadCount)); From b4ece2e056450b595cb1d792c184163f100cfe86 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 20 Jun 2024 12:09:50 +0200 Subject: [PATCH 24/73] Doc: Update topics about reading documentation - Describe the Open Online Documentation option - Edit the style - Use How To: Read Documentation as \sa for all topics in the group Task-number: QTCREATORBUG-30604 Change-Id: I7219ef9a38e993fc1387dd0ece9c8dfe762387d1 Reviewed-by: Eike Ziller --- .../src/cmake/creator-projects-cmake.qdoc | 9 +- doc/qtcreator/src/howto/creator-help.qdoc | 157 +++++++++--------- 2 files changed, 84 insertions(+), 82 deletions(-) diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc index 5fdbd09dd8e..524163a2894 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc @@ -120,11 +120,14 @@ tooltips \li Selecting any of the above elements and pressing \key F1 to show its documentation - \li Switching to the Help mode + \li Switching to the \uicontrol Help mode \endlist - \sa {Build with CMake}{How To: Build with CMake}, {CMake}, - {Read Documentation}{How To: Read Documentation} + To view the documentation online, open it in the \uicontrol Help mode and + select \inlineimage icons/online.png (\uicontrol {Open Online Documentation}). + + \sa {Build with CMake}{How To: Build with CMake}, + {Read Documentation}{How To: Read Documentation}, {CMake} */ /*! diff --git a/doc/qtcreator/src/howto/creator-help.qdoc b/doc/qtcreator/src/howto/creator-help.qdoc index 434ee6fe9b2..f9f3028a022 100644 --- a/doc/qtcreator/src/howto/creator-help.qdoc +++ b/doc/qtcreator/src/howto/creator-help.qdoc @@ -23,23 +23,23 @@ \li To view context sensitive help on a Qt class or function as a tooltip, move the mouse cursor over the class or function. If help - is not available, the tooltip displays type information for the + is not available, the tooltip shows type information for the symbol. - \li To display tooltips for function signatures regardless of the + \li To show tooltips for function signatures regardless of the cursor position in the function call, press \key {Ctrl+Shift+D}. - \li To display the full help on a Qt class or function, press \key F1 or + \li To show the full help on a Qt class or function, press \key F1 or select \uicontrol {Context Help} in the context menu. - The documentation is displayed in a + The documentation is shown in a view next to the code editor, or, if there is not enough vertical space, in the fullscreen \uicontrol Help mode. - \li To select and configure how the documentation is displayed in the - \uicontrol Help mode, select \preferences > \uicontrol Help. + \li To change how the documentation is shown in the + \uicontrol Help mode, go to \preferences > \uicontrol Help. \endlist - The following image displays the context sensitive help in the \uicontrol Edit + The following image shows the context sensitive help in the \uicontrol Edit mode. \image qtcreator-context-sensitive-help.png {Context-sensitive help in Edit mode} @@ -52,43 +52,43 @@ \image qtcreator-preferences-help-general.webp {General tab in Help preferences} - You can set the default zoom level in the \uicontrol Zoom field. When - viewing help pages, you can use the mouse scroll wheel to zoom them. To - disable this feature, deselect the \uicontrol {Enable scroll wheel zooming} - check box. + Set the default zoom level in \uicontrol Zoom. When viewing help pages, use + the mouse scroll wheel to zoom them. To turn off this feature, clear + \uicontrol {Enable scroll wheel zooming}. - To disable antialiasing, deselect the \uicontrol Antialiasing check box. + To turn off antialiasing, clear \uicontrol Antialias. \section1 Return to the editor To switch to the editor context when you close the last help page, select - the \uicontrol {Return to editor on closing the last page} check box. + \uicontrol {Return to editor on closing the last page}. \section1 Select help viewer backend - The help viewer backend determines the style sheet that is used to display + The help viewer backend determines the style sheet that is used to show the help files. The default help viewer backend that is based on litehtml is recommended for viewing Qt documentation. You can choose another help - viewer backend in the \uicontrol {Viewer backend} field. To take the new + viewer backend in the \uicontrol {Viewer backend}. To take the new backend to use, reload the help page. \section1 View function tooltips - To hide function tooltips by default, select \preferences > - \uicontrol {Text Editor} > \uicontrol Behavior > - \uicontrol {Show help tooltips using the mouse} > - \uicontrol {On Shift+Mouseover}. You can still view the tooltips by pressing - and holding down the \key Shift key. + To hide function tooltips by default: + + \list 1 + \li Go to \preferences > \uicontrol {Text Editor} > \uicontrol Behavior. + \image qtcreator-preferences-texteditor-behavior.webp {Text Editor Behavior preferences} + \li In \uicontrol {Show help tooltips using the mouse}, select + \uicontrol {On Shift+Mouseover}. + \endlist + + You can still view the tooltips by pressing and holding down the \key Shift + key. To use a keyboard shortcut for viewing help tooltips, select \uicontrol {Show help tooltips using keyboard shortcut (Alt)}. - \sa {Find information in Qt documentation}, {Filter documentation}, - {Search from documentation} - - \sa {Add external documentation}, {Detach the help window}, - {Filter documentation}, {Find information in Qt documentation}, - {Select the help start page} + \sa {Read Documentation}{How To: Read Documentation} */ /*! @@ -103,15 +103,18 @@ \title Find information in Qt documentation - \QC, \QSDK and other Qt deliverables have documentation - as .qch files. All the documentation is accessible in the \uicontrol Help mode. + \QC installer, \QOI, and other Qt deliverables install documentation as .qch + files. View the documentation in the \uicontrol Help mode. To view the + currently open document online, select \inlineimage icons/online.png + (\uicontrol {Open Online Documentation}). By default, \QC registers only the latest available version of the documentation for each installed Qt module. To register all installed - documentation, select \preferences > \uicontrol Kits > - \uicontrol {Qt Versions} > \uicontrol {Register documentation}. + documentation, go to \preferences > \uicontrol Kits > + \uicontrol {Qt Versions} and select an option in + \uicontrol {Register documentation}. - \image qtcreator-qt-versions.png {Register documentation field in Qt Versions tab in Kit Preferences} + \image qtcreator-qt-versions.png {Register documentation in Qt Versions preferences} \section1 Help mode sidebar views @@ -137,7 +140,7 @@ \endlist - \sa {Add bookmarks to help pages}, {Search from documentation} + \sa {Read Documentation}{How To: Read Documentation} */ /*! @@ -152,8 +155,8 @@ \title Add bookmarks to help pages - You can add bookmarks to useful help pages to easily find them later - in the \uicontrol Bookmarks view. You can either use the page title as the + Add bookmarks to useful help pages to easily find them later + in the \uicontrol Bookmarks view. Either use the page title as the bookmark or change it to any text. You can organize the bookmarks in folders in the view. @@ -163,21 +166,21 @@ \list 1 - \li Click the \inlineimage icons/bookmark.png - (\uicontrol {Add Bookmark}) button on the toolbar. + \li Select \inlineimage icons/bookmark.png (\uicontrol {Add Bookmark}) + on the toolbar. - \li In the \uicontrol {Add Bookmark} dialog, click \uicontrol OK to save the + \li In the \uicontrol {Add Bookmark} dialog, select \uicontrol OK to save the page title as a bookmark in the selected folder. \endlist \section1 Import and export bookmarks - To import and export bookmarks, select \preferences > - \uicontrol Help > \uicontrol General > \uicontrol {Import Bookmarks} or + To import and export bookmarks, go to \preferences > \uicontrol Help > + \uicontrol General and select \uicontrol {Import Bookmarks} or \uicontrol {Export Bookmarks}. - \sa {Find information in Qt documentation} + \sa {Read Documentation}{How To: Read Documentation} */ /*! @@ -192,10 +195,10 @@ \title Search from documentation - In the \uicontrol Help mode \uicontrol Search pane, you can use full-text + In the \uicontrol Help mode \uicontrol Search pane, use full-text search for finding a particular word in all the installed documents. Enter the term you are - looking for, and select the \uicontrol Search button. All documents that + looking for, and select \uicontrol Search. All documents that have the specified term are listed. The list is sorted by document version (if you have installed several Qt versions, for example) and the number of search hits that the documents have. Select a document in @@ -225,16 +228,15 @@ time when you open the \uicontrol Search pane. If you add or remove documents, \QC recreates the index. - If you cannot find words that you know are there, indexing might not have - been completed for some reason. To regenerate the index, click - \inlineimage icons/reload_gray.png + If you cannot find words that you know are there, the index might not be + complete. To recreate it, select \inlineimage icons/reload_gray.png (\uicontrol {Regenerate Index}). Punctuation is not included in indexed terms. To find terms that have punctuation, such as domain names, use the asterisk as a wild card. For example, to find \c {Pastebin.Com}, enter the search term \c {Pastebin*}. - \sa {Find information in Qt documentation} + \sa {Read Documentation}{How To: Read Documentation} */ /*! @@ -249,7 +251,7 @@ \title Add external documentation - You can display external documentation in the \uicontrol Help mode. + You can view external documentation in the \uicontrol Help mode. To add documentation or replace the documentation that ships with \QC and Qt: \list 1 @@ -259,14 +261,14 @@ For information on how to prepare your documentation and create a .qch file, see \l{The Qt Help Framework}. - \li To add the .qch file to \QC, select \preferences > + \li To add the .qch file to \QC, go to \preferences > \uicontrol Help > \uicontrol Documentation > \uicontrol Add. \image qtcreator-preferences-help-documentation.webp {Documentation tab in Help Preferences} \endlist - \sa {Get help} + \sa {Read Documentation}{How To: Read Documentation} */ /*! @@ -281,26 +283,24 @@ \title Detach the help window - By default, context-sensitive help is opened in a window next to the + By default, context-sensitive help opens in a window next to the code editor when you press \key F1. If there is not enough vertical space, the help opens in the full-screen help mode. \image qtcreator-context-sensitive-help.png {Context-sensitive help in Edit mode} - To specify that the help always opens in full-screen mode or - is detached to an external window, select \preferences > \uicontrol Help > - \uicontrol General. + To specify that the help always opens in full-screen mode or in an external + window, go to \preferences > \uicontrol Help > \uicontrol General. \image qtcreator-preferences-help-general.webp {General tab in Help preferences} - Set preferences for displaying context-sensitive help - in the \uicontrol {On context help} field. To detach the help window, select + Set preferences for viewing context-sensitive help + in \uicontrol {On context help}. To detach the help window, select \uicontrol {Always Show in External Window}. - To change this setting in a help view, select the \inlineimage icons/linkicon.png - toolbar button. + To change this setting in a help view, select \inlineimage icons/linkicon.png. - \sa {Get help} + \sa {Read Documentation}{How To: Read Documentation} */ /*! @@ -315,27 +315,27 @@ \title Select the help start page - You can select the page to display when you open the \uicontrol Help mode in the - \preferences > \uicontrol Help > \uicontrol General > - \uicontrol {On help start} field. + To set the page to show when you open the \uicontrol Help mode, go to + \preferences > \uicontrol Help > \uicontrol General and select + \uicontrol {On help start}. \image qtcreator-preferences-help-general.webp {General tab in Help preferences} \list - \li To display the page and help views that were open when you exited the mode, + \li To show the page and help views that were open when you exited the mode, select the \uicontrol {Show My Tabs from Last Session} option. However, Web pages are not opened because loading them would slow down opening the \uicontrol Help mode. - \li To display a particular page, select \uicontrol {Show My Home Page}, and specify - the page in the \uicontrol {Home Page} field. + \li To show a particular page, select \uicontrol {Show My Home Page}, and specify + the page in \uicontrol {Home Page}. - \li To display a blank page, select the \uicontrol {Show a Blank Page} option. You can - also select the \uicontrol {Use Blank Page} button to set a blank page as your + \li To show a blank page, select the \uicontrol {Show a Blank Page} option. + Select \uicontrol {Use Blank Page} to set a blank page as your home page. \endlist - \sa {Get help} + \sa {Read Documentation}{How To: Read Documentation} */ /*! @@ -350,40 +350,40 @@ \title Filter documentation - You can filter the documents displayed in the \uicontrol Help mode to find + Filter the documents in the \uicontrol Help mode to find relevant information faster. Select a filter from a list of filters. The contents of the \uicontrol Index and \uicontrol Contents view in the sidebar change accordingly. - \image qtcreator-help-filters.png {Filters field on the Help mode toolbar} + \image qtcreator-help-filters.png {Filters on the Help mode toolbar} \section1 Add filters - You can define your own filters to display documentation for a set of + Define your own filters to show documentation for a set of Qt modules and versions. To add filters: \list 1 - \li Select \preferences > \uicontrol Help > \uicontrol Filters. + \li Go to \preferences > \uicontrol Help > \uicontrol Filters. \image qtcreator-help-filter-attributes.png {Filters tab in Help preferences} \li Select \inlineimage icons/plus.png to add a new filter in the \uicontrol {Add Filter} dialog. - \li In the \uicontrol {Filter name} field, enter a name for the filter, + \li In \uicontrol {Filter name}, enter a name for the filter, and then select \uicontrol {OK} to return to the \uicontrol Filters tab. - \li In the \uicontrol Components field, select the Qt modules to include + \li In \uicontrol Components, select the Qt modules to include in the filter. - \li In the \uicontrol Versions field, select the Qt versions to include + \li In \uicontrol Versions, select the Qt versions to include in the filter. - \li Click \uicontrol OK. + \li Select \uicontrol OK. \li In the \uicontrol Help mode, select the filter in the list of filters to see the filtered documentation in the sidebar. @@ -392,15 +392,14 @@ \section1 Change filters - To modify the selected filter, add and remove Qt modules and versions, and + To modify the selected filter, add and remove Qt modules and versions and then select \uicontrol Apply. To rename the selected filter, select \uicontrol Rename. \section1 Remove filters - To remove the selected filter select \inlineimage icons/minus.png - . + To remove the selected filter, select \inlineimage icons/minus.png. - \sa {Get help} + \sa {Read Documentation}{How To: Read Documentation} */ From 6db4c7af32d62f925822cd9c31e12b39a03debd3 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Thu, 13 Jun 2024 13:12:55 +0200 Subject: [PATCH 25/73] AppStatisticMonitor: Change background color to current theming Change-Id: Ib12305cfda1d6ed4404c606314fa73451ed4afe7 Reviewed-by: hjk --- src/plugins/appstatisticsmonitor/chart.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/appstatisticsmonitor/chart.cpp b/src/plugins/appstatisticsmonitor/chart.cpp index 260282b39a4..86e99283fa7 100644 --- a/src/plugins/appstatisticsmonitor/chart.cpp +++ b/src/plugins/appstatisticsmonitor/chart.cpp @@ -38,7 +38,8 @@ AppStatisticsMonitorChart::AppStatisticsMonitorChart( m_chartView->setMinimumHeight(200); m_chartView->setMinimumWidth(400); const QBrush brushTitle(creatorColor(Theme::Token_Text_Muted)); - const QBrush brush(creatorColor(Theme::Token_Background_Default)); + // const QBrush brush(creatorColor(Theme::Token_Background_Default)); left for the future + const QBrush brush(creatorColor(Theme::BackgroundColorNormal)); const QPen penBack(creatorColor(Theme::Token_Text_Muted)); const QPen penAxis(creatorColor(Theme::Token_Text_Muted)); @@ -160,8 +161,8 @@ void Chart::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); - - painter.fillRect(rect(), creatorColor(Theme::Token_Background_Default)); + // painter.fillRect(rect(), creatorColor(Theme::Token_Background_Default)); left for the future + painter.fillRect(rect(), creatorColor(Theme::BackgroundColorNormal)); // add the name of the chart in the middle of the widget width and on the top painter.drawText( From 660e57976081b93a01b629caf389731d9d000e5b Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 18 Jun 2024 18:28:09 +0200 Subject: [PATCH 26/73] CMakePM: Code readability fix Amends b240bfb3dbd7b0da4be1490f7262bcc2c5542731 Having the assignement sepparate makes the code easier to understand. Change-Id: I10112224c9752788e157012d53f638406b79793b Reviewed-by: hjk --- src/plugins/cmakeprojectmanager/cmakeeditor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp index 92f63ea04c7..c4e91031015 100644 --- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp @@ -330,7 +330,8 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor, if (auto project = ProjectTree::currentProject()) { buffer.replace("${CMAKE_SOURCE_DIR}", project->projectDirectory().path()); - if (auto bs = ProjectTree::currentBuildSystem(); bs && bs->buildConfiguration()) { + auto bs = ProjectTree::currentBuildSystem(); + if (bs && bs->buildConfiguration()) { buffer.replace("${CMAKE_BINARY_DIR}", bs->buildConfiguration()->buildDirectory().path()); // Get the path suffix from current source dir to project source dir and apply it From 460a5bbb56b57b2341782eb7a14d75d0bda06165 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 14 Jun 2024 11:44:44 +0200 Subject: [PATCH 27/73] TaskTree: Qt-ify the code (part 4) 13. Make s_activeStorageWarning a QLatin1StringView, otherwise having "qstring.h:1007:5: note: declared private here" on ubuntu-24.04-x64. Amends e331329e4f8bb3de30f99f0905a0d2517d4c227c Change-Id: I6f5784f00b2894daa48128edd50bf57b54686acf Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 55ae3cfb56a..91bdaf2d9e1 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -18,6 +18,7 @@ #include #include +using namespace Qt::StringLiterals; using namespace std::chrono; QT_BEGIN_NAMESPACE @@ -1298,11 +1299,11 @@ const void *Loop::valuePtr() const using StoragePtr = void *; -static QString s_activeStorageWarning = +static constexpr QLatin1StringView s_activeStorageWarning = "The referenced storage is not reachable in the running tree. " "A nullptr will be returned which might lead to a crash in the calling code. " "It is possible that no storage was added to the tree, " - "or the storage is not reachable from where it is referenced."; + "or the storage is not reachable from where it is referenced."_L1; class StorageThreadData { From da957a5b1a534896c95e14ff2027a6eb52de575a Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Fri, 21 Jun 2024 19:20:24 +0300 Subject: [PATCH 28/73] Utils: Fix MSVC warning icon.cpp(214): warning C5030: attribute [[__maybe_unused__]] is not recognized icon.cpp(214): warning C5222: '__maybe_unused__': all unscoped attribute names are reserved for future standardization Change-Id: I99e484a508965ef256b20286b3c3795220c4f748 Reviewed-by: Christian Stenger --- src/libs/utils/icon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/icon.cpp b/src/libs/utils/icon.cpp index 06570e6505a..073ec771531 100644 --- a/src/libs/utils/icon.cpp +++ b/src/libs/utils/icon.cpp @@ -211,7 +211,7 @@ QIcon Icon::sideBarIcon(const Icon &classic, const Icon &flat) } QIcon Icon::modeIcon(const Icon &classic, const Icon &flat, - [[__maybe_unused__]] const Icon &flatActive) + [[maybe_unused]] const Icon &flatActive) { QIcon result = sideBarIcon(classic, flat); return result; From 8910356ffcb7fc80a26f49609198dd83a267b84d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 24 Jun 2024 15:16:45 +0200 Subject: [PATCH 29/73] LanguageClient: avoid crash on collecting clients for a null setting And assert in that case. Change-Id: I7b74589e6f08eb57e1b08bf509729bef32d0a9ff Reviewed-by: Marcus Tillmanns --- src/plugins/languageclient/languageclientmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 8ee2254c746..11ce6b4618e 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -387,6 +387,7 @@ void LanguageClientManager::enableClientSettings(const QString &settingsId, bool QList LanguageClientManager::clientsForSetting(const BaseSettings *setting) { QTC_ASSERT(managerInstance, return {}); + QTC_ASSERT(setting, return {}); auto instance = managerInstance; return instance->m_clientsForSetting.value(setting->m_id); } From 96815bb95ebff3ee0c07ff7ab670015003ab89e0 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 24 Jun 2024 13:52:33 +0200 Subject: [PATCH 30/73] LuaLanguageClient: Fix crash on exit Change-Id: I2f70d0b1586bc2bfbb27ea1513313e5c6ca32754 Reviewed-by: David Schulz --- .../lualanguageclient/lualanguageclient.cpp | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp index c9a12900230..47b2f7599dc 100644 --- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp +++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp @@ -175,7 +175,7 @@ public: std::optional m_startFailedCallback; QMap m_messageCallbacks; - QList m_clients; + LuaClientSettings *m_settings{nullptr}; public: static BaseSettings::StartBehavior startBehaviorFromString(const QString &str) @@ -190,6 +190,8 @@ public: throw sol::error("Unknown start behavior: " + str.toStdString()); } + void setSettings(LuaClientSettings *settings) { m_settings = settings; } + LuaClientWrapper(const sol::table &options) { m_cmdLineCallback = addValue( @@ -267,8 +269,6 @@ public: auto luaClient = qobject_cast(c); if (luaClient && luaClient->m_settingsId == m_settingsTypeId && m_onInstanceStart) { QTC_CHECK(::Lua::LuaEngine::void_safe_call(*m_onInstanceStart, c)); - - m_clients.push_back(c); updateMessageCallbacks(); } }); @@ -286,22 +286,11 @@ public: if (!luaClient || luaClient->m_settingsId != m_settingsTypeId) return; - if (m_clients.contains(c)) - m_clients.removeOne(c); - if (unexpected && m_startFailedCallback) { QTC_CHECK_EXPECTED(::Lua::LuaEngine::void_safe_call(*m_startFailedCallback)); } } - ~LuaClientWrapper() - { - for (auto client : m_clients) - LanguageClientManager::shutdownClient(client); - - // TODO: Unregister Client settings from LanguageClientManager - } - TransportType transportType() { return m_transportType; } void applySettings() @@ -340,7 +329,9 @@ public: void updateMessageCallbacks() { - for (Client *c : m_clients) { + for (Client *c : LanguageClientManager::clientsForSetting(m_settings)) { + if (!c) + continue; for (const auto &[msg, func] : m_messageCallbacks.asKeyValueRange()) { c->registerCustomMethod( msg, @@ -367,8 +358,10 @@ public: if (!messageValue.isObject()) throw sol::error("Message is not an object"); const LanguageServerProtocol::JsonRpcMessage jsonrpcmessage(messageValue.toObject()); - for (Client *c : m_clients) - c->sendMessage(jsonrpcmessage); + for (Client *c : LanguageClientManager::clientsForSetting(m_settings)) { + if (c) + c->sendMessage(jsonrpcmessage); + } } void updateOptions() @@ -536,6 +529,7 @@ static void registerLuaApi() [](const sol::table &options) -> std::shared_ptr { auto luaClient = std::make_shared(options); auto client = new LuaClientSettings(luaClient); + luaClient->setSettings(client); // The order is important! // First restore the settings ... From 2f76130a496e258e661002d9f9a9a5d59df85ff3 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 25 Jun 2024 09:40:42 +0200 Subject: [PATCH 31/73] Doc: Update info about QML Language Server - Rename topic as "Configure QML Language Server", as QMLLS is now turned on by default - Describe new preferences - Remove "QML Language Server" from checkbox labels - Add a link to the docs to the change log Task-number: QTCREATORBUG-30604 Change-Id: I397b1747a3d23d728c78dc2eae000839655c4f32 Reviewed-by: Eike Ziller --- dist/changelog/changes-14.0.0.md | 5 ++- .../images/qtcreator-qml-js-editing.webp | Bin 11266 -> 11482 bytes .../creator-only/creator-language-server.qdoc | 33 ++++++++---------- .../qmljseditor/qmljseditingsettingspage.cpp | 10 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/dist/changelog/changes-14.0.0.md b/dist/changelog/changes-14.0.0.md index 8ef28236d6e..8c51242e3d5 100644 --- a/dist/changelog/changes-14.0.0.md +++ b/dist/changelog/changes-14.0.0.md @@ -95,12 +95,15 @@ Editing ([QTCREATORBUG-30594](https://bugreports.qt.io/browse/QTCREATORBUG-30594)) * Language Server * Switched on by default for Qt 6.8 and later - * Added option for generating `qmlls.ini` files for CMake projects + * Added an option for generating `qmlls.ini` files for CMake projects in + `Preferences` > `Qt Quick`> `QML/JS Editing` ([QTCREATORBUG-30394](https://bugreports.qt.io/browse/QTCREATORBUG-30394)) ([Qt Documentation](https://doc.qt.io/qt-6/cmake-variable-qt-qml-generate-qmlls-ini.html)) * Fixed that tool tips from the built-in model were shown instead of tool tips from the server + [Documentation](https://doc.qt.io/qtcreator/creator-how-to-use-qml-language-server.html) + ### Python * Added options for updating Python Language Server diff --git a/doc/qtcreator/images/qtcreator-qml-js-editing.webp b/doc/qtcreator/images/qtcreator-qml-js-editing.webp index c0b56264dd1e7b274fb66e8888a8ae0373676b6f..f9475414f54bca2361312c15f5e3d0fac9956090 100644 GIT binary patch literal 11482 zcmWIYbaT6;!@v;k>J$(bVBvFAhk-$#`_OKNt6h)XCW&ZXs^8rHO(IUvka5Ds*Y6+5 z-SsMeQMUeS@0Ryn(!1`4-}|Cg-*zm7kNve#*~&7_qJr$a>#b7?Kji%Vzr^L%wzu9_ zEBkh3J^#BR=24|k*!^(Fq~dEgQs-_e;`R}@Ea{1`KA@7M{%`k_|KETAZ|+#)*}h?s zg5s5!Iq3=O3)%uzd{sOS{oH)eEiX5E>ft*|4GAF)&ly)HHxgfZ0I)z_icrCr;w`U-_T$1?Q4i`&B$9J=wPM8fynjme}H>r?&6Ew=K8& z&bFJ|{ug~c_vPN|#UaZ)BC96PSp6bulgIo?1v~ZrwZ!cGerWag*T0U~H|~F8*`I9R zXK83WLpZEQF{Xf5Q9N#5pi_a%g+~*%bxtVuY&?H}A@$J2oM^vdW;fAOXTEH0cGvkf zf6<>x*8kN%&V`(LP`38X#RJ3QLeU+ zitIHD?&!DNLC3r*`q{r+k3Sm!;QR!?o44fv%BZp?X zOj)s#LDPc!ZUXNz)8zj1NxTMu-=&$_t60@1{?VFJv>z?t>do?p5 zxZSYxN|C?F5}$%ihV^f}j~%k;obj%+uWxdq+l9E!f($d?ro2zOl3dGL*;d@XaZ>E+ zBF)0*f)g9gJkFdafBob%v8o%}wg)Js+H8B*$v6Fx+OvbwJms_PeO4TKHM`@T&{V~S zxk8qlJ1!S#aVp(%QTV?j$@$BKz3#?SSKfJOeaY{*{JDt4iMscC*p1u*y<752OJ>|W z*Ed6Cb;F%T*OJH02lKV|*gvbfWbld8-G+Dail)9TcOF*!KfHa3t=X14%yRA`@9n!p zU!3SH>hh~{JM?PF;n|t$S)Qi8D^;dHkl$W#Uvq|-YsB1$4GACDu279SqhNn$ar(d1 zb?T{$iykMxnX0wz__aS9^(`)avYDACxomE0q270aFhf!4%p<>ZZ-2a~Rc(7v^GNTM zUfb!?)*>;7V%?3{ul|$YI>oX_@1%U!i9VMvOWsT0pYJ+EJ_}Zlg_+pp1W|yufO}8E;<=+`;%C`T-rC@lvnknd=pdI%kRH$ER^To ze~>TX*C!bs7WFy_K5M> z@Cyg-y0~nd^)1Nvg}Fh~R!xZ{`FkrxRv(%>yGnpbXWh%LLnDmUzF_;v5DXXbXYqOd-Cnmt&q8qYG!lR?01yj@N83( z;itN&uhF9K!*e-9)~ri@A;sMqz}<5%82 z*}w3^J{7I{!$+!C%CStGAsN^#X_>$}D?{_yW7f>cERIO2A9!=i72o8=RXgPZc)A3w4UZc0)*Xy` zkrEa9waLqC^$h#mWi$T0>)C(v&%e&^?J`Q-H4O<uFmj?b=?(iW|ev-qy4{%X@I zkFrO9cTG&cx-0*MGhb#m)7ic)d)Q8JeqZrN(P3%S%D`@eqt!l3!@mmHr^-*i+%+}H zZl2KIm&U@+MJ6upwhp>4SHd}?|Lo2;?+%%6YS}ciAJ~X5G$XE|&?JaIBXj`^dw)EiY`EE;w;4HMVmIdFOEHTkoNb?AZ(_WRD;D z?aWdB%3j_(W zU)*>s5L^3ZWi!{M9fAubx$~SRxC_YMcb5pN_8`C*uBs5=c(B+ycaZhyUXsks90e$^J$*z z=i(0A{J--l`1sN11#f@WZ~V!B{Q0@)mvxF`pcm);f+4n(TS=Fuv{S*eCDod_0ET$C+&I8wLR0naYvd<-u79?k-lFG46isC zdAev_zdmQ`vjgod=IjxtPhNQO`%~qPWBVC3nOyf+{j8CE!OZ$-4zK6kfUiy;I}(DP zDQerTnzKMI`21OLIC4r%pY~@|nCY;jsMbg3q00I9pRP4r ziF^7vHB4tohp5*DcCI5{hgt(eH&pDI#rHkIbYarH*~{mj$?>?CI63X-yxIjRram8^ zUEM6Rz)Ymc&eW%;>A_)dmJoNXDvx5bC0S|CZFb6g-%m=J_wbj3`m=_Ej9Hm#EDJ*R zI4mm+RWE03tl~{~4oi!xQLyJtU6mzfGC}@XW#y#V`ep5vo%fPI&wW3k?zr_5{+-d` zmwxl9hKo);^~La~Tj7V?kFTD*f91>*m$1n_BL1X7Rggw*QYGedB1a_e}eP z^QPGcT>tnN%4(zuaDLhm;dsiE`Sv!Y0GY<%Yf5cDNwfo^m+-!PE$m`~&;N|Et{VF)H!# zGT>94*mz9i)9Phr+j12G6**TWFV6CE%(=Yn@D>hL=`$UEu3K)Gu$=4Sz0G+%=!tV_ z*bbd*ZEs?>%WAEiX!d$djp)DNKeH;f{b0Kio~r14YzfQbfJ*``%nd5JIk#gLc}+5K zSf&UGyscmuf2+Ja;kFy2&Y9)Bro)l=m$0M6)uA?iNuy*q&t3S#s)}JbWxW9Y9 z(0WGJ6dx};CsnCieV&*2D^IAdQaLGDz}@KmS$bp2ng=e+)edFOSt)Mx#hF!fhLGK% zyog(KZC>w~x&6`oj{hR1ew|;Xw z=G1a`#g@4<9{v5GuwQ+i>hm2A8xG_oiSYieU}Kjt<5QcsME2jL^pHtkKIUBRVbF^_ z>HhEuQ{cjgHs0Hw>@Rux*K+K3PhGz3hswX*I~rJ7Yo6}0U635qRH%_T<5rH0kCLbK zZLb+J#F`}>_< zjPPr{8145z&+~@Y$j&RCSt4RRPdi4<_Ife%ox|76tSi-uRz8_!vwy<8?ngx@H!u2- zT@~jgc2wwTmEQB`*Ka>xdhLVG#O$M=KY#Xq8QCd>Um8s;oi2WO1&IO!flPqPm^c zny)?=#~u3^WhwLddF+YoWlyjD{Q1mmGMm_JC4u@YTncleH$C*gqlV z*Nwm@MJGGCF4!Ia+u7z|_;5ys*)0Y~*4avNUXN~ZR(MB!J%3((4WDQ1={CN1z0pg~ zP3o;~UX|6&y3WT@?tmSG-@fYwKW>ZP@xOnw(^BHDk?*R<9ap%`H=Oxkt{#zdq2Zjm z+ajlYhSM{Y48gVvoaEmTGU<`z1MiNX(~?)U|Ks^F`*}K3?dPQ}hqzp}Z1msezTGoX zf9jkAw-UJ`btmka=JoKWmSp~|v_|csooo7<<@a)*bl=W>_N?LmEf)6oCmmU^y30m? zy3OLEiF$gD*Se!PHTi;hS%QB0+}CwGF}tZ|^Q1f<=S3{HjxYDPz4-Qawbq}8!rAH$ zt61Il)r-%vlYGA|rBPa}_=B4MN3o}hJEPk-^)~he?|sVqWS_~Ie{Q+h2P_KSwRDPoPJrn0 znZ@`2ED7@2IpO-XbL;c+w);z2yjv=hG-c8M&gB1BvdbU-deIwGBL3^q_a$52zq^@v zUw7@!>93X7?VKK4_UVkN;PpGJvl*oGCh-XS=x(3c%eUqIvgY2P-|yxM%J!YpXVR8+ zciH?bu07Rt?WY;Na%NwjDRcVofz{n2W@D57|MbI~!Qihb)I7=)e*@qO6`Qs9`rabf36fg>|k*}F&@Z!wU(c|-C& z-^4ZN*WV~zna>|Hdjj{Pshiey+TK}PTYkPiPhe5@Mz$%j4Oc$Tm+sBj^F26{eV${- z3%NDl)TRnNV?4x~+4D5dSB5E3_F>G?iQk@0>ewgy!f6Jl)tot;f1j+ZKV0X2&wpW` zQ00Hd&GI)TeJxGaNQ>R&{cgsgyel$YMkl&wZ~P81-lc}Qe6Jfm-0WX7<1y=x9}5%j zHiVxtHscjsw`z@Au=sAlnH>)Oh0;B#tO*PEZ0LxqSQfXSBk$MYON#Hq3~n`KW;}b$ z8rQP>*i55I#w&i#u<^a%xR>LRPuTRJwDPt^yAv-92#P&ir+N3yo?{CwH~i4N*0`6W zZ%_P$V-?j6a!E%PzR0^_;^N?9Uc#oDSGI4nz0H{v*}JX9_hXIa=H>8;t3UZYUf&Na6M+?6-wIm`5(*u`5Ye+Q_>vL*}dXrx);0O+-0^dN55P)%{a9zhku)oy)5^Zq`I$7 z-&Vx`|FzvddyWjG%*;foEM`tn36*T|rbNa;XHv5@jldV&)PN}edaN@+vJ%JN% zUfFUb?MjgF%bp!C)1%zxSoK!kER_$xUid!4c=9&pzHQ9=WV$bS^uO-e_A7}8_o=0Ox9<_lW0#S!-20K6bAj=uW%FN39leq%RlFp!eG}7d#`5X? zbM$I=79W1()wTI6F~kLb^{-eT0?CZsT8jelFvf>XN?e z(TN9V4HP;4+we5hTTHL(n7?SPmSf)C87fAXMW@@}ziC{UrxROW^)LAAr~CHT4NhNN zeW&T#TpR9}nhjA+U!O~=YsT;_S^T$HG|BQ1uj^*kwNg%In+;S#lYJO}Ki4{1B+_Q{ zx?xGj-{Q3o^jbFcW;|sS)7-Ye)R;@oxFMn2NN55-=ku0X-RwaQ3U0c&=C5{SadZD` z;dHa}I3c!EO=xcA|CrK^GK~Kf7PE5fWO;StwS?EmTIv0Lp6Iy5{KtbYF6 z$#weT>V~wb1^G%@4hn8>tOc007wr=6;M-fjZdODe%W?(o2P$l@93&t3wscK3RuEAB zwp;Lof~!f)5|%~A@8_>po2L9uq$Pi{_AjF*WnHc#7uz=!^mjyjn!skq!jjZ-Zl=M( zJM5gF-6lCKx%;t;I-bD*)M+jhxeN&eN-0M9#ipeTClo`xx(YoI4a$!CKF0-(BckeO}(0+n#BE*ZhM&mZpD`Y198Xsj^VA&N1HU z+0$i*Kj{BpGSct2=K1`=G9@l8v#oRM!EaaRE}j^A?5$|1P;p(v%|-*&{k8UWyYJ6A zZ+YYU%>DMg$)N%fpI%P(^tN4n#)kQgitUL@<}5x_+AM$YD183ye0lk|{-5&xd;dwY z|F+wIo!8|V`@u>68k4^;&3xarac72ogyaLtT?<`^~>EOu5XNEhTUDy3pk<@A=Jr*Mg&77YeM6-W4@vVyf%m zt#dA)JmsRiaz3|Q%==lbuP!G9+4a|R)T^E@Dw*F^VRf`1-(mi_Wy;Dq4|~|QeK&rz z>^#S#B?o^VJd?RX$!@)r;Jt`FdmFCpT6*=;lH=dD$sOOA8`;#h_2RS-Hr}tUuToxp zQ~E`~=eRTVJs~BN4L8Sbu~nCPP`CfXHce&TbNp$3%AKw=IW!IkbN630zo-#7S)|4y z`TUtO-<2vtfs0o5Oi8)R=z4diOFd7G*h-0gWuG=3>)SE?3ct;cCCe@;3V*iznQQS( zNY2x-eDTW@A)!~}AWr*Y)1a{BwxbsJ!uzf=CbJHA*gERS8(u!gp=RB$a^0k<^F&$M zu|R>-)o*81uUYoC$awa&EU&*4+%H@0%(S1mXGYpQvl$zE|7*Vdlj6k^+K^M-$eV8g zFZZAKw;nY1^|t%$|jzZ2M}`|Q~5 zKRZO&e_!mTmnSah&JlEAes3(eKe26(Alq|yMGx|xxE%#vr~(bLDLp?GI#J+w*UC-`p*y_Z=2!(lnUyVb!W*A!_r>BzH;$=d6;x z%yWIJzq8D+oIA{iswg|f8ubMTV)}BN$bg)h%I~0_GqiKnrskz z6(sPJ|4CfzACZ=um*g)w3w`7`Vk3B{B4$V5!84u{!WEath5Y5c^=a23X`P0hB2#Ld z13d#yx7d{Ld#KF)C@pAFMN9+V^qmhc-0*sJl+Q`Lr2C0+pU0!98%L_OesR3$oS-+E z@4`d3^7PMVua@4Cb||=@8`YuG_h8G8nL++78gk;R4#x(p@#_01wYq`r?4gO@3TAmQ z%?$L6{Aw`o?9ITAqmMTQS{DYrFgp->Lh+3Gp7R;j$WaV6NroBiC-6vwU_&xHu;HoDI{Ty2tyIZ)$aX>O42K{U=+e+B<`EIo-vZ zm;&uK?)+46U*X~r(Pw8CJN517IM=VX>$raS3}gSG2OP!ECN4C7Ht|96(@v89Xhcq38eC&fR!xW{~yuVy$?A#7yptta=X?zYg7iU-z#| zHk?i2wvKiPp4`UXHSgc|QZ=^~+e%v2IWW#nb=~Xn{ldcn$yu_qXZ9cccxk%sjdy1} z!sgX1GkL_4V`LreusN@%Y3qlCvzwmgPCGX7x!n;RvMR=gDcw$^RarzgfsC#oe( zP7mAGkXAHfqx~EHy?_3H*|*;KlU9gl5y^1XI$;JX_=HgQ%zG$yXGi4+!6OGr-V&RAg; zl^4ufI`iJdG~LB_HcD3RDcN<<*h8tAtx(zTz_CkW7X*5@IGWw_zx$^qy}n|GH?x_ZG0lyjJl5=%sllILlHTrZ$%lGCpHeu%tm4Tvyt4^9MRA`%_ zz>zC6>s!}J9m`gSZ3}(G4wywVI7LhEJW#h|qEwt*kVWQP=@}|p=C$NJlrEVRq3L;Z z$%kF7MynrxT9;7!t2HSjU{e_Pn^aHByo*P5L~_DkURWf#W*1kOPSkm)=E!+lQj(0G z+AAOUG_PH@CoIk2dD`sHg`6o|uT3K&@0?&w-q(HQz(tGVJ?D74ZtT3szgdUVXy&QX z<+ohemKFs4J@X^P&}79*?Wp86+fFz=?cBC{anKs8g-K^`^V|~&?t8*0k<_HHrS-y= zm#28V8gt&C)6$!)_fG!sB{#i-1p(J;LaQnRGe0U=d7fA$a(!-6t<09fO6iQR@6X-v zpPRBE<6lG5D)WHlQAgNgN;k=crG)jRB<`EJaaG$xl0`pA$*XiTJc8w&QWc&Y(FP7rwEWIakGe)0b|p zNL8T^N!OK`Plgsh`5Pkl{nEVyvtHVryHQX!$LGMg6)9ysH?$_!ze{-B?8zB&`f*&8 zOoZ{(6y;=dnizW@Xx)yD_0`&O*lSSbgdASMRo2Y)G30 za-ZyShV98B0&jKQQ(NuopA_on@~xTq=y4Bk_VLaKWj$OI=Bk;UTLZTL(Sccc(&;(% z6*DZanr>`gwQlP7Kg(Y&O+8-8%)Ddq($a>+wqpjH?fG|>e40F=bxXqEnPtf*Wc0MI zHhH{#GBb6RS1M=LO{Xos_NgT^0aQmg*V}9!AB{4xqK40kOc?*bMp4w#$8&$FYZ2=yDmlgY`_PGWM?K_TW5wR zjSVT1pEq)>l)kBDVr!TC=;Y;+6JnnQe9^ zP0HrJ9OLGkZ~tHD#J&YOMd{@lRre2TNe>wo7x+tFcm@nOcPWhJQ{%%Vc!`%PXlJgDep zt1W)*i_5u%-KM8WOxPUBJ3&C}fYNsBhnIgH zZgn(tX1r@J$Ed}3Cad9(V8oNM@70PMGFxUza=rNXk%OV|&Fj;vu4{h3_N;>A^|g8F zvn07r2)l_Zy;azME#SP5_2Nss57&oXy)*Z&X9SxVQdh1(~-PF0!^ zl5P9o!z#-ei--*>SA8Oxu3qr&*pkAY z_@~dnblaZ3B@rL)M0|5T)5}^_^o54ex6QWjXL2vSkDr*FwEo_W%z_tmWx zOgV8R+=*dtONV!vz@hgX!N~_-d)#7$x?`4L_&bJkQ(T#k~yl zn(J2V+!(;GSn-svBFDWwQk4;G#)5CwOk%$dG+m!);`5O~?Z(dcRTo`%s9oD{{z587 zdwxIv=66n@!e)nRe0x6Ebzk?g$33aR~lJq_Vkr)ikEV?-f3``V;}41Z65+9=ZXl)dp>?M{Z{?)odzxWC-+Zj&QGfT zvEtpC3+?xJz+XJWZgc zWkdADovYNs0&V_m?cJ04b6fbb8LOUr&fXk$Fz&eWQpL#}3yzDM*5N+<3;WjqE5MAOO#f;kVv#m{ux=L!Lt3rx*Ycfi9w=Hy3bm~)fV`c z+CE-Y)PJSTN2x*1JVh?N%6ap$O_$ihBff0ACL*%adFeJgmur05Mrwh}uS*NA-TFXB zZ1c)yj<;Et|BBk=FFk3)bSq^0QMhT}dfEul~l?FBX z?nisWZvA&&wCT!X=Bqs1D@+4dJ}8JVb6auqrfB}X>Nsu}-8HH~+IzaJbQzzpugK~0 zERoNUnzMfE?f5xw|4lt_dt=T*EB5DEoep6cq1&FnOOW68=bl&h!JkRo^{Lk`$KH>q zbCXwE^5!?A&s?)->Mulh^j*~2pdQh1_5XcCqsWglB|;?qFC^vc4w$u%eccQDTJfnu ztAdvIwl)=B%{iuhccJ9RSs|_p;c?tcni6y`MkOxVH~+}WyKlPRHXNJl*`nWIFIDWc z`cVFSoja?#Y}cjBy}F_&R91UGLR4vc&T;L7uYRxi;lUGJp>^pp>u#lxnXjc=uj|UP z203n+=ChU|aPBnE48Kd?>ho52&SU>wA9r?Uj?bo*!PgZwUX@Sg*DGD9rDp7LKBBIP z-$A2s^&(-LS-qagi$fFqp9sz8UDFrvaiYYs30h)Z6RJ6~CN0|ae3i)i#$$=Ab$Sj? zU2km?{q$(gszq9Ys-i5}C$De`PrdN+-{ttj?qMH}HaGwMd)nfc*0z~PFJ2M4%DwG* z>GwZ@@;jy;V2Hg@xVa=t=z+$RAT6o2PLDWqSF;N@TV!1k3cYvYqudK`$9EgA%A2nZ zPFNj(Dg zvo&JBSRG$Za#qh|#+@7d*MGIWRGjf*zFIlky*=hHY>uqS`jNQS*tqkOy8S}_3z@gn z@IJNK2*?Um?=bP2?+pPFq z10#;y=G$MbSKE9&jBDenzYm{F*Jz48m{l=%-t)CFTrts_C)D51jo)AODbW1)W83-_ z;*(c|y`L_#d}7VlSFef$*rYSWfgs>gj-?JtbAYtM6O!?c!nxOUf19H)(_Y?)(K?rwZNpk@Mr$ z;2G9<#xk4;Rjwk3c*|&DnBkCxaHM(W%Bv==J%cmy{fI7zw-OcDK&rn{!OxY z{-*lZ1g5M&?TzQ|Dc4_-?#zl}^K{Lnq7`3YRTD8f0(#)kfR$#j3yubrLc8E2JiQd0bi5;kmyv z$@=2^e+T~x$jan=nc1Ku`P;bSbIZ=Ywh$&)hnT-CnSpDbJTQ`Z)2{euOUnwyg)J^? zyDGlSj!>GtNn_G)xB9@_N%J|Cq`kEYk8Mdp%yq)`+H`3XOlX>eY zADv&mGuTU&)_j>6Af%Do$(VA7XNQ;Cehn_Ab7Btp9xXzzI$ig7{*9dYqUF_tgw^L; zG-jJbpA%m4vuLW1-PMASEC$IN{LC+SBb|4&?71f5-|f1;bMZ8epqWpen|hV9vsc%u zsoea1@Bf3kkM4($g#4X&?H)hZvPmb+843mNgff3We4xs?p{+RIZn&8ELjubV6}B&V0SvpWd-yF*-pO4wA!$#S>;BF~9{;4Dr7~JX zFNjslVCVD$8+zk>l2M-P#5d*V=cUJqE!fO@Yj0!8ga-w4L)AGv#W(d_8zs aR`0LVhaz>a@A5}YtN-J$(bVBzytn}I>!{?Jy2t6Yz_^~!YqoxXSX^uy*#Y6_=B^#ztL zIxKn2coFw0)_d12XPhy1+qCg}X=iz9=lWMtm+x#`tKPHplJM>$^-s92Z_)F#+-5Rs z`nj-MzBfMo&@0@R|MS1h_Kmr(W0!q@^YZzgZ}+O-FJC5?D0TPiSCd^*;rI47UUhyj zb=Rl=zyJQ9dcr7DsP)Bx5|vc}4-}4cN^D-F+52INrh(cFl^cc<8?tYQU0tJe;l}@| zJMRBlyu+E*kGK5b#9Zs%lKjt19wK9@?bUu=k4Z!J59a#@Gz zj7tk<`%Vkyd@Q+IsnK}~XOdKmW8ciDU2?aJ4x|;VjPUj7yFdBiqv<{KE7B zGj6uAgq&M*=tu_t3DM0p2TTtpgjfbTe=)St*=_sJ&`016}9I#ySG2S|NcDJ=1nzD zCw{opMCsUVe8HRlPu}F|j!8y4LJX%DzCAESAlKttX=Rw@1j{3nQqFarc*pruVnuh! zD$dfArzKX2lr?>czV4-#=Focd#u}e>v9XVqTwvFmkdn1k`+-GYchE_mT_;_QxBtq# zborU#^oMt3G!(>l$d(mw3GeoMG@;-1fWwE$cPBr1>~V>`Ep@9|(51$W-=eQCx*7I1 z=k1y^o(FsHYMidPle(+-XM5SnczH$kh^U9lxkS+{k)BO1Y7$BEad%B_HLot6 z=_7gL_=W{V;V*UsSIuAcO0>_IGrV!5;C<;D;S$?@`;@F!u1K30`owyTkyg;sZ|J(t= ze|+~v{LlLw&kYO3e}wP*8Mpq;p#vwDH6|Rr|0(uU4-e0~!|6wsZb*{Y^fLcvb&V4X z2Y+(eWeXMgS114feg5Cq(C)oY{-ymUYnIj7d;j2dUzhbJvEth@GxjWrnMVpY-Bgu4 z?0l5P@N2ANv$I=Zkk+NBH@w+1c1@0RkDbY8EuUCuwB}o9P1+7yDVcr7Zzq3E>6{og zYv1XN3b9=rUQNHIy9L&BuD-GNN|ET8i9xaGo6SS(Y?U>fYmkq)%N(E=d zbUTF9b^W@T|74=)%ZmTb8)SdCn;6+TJw2>&UHhv+%aJ2XKNP%7*(sdox@M+RY0s1- zrhRSe4@}qi=rfxy&C4$=^H z9s$``iisW$X1%k-vyCPSt+L8}_W7zvSQlqPcI~;yyShi11g|fjxgb_>iEG@79bUVG zA~|$dG#faBA?;@SCA4o$P)F&f3y2ry%z9dZ&?P9lmIRzHCmX~bHsM~hiF7UwR2WWWN**kD|*V+(}S!7$~84lB-OI+FTZ`~T3GSjqg-FJYS=%j_X|L)uE%{g7`KgY(n1!ju7IZIZxhPK>!%BLZ+Py1SE z;Movi8*^WSbe>woXWHPv*Ji!BY*OI$ z_vPx@J+-sgYP0wR*7A06eP3Mb#lL9wlxK^Y?1Eidcn+U9^>*u~O0}KE9E@I5_Xg-_ zf8YAg@0{3@)55DboJy|#cai7hSk?PvN6cK^7A?7Z4mr#YVXxSXEOKPBpPenP*i~kE zTzsxCx2(a2=@wCW>!+MGK3ViOi#PO}&yO3$x~Hd=oxG53`g2jk{1?iMinGIddPCN? zZ9n+Rn`1ujxr_VO&JPdRuA_Y?{JHMWrL0{NTVkR#XRA+Qof+ahb&Ipu!)A^}(@I|+ z6gk+msGo&p;sS$}U2W}$x4eB}u+iYX*w+%rupP+{ch|3Y5;H-mMs-Py#;-FC65RU} zZxnmX*eV+LdtWx=@1||*GA3UUvq6p0{&jjh zhy5&EmhRN3IsVSqgIztq(*HClShOl7mV~T5bx%`F^)E-D_HLVt4FaOIDhh$W{8iVT zyUEnUzm-?uVero!na971-!uHX@G&jWfBWq)`90=4s%Du7P25qv*YB+Vy^Ck+)7(GI zK7A_x|MeG7eT5HyHr;EJUsCb$^o=VAzFYs7*}SJ~`pLe+b@Np9nXcO2Ssk@tP0y(d zt=D{B)IGNqzO%~q+ewXMZT&(2H$FG7xUc%}#_}lEyYFi>FRQ=*va;;ZH|zDvr=G5L zeYYe+cJ<4f>z;Zp-0LV5uAcpF;e&f&S?gWOwh37A8Y@h!-XZ@Y@8iRbJGB2C4B2=8 z+5A$@?l6&8*X3^1Juh`Rxp(P_xgML&m9uca^_?VAI<2!;Bg(*tBPNTfQAcA()7?kL zC#DANTi+jQE#bzbqvUVGLrkrO2h-OM=V zif!3d^?GVwd*t*D8LtIv_J2NqQ-yb1ab!`xZjt!aAJ^`le%<;_?ogN`>XQr$#To<|6?n^*?V&DaF2TTSbX)ZEYDjJpQg-L zxwr0ZS!>D#^N3o>EgKa#uAQ{JrCCN&utY~+f!%w?(Oet^M}T%XI1~!9lE?iO5DZe zh}LaIZmx~*ZuYZge|NgdX6Eoibna~q$G+7OVPB@QpY+JQcX_M-gOV%&s#g3t&r7?zVzu8xBy}Ry$u>HcloT*~Z@&TcwpSb9H)cafs#hEh$R2!WT|=W6{}__4SCWTtb_m8D1L zsO>OrnqYdu^Te$c=KmIG%gdkps{VY>R?CIrM>8%TT)i!-@JhBZ&pMIH8C|EF`dZg1 zyvcYa?XC2P`P}u#Q6~;MNVXZNcrV$Kad?a7u4$7`e_E9N)FH4rpH0VMGRy0r85{7G%f!;sjojl;|uevTrIDCdgnsK zgNq{rj@H(f{XO|TXZ6Z?+Mk6)uhibGYMrGV;mxA@ z>(bBCu=lO4%esDr?)8+&>+gM~DP5bnJNBtgMbWCqhbMkx7HxU|t2|>_)Z3G(iuwkk zj^%~6t3|g&NlU#J$|+fVuzk(6B9$hY_v_u3)~*qb-ORcuyE^eu(S^1bfy^eb=FE`ZB z`hDl*{?kp3IehmeXI+c>Dk4+fwDC~wnk6n9ePgz)c$E2uPto@a?}5X|HWiut&`QW& zsc=pF&xgY0vO*Wi?wmZvYZsR9woS?4@S!4yYuj`R&b?ct^p<_<|CsE(pMG4|W)ED? zYJGe!^N*Rl{t{~s?$)i(x_?l+z0mX8$*)DbJ1Z6#7&taBna;N*oy)Fda?dG8^~;X0 zR?cP6QWOQ%nf}Wz{kg(>w&wfa8J+KcFO+RQtH$HFUc&mSpBEk2evzg0&QPw|w;*N14>O5p zk2YB4C)Xb=;4v#sn$>+ck16&}vIX1hn_ivVMM``!w_{|=a_{I%^c`FlExk~e(^8PV zFHw(g(dy0>`y=;e*!B3Hcs{L?e?pqD(>>-Tk=xg$3IC`&^XK^l!QM-StMfASjQ{`4 zS1r?Ax^rFgc@e*@FV+|_W?CjVioAStPV7)#)f?gK6VE>qotp7xaTWJTW`k8PGJGP= zJ=H(l{_y@;-o95EGmYhDKAkh!)OEpj^Nf$YYg;p;^TX5kPi(fnVlH^bZ&UGW&FhW_ zBhP)Uo~?P3_1m|$^H%C?BKdTu$x7v~Xfh}J3TF9(@YWq)RfAYC0dd9qO%U8AKUgDeQS3kG;p|kq)^_4$w z=3UD8^yS*;WhEKyGyn4#|Ld3DtdSIB>+QTCEL_lMe%ss}d3Bc6t25Zc^yS0Cec5hK zvT?k(FgjNEQE8)W{;~~g*Dd<0ck`6hq-%E%ZQIp#tu=8$OLnQ~c{s6jg}8oLIPc-I z+t1YVpKRbT{x6yKeZG0hu`<2aVWr7J;#n)}Z04G$Scx8fDNumPwi9*!qMY&~{pshK zAJtCT?|OVcgZ1W|&NZ8-mwt(e@GoJDUnQ^qoHz1+)UG9GYpSegu2+95e|KZXIhHUN zo9UjLHq3j;voFLx?ws@{D^ceiw?A5PAK&G3Lt$(GyNGpGf2L?T)|$NH*$+`+Cwf@# zklTL!?_pD?{JQNH7(cnL*uUPgVuI<>WihD0-_iEQUz0q)DvV8yLEZe1$ z&^ha@L^VDAn${m|m@i=6_(}AP;=Xmh$73(enY+#^>$ul>>)Okoc7FHyRQXxxnk9tgZud9<#de;`f|owsZ`tm?yo$ZH zvN0}gwrNiAtZL;&zt~jfh0X5Ua@e)B$JTP{Uk%Qq_x`xa-TmWM#xjN3n00S(W1P~p z*O%Qw?>8L2p?<4-u0<_(NPCeOmngeVp%oLS&!jgt0#+-6L^xUJbu8b<$a}(7`9(u& z>y|(4`7asPd7S#@V)K=Eg+yfO5uV;x3EW2*y}LriJx)QS1My$u_`ZvnD7qsV@d0RA2Q-8E9|A11=w%EfP z?_TqM-gwsG-iZ)v{+zl`eQEzbKj92tSjxks`+EKcf$2K&TVEa%H@r~vRruFrp{X$& zZgw;OFkp)cJC`Tz)pzjo4*|9~u`nJr{!dyTl1wV)y#dy4%L~zW%S1XOuTA zF--Vr#q0k2T5w9)jM>h74pUkk_wXy8|GUQS;>*dWipzHLhreGubMCHreJB1XL|k&e z$*Ct;{IJ+G_40E6%SjCHT~GWj{Qghx*|g`+-!Gk6drj}NmD1k+XQJG!n?GFc>`RW`5t~x|D7DAui0;KBdfx)HEW6#5-uF~5m8|mF z=_xYx*Vlk1_Uqjny}JbUpZb4c{v=paR`t_n+6k7KHcIiQ+7G{Bn;Pts!FbMhVO0>9 zXkpZ4gA}#4Ai;B&16swE^*tZVEsXC`5wW~={6xkbb0tAX|CfeP4~+}?n<}kvCS(2RK&j*H|NR4 zteSD!LNMPZcioEenF~_9o=9q|Wo%E`WV54bSy1(K!}D5qykE83oUwF`Y~C}&{#gCQ z+`xtW%~!7GlrE6S>B;z4cgy!`379d zT(CCz?y<(DX{9gt=G~MiD6TBI)%)%4!oz3zPA2yU*+1EMzCQNwru;|85 zSGR=3g_Hzod8ht(?D2O3`*fLp>*E{-I_e7d5)Z#&d#b4xlE8bgp`-oaoN%wp203bN z$@*_3d2*`Wo7+zL`OvL%|GI_znKZ>w~ZTqGt7QSeqNZl)z%y zgFDVgz7sCUa^XGUcXCOs!DlYE@0;F~>%E+5OZI~X?bU)v+LRArSa@AlTucRagark0UlI3d{M5>*{M0T|D1KAhs^v7$`b7_lr%I|3vv&= zTfBtfn&!TiE9IrvN4_~>L7?p?*NtaSdxHT2C$ndNSfSGs*eCg;LEd7DgY*M*$D z;>7#pk6q@CeaTY)g};9O*nHBXN{ZRf6%d#ayw zBoA$jX;PHV7b`IdxD><3G3PFGU6J6N3%SwU&)<54TN$e+)J+xr;~aAPTxUYMB>$t> zdAdeCiw(c^uP8TANS^=TiITycCC6Xg-y{1sfazKI?lOj!)Xt5+SMiuhwVYYd6zqR( za?q#Km2YQnU(8ey*4QXo(rvLQFm&SC^$AWLMWW~W%J(s6>ZP2G~qX<_N9xq9*G zS?2lfU-vLhx+Z)#%5hc@%i>i^v*UZsxh*y}3drg_NLXqj{^&(UgNmUJho4_i%6c~4 zRh^&9QdUp3+IZ}3^AC@nRb5$itqB#kzss3^QnmGNJIvtc!B=aNvZ0toU0w5nt3-S- z@3$4E`S<$5W;9;C7+0`eW7W^8eKyUak3xf_*TlXy=xLML#UAJ|b54q#{+1Q@&fdPr zRk$+irl*0%mY+_wnpS7Cp zzqM81>NU?>=Zv=;ED~((B&+<5YBMGrHzH#d)*3idp=t4>zQK`YxSwZHw^D z8sXZW^Cj-)r-k_Mmng(=U3}v?p=Y+=b(u6R^KOHRy2BrqitKyout8+e&B+EYCx@54 zopOD%lY!3jhqL)wI%ZfUeti9A=Y#5#d#@~Qad&4w)Rdh4<{8npDX*tK<+}x5@IlOFpIv?gJUHQdn&N zxi~?c(#(foSZqjYvm(AN=&SYxI zw-R_$cDpO*TZ;MoV;%pNi_c!vz*cL`f4}5F@jZ{ft2S@%y?5n_nSEt;fAWl<=M66J ze`n{f6MgJSX%V8qifaf z>7{QYMCMyXap*r_ubUyd#l9miXjb&TpN#I+rfcq>ILN!^vR+aXJ$9gPJcSfZ_v^zmFi=WaMd^T>fPqNHHvJKZ#L?L1zkAT=6F~@EbB_r zsywab@9s(Kg!QDEH=e87EH~{+gz}1MyQ-NZn)4ctXg%3<-SV=zy#s%DM#~JX`KMOy z4sVnyVP3Otp7@shtqUhv@g(XV{LPfKs%q8lclRy_TwU~b+tR3V`Nm3R*Zb#dK2I(; z`8@yD(KG)aAG^#TYd&x0e;F;Otvzq4-Ba6D7qa{6Mt{q&lUF}qzLKI~eayhg ze@^t|gF7-08hgFw>N0uEB32&79dM)U%Hi1X8ETuD4+-BjFWw#cv&t=cgW%~Ux@v1# zSIpZYYkE)T1mnZbZ|!T(S+_52)wtbRto-PSXTI=%@t3|@=jM0FJSn*8G=(p}+jC=B z>-OZ+KN;?=5$sFaeoOtP)0BM!etgzxPic4AjJvO@Jd1Re>^}yp}i#s*fhNtDkxeK1$dB`Bb*naE#9Uq^(l`ar4S|BpN^!f7b zpPz@kov~T8go|U7e{p4MZtyJe`GvC~ z7Fq9?2}svAJ8q+B+8!>pLUT`W*k0>A8_VBpQ@CH1eCT=m=iut8iCWc4T{dx%3zmKG zi`@Ed$H$5n(gC}oKE8Z#Q9q@Dt#n&b@Im3AvvH9rOqF$WHZA&9EiTXz9Cmo~-LkJ8 zHIiQ|l@l#eP3-RrsLf7SC(RX=_9MO=HQ?*7; z-YkA?+VuIyLQd}fak=tq{?V5ouKeHqGePxi5BJKLbI;!&EKzT>|7`Z%8p&2!WErC#2d=HqZ@{rokb*WX>q>noP+e`D_o>6(Au7NxJm1HLmpEKuiOBzld4KOY`-g{jGCjb;XP}A0>r%-*bM} z-@2f|wEf4|?(*y-t)ER}7#8JwzQ3%fEn9V`sD0%kAxGDv9Is!VzWgaobH~od%1$X(Hb z$()NyHz;tw%B=J~G(E|o_3>Z-w)87I-U@!7zdCKHoPLand%WOk<18(U4K88w?*iuK zd}#82puw@VWXh2h4+L19OB(JTWY%Y0cH?7P@KnRwx18-?m0W!$7oBH6ZnMJSFm(LkxOw}+KX;ZUYP*=E-F}ke&VK!~+$kR+PU~%J z*NZB>yR^YHjCFOmPK_Fy$h;M2Rx52)5-~b{jXQt)7IBbyMT?zWSe>^dZ=8F4?L7n0 zi*FNZ^LM6a=hP=#Z=ZZo%j1b!vfUH@8_nKx=Y-_Ecd7dIN#tIOlkg6$Uu^GtO@*ER zE!Zx4LwIM8Z}o;>THNzH8C!!kUf|ft?xF118krQ-cXL~Wi=P48yAEUXImlB_Ge+m_glgb zG)$hpGszcmSss1W)PYAax^wxgfHOyr<#f-p3*xVE67k;cptr5zXu7yc+UA*y#JW_Y zG`y-9ODAlZUa-C)Wa=l`Pt8-ee>oaGDfZr~9`;>!6Rz18YHxhi~%bc}7}t zs*4P{cR8%}Te$D>c3rVz!$q2mxlh!RZ%zBk^hzO9e_@>9?iEHqpM|X7GwaWf+670- zSHF_`chhvz+N+%VcQ$Fmsgh>FOL_mO z`yb#HnECJ1%QTgUlOdLD3mbi=avPXT5Gd@PWRkx1foI;8;Gl^Yn$&j&_J8@?;AC>* zKEKD4116Fm4<7eEc)R{H=j!;{-!bdo*Xyd^kr6pPtMc2|*r?gOzpe7hWA>({-Vx*3 zVj*cU?*RMpeEl5;I~?EsZ8&oL{pAY9dGBQTY<_()sQWPS7t z_vAgh%H!r^+vlIV8~-!>-Sdi|uO;FK`7V8Dp7d#T{_mUT|Gc~Gyg%aKndSS=$_hV` zk(G%Gt9jVOUH|Rl%oS`7x@HlL`~EUI%octzt6+1XTjM)Jgj?Ug{LvTiplZ|ZlWuW;L}Y@5*4+Ox^TD@Qu?fGKgLcf`U-f^P z)rLuaml{7=8<{$o1_rE*lA1UvizTJrK`Q%u_5!Djngt)5jg}>rUA=K>!-A}$_lF<( zEH-dEC3fc)SIQ&?rOA&}Lf#xc@vk8S6s!fM0c(W%__D`Y!h_e*N2>Y@U;B9ky zBKt9YV{+u>@2$264=10SIN_{n@2x|#qZb98C{KCBGplkH*Li2hy_W7Cod&_u7n~G7 z^*!)17K|(E>q+sttb6$HGuNpK_LCKk{A_x0wo@oELPY7kM%?CQrA4Y7KTlZ(rFMtP z?i5;Wvx?L<4ZckEG~kt^qSfBo)*VMdSLXZ^JQ zH0M{_uSrV;D&0Rf@7XBz^yTl;|Ng@H-G@EP1udS=D>s=xbKglb*)X=J^U6im`#xU3 zyLN-QXs2|YQKgNFA}1sJQw{GX3p?8#o-wB0#*?gEssevZ$+{OfsdJWTukz>4Jt?1l z7$`9Hu5O+bHtUtn`nG&y>7~jpkwF6Y6}Ru*y=VLHbnV6KedOdlJro{T++8PnRcAJH z$)5V)Mck|(WsBCcJ@x(O{q|q?Jfq4Q6-7@*CRbBN5s{{%v(~%*FD>rZ{HXoC$Tab( z`sCy8LX)m&h>2WHVVrW%>4*80^m`M14E2kzy=|E~-)G(*Pmc{h4j#XrqndkvCwI8+ zrP+D0dXugwUhd{{xbswYZi)ET;@!C_!e5s9ef+X_kMj2&lPIgPC`_ z6`!zovM7IH;WBu;Lhp$z=l%YkpzpFy)8#AFOs8_}sdMtNUd3PO{&t7nSMBY~n!LG< zvlS&>I-fAL%qRwa(J})aSRW``6C9W_>GXX1e^vgCJWi{M-_uIOU zC#`pJf7N@Pd0%x^M%AajeX&z3*NYq~=jgkwqrYnP`-}>ix&vzF6GHAxy|g{Z@l)S} z(EqCxgA*L;@_x3aehu8SZ}HF9vqZb9mvt=_sB|x!U8|Zcvv<|6zHKpc?}g~Jp0Ms( z+&lGZ`Ifq3we_DaJbN3_u}As4vi-g_tM)CPsy)*ns5av>8?XKQj)2Ts_xop!*X`dp z<!}P+WTil \uicontrol {Qt Quick} > \uicontrol {QML/JS Editing} and - select \uicontrol {Enable \QMLLS}. + To configure \l{Configure \QMLLS}{\QMLLS}, go to + \preferences > \uicontrol {Qt Quick} > \uicontrol {QML/JS Editing}. To remove language servers from the list, select \uicontrol Delete. @@ -237,35 +236,33 @@ \ingroup creator-how-to-lsp - \title Turn on \QMLLS + \title Configure \QMLLS - Since Qt 6.4, \QMLLS offers code completion and - issues warnings for QML. To use it, go to \preferences > - \uicontrol {Qt Quick} > \uicontrol {QML/JS Editing} and select - \uicontrol {Enable \QMLLS}. + Since Qt 6.4, \QMLLS offers code completion and issues warnings for QML. - By default, enabling \QMLLS will only enable warning messages - and code completion, while advanced features such as renaming and finding usages - will be handled by the embedded code model. - To disable the embedded code model and use \QMLLS for everything, - select \uicontrol {Use \QMLLS advanced features}. + To turn off \QMLLS, go to \preferences > \uicontrol {Qt Quick} > + \uicontrol {QML/JS Editing} and clear \uicontrol {Turn on}. + + By default, \QMLLS issues warning messages and provides code completion, + while the embedded code model handles advanced features, such as renaming + symbols and finding usages. To disable the embedded code model and use + \QMLLS for everything, select \uicontrol {Use advanced features}. Also, \QC tries to use \QMLLS shipped with the Qt version in your current \l{Kits}{kit}. To override that behavior and always use \QMLLS of the highest registered Qt version, select - \uicontrol {Use \QMLLS from latest Qt version}. + \uicontrol {Use from latest Qt version}. To use older \QMLLS versions, select \uicontrol{Allow versions below Qt 6.8}. \image qtcreator-qml-js-editing.webp {QML/JS Editing preferences} - When using \c qmlls from Qt 6.7 or later, set \l{QT_QML_GENERATE_QMLLS_INI} - to \c{ON} in \uicontrol Projects > \uicontrol {Build Settings} - > \uicontrol {Initial Configuration}. + To automatically configure new CMake projects, select + \uicontrol {Create .qmlls.ini files for new projects}. \sa {Manage Language Servers}{How To: Manage Language Servers}, - {Enabling and Disabling Messages}, {CMake Build Configuration}, {Kits} + {Enabling and Disabling Messages}, {CMake Build Configuration}, {Kits}, {Language Servers} */ diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 433f0f8b1e0..c0e16b12887 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -401,7 +401,7 @@ public: uiQmlOpenComboBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); uiQmlOpenComboBox->setSizeAdjustPolicy(QComboBox::QComboBox::AdjustToContents); - useQmlls = new QCheckBox(Tr::tr("Enable QML Language Server")); + useQmlls = new QCheckBox(Tr::tr("Turn on")); useQmlls->setChecked(s.qmllsSettings().useQmlls); ignoreMinimumQmllsVersion = new QCheckBox( @@ -411,16 +411,16 @@ public: ignoreMinimumQmllsVersion->setEnabled(s.qmllsSettings().useQmlls); disableBuiltInCodemodel = new QCheckBox( - Tr::tr("Use QML Language Server advanced features (renaming, find usages and co.) " - "(EXPERIMENTAL!)")); + Tr::tr("Use advanced features (renaming, find usages, and so on) " + "(experimental)")); disableBuiltInCodemodel->setChecked(s.qmllsSettings().disableBuiltinCodemodel); disableBuiltInCodemodel->setEnabled(s.qmllsSettings().useQmlls); - useLatestQmlls = new QCheckBox(Tr::tr("Use QML Language Server from latest Qt version")); + useLatestQmlls = new QCheckBox(Tr::tr("Use from latest Qt version")); useLatestQmlls->setChecked(s.qmllsSettings().useLatestQmlls); useLatestQmlls->setEnabled(s.qmllsSettings().useQmlls); generateQmllsIniFiles = new QCheckBox( - Tr::tr("Generate QML Language Server .qmlls.ini configurations for new projects.")); + Tr::tr("Create .qmlls.ini files for new projects")); generateQmllsIniFiles->setChecked(s.qmllsSettings().generateQmllsIniFiles); generateQmllsIniFiles->setEnabled(s.qmllsSettings().useQmlls); QObject::connect(useQmlls, &QCheckBox::stateChanged, this, [this](int checked) { From 600fba3de894ec60ce56a0a5162b4fc51660fce2 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 24 Jun 2024 17:26:10 +0200 Subject: [PATCH 32/73] Update qbs submodule to HEAD of 2.4 branch Change-Id: I27e7076a1cab41f5df816e27a1b76c1baf3ab4ad Reviewed-by: Christian Stenger --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 2e54309c02a..c99763b462a 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 2e54309c02a56c602909ee3f4fef6c654a616c85 +Subproject commit c99763b462a93b547f4f3f41ab84e9e793276d4c From 6ca917c123dd38b20056276922785793a99dcf9c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 25 Jun 2024 08:26:23 +0200 Subject: [PATCH 33/73] Core: remove unneeded template of mimeTypeFactoryLookup Change-Id: I2ca6defe1054b0ac06aa134c099a77f253d61a02 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/editormanager/ieditorfactory.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp index 22aa24e7377..74c35a7b5ca 100644 --- a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp +++ b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp @@ -16,15 +16,14 @@ namespace Core { /* Find the one best matching the mimetype passed in. * Recurse over the parent classes of the mimetype to find them. */ -template static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, - const QList &allFactories, - QList *list) + const QList &allFactories, + QList *list) { - QSet matches; + QSet matches; Utils::visitMimeParents(mimeType, [&](const Utils::MimeType &mt) -> bool { // check for matching factories - for (EditorTypeLike *factory : allFactories) { + for (IEditorFactory *factory : allFactories) { if (!matches.contains(factory)) { const QStringList mimeTypes = factory->mimeTypes(); for (const QString &mimeName : mimeTypes) { From a9a611e21eb9050f490de571a350ecfa1d2ab9fa Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 25 Jun 2024 10:49:24 +0200 Subject: [PATCH 34/73] UI text: Add dots to ends of messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use consistent wording for things that failed. Change-Id: If8593077352b48418ca739d6933beef588057ac1 Reviewed-by: Sivert Krøvel Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/presetsparser.cpp | 4 ++-- src/plugins/mcusupport/mcubuildstep.cpp | 6 +++--- src/plugins/mcusupport/mcusupportoptionspage.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/presetsparser.cpp b/src/plugins/cmakeprojectmanager/presetsparser.cpp index 6c15f217f09..35567b64a64 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.cpp +++ b/src/plugins/cmakeprojectmanager/presetsparser.cpp @@ -527,14 +527,14 @@ bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage if (!parseBuildPresets(root.value("buildPresets"), m_presetsData.buildPresets, jsonFile.parentDir())) { - errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"buildPresets\" section in %1 file") + errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"buildPresets\" section in %1 file.") .arg(jsonFile.fileName()); return false; } // optional if (!parseVendor(root.value("vendor"), m_presetsData.vendor)) { - errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"vendor\" section in %1 file") + errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"vendor\" section in %1 file.") .arg(jsonFile.fileName()); } diff --git a/src/plugins/mcusupport/mcubuildstep.cpp b/src/plugins/mcusupport/mcubuildstep.cpp index 102ee306fef..786b363d38f 100644 --- a/src/plugins/mcusupport/mcubuildstep.cpp +++ b/src/plugins/mcusupport/mcubuildstep.cpp @@ -67,12 +67,12 @@ DeployMcuProcessStep::DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, I , m_tmpDir() { if (!buildSystem()) { - showError(QmlProjectManager::Tr::tr("Failed to find valid build system")); + showError(QmlProjectManager::Tr::tr("Cannot find a valid build system.")); return; } if (!m_tmpDir.isValid()) { - showError(QmlProjectManager::Tr::tr("Failed to create valid build directory")); + showError(QmlProjectManager::Tr::tr("Cannot create a valid build directory.")); return; } @@ -193,7 +193,7 @@ void MCUBuildStepFactory::updateDeployStep(ProjectExplorer::Target *target, bool stepList->appendStep(DeployMcuProcessStep::id); } else { DeployMcuProcessStep::showError( - QmlProjectManager::Tr::tr("Failed to find valid Qt for MCUs kit")); + QmlProjectManager::Tr::tr("Cannot find a valid Qt for MCUs kit.")); } } else { if (!step) diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 1383c737e71..d2269a40b51 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -320,7 +320,7 @@ void McuSupportOptionsWidget::apply() QMessageBox warningPopup(QMessageBox::Icon::Warning, Tr::tr("Warning"), - Tr::tr("Unable to apply changes in Devices > MCU."), + Tr::tr("Cannot apply changes in Devices > MCU."), QMessageBox::Ok, this); From 9cc4c6a93eb6c8b0d5b93674ad6217fa33a56ff5 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 25 Jun 2024 10:39:56 +0200 Subject: [PATCH 35/73] Boot2Qt: Edit UI text - Replace "Boot2Qt" with "Boot to Qt" - Add dots to ends of messages Change-Id: I0c4a795199bf6dee41cc69c5eea34bf28246f0b6 Reviewed-by: Mikko Gronoff --- .../boot2qt/device-detection/devicedetector.cpp | 2 +- src/plugins/boot2qt/qdbdevice.cpp | 10 +++++----- src/plugins/boot2qt/qdbplugin.cpp | 2 +- src/plugins/boot2qt/qdbrunconfiguration.cpp | 4 ++-- src/plugins/boot2qt/qdbutils.cpp | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/boot2qt/device-detection/devicedetector.cpp b/src/plugins/boot2qt/device-detection/devicedetector.cpp index abe06bc566b..bc4fbcee665 100644 --- a/src/plugins/boot2qt/device-detection/devicedetector.cpp +++ b/src/plugins/boot2qt/device-detection/devicedetector.cpp @@ -80,7 +80,7 @@ void DeviceDetector::handleDeviceEvent(QdbDeviceTracker::DeviceEventType eventTy DeviceManager * const dm = DeviceManager::instance(); if (eventType == QdbDeviceTracker::NewDevice) { - const QString name = Tr::tr("Qt Debug Bridge device %1").arg(serial); + const QString name = Tr::tr("Boot to Qt device %1").arg(serial); QdbDevice::Ptr device = QdbDevice::create(); device->setupId(IDevice::AutoDetected, deviceId); device->settings()->displayName.setValue(name); diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index d9cbd3ed2aa..581767be99d 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -88,9 +88,9 @@ private: } showMessage(errorString, true); if (!stdOut.isEmpty()) - showMessage(Tr::tr("stdout was: \"%1\"").arg(stdOut)); + showMessage(Tr::tr("stdout was: \"%1\".").arg(stdOut)); if (!stdErr.isEmpty()) - showMessage(Tr::tr("stderr was: \"%1\"").arg(stdErr)); + showMessage(Tr::tr("stderr was: \"%1\".").arg(stdErr)); } else { showMessage(Tr::tr("Commands on device \"%1\" finished successfully.") .arg(m_deviceName)); @@ -107,7 +107,7 @@ private: QdbDevice::QdbDevice() { - setDisplayType(Tr::tr("Boot2Qt Device")); + setDisplayType(Tr::tr("Boot to Qt Device")); setType(Constants::QdbLinuxOsType); addDeviceAction({Tr::tr("Reboot Device"), [](const IDevice::Ptr &device, QWidget *) { @@ -218,7 +218,7 @@ public: QdbDeviceWizard(QWidget *parent) : QWizard(parent) { - setWindowTitle(Tr::tr("Boot2Qt Network Device Setup")); + setWindowTitle(Tr::tr("Boot to Qt Network Device Setup")); settingsPage.setCommitPage(true); enum { SettingsPageId }; @@ -253,7 +253,7 @@ public: QdbLinuxDeviceFactory() : IDeviceFactory(Constants::QdbLinuxOsType) { - setDisplayName(Tr::tr("Boot2Qt Device")); + setDisplayName(Tr::tr("Boot to Qt Device")); setCombinedIcon(":/qdb/images/qdbdevicesmall.png", ":/qdb/images/qdbdevice.png"); setQuickCreationAllowed(true); setConstructionFunction(&QdbDevice::create); diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index d3943e94b12..522e9151c76 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -106,7 +106,7 @@ public: { setConfigBaseId(Constants::QdbDeployConfigurationId); addSupportedTargetDeviceType(Constants::QdbLinuxOsType); - setDefaultDisplayName(Tr::tr("Deploy to Boot2Qt target")); + setDefaultDisplayName(Tr::tr("Deploy to Boot to Qt target")); setUseDeploymentDataView(); addInitialStep(RemoteLinux::Constants::MakeInstallStepId, [](Target *target) { diff --git a/src/plugins/boot2qt/qdbrunconfiguration.cpp b/src/plugins/boot2qt/qdbrunconfiguration.cpp index e95c9562c48..66ca757bf9c 100644 --- a/src/plugins/boot2qt/qdbrunconfiguration.cpp +++ b/src/plugins/boot2qt/qdbrunconfiguration.cpp @@ -33,7 +33,7 @@ public: QdbRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - setDefaultDisplayName(Tr::tr("Run on Boot2Qt Device")); + setDefaultDisplayName(Tr::tr("Run on Boot to Qt Device")); executable.setDeviceSelector(target, ExecutableAspect::RunDevice); executable.setSettingsKey("QdbRunConfig.RemoteExecutable"); @@ -87,7 +87,7 @@ private: Tasks tasks; if (executable().isEmpty()) { tasks << BuildSystemTask(Task::Warning, Tr::tr("The remote executable must be set " - "in order to run on a Boot2Qt device.")); + "to run on a Boot to Qt device.")); } return tasks; } diff --git a/src/plugins/boot2qt/qdbutils.cpp b/src/plugins/boot2qt/qdbutils.cpp index 922f0838f7a..e788717829e 100644 --- a/src/plugins/boot2qt/qdbutils.cpp +++ b/src/plugins/boot2qt/qdbutils.cpp @@ -65,7 +65,7 @@ QString overridingEnvironmentVariable(QdbTool tool) void showMessage(const QString &message, bool important) { - const QString fullMessage = Tr::tr("Boot2Qt: %1").arg(message); + const QString fullMessage = Tr::tr("Boot to Qt: %1").arg(message); if (important) Core::MessageManager::writeFlashing(fullMessage); else From 2cb03eccc885e4439f9bf713b983fab314ef0c79 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jun 2024 15:17:58 +0200 Subject: [PATCH 36/73] ExtensionSystem: Make PluginView::setPluginsEnabled public Change-Id: I0468e200b0fec76e699f9e5a64924b437557aab9 Reviewed-by: hjk --- src/libs/extensionsystem/pluginview.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h index cd0c60b69a7..698fac77ca5 100644 --- a/src/libs/extensionsystem/pluginview.h +++ b/src/libs/extensionsystem/pluginview.h @@ -38,6 +38,7 @@ public: PluginSpec *currentPlugin() const; void setFilter(const QString &filter); + bool setPluginsEnabled(const QSet &plugins, bool enable); void cancelChanges(); signals: @@ -48,7 +49,6 @@ signals: private: PluginSpec *pluginForIndex(const QModelIndex &index) const; void updatePlugins(); - bool setPluginsEnabled(const QSet &plugins, bool enable); Utils::TreeView *m_categoryView; Utils::TreeModel *m_model; From f68c7e10243a4469b428d8583d2fb0b72f191bcf Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 25 Jun 2024 15:10:19 +0200 Subject: [PATCH 37/73] Debugger: remove unsupported type annotations from cdbbridge Change-Id: I997a2df2b6352e022a955f2441f4e7f9d9fa02ae Reviewed-by: Christian Stenger --- share/qtcreator/debugger/cdbbridge.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index 347d2f89c9e..b6c9593474a 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -187,7 +187,7 @@ class Dumper(DumperBase): self.nativeTypeEnumDisplay(nativeType, intval, form) return typeid - def listNativeValueChildren(self, nativeValue: cdbext.Value, include_bases: bool) -> list[DumperBase.Value]: + def listNativeValueChildren(self, nativeValue: cdbext.Value, include_bases: bool): fields = [] index = 0 nativeMember = nativeValue.childFromIndex(index) @@ -202,13 +202,13 @@ class Dumper(DumperBase): nativeMember = nativeValue.childFromIndex(index) return fields - def listValueChildren(self, value: DumperBase.Value, include_bases=True) -> list[DumperBase.Value]: + def listValueChildren(self, value: DumperBase.Value, include_bases=True): nativeValue = value.nativeValue if nativeValue is None: nativeValue = cdbext.createValue(value.address(), self.lookupNativeType(value.type.name, 0)) return self.listNativeValueChildren(nativeValue, include_bases) - def nativeListMembers(self, value: DumperBase.Value, native_type: cdbext.Type, include_bases: bool) -> list[DumperBase.Value]: + def nativeListMembers(self, value: DumperBase.Value, native_type: cdbext.Type, include_bases: bool): nativeValue = value.nativeValue if nativeValue is None: nativeValue = cdbext.createValue(value.address(), native_type) From 9eaa9b1f66373f8e7fc07ed908e61bbda683e9ff Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Jun 2024 14:32:06 +0200 Subject: [PATCH 38/73] ExtensionManager: Switch on by default But keep experimental. It is currently less functional than the old plugin dialog, it misses e.g. dependency tracking when disabling plugins and the design misses a way to restart Creator in the common case where this is necessary. Change-Id: Ib6c5aba762426510fc174c99ddc486d31d240484 Reviewed-by: Eike Ziller (cherry picked from commit c57d70e242e446512876310b3da2112131a84f90) Reviewed-by: hjk --- src/plugins/extensionmanager/ExtensionManager.json.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/extensionmanager/ExtensionManager.json.in b/src/plugins/extensionmanager/ExtensionManager.json.in index 7cf4fec4364..e3710427c4f 100644 --- a/src/plugins/extensionmanager/ExtensionManager.json.in +++ b/src/plugins/extensionmanager/ExtensionManager.json.in @@ -15,6 +15,7 @@ "Category" : "Core", "Description" : "Extension Manager", "Experimental": true, + "DisabledByDefault": false, "Url" : "https://www.qt.io", ${IDE_PLUGIN_DEPENDENCIES} } From 44e36686c8ea5dd6601f80ab57c27bd34e1f7894 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 25 Jun 2024 15:41:38 +0200 Subject: [PATCH 39/73] Fix lupdate issues Change-Id: Ie71649f38e29c2fd6f644e023772f15865d6e6aa Reviewed-by: hjk Reviewed-by: Leena Miettinen --- src/plugins/coreplugin/outputwindow.cpp | 2 +- src/plugins/debugger/gdb/gdbsettings.cpp | 2 +- src/plugins/languageclient/callandtypehierarchy.cpp | 2 +- src/plugins/lua/luaengine.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index d5fe9205602..4183a8457ca 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -74,7 +74,7 @@ public: QElapsedTimer lastMessage; QHash> taskPositions; //: default file name suggested for saving text from output views - QString outputFileNameHint{Tr::tr("output.txt")}; + QString outputFileNameHint{::Core::Tr::tr("output.txt")}; }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/gdbsettings.cpp b/src/plugins/debugger/gdb/gdbsettings.cpp index 9ca93263069..08313c7c6ce 100644 --- a/src/plugins/debugger/gdb/gdbsettings.cpp +++ b/src/plugins/debugger/gdb/gdbsettings.cpp @@ -166,7 +166,7 @@ GdbSettings::GdbSettings() useDebugInfoD.setSettingsKey("UseDebugInfoD"); useDebugInfoD.setLabelText(Tr::tr("Use debug info daemon")); - useDebugInfoD.setOptionText(TriState::DefaultValue, tr("Use system settings")); + useDebugInfoD.setOptionText(TriState::DefaultValue, Tr::tr("Use system settings")); useDebugInfoD.setToolTip(Tr::tr("Lets GDB attempt to automatically retrieve " "debug information for system packages.")); diff --git a/src/plugins/languageclient/callandtypehierarchy.cpp b/src/plugins/languageclient/callandtypehierarchy.cpp index d759ea35341..43e47ddc00b 100644 --- a/src/plugins/languageclient/callandtypehierarchy.cpp +++ b/src/plugins/languageclient/callandtypehierarchy.cpp @@ -432,7 +432,7 @@ public: Icons::RELOAD_TOOLBAR.icon(); auto button = new QToolButton; button->setIcon(Icons::RELOAD_TOOLBAR.icon()); - button->setToolTip(LanguageClient::Tr::tr( + button->setToolTip(::LanguageClient::Tr::tr( "Reloads the call hierarchy for the symbol under cursor position.")); connect(button, &QToolButton::clicked, this, [h] { h->updateHierarchyAtCursorPosition(); }); return {h, {button}}; diff --git a/src/plugins/lua/luaengine.cpp b/src/plugins/lua/luaengine.cpp index abfc78957b1..34faee83847 100644 --- a/src/plugins/lua/luaengine.cpp +++ b/src/plugins/lua/luaengine.cpp @@ -132,7 +132,7 @@ std::unique_ptr LuaEngine::runScript(const QString &script, con sol::error err = result; qWarning() << "Failed to run script" << name << ":" << QString::fromUtf8(err.what()); Core::MessageManager::writeFlashing( - tr("Failed to run script %1: %2").arg(name, QString::fromUtf8(err.what()))); + Tr::tr("Failed to run script %1: %2").arg(name, QString::fromUtf8(err.what()))); } return opaque; From 828c50d33d1127081131a6764d83353f601f7bcf Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Jun 2024 15:50:22 +0200 Subject: [PATCH 40/73] ExtensionSystem: Split PluginView in PluginData and view Change-Id: I7337b83eafe391b4fc46ef9c2e2617a76adf0f5f Reviewed-by: Alessandro Portale --- src/libs/extensionsystem/pluginview.cpp | 68 ++++++++++++++----------- src/libs/extensionsystem/pluginview.h | 28 +++++++--- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp index 0c6aeb2dff3..fb02b492840 100644 --- a/src/libs/extensionsystem/pluginview.cpp +++ b/src/libs/extensionsystem/pluginview.cpp @@ -89,8 +89,8 @@ static const QIcon &icon(IconIndex icon) class PluginItem : public TreeItem { public: - PluginItem(PluginSpec *spec, PluginView *view) - : m_spec(spec), m_view(view) + PluginItem(PluginSpec *spec, PluginData *data) + : m_spec(spec), m_data(data) {} QVariant data(int column, int role) const override @@ -167,7 +167,7 @@ public: bool setData(int column, const QVariant &data, int role) override { if (column == LoadedColumn && role == Qt::CheckStateRole) - return m_view->setPluginsEnabled({m_spec}, data.toBool()); + return m_data->setPluginsEnabled({m_spec}, data.toBool()); return false; } @@ -193,19 +193,19 @@ public: public: PluginSpec *m_spec; // Not owned. - PluginView *m_view; // Not owned. + PluginData *m_data; // Not owned. }; class CollectionItem : public TreeItem { public: - CollectionItem(const QString &name, const PluginSpecs &plugins, PluginView *view) + CollectionItem(const QString &name, const PluginSpecs &plugins, PluginData *data) : m_name(name) , m_plugins(plugins) - , m_view(view) + , m_data(data) { for (PluginSpec *spec : plugins) - appendChild(new PluginItem(spec, view)); + appendChild(new PluginItem(spec, data)); } QVariant data(int column, int role) const override @@ -241,7 +241,7 @@ public: if (column == LoadedColumn && role == Qt::CheckStateRole) { const PluginSpecs affectedPlugins = Utils::filtered(m_plugins, [](PluginSpec *spec) { return !spec->isRequired(); }); - if (m_view->setPluginsEnabled(toSet(affectedPlugins), data.toBool())) { + if (m_data->setPluginsEnabled(toSet(affectedPlugins), data.toBool())) { update(); return true; } @@ -260,19 +260,31 @@ public: public: QString m_name; const PluginSpecs m_plugins; - PluginView *m_view; // Not owned. + PluginData *m_data; // Not owned. }; } // Internal using namespace ExtensionSystem::Internal; +PluginData::PluginData(QWidget *parent, PluginView *owner) + : m_parent(parent), m_pluginView(owner) +{ + m_model = new TreeModel(parent); + m_model->setHeader({ Tr::tr("Name"), Tr::tr("Load"), Tr::tr("Version"), Tr::tr("Vendor") }); + + m_sortModel = new CategorySortFilterModel(parent); + m_sortModel->setSourceModel(m_model); + m_sortModel->setSortRole(SortRole); + m_sortModel->setFilterKeyColumn(-1/*all*/); +} + /*! Constructs a plugin view with \a parent that displays a list of plugins from a plugin manager. */ PluginView::PluginView(QWidget *parent) - : QWidget(parent) + : QWidget(parent), m_data(this, this) { m_categoryView = new TreeView(this); m_categoryView->setAlternatingRowColors(true); @@ -282,14 +294,7 @@ PluginView::PluginView(QWidget *parent) m_categoryView->setSelectionMode(QAbstractItemView::SingleSelection); m_categoryView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_model = new TreeModel(this); - m_model->setHeader({ Tr::tr("Name"), Tr::tr("Load"), Tr::tr("Version"), Tr::tr("Vendor") }); - - m_sortModel = new CategorySortFilterModel(this); - m_sortModel->setSourceModel(m_model); - m_sortModel->setSortRole(SortRole); - m_sortModel->setFilterKeyColumn(-1/*all*/); - m_categoryView->setModel(m_sortModel); + m_categoryView->setModel(m_data.m_sortModel); auto *gridLayout = new QGridLayout(this); gridLayout->setContentsMargins(2, 2, 2, 2); @@ -329,7 +334,7 @@ PluginSpec *PluginView::currentPlugin() const */ void PluginView::setFilter(const QString &filter) { - m_sortModel->setFilterRegularExpression( + m_data.m_sortModel->setFilterRegularExpression( QRegularExpression(QRegularExpression::escape(filter), QRegularExpression::CaseInsensitiveOption)); m_categoryView->expandAll(); @@ -337,15 +342,15 @@ void PluginView::setFilter(const QString &filter) PluginSpec *PluginView::pluginForIndex(const QModelIndex &index) const { - const QModelIndex &sourceIndex = m_sortModel->mapToSource(index); - PluginItem *item = m_model->itemForIndexAtLevel<2>(sourceIndex); + const QModelIndex &sourceIndex = m_data.m_sortModel->mapToSource(index); + PluginItem *item = m_data.m_model->itemForIndexAtLevel<2>(sourceIndex); return item ? item->m_spec: nullptr; } void PluginView::updatePlugins() { // Model. - m_model->clear(); + m_data.m_model->clear(); const QHash pluginCollections = PluginManager::pluginCollections(); @@ -353,14 +358,14 @@ void PluginView::updatePlugins() const auto end = pluginCollections.cend(); for (auto it = pluginCollections.cbegin(); it != end; ++it) { const QString name = it.key().isEmpty() ? Tr::tr("Utilities") : it.key(); - collections.push_back(new CollectionItem(name, it.value(), this)); + collections.push_back(new CollectionItem(name, it.value(), &m_data)); } Utils::sort(collections, &CollectionItem::m_name); for (CollectionItem *collection : std::as_const(collections)) - m_model->rootItem()->appendChild(collection); + m_data.m_model->rootItem()->appendChild(collection); - emit m_model->layoutChanged(); + emit m_data.m_model->layoutChanged(); m_categoryView->expandAll(); } @@ -371,7 +376,7 @@ static QString pluginListString(const QSet &plugins) return names.join(QLatin1Char('\n')); } -bool PluginView::setPluginsEnabled(const QSet &plugins, bool enable) +bool PluginData::setPluginsEnabled(const QSet &plugins, bool enable) { QSet additionalPlugins; if (enable) { @@ -383,7 +388,7 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl } additionalPlugins.subtract(plugins); if (!additionalPlugins.isEmpty()) { - if (QMessageBox::question(this, Tr::tr("Enabling Plugins"), + if (QMessageBox::question(m_parent, Tr::tr("Enabling Plugins"), Tr::tr("Enabling\n%1\nwill also enable the following plugins:\n\n%2") .arg(pluginListString(plugins), pluginListString(additionalPlugins)), QMessageBox::Ok | QMessageBox::Cancel, @@ -400,7 +405,7 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl } additionalPlugins.subtract(plugins); if (!additionalPlugins.isEmpty()) { - if (QMessageBox::question(this, Tr::tr("Disabling Plugins"), + if (QMessageBox::question(m_parent, Tr::tr("Disabling Plugins"), Tr::tr("Disabling\n%1\nwill also disable the following plugins:\n\n%2") .arg(pluginListString(plugins), pluginListString(additionalPlugins)), QMessageBox::Ok | QMessageBox::Cancel, @@ -422,13 +427,16 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl item->updateColumn(LoadedColumn); item->parent()->updateColumn(LoadedColumn); } - emit pluginsChanged(affectedPlugins, enable); + + if (m_pluginView) + emit m_pluginView->pluginsChanged(affectedPlugins, enable); + return true; } void PluginView::cancelChanges() { - for (auto element : m_affectedPlugins) + for (auto element : m_data.m_affectedPlugins) element.first->setEnabledBySettings(element.second); } diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h index 698fac77ca5..aa01332dbf7 100644 --- a/src/libs/extensionsystem/pluginview.h +++ b/src/libs/extensionsystem/pluginview.h @@ -22,12 +22,32 @@ class TreeView; namespace ExtensionSystem { class PluginSpec; +class PluginView; namespace Internal { class CollectionItem; class PluginItem; } // Internal +class EXTENSIONSYSTEM_EXPORT PluginData +{ +public: + explicit PluginData(QWidget *parent, PluginView *pluginView = nullptr); + + bool setPluginsEnabled(const QSet &plugins, bool enable); + +private: + QWidget *m_parent = nullptr; + PluginView *m_pluginView = nullptr; + Utils::TreeModel *m_model; + Utils::CategorySortFilterModel *m_sortModel; + std::unordered_map m_affectedPlugins; + + friend class Internal::CollectionItem; + friend class Internal::PluginItem; + friend class PluginView; +}; + class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget { Q_OBJECT @@ -38,7 +58,6 @@ public: PluginSpec *currentPlugin() const; void setFilter(const QString &filter); - bool setPluginsEnabled(const QSet &plugins, bool enable); void cancelChanges(); signals: @@ -50,13 +69,8 @@ private: PluginSpec *pluginForIndex(const QModelIndex &index) const; void updatePlugins(); + PluginData m_data; Utils::TreeView *m_categoryView; - Utils::TreeModel *m_model; - Utils::CategorySortFilterModel *m_sortModel; - std::unordered_map m_affectedPlugins; - - friend class Internal::CollectionItem; - friend class Internal::PluginItem; }; } // namespace ExtensionSystem From 1e0fc74739442d8d05278c4315ff70005b58c106 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Jun 2024 13:30:11 +0200 Subject: [PATCH 41/73] CppModelManager: Simplify future template parameter Since we don't use the future interface for result reporting, simplify it to be QFutureInterface. Change-Id: I4d3a2e7f87721c54996894d744e5c43cc6223d47 Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppmodelmanager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 6f2aebcca32..801fb519e03 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -553,7 +553,7 @@ using FindUnusedActionsEnabledSwitcherPtr = std::shared_ptr &search, - const std::shared_ptr> &findRefsFuture, + const std::shared_ptr> &findRefsFuture, const FindUnusedActionsEnabledSwitcherPtr &actionsSwitcher) { if (!search || findRefsFuture->isCanceled()) @@ -650,14 +650,14 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) Utils::transform(links, [](const Link &l) { return QVariant::fromValue(l); })); search->setUserData(remainingAndActiveLinks); - const auto findRefsFuture = std::make_shared>(); + const auto findRefsFuture = std::make_shared>(); FutureProgress *const progress = ProgressManager::addTask(findRefsFuture->future(), Tr::tr("Finding Unused Functions"), "CppEditor.FindUnusedFunctions"); connect(progress, &FutureProgress::canceled, search, - [search, future = std::weak_ptr>(findRefsFuture)] { + [search, future = std::weak_ptr>(findRefsFuture)] { search->finishSearch(true); if (const auto f = future.lock()) { f->cancel(); From bb32b446718c8e784fb899534070e3f268fd32a0 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jun 2024 11:57:18 +0200 Subject: [PATCH 42/73] ExtensionManager: Enable opening of external links Amends: 81163b431e68f281bd7c6cdd4e6c8ba279ff9155 Change-Id: I512279d86590bc35d7816ff69bb618aea58b4fcb Reviewed-by: Cristian Adam --- src/plugins/extensionmanager/extensionmanagerwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index dea2f9e806f..6606b2d0bbc 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -427,6 +427,7 @@ ExtensionManagerWidget::ExtensionManagerWidget(QWidget *parent) d->description->setWordWrap(true); d->linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information")); d->links = tfLabel(contentTF, false); + d->links->setOpenExternalLinks(true); d->imageTitle = sectionTitle(h6CapitalTF, {}); d->image = new QLabel; d->imageMovie.setDevice(&d->imageDataBuffer); From 5be68d7256dbf9de22c10589e061c17d98361199 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jun 2024 16:43:07 +0200 Subject: [PATCH 43/73] ExtensionManager: Enable/disable dependencies, inform users accordingly This instantiates PluginView in order to use setPluginsEnabled. It enables dependencies of a plugin that is being enabled. Likewise, it disables dependent plugins when users disable a plugin. In both cases, the user sees the familiar info dialog. On confirmation, a "Restart now" button is shown. Change-Id: Ie74ed377bfdd1ce3cb06289c2aae78377475bc53 Reviewed-by: Alessandro Portale Reviewed-by: hjk --- src/libs/extensionsystem/pluginview.cpp | 5 +++++ src/libs/extensionsystem/pluginview.h | 2 ++ .../extensionmanagerwidget.cpp | 19 +++++++++++++++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp index fb02b492840..24ec0a969d5 100644 --- a/src/libs/extensionsystem/pluginview.cpp +++ b/src/libs/extensionsystem/pluginview.cpp @@ -369,6 +369,11 @@ void PluginView::updatePlugins() m_categoryView->expandAll(); } +PluginData &PluginView::data() +{ + return m_data; +} + static QString pluginListString(const QSet &plugins) { QStringList names = Utils::transform(plugins, &PluginSpec::name); diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h index aa01332dbf7..db144247277 100644 --- a/src/libs/extensionsystem/pluginview.h +++ b/src/libs/extensionsystem/pluginview.h @@ -60,6 +60,8 @@ public: void setFilter(const QString &filter); void cancelChanges(); + PluginData &data(); + signals: void currentPluginChanged(ExtensionSystem::PluginSpec *spec); void pluginActivated(ExtensionSystem::PluginSpec *spec); diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 6606b2d0bbc..3b16f0d9c84 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -279,21 +280,33 @@ public: { m_label = new InfoLabel; m_checkBox = new QCheckBox(Tr::tr("Load on Start")); + m_restartButton = new Button("Restart now", Button::MediumPrimary); + m_restartButton->setVisible(false); + m_pluginView.hide(); using namespace Layouting; Column { m_label, m_checkBox, + m_restartButton, }.attachTo(this); connect(m_checkBox, &QCheckBox::clicked, this, [this](bool checked) { ExtensionSystem::PluginSpec *spec = ExtensionsModel::pluginSpecForName(m_pluginName); if (spec == nullptr) return; - spec->setEnabledBySettings(checked); - ExtensionSystem::PluginManager::writeSettings(); + const bool doIt = m_pluginView.data().setPluginsEnabled({spec}, checked); + if (doIt) { + m_restartButton->show(); + ExtensionSystem::PluginManager::writeSettings(); + } else { + m_checkBox->setChecked(!checked); + } }); + connect(m_restartButton, &QAbstractButton::clicked, + ICore::instance(), &ICore::restart, Qt::QueuedConnection); + update(); } @@ -328,7 +341,9 @@ private: InfoLabel *m_label; QCheckBox *m_checkBox; + QAbstractButton *m_restartButton; QString m_pluginName; + ExtensionSystem::PluginView m_pluginView{this}; }; class TagList : public QWidget From c8e1af0292ff9d309d9b655a3f4b4536f9be5731 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jun 2024 17:14:35 +0200 Subject: [PATCH 44/73] ExtensionManager: Remove "Install..." button Change-Id: I0b7a79a1182eca26d0dc97750db2fa84eb444cea Reviewed-by: hjk --- src/plugins/extensionmanager/extensionsbrowser.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 330c2395920..cd4c591097d 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -251,7 +251,6 @@ class ExtensionsBrowserPrivate public: ExtensionsModel *model; QLineEdit *searchBox; - QAbstractButton *updateButton; QListView *extensionsView; QItemSelectionModel *selectionModel = nullptr; QSortFilterProxyModel *filterProxyModel; @@ -272,7 +271,6 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) d->searchBox = new SearchBox; d->searchBox->setPlaceholderText(Tr::tr("Search")); - d->updateButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); d->model = new ExtensionsModel(this); @@ -300,7 +298,6 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) }, Row { d->searchBox, - d->updateButton, spacing(gapSize), customMargins(0, VPaddingM, extraListViewWidth() + gapSize, VPaddingM), }, @@ -326,9 +323,6 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) } }; - connect(d->updateButton, &QAbstractButton::pressed, this, []() { - executePluginInstallWizard(); - }); connect(PluginManager::instance(), &PluginManager::pluginsChanged, this, updateModel); connect(PluginManager::instance(), &PluginManager::initializationDone, this, &ExtensionsBrowser::fetchExtensions); @@ -350,7 +344,6 @@ void ExtensionsBrowser::adjustToWidth(const int width) { const int widthForItems = width - extraListViewWidth(); d->columnsCount = qMax(1, qFloor(widthForItems / cellWidth)); - d->updateButton->setVisible(d->columnsCount > 1); updateGeometry(); } From cc05c1637778db8210ea901b8da71aeef1bde05e Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 25 Jun 2024 15:28:02 +0200 Subject: [PATCH 45/73] CMakePM: Ask for a build configuration name for new configurations Amends f866b03b191299e5d5cde11cdad905a90b94bf26 This would do what the QMake build system does on new build types, it asks for a name and uses that name in the build directory. Fixes: QTCREATORBUG-26066 Change-Id: Iec5b4ace1e203affad718b42ec2bcbbc87aef51f Reviewed-by: Alessandro Portale Reviewed-by: Artem Sokolovskii --- src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index fed2112822e..178c2a68bfa 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1585,7 +1585,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) if (info.buildDirectory.isEmpty()) { setBuildDirectory(shadowBuildDirectory(target->project()->projectFilePath(), k, - info.typeName, + info.displayName, info.buildType)); } @@ -1960,6 +1960,9 @@ CMakeBuildConfigurationFactory::CMakeBuildConfigurationFactory() k, info.typeName, info.buildType); + } else { + info.displayName.clear(); // ask for a name + info.buildDirectory.clear(); // This depends on the displayName } result << info; } From 313ed327bec59bdefffa29d03ea00e36923f4b1f Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Jun 2024 17:23:07 +0200 Subject: [PATCH 46/73] ExtensionManager: Make restart string translatable Change-Id: I1505625e23a1ec67876d34bda0592ee6e9fa47c4 Reviewed-by: Alessandro Portale --- src/plugins/extensionmanager/extensionmanagerwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 3b16f0d9c84..a7caa5f2e11 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -280,7 +280,7 @@ public: { m_label = new InfoLabel; m_checkBox = new QCheckBox(Tr::tr("Load on Start")); - m_restartButton = new Button("Restart now", Button::MediumPrimary); + m_restartButton = new Button(Tr::tr("Restart now"), Button::MediumPrimary); m_restartButton->setVisible(false); m_pluginView.hide(); From 030e3c2cd5391a7d7d2ace8a1124c2f1b06f266b Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 1 Mar 2024 14:21:10 +0100 Subject: [PATCH 47/73] CMakePM: Do not add sources to globbed targets If a class is being added to a target that has a variable resulted from a `file(GLOB|_RECURSE)` call, we skip adding the files to the target. Do not add the files, just run CMake which would gather the new sources into the project. Adding sources to a globbed target will no longer open the CMakeLists.txt file, since nothing has changed. CMake will be run after adding, renaming and removing of sources files. Fixes: QTCREATORBUG-30445 Change-Id: I82e126737789f215a6400f5a43f303dcc57de005 Reviewed-by: Alessandro Portale --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 143 ++++++++++-------- .../cmakeprojectmanager/cmakeprojectnodes.cpp | 9 +- .../cmakeprojectmanager/cmakeprojectnodes.h | 3 + 3 files changed, 95 insertions(+), 60 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index f1c3731d4f2..c396bde59a1 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -642,6 +642,25 @@ bool CMakeBuildSystem::addTsFiles(Node *context, const FilePaths &filePaths, Fil return false; } +static bool isGlobbingFunction(const cmListFile &cmakeListFile, const cmListFileFunction &func) +{ + // Check if the filename is part of globbing variable result + const auto globFunctions = std::get<0>( + Utils::partition(cmakeListFile.Functions, [](const auto &f) { + return f.LowerCaseName() == "file" && f.Arguments().size() > 2 + && (f.Arguments().front().Value == "GLOB" + || f.Arguments().front().Value == "GLOB_RECURSE"); + })); + + const auto globVariables = Utils::transform(globFunctions, [](const auto &func) { + return std::string("${") + func.Arguments()[1].Value + "}"; + }); + + return Utils::anyOf(func.Arguments(), [globVariables](const auto &arg) { + return globVariables.contains(arg.Value); + }); +} + bool CMakeBuildSystem::addSrcFiles(Node *context, const FilePaths &filePaths, FilePaths *notAdded) { if (notAdded) @@ -670,26 +689,32 @@ bool CMakeBuildSystem::addSrcFiles(Node *context, const FilePaths &filePaths, Fi return false; } - const std::string target_name = function->Arguments().front().Value; - auto qtAddModule = [target_name](const auto &func) { - return (func.LowerCaseName() == "qt_add_qml_module" - || func.LowerCaseName() == "qt6_add_qml_module") - && func.Arguments().front().Value == target_name; - }; - // Special case: when qt_add_executable and qt_add_qml_module use the same target name - // then qt_add_qml_module function should be used - function = findFunction(*cmakeListFile, qtAddModule).value_or(*function); + const bool haveGlobbing = isGlobbingFunction(cmakeListFile.value(), function.value()); + n->setVisibleAfterAddFileAction(!haveGlobbing); + if (haveGlobbing && settings(project()).autorunCMake()) { + runCMake(); + } else { + const std::string target_name = function->Arguments().front().Value; + auto qtAddModule = [target_name](const auto &func) { + return (func.LowerCaseName() == "qt_add_qml_module" + || func.LowerCaseName() == "qt6_add_qml_module") + && func.Arguments().front().Value == target_name; + }; + // Special case: when qt_add_executable and qt_add_qml_module use the same target name + // then qt_add_qml_module function should be used + function = findFunction(*cmakeListFile, qtAddModule).value_or(*function); - const QString newSourceFiles = newFilesForFunction(function->LowerCaseName(), - filePaths, - n->filePath().canonicalPath()); + const QString newSourceFiles = newFilesForFunction(function->LowerCaseName(), + filePaths, + n->filePath().canonicalPath()); - const SnippetAndLocation snippetLocation = generateSnippetAndLocationForSources( - newSourceFiles, *cmakeListFile, *function, targetName); - expected_str inserted = insertSnippetSilently(targetCMakeFile, snippetLocation); - if (!inserted) { - qCCritical(cmakeBuildSystemLog) << inserted.error(); - return false; + const SnippetAndLocation snippetLocation = generateSnippetAndLocationForSources( + newSourceFiles, *cmakeListFile, *function, targetName); + expected_str inserted = insertSnippetSilently(targetCMakeFile, snippetLocation); + if (!inserted) { + qCCritical(cmakeBuildSystemLog) << inserted.error(); + return false; + } } if (notAdded) @@ -770,22 +795,7 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q return ProjectFileArgumentPosition{filePathArgument, targetCMakeFile, fileName}; } else { // Check if the filename is part of globbing variable result - const auto globFunctions = std::get<0>( - Utils::partition(cmakeListFile->Functions, [](const auto &f) { - return f.LowerCaseName() == "file" && f.Arguments().size() > 2 - && (f.Arguments().front().Value == "GLOB" - || f.Arguments().front().Value == "GLOB_RECURSE"); - })); - - const auto globVariables = Utils::transform(globFunctions, [](const auto &func) { - return std::string("${") + func.Arguments()[1].Value + "}"; - }); - - const auto haveGlobbing = Utils::anyOf(func->Arguments(), - [globVariables](const auto &arg) { - return globVariables.contains(arg.Value); - }); - + const auto haveGlobbing = isGlobbingFunction(cmakeListFile.value(), func.value()); if (haveGlobbing) { return ProjectFileArgumentPosition{filePathArgument, targetCMakeFile, @@ -833,6 +843,7 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context, const FilePath projDir = n->filePath().canonicalPath(); const QString targetName = n->buildKey(); + bool haveGlobbing = false; for (const auto &file : filePaths) { const QString fileName = file.canonicalPath().relativePathFrom(projDir).cleanPath().toString(); @@ -847,6 +858,11 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context, continue; } + if (filePos.value().fromGlobbing) { + haveGlobbing = true; + continue; + } + BaseTextEditor *editor = qobject_cast( Core::EditorManager::openEditorAt({filePos.value().cmakeFile, static_cast(filePos.value().argumentPosition.Line), @@ -869,8 +885,7 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context, if (filePos->argumentPosition.Delim == cmListFileArgument::Quoted) extraChars = 2; - if (!filePos.value().fromGlobbing) - editor->replace(filePos.value().relativeFileName.length() + extraChars, ""); + editor->replace(filePos.value().relativeFileName.length() + extraChars, ""); editor->editorWidget()->autoIndent(); if (!Core::DocumentManager::saveDocument(editor->document())) { @@ -889,6 +904,9 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context, if (notRemoved && !badFiles.isEmpty()) *notRemoved = badFiles; + if (haveGlobbing && settings(project()).autorunCMake()) + runCMake(); + return badFiles.isEmpty() ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error; } @@ -949,40 +967,47 @@ bool CMakeBuildSystem::renameFile(Node *context, return false; } + bool haveGlobbing = false; do { - BaseTextEditor *editor = qobject_cast( - Core::EditorManager::openEditorAt( - {fileToRename->cmakeFile, - static_cast(fileToRename->argumentPosition.Line), - static_cast(fileToRename->argumentPosition.Column - 1)}, - Constants::CMAKE_EDITOR_ID, - Core::EditorManager::DoNotMakeVisible)); - if (!editor) { - qCCritical(cmakeBuildSystemLog).noquote() - << "BaseTextEditor cannot be obtained for" << fileToRename->cmakeFile.path() - << fileToRename->argumentPosition.Line - << int(fileToRename->argumentPosition.Column); - return false; - } + if (!fileToRename->fromGlobbing) { + BaseTextEditor *editor = qobject_cast( + Core::EditorManager::openEditorAt( + {fileToRename->cmakeFile, + static_cast(fileToRename->argumentPosition.Line), + static_cast(fileToRename->argumentPosition.Column - 1)}, + Constants::CMAKE_EDITOR_ID, + Core::EditorManager::DoNotMakeVisible)); + if (!editor) { + qCCritical(cmakeBuildSystemLog).noquote() + << "BaseTextEditor cannot be obtained for" << fileToRename->cmakeFile.path() + << fileToRename->argumentPosition.Line + << int(fileToRename->argumentPosition.Column); + return false; + } - // If quotes were used for the source file, skip the starting quote - if (fileToRename->argumentPosition.Delim == cmListFileArgument::Quoted) - editor->setCursorPosition(editor->position() + 1); + // If quotes were used for the source file, skip the starting quote + if (fileToRename->argumentPosition.Delim == cmListFileArgument::Quoted) + editor->setCursorPosition(editor->position() + 1); - if (!fileToRename->fromGlobbing) editor->replace(fileToRename->relativeFileName.length(), newRelPathName); - editor->editorWidget()->autoIndent(); - if (!Core::DocumentManager::saveDocument(editor->document())) { - qCCritical(cmakeBuildSystemLog).noquote() - << "Changes to" << fileToRename->cmakeFile.path() << "could not be saved."; - return false; + editor->editorWidget()->autoIndent(); + if (!Core::DocumentManager::saveDocument(editor->document())) { + qCCritical(cmakeBuildSystemLog).noquote() + << "Changes to" << fileToRename->cmakeFile.path() << "could not be saved."; + return false; + } + } else { + haveGlobbing = true; } // Try the next occurrence. This can happen if set_source_file_properties is used fileToRename = projectFileArgumentPosition(targetName, fileToRename->relativeFileName); } while (fileToRename && !fileToRename->fromGlobbing); + if (haveGlobbing && settings(project()).autorunCMake()) + runCMake(); + return true; } diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 80c5e58c029..54f28f7b2ad 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -187,9 +187,16 @@ void CMakeTargetNode::setConfig(const CMakeConfig &config) m_config = config; } +void CMakeTargetNode::setVisibleAfterAddFileAction(bool visibleAfterAddFileAction) +{ + m_visibleAfterAddFileAction = visibleAfterAddFileAction; +} + std::optional CMakeTargetNode::visibleAfterAddFileAction() const { - return filePath().pathAppended(Constants::CMAKE_LISTS_TXT); + if (m_visibleAfterAddFileAction) + return filePath().pathAppended(Constants::CMAKE_LISTS_TXT); + return std::nullopt; } void CMakeTargetNode::build() diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h index 94cde6dfef1..57b180bbba3 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h @@ -57,11 +57,14 @@ public: QVariant data(Utils::Id role) const override; void setConfig(const CMakeConfig &config); + void setVisibleAfterAddFileAction(bool visibleAfterAddFileAction); + private: QString m_tooltip; Utils::FilePath m_buildDirectory; Utils::FilePath m_artifact; CMakeConfig m_config; + bool m_visibleAfterAddFileAction = true; }; } // CMakeProjectManager::Internal From 6a192bcce8ab9e07f9a006470235342928e8354b Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jun 2024 18:38:00 +0200 Subject: [PATCH 48/73] ExtensionManager: Hide all details if no extension is selected Change-Id: I87b901d474ae438c87d26cfa12a644398fd1f950 Reviewed-by: Cristian Adam --- src/plugins/extensionmanager/extensionmanagerwidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index a7caa5f2e11..4b0bfcfb325 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -550,6 +550,8 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t) const bool showContent = current.isValid(); d->primaryContent->setVisible(showContent); d->secondaryContent->setVisible(showContent); + d->headingWidget->setVisible(showContent); + d->pluginStatus->setVisible(showContent); if (!showContent) return; From eca562af5442b2b6dfdb3bc3589e4c5969adf5ec Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 24 Jun 2024 09:20:39 +0200 Subject: [PATCH 49/73] Debugger: remove unused function from cdbbridge Change-Id: I3e3fe0c89d7ecfa7c727a26998978d07fd9bc390 Reviewed-by: Christian Stenger --- share/qtcreator/debugger/cdbbridge.py | 94 --------------------------- 1 file changed, 94 deletions(-) diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index b6c9593474a..1ce2a5f96fd 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -629,100 +629,6 @@ class Dumper(DumperBase): if self.showQObjectNames: self.tryPutQObjectGuts(value) - - def putFormattedPointerX(self, value: DumperBase.Value): - self.putOriginalAddress(value.address()) - pointer = value.pointer() - self.putAddress(pointer) - if pointer == 0: - self.putType(value.type) - self.putValue('0x0') - return - - typeName = value.type.name - - try: - self.readRawMemory(pointer, 1) - except: - # Failure to dereference a pointer should at least - # show the value of a pointer. - #DumperBase.warn('BAD POINTER: %s' % value) - self.putValue('0x%x' % pointer) - self.putType(typeName) - return - - if self.currentIName.endswith('.this'): - self.putDerefedPointer(value) - return - - displayFormat = self.currentItemFormat(value.type.name) - - if value.type.targetName == 'void': - #DumperBase.warn('VOID POINTER: %s' % displayFormat) - self.putType(typeName) - self.putSymbolValue(pointer) - return - - if displayFormat == DisplayFormat.Raw: - # Explicitly requested bald pointer. - #DumperBase.warn('RAW') - self.putType(typeName) - self.putValue('0x%x' % pointer) - self.putExpandable() - if self.currentIName in self.expandedINames: - with Children(self): - with SubItem(self, '*'): - self.putItem(value.dereference()) - return - - limit = self.displayStringLimit - if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String): - limit = 1000000 - if self.tryPutSimpleFormattedPointer(pointer, typeName, - value.type.targetName, displayFormat, limit): - self.putExpandable() - return - - if DisplayFormat.Array10 <= displayFormat and displayFormat <= DisplayFormat.Array10000: - n = (10, 100, 1000, 10000)[displayFormat - DisplayFormat.Array10] - self.putType(typeName) - self.putItemCount(n) - self.putArrayData(value.pointer(), n, value.type.targetName) - return - - #DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers) - #DumperBase.warn('INAME: %s' % self.currentIName) - if self.autoDerefPointers: - # Generic pointer type with AutomaticFormat, but never dereference char types: - if value.type.targetName.strip() not in ( - 'char', - 'signed char', - 'int8_t', - 'qint8', - 'unsigned char', - 'uint8_t', - 'quint8', - 'wchar_t', - 'CHAR', - 'WCHAR', - 'char8_t', - 'char16_t', - 'char32_t' - ): - self.putDerefedPointer(value) - return - - #DumperBase.warn('GENERIC PLAIN POINTER: %s' % value.type) - #DumperBase.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress) - self.putType(typeName) - self.putSymbolValue(pointer) - self.putExpandable() - if self.currentIName in self.expandedINames: - with Children(self): - with SubItem(self, '*'): - self.putItem(value.dereference()) - - def putCStyleArray(self, value: DumperBase.Value): arrayType = value.type innerType = arrayType.target() From c1b8320ca27be8c91df91fdfa55418f29fe53705 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Jun 2024 14:04:26 +0200 Subject: [PATCH 50/73] Debugger: Execute all inheritance tests also for LLDB LLDB 3.8/360.x was not working with multiple inheritance even on the command line, but looks ok nowadays at least in this simple case. This does not fix the linked task. Task-number: QTCREATORBUG-31042 Change-Id: Ibc52c9aaf31513af05487657a229fc4945d7e08f Reviewed-by: Christian Stenger --- tests/auto/debugger/tst_dumpers.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 8e5109eee5c..408d6d7c133 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -7596,20 +7596,19 @@ void tst_Dumpers::dumper_data() {"tt.@2.@1.v", "45", "int"}}) + Check("dd.@1.@1.a", "1", "int") // B::a - // C::a - fails with command line LLDB 3.8/360.x - + Check("dd.@2.@1.a", "1", "int") % NoLldbEngine // C::a + + Check("dd.@2.@1.a", "1", "int") + Check("dd.@1.b", "2", "int") + Check("dd.@2.c", "3", "int") + Check("dd.d", "4", "int") + Check("dp.@1.@1.a", "1", "int") // B::a - + Check("dp.@2.@1.a", "1", "int") % NoLldbEngine // C::a + + Check("dp.@2.@1.a", "1", "int") + Check("dp.@1.b", "2", "int") + Check("dp.@2.c", "3", "int") + Check("dp.d", "4", "int") + Check("dr.@1.@1.a", "1", "int") // B::a - + Check("dr.@2.@1.a", "1", "int") % NoLldbEngine // C::a + + Check("dr.@2.@1.a", "1", "int") + Check("dr.@1.b", "2", "int") + Check("dr.@2.c", "3", "int") + Check("dr.d", "4", "int") From 064f77a5a8a8fe233e74940221a4fc0de4cc7da1 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 25 Jun 2024 16:32:06 +0200 Subject: [PATCH 51/73] Doc: Update screenshot of Preferences > Axivion Add the new options and a link to the docs to the change log Task-number: QTCREATORBUG-30604 Change-Id: I50acab63b6d7a49c5e2dbf7ebd772f88280fb3a3 Reviewed-by: Christian Stenger --- dist/changelog/changes-14.0.0.md | 4 +++- .../images/qtcreator-preferences-axivion.webp | Bin 2156 -> 3184 bytes 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dist/changelog/changes-14.0.0.md b/dist/changelog/changes-14.0.0.md index 8c51242e3d5..e375cb0fa9f 100644 --- a/dist/changelog/changes-14.0.0.md +++ b/dist/changelog/changes-14.0.0.md @@ -220,7 +220,9 @@ Analyzer ### Axivion -* Made it possible to register multiple servers +* Added the `Add` and `Remove` buttons to `Preferences` > `Axivion` for + registering multiple servers + ([Documentation](https://doc-snapshots.qt.io/qtcreator-14.0/creator-preferences-axivion.html)) ### Cppcheck diff --git a/doc/qtcreator/images/qtcreator-preferences-axivion.webp b/doc/qtcreator/images/qtcreator-preferences-axivion.webp index a6b69dd1ff54ec5b9038e9b84c82eda59ba5999e..6d3ebc35ec48133ae987378b94459035dbfc7889 100644 GIT binary patch literal 3184 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 literal 2156 zcmWIYbaPALU|)-hZs^RPO>g(TKWVSf^h2njV1mkn zYunaFMZP}ugLQ|Jq~hOlN6C1lP0OW=a&9kMYdJr6>spDrFZNyXjW_p2e2#B_{{3I> z<>b)FsF2e9i)@a&->l$rcyO!1D%fJVN0a9Qr^dejhaPYDT^h8~g<~qmQh}8MN?cAN znGT#GVN0*Ax|Zaa7@RiYLYvb{hmQX$T>%{-Orom-R+Q_$4c25~bZHXsbjbPV-6ZBI zvh-lCa~7|XqtN9rr52ACp_P8z0-R0<#B!!&zKW5E2;|j2;2O4Jfj#pQ{E)fx^Fr%R;K!U+5_u2y^`FCgT-n}bZUjAakqj!Aw zHz_(=@xOa#aOa`^#p?HWRegU>iY)fLue#{}Bn8h&S2T*&AB@TgX{-_`x&0^G{_jh5 z*6wFfSF=LOR=%^ksH@^{U%jWHa@y)PjxQgZ+`?B1%6;-o^!(3#JiVQJ)(?4ozjK=_ zDx;_8%)MaE5*Rlj!*)yUkH;4}?6-LQc>Ki4`Oeo%-=fud662gbe4=jE%{aQ+Noez} zSJ^QaqitOE)^%=P={IfLaiP?b?1*2?Hm*nReqQxQ*i~(zzEOCKgq^)p%IOxnggYl& zWf!#iDCHLvc*!feKlyBMP~3fGOzf?R=Ke2cr(KszRaBU~W5b`_`^CP9vbpTz(B80Z z#&x-;`=3STC~I^wA6_f3-X_I0;s4Jkr;}NIrPO|`S}^CwuC%EiCZuzn4t_aZQAtf_ z*%SN!t5SonC7tuUVX{zum%5aysh^So-wx|78lTEeS4#IRw%ocvUh#ooORC_5(*AR| zkGfwvUyvg{OU3B<^pc>~$sSu<{st>sybF`OpzJT&EmWKpxctyz&nK2Ivn<|;c}Z2T zj+paC{+-O}h@9CfX=Qmv8S|!Ex4k<#r|W16?_M+2$*1RjQnFwDXX74Tm0nYZ%I=+Y zu4i%%8zrP3c-u8u-APpSaB;xi{{`+l^5nX_sH6;b@mbiefPwLiQTZ59adIG0^UFN=IQOhs= z{Xbj!4{Z!%Ez!QpSrJ%pw8-Nd|8WL=O$QTw6`gfYVwz7eO!ahY?h@S4&C8Wa6d=f(*e^{T77Zn`C1! z^J%V6mb6LBj!3}}wiP<@EQV5HK4&MY&9&v_SkRQ&u}z@p2;)~D*H6OA%u7A$S1k_F z&I}Ih+_lEsc9F=qlyu6|zBJOmy5#7@&;J(h^YRKVVT@g-yKH;o<3F=|9&ciuH@oVNvftJ@ z-{n4q?)ag(ZoXl9=JXY_ewp*$ue}iNsTKH*e|<-fw}@};S>{zY=Wd-*&&-xwHFx%U z;d~{Q;(Lu-L`!H^!z^;<{s}_947aqSK<6?-O$asIoqcd z)}%c%Kg1xn^^1bliO*5oSKmlp56!NvI=1}~gIp&6r>F_fuRdFK(|TX`k6jn*&GyG# zRMl6s`IeQlKt}jU<T<)i*%>-W;<&+gm)rnZt%TSVS?jTVT;4yJpD7*1j>VqT$IJyompUEPzP&ub=c+P8e2_PN_0N@okh zq_aw8{1;5$;b^R{F#YezHI|(pxa@*wK3i8U{YzunJHzlfv)K2aoS9oB$QpCXt;@mq zd|KYgP4% ze15~A_nZ4jK=#`QLKX!XlTS?BR4C+Vd_J%3^uLr2)#}DckA9p?+xR*>U}5LyjeMOU zE)NUst54Q@{rl`MD8F9)aAMyIwwYi5`!sFiDiCUvec94AsarkT`w-(M^(N`*_2(X_ z7=1|6|1ilQOYg-j#V7O1KLr^|PpX@<^G-l?&RBl4G*CfoZ9 zEz@^-zBTy3zRQE-*8f#+lv1XeA3V>x`$=iWp`&U)-pK4Ye5;7b=F6Slz%s*iW(U)Y z9!%%^q?B%jo+VV?&zK6ed5=ioc{%e klB;*N96xXC{V({_{7L_({8|3QUiH7`Pk)fVln*ih0Lq#QG5`Po From 3b7e782bc670b20de3ac22645c6b8e0456891d35 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 24 Jun 2024 10:20:07 +0200 Subject: [PATCH 52/73] Debugger: remove unneeded check and assignment If the inner type is null at this point it will also be null when assigning the same type again. Change-Id: I4dbad41a60d4853ac016adb54c693ce19d6f65d0 Reviewed-by: Christian Stenger --- share/qtcreator/debugger/dumper.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 33c7eb1a846..7f704590664 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -1295,8 +1295,6 @@ class DumperBase(): innerType = arrayType.target() #self.warn("ARRAY TYPE: %s" % arrayType) #self.warn("INNER TYPE: %s" % innerType) - if innerType is None: - innerType = value.type.target() address = value.address() if address: From d9d5b87141fd5138e292ca5ab6848ffdba27ec42 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 25 Jun 2024 16:50:30 +0200 Subject: [PATCH 53/73] LLDB-DAP: Fix passing program arguments This way if we pass arguments to the Run configuration, they will reach the inferior whilst being debugged. Change-Id: I93d99ff0d69b4ec710887097efc643fb48c8acca Reviewed-by: Artem Sokolovskii --- src/plugins/debugger/dap/lldbdapengine.cpp | 16 ++++++---------- src/plugins/debugger/dap/lldbdapengine.h | 1 - 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/plugins/debugger/dap/lldbdapengine.cpp b/src/plugins/debugger/dap/lldbdapengine.cpp index 8dfd75a75b2..0dded62b776 100644 --- a/src/plugins/debugger/dap/lldbdapengine.cpp +++ b/src/plugins/debugger/dap/lldbdapengine.cpp @@ -115,14 +115,6 @@ LldbDapEngine::LldbDapEngine() setDebuggerType("DAP"); } -QJsonArray LldbDapEngine::environment() const -{ - QJsonArray envArray; - for (const QString &value : runParameters().inferior.environment.toDictionary().toStringList()) - envArray.append(value); - return envArray; -} - QJsonArray LldbDapEngine::sourceMap() const { QJsonArray sourcePathMapping; @@ -160,11 +152,13 @@ void LldbDapEngine::handleDapInitialize() const QJsonArray commands = preRunCommands(); if (!isLocalAttachEngine()) { - const QJsonArray env = environment(); + const QJsonArray env = QJsonArray::fromStringList( + rp.inferior.environment.toDictionary().toStringList()); + const QJsonArray args = QJsonArray::fromStringList(rp.inferior.command.splitArguments()); + QJsonObject launchJson{ {"noDebug", false}, {"program", rp.inferior.command.executable().path()}, - {"args", rp.inferior.command.arguments()}, {"cwd", rp.inferior.workingDirectory.path()}, {"env", env}, {"__restart", ""}, @@ -173,6 +167,8 @@ void LldbDapEngine::handleDapInitialize() launchJson.insert("sourceMap", map); if (!commands.isEmpty()) launchJson.insert("preRunCommands", commands); + if (!args.isEmpty()) + launchJson.insert("args", args); m_dapClient->postRequest("launch", launchJson); diff --git a/src/plugins/debugger/dap/lldbdapengine.h b/src/plugins/debugger/dap/lldbdapengine.h index f4f59903820..0ebeb2d2ee1 100644 --- a/src/plugins/debugger/dap/lldbdapengine.h +++ b/src/plugins/debugger/dap/lldbdapengine.h @@ -22,7 +22,6 @@ private: bool acceptsBreakpoint(const BreakpointParameters &bp) const override; const QLoggingCategory &logCategory() override; - QJsonArray environment() const; QJsonArray sourceMap() const; QJsonArray preRunCommands() const; }; From aefc50f1de4c532fe7ac4c5aafa7e20a134ad79f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jun 2024 20:16:23 +0200 Subject: [PATCH 54/73] ExtensionManager: Prioritize plugin metadata data from service This change enables the Qt Creator Extension service data to override data of locally installed plugins (so far it was the other way around). We might want to add more description text, links, images or tags to plugins. And we want to be able do that independently of Qt Creator releases. This change also allows for substantial simplification of the "data merging" code. The parsing of extension plugin dependencies from the json data needed to be fixed. See dependenciesFromJson() Change-Id: Ia0433f0e0c7a0f13c43e0569c0915b7d08f7370a Reviewed-by: Cristian Adam --- .../extensionmanager_test.qrc | 1 + .../extensionmanager/extensionsbrowser.cpp | 2 +- .../extensionmanager/extensionsmodel.cpp | 196 ++++++++---------- .../testdata/augmentedplugindata.json | 71 +++++++ .../testdata/defaultpacks.json | 35 ---- 5 files changed, 164 insertions(+), 141 deletions(-) create mode 100644 src/plugins/extensionmanager/testdata/augmentedplugindata.json diff --git a/src/plugins/extensionmanager/extensionmanager_test.qrc b/src/plugins/extensionmanager/extensionmanager_test.qrc index f8a11b4e084..e7e934e5316 100644 --- a/src/plugins/extensionmanager/extensionmanager_test.qrc +++ b/src/plugins/extensionmanager/extensionmanager_test.qrc @@ -1,5 +1,6 @@ + testdata/augmentedplugindata.json testdata/defaultpacks.json testdata/thirdpartyplugins.json testdata/varieddata.json diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index cd4c591097d..bfe4fb102f8 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -381,7 +381,7 @@ void ExtensionsBrowser::fetchExtensions() const auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) { if (result != DoneWith::Success) { #ifdef WITH_TESTS - // Available test sets: "defaultpacks", "varieddata", "thirdpartyplugins" + // Available: "augmentedplugindata", "defaultpacks", "varieddata", "thirdpartyplugins" d->model->setExtensionsJson(testData("defaultpacks")); #endif // WITH_TESTS return; diff --git a/src/plugins/extensionmanager/extensionsmodel.cpp b/src/plugins/extensionmanager/extensionsmodel.cpp index 56fcc54ad8b..702e3019f75 100644 --- a/src/plugins/extensionmanager/extensionsmodel.cpp +++ b/src/plugins/extensionmanager/extensionsmodel.cpp @@ -36,8 +36,8 @@ using Dependencies = QList; struct Plugin { - Dependencies dependencies; QString copyright; + Dependencies dependencies; bool isInternal = false; QString name; QString packageUrl; @@ -69,23 +69,29 @@ struct Extension { }; using Extensions = QList; +static const Dependencies dependenciesFromJson(const QJsonObject &obj) +{ + const QJsonArray dependenciesArray = obj.value("Dependencies").toArray(); + Dependencies dependencies; + for (const QJsonValueConstRef &dependencyVal : dependenciesArray) { + const QJsonObject dependencyObj = dependencyVal.toObject(); + const QJsonObject metaDataObj = dependencyObj.value("meta_data").toObject(); + dependencies.append({ + .name = metaDataObj.value("Name").toString(), + .version = metaDataObj.value("Version").toString(), + }); + } + + return dependencies; +} + static Plugin pluginFromJson(const QJsonObject &obj) { const QJsonObject metaDataObj = obj.value("meta_data").toObject(); - const QJsonArray dependenciesArray = metaDataObj.value("Dependencies").toArray(); - Dependencies dependencies; - for (const QJsonValueConstRef &dependencyVal : dependenciesArray) { - const QJsonObject dependencyObj = dependencyVal.toObject(); - dependencies.append(Dependency{ - .name = dependencyObj.value("Name").toString(), - .version = dependencyObj.value("Version").toString(), - }); - } - return { - .dependencies = dependencies, .copyright = metaDataObj.value("Copyright").toString(), + .dependencies = dependenciesFromJson(metaDataObj), .isInternal = obj.value("is_internal").toBool(false), .name = metaDataObj.value("Name").toString(), .packageUrl = obj.value("url").toString(), @@ -192,30 +198,78 @@ static Extensions parseExtensionsRepoReply(const QByteArray &jsonData) return parsedExtensions; } +static Extension extensionFromPluginSpec(const PluginSpec *pluginSpec) +{ + const Dependencies dependencies = transform(pluginSpec->dependencies(), + [](const PluginDependency &pd) -> Dependency { + return { + .name = pd.name, + .version = pd.version, + }; + }); + const Plugin plugin = { + .copyright = pluginSpec->copyright(), + .dependencies = dependencies, + .name = pluginSpec->name(), + .packageUrl = {}, + .vendor = pluginSpec->vendor(), + .version = pluginSpec->version(), + }; + + const QStringList lines = pluginSpec->description().split('\n', Qt::SkipEmptyParts) + + pluginSpec->longDescription().split('\n', Qt::SkipEmptyParts); + const TextData text = {{ pluginSpec->name(), lines }}; + LinksData links; + if (const QString url = pluginSpec->url(); !url.isEmpty()) + links.append({{}, url}); + const Description description = { + .images = {}, + .links = links, + .text = text, + }; + + const QString platformsPattern = pluginSpec->platformSpecification().pattern(); + const QStringList platforms = platformsPattern.isEmpty() + ? QStringList({"macOS", "Windows", "Linux"}) + : QStringList(platformsPattern); + + const Extension extension = { + .copyright = pluginSpec->copyright(), + .description = description, + .id = {}, + .license = pluginSpec->license(), + .name = pluginSpec->name(), + .platforms = platforms, + .plugins = {plugin}, + .tags = {}, + .type = ItemTypeExtension, + .vendor = pluginSpec->vendor(), + .version = pluginSpec->version(), + }; + return extension; +} + class ExtensionsModelPrivate { public: void setExtensions(const Extensions &extensions); - void removeLocalExtensions(); + void addUnlistedLocalExtensions(); - Extensions allExtensions; // Original, complete extensions entries - Extensions absentExtensions; // All packs + plugin extensions that are not (yet) installed + Extensions extensions; }; void ExtensionsModelPrivate::setExtensions(const Extensions &extensions) { - allExtensions = extensions; - removeLocalExtensions(); + this->extensions = extensions; + addUnlistedLocalExtensions(); } -void ExtensionsModelPrivate::removeLocalExtensions() +void ExtensionsModelPrivate::addUnlistedLocalExtensions() { - const QStringList installedPlugins = transform(PluginManager::plugins(), &PluginSpec::name); - absentExtensions.clear(); - for (const Extension &extension : allExtensions) { - if (extension.type == ItemTypePack || !installedPlugins.contains(extension.name)) - absentExtensions.append(extension); - } + const QStringList listedModelExtensions = transform(extensions, &Extension::name); + for (const PluginSpec *plugin : PluginManager::plugins()) + if (!listedModelExtensions.contains(plugin->name())) + extensions.append(extensionFromPluginSpec(plugin)); } ExtensionsModel::ExtensionsModel(QObject *parent) @@ -231,66 +285,7 @@ ExtensionsModel::~ExtensionsModel() int ExtensionsModel::rowCount([[maybe_unused]] const QModelIndex &parent) const { - const int remoteExtnsionsCount = d->absentExtensions.count(); - const int installedPluginsCount = PluginManager::plugins().count(); - return remoteExtnsionsCount + installedPluginsCount; -} - -static QVariant dataFromPluginSpec(const PluginSpec *pluginSpec, int role) -{ - switch (role) { - case Qt::DisplayRole: - case RoleName: - return pluginSpec->name(); - case RoleCopyright: - return pluginSpec->copyright(); - case RoleDependencies: { - QStringList dependencies = transform(pluginSpec->dependencies(), - &PluginDependency::toString); - dependencies.sort(); - return dependencies; - } - case RoleDescriptionImages: - break; - case RoleDescriptionLinks: { - const QString url = pluginSpec->url(); - if (!url.isEmpty()) { - const LinksData links = {{{}, url}}; - return QVariant::fromValue(links); - } - break; - } - case RoleDescriptionText: { - QStringList lines = pluginSpec->description().split('\n', Qt::SkipEmptyParts); - lines.append(pluginSpec->longDescription().split('\n', Qt::SkipEmptyParts)); - const TextData text = {{ pluginSpec->name(), lines }}; - return QVariant::fromValue(text); - } - case RoleItemType: - return ItemTypeExtension; - case RoleLicense: - return pluginSpec->license(); - case RoleLocation: - return pluginSpec->filePath().toVariant(); - case RolePlatforms: { - const QString pattern = pluginSpec->platformSpecification().pattern(); - const QStringList platforms = pattern.isEmpty() - ? QStringList({"macOS", "Windows", "Linux"}) - : QStringList(pattern); - return platforms; - } - case RoleSize: - return pluginSpec->filePath().fileSize(); - case RoleTags: - break; - case RoleVendor: - return pluginSpec->vendor(); - case RoleVersion: - return pluginSpec->version(); - default: - break; - } - return {}; + return d->extensions.count(); } static QStringList dependenciesFromExtension(const Extension &extension) @@ -299,7 +294,7 @@ static QStringList dependenciesFromExtension(const Extension &extension) for (const Plugin &plugin : extension.plugins) { for (const Dependency &dependency : plugin.dependencies) { const QString withVersion = QString::fromLatin1("%1 (%2)").arg(dependency.name) - .arg(dependency.version); + .arg(dependency.version); dependencies.append(withVersion); } } @@ -371,27 +366,18 @@ QVariant ExtensionsModel::data(const QModelIndex &index, int role) const if (role == RoleSearchText) return searchText(index); - const bool itemIsLocalPlugin = index.row() >= d->absentExtensions.count(); - if (itemIsLocalPlugin) { - const PluginSpecs &pluginSpecs = PluginManager::plugins(); - const int pluginIndex = index.row() - d->absentExtensions.count(); - QTC_ASSERT(pluginIndex >= 0 && pluginIndex <= pluginSpecs.size(), return {}); - const PluginSpec *plugin = pluginSpecs.at(pluginIndex); - return dataFromPluginSpec(plugin, role); - } else { - const Extension &extension = d->absentExtensions.at(index.row()); - const QVariant extensionData = dataFromExtension(extension, role); - - // If data is unavailable, retrieve it from the first contained plugin - if (extensionData.isNull() && !extension.plugins.isEmpty()) { - const PluginSpec *pluginSpec = ExtensionsModel::pluginSpecForName( - extension.plugins.constFirst().name); - if (pluginSpec) - return dataFromPluginSpec(pluginSpec, role); - } - return extensionData; + const Extension &extension = d->extensions.at(index.row()); + const QVariant extensionData = dataFromExtension(extension, role); + // If data is unavailable, retrieve it from the first contained plugin + if (extensionData.isNull() && !extension.plugins.isEmpty()) { + const QString firstPluginName = extension.plugins.constFirst().name; + const Extension firstPluginExtension = + findOrDefault(d->extensions, Utils::equal(&Extension::name, firstPluginName)); + if (firstPluginExtension.name.isEmpty()) + return {}; + return dataFromExtension(firstPluginExtension, role); } - return {}; + return extensionData; } void ExtensionsModel::setExtensionsJson(const QByteArray &json) diff --git a/src/plugins/extensionmanager/testdata/augmentedplugindata.json b/src/plugins/extensionmanager/testdata/augmentedplugindata.json new file mode 100644 index 00000000000..32efe15b708 --- /dev/null +++ b/src/plugins/extensionmanager/testdata/augmentedplugindata.json @@ -0,0 +1,71 @@ +{ + "items": [ + { + "name": "ScreenRecorder", + "description": { + "paragraphs": [ + { + "header": "Screen Recorder plugin", + "text": [ + "With FFmpeg, you can record your screens and save the recordings as animated images or videos.", + "To record screens:", + "", + "- Select Tools > Screen Recording.", + "- Select to select the screen to record from and to set the recorded screen area.", + "- Select to start recording.", + "- Select when you are done recording.", + "- Select Crop and Trim to edit the recording.", + "- Select Export to save the recording as an animated image or a video." + ] + }, + { + "header": "Set the screen and area to record", + "text": [ + "Set the screen and the area to record in the Screen Recording Options dialog.", + "To select a screen and area:", + "", + "- In Display, select the display to record.", + "- In Recorded screen area, drag the guides to set the x and y coordinates of the starting point for the recording area, as well as the width and height of the area.", + "- Select OK to return to the Record Screen dialog." + ] + } + ], + "images": [ + { + "image_label": "Create animated imges like this", + "url": "https://bugreports.qt.io/secure/attachment/156058/156058_DragAndCopyOnLinux.gif" + } + ], + "links": [ + { + "link_text": "Documentation", + "url": "https://doc.qt.io/qtcreator/creator-how-to-record-screens.html" + }, + { + "link_text": "Homepage", + "url": "https://www.qt.io/" + } + ] + }, + "is_pack": false, + "plugins": [ + { + "meta_data": { + "Name": "ScreenRecorder", + "Dependencies": [ + { + "meta_data": { + "Name": "Core", + "Version": "13.0.2" + } + } + ], + "Version": "13.0.2" + } + } + ], + "tags": [ "Utility", "Docs" ], + "vendor": "The Qt Company Ltd" + } + ] +} diff --git a/src/plugins/extensionmanager/testdata/defaultpacks.json b/src/plugins/extensionmanager/testdata/defaultpacks.json index 0323b08d27e..d26b0a42c60 100644 --- a/src/plugins/extensionmanager/testdata/defaultpacks.json +++ b/src/plugins/extensionmanager/testdata/defaultpacks.json @@ -121,41 +121,6 @@ "plugins": [ { "meta_data": { "Name": "Designer" } } ] - }, - - { - "name": "SpellChecker", - "tags": [ "Editor" ], - "platforms": [ "macOS", "Windows", "Linux" ], - "license": "os", - "is_pack": false, - "description": { - "paragraphs": [ - { - "text": [ - "Spellcheck comments in source files." - ], - "header": "Get started" - } - ], - "links": [ - { - "url": "https://github.com/CJCombrink/SpellChecker-Plugin", - "link_text": "GitHub page" - } - ] - }, - "plugins": [ - { - "meta_data": { - "Name": "SpellChecker", - "Copyright": "(C) 2015 - 2024 Carel Combrink" - }, - "url": "https://github.com/CJCombrink/SpellChecker-Plugin/releases/download/v3.6.0/SpellChecker-Plugin_QtC13.0.0_macos_x64.tar.gz" - } - ], - "vendor": "Carel Combrink", - "copyright": "(C) 2015 - 2024 Carel Combrink" } ] } From 62e37eec422ea37418d135961a09a9a9b2ed92db Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 26 Jun 2024 08:07:09 +0200 Subject: [PATCH 55/73] ExtensionManager: Let QtC developer test data sets explicitly The extansion query service is currently only reachable from within the internal network. So far, if the request failed, and if Qt Creator was configured with WITH_TESTS, a set of test json got loaded. That test data confuses people in the team. This change makes loading of test data explicit, and comments it off by default. Change-Id: I89236064b6af32be7559bb6d36cbf0d42982085d Reviewed-by: Cristian Adam --- src/plugins/extensionmanager/extensionsbrowser.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index bfe4fb102f8..352f2f8e502 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -362,6 +362,12 @@ int ExtensionsBrowser::extraListViewWidth() const void ExtensionsBrowser::fetchExtensions() { +#ifdef WITH_TESTS + // Uncomment for testing with local json data. + // Available: "augmentedplugindata", "defaultpacks", "varieddata", "thirdpartyplugins" + // d->model->setExtensionsJson(testData("defaultpacks")); return; +#endif // WITH_TESTS + using namespace Tasking; const auto onQuerySetup = [](NetworkQuery &query) { @@ -379,13 +385,6 @@ void ExtensionsBrowser::fetchExtensions() query.setNetworkAccessManager(NetworkAccessManager::instance()); }; const auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) { - if (result != DoneWith::Success) { -#ifdef WITH_TESTS - // Available: "augmentedplugindata", "defaultpacks", "varieddata", "thirdpartyplugins" - d->model->setExtensionsJson(testData("defaultpacks")); -#endif // WITH_TESTS - return; - } const QByteArray response = query.reply()->readAll(); d->model->setExtensionsJson(response); }; From ee1ae662b9a8a419b07aa1c84f106df5c6288132 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 26 Jun 2024 09:03:39 +0200 Subject: [PATCH 56/73] ExtensionManager: Add logging Log the network request, incl. result and response. And how many extensions were fetched remotely and added locally. Change-Id: I634d72462c8076c2fa01e88a1918163f76d28aff Reviewed-by: Cristian Adam --- src/plugins/extensionmanager/extensionsbrowser.cpp | 9 ++++++++- src/plugins/extensionmanager/extensionsmodel.cpp | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 352f2f8e502..573c915a69c 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -383,10 +383,17 @@ void ExtensionsBrowser::fetchExtensions() query.setRequest(QNetworkRequest(QUrl::fromUserInput(request))); query.setNetworkAccessManager(NetworkAccessManager::instance()); + qCDebug(browserLog).noquote() << "Sending request:" << request; }; const auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) { const QByteArray response = query.reply()->readAll(); - d->model->setExtensionsJson(response); + qCDebug(browserLog).noquote() << "Got result" << result; + if (result == DoneWith::Success) { + d->model->setExtensionsJson(response); + } else { + qCDebug(browserLog).noquote() << response; + d->model->setExtensionsJson({}); + } }; Group group { diff --git a/src/plugins/extensionmanager/extensionsmodel.cpp b/src/plugins/extensionmanager/extensionsmodel.cpp index 702e3019f75..1d8fad89dfa 100644 --- a/src/plugins/extensionmanager/extensionsmodel.cpp +++ b/src/plugins/extensionmanager/extensionsmodel.cpp @@ -261,7 +261,9 @@ public: void ExtensionsModelPrivate::setExtensions(const Extensions &extensions) { this->extensions = extensions; + qCDebug(modelLog) << "Number of extensions from json:" << this->extensions.count(); addUnlistedLocalExtensions(); + qCDebug(modelLog) << "Number of extensions with added local ones:" << this->extensions.count(); } void ExtensionsModelPrivate::addUnlistedLocalExtensions() From d6efab3c44e2b22e7776802fc36a703d494c0f86 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 26 Jun 2024 12:19:48 +0200 Subject: [PATCH 57/73] LLDB-DAP: Remove usage of "avoid" marked function Didn't notice the `toStringList` member function of `Environmen`. The code now is now also nicely indented. Change-Id: Id570ddc48e915d9090f9975d05761aa908311f0d Reviewed-by: hjk --- src/plugins/debugger/dap/lldbdapengine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/debugger/dap/lldbdapengine.cpp b/src/plugins/debugger/dap/lldbdapengine.cpp index 0dded62b776..d767ab723ae 100644 --- a/src/plugins/debugger/dap/lldbdapengine.cpp +++ b/src/plugins/debugger/dap/lldbdapengine.cpp @@ -152,8 +152,7 @@ void LldbDapEngine::handleDapInitialize() const QJsonArray commands = preRunCommands(); if (!isLocalAttachEngine()) { - const QJsonArray env = QJsonArray::fromStringList( - rp.inferior.environment.toDictionary().toStringList()); + const QJsonArray env = QJsonArray::fromStringList(rp.inferior.environment.toStringList()); const QJsonArray args = QJsonArray::fromStringList(rp.inferior.command.splitArguments()); QJsonObject launchJson{ From 38520cd8a59aa28777fc1f32a490e48f896eae2b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 26 Jun 2024 10:13:02 +0200 Subject: [PATCH 58/73] QtSupport: Simplify startEditorProcess() Skip pid arg, as it's not used. Inline error message construction. Change-Id: I429d2094c2c8117fb79e9c9309036d9573b29f3f Reviewed-by: hjk --- src/plugins/qtsupport/externaleditors.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/plugins/qtsupport/externaleditors.cpp b/src/plugins/qtsupport/externaleditors.cpp index 371623f6cf7..47200a6aeb3 100644 --- a/src/plugins/qtsupport/externaleditors.cpp +++ b/src/plugins/qtsupport/externaleditors.cpp @@ -118,12 +118,6 @@ static QString locateBinary(const QString &path, const QString &binary) return {}; } -static QString msgStartFailed(const QString &binary, QStringList arguments) -{ - arguments.push_front(binary); - return Tr::tr("Unable to start \"%1\"").arg(arguments.join(QLatin1Char(' '))); -} - static QString designerBinary(const QtSupport::QtVersion *qtVersion) { if (qtVersion) @@ -227,12 +221,11 @@ static bool startEditorProcess(const LaunchData &data, QString *errorMessage) { if (debug) qDebug() << Q_FUNC_INFO << '\n' << data.binary << data.arguments << data.workingDirectory; - qint64 pid = 0; - if (!Process::startDetached({FilePath::fromString(data.binary), data.arguments}, data.workingDirectory, &pid)) { - *errorMessage = msgStartFailed(data.binary, data.arguments); - return false; - } - return true; + const CommandLine cmd{FilePath::fromString(data.binary), data.arguments}; + if (Process::startDetached(cmd, data.workingDirectory)) + return true; + *errorMessage = Tr::tr("Unable to start \"%1\".").arg(cmd.toUserOutput()); + return false; } // ExternalDesignerEditorFactory with Designer Tcp remote control. From 3a007ee499ada33a357d2fcdf9faf2788e772fa2 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 26 Jun 2024 12:09:36 +0200 Subject: [PATCH 59/73] ExtensionManager: Reduce spacing between "cards" from 24px to 16px Use the dedicated gapSize contant more consistently. Change-Id: I3d4e27493a758b3bfa1b29988496f53ad0fbd811 Reviewed-by: hjk --- .../extensionmanager/extensionsbrowser.cpp | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 573c915a69c..a4970d113c3 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -52,9 +52,9 @@ namespace ExtensionManager::Internal { Q_LOGGING_CATEGORY(browserLog, "qtc.extensionmanager.browser", QtWarningMsg) -constexpr int gapSize = ExVPaddingGapXl; +constexpr int gapSize = HGapL; constexpr int itemWidth = 330; -constexpr int cellWidth = itemWidth + HPaddingL; +constexpr int cellWidth = itemWidth + gapSize; class ExtensionItemDelegate : public QItemDelegate { @@ -80,25 +80,25 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { - // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+-----------+ - // | | | | (ExPaddingGapL) | | | - // | | | +-------------------------------------------------------------+--------+ | | - // | | | | || | | - // | | | +-------------------------------------------------------------+--------+ | | - // | | | | (VGapXxs) | | | - // | | | +--------+--------+--------------+--------+--------+---------+---------+ | | - // |(ExPaddingGapL)| |(ExPaddingGapL)||(HGapXs)|(h16)|(HGapXs)||(HGapXxs)||(ExPaddingGapL)|(HPaddingL)| - // | |(50x50)| +--------+--------+--------------+--------+--------+---------+---------+ | | - // | | | | (VGapXxs) | | | - // | | | +----------------------------------------------------------------------+ | | - // | | | | | | | - // | | | +----------------------------------------------------------------------+ | | - // | | | | (ExPaddingGapL) | | | - // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+-----------+ - // | (ExVPaddingGapXl) | - // +------------------------------------------------------------------------------------------------------------------------------------------+ + // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+---------+ + // | | | | (ExPaddingGapL) | | | + // | | | +-------------------------------------------------------------+--------+ | | + // | | | | || | | + // | | | +-------------------------------------------------------------+--------+ | | + // | | | | (VGapXxs) | | | + // | | | +--------+--------+--------------+--------+--------+---------+---------+ | | + // |(ExPaddingGapL)| |(ExPaddingGapL)||(HGapXs)|(h16)|(HGapXs)||(HGapXxs)||(ExPaddingGapL)|(gapSize)| + // | |(50x50)| +--------+--------+--------------+--------+--------+---------+---------+ | | + // | | | | (VGapXxs) | | | + // | | | +----------------------------------------------------------------------+ | | + // | | | | | | | + // | | | +----------------------------------------------------------------------+ | | + // | | | | (ExPaddingGapL) | | | + // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+---------+ + // | (gapSize) | + // +----------------------------------------------------------------------------------------------------------------------------------------+ - const QRect bgRGlobal = option.rect.adjusted(0, 0, -HPaddingL, -gapSize); + const QRect bgRGlobal = option.rect.adjusted(0, 0, -gapSize, -gapSize); const QRect bgR = bgRGlobal.translated(-option.rect.topLeft()); const int middleColumnW = bgR.width() - ExPaddingGapL - iconBgS.width() - ExPaddingGapL @@ -356,7 +356,9 @@ QSize ExtensionsBrowser::sizeHint() const int ExtensionsBrowser::extraListViewWidth() const { // TODO: Investigate "transient" scrollbar, just for this list view. + constexpr int extraPadding = qMax(0, ExVPaddingGapXl - gapSize); return d->extensionsView->style()->pixelMetric(QStyle::PM_ScrollBarExtent) + + extraPadding + 1; // Needed } From a6b747383496191f928e001e2f0811dbd489e78b Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 26 Jun 2024 12:25:40 +0200 Subject: [PATCH 60/73] ExtensionManager: Set icon background green or grey depending of state This change sets green vs. grey background for extension icons depending of enabled state. Change-Id: Id99419544a00acca897aa0ad6c98d2598e4b2210 Reviewed-by: hjk --- .../extensionmanager/extensionmanagerwidget.cpp | 6 +++--- src/plugins/extensionmanager/extensionsbrowser.cpp | 12 +++++++----- src/plugins/extensionmanager/extensionsmodel.cpp | 2 +- src/plugins/extensionmanager/extensionsmodel.h | 3 ++- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 4b0bfcfb325..b62951529ee 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -223,7 +223,7 @@ public: const ItemType itemType = current.data(RoleItemType).value(); const bool isPack = itemType == ItemTypePack; - const bool isRemotePlugin = !(isPack || ExtensionsModel::pluginSpecForName(name)); + const bool isRemotePlugin = !(isPack || pluginSpecForName(name)); installButton->setVisible(isRemotePlugin && !pluginData.empty()); if (installButton->isVisible()) installButton->setToolTip(pluginData.constFirst().second); @@ -292,7 +292,7 @@ public: }.attachTo(this); connect(m_checkBox, &QCheckBox::clicked, this, [this](bool checked) { - ExtensionSystem::PluginSpec *spec = ExtensionsModel::pluginSpecForName(m_pluginName); + ExtensionSystem::PluginSpec *spec = pluginSpecForName(m_pluginName); if (spec == nullptr) return; const bool doIt = m_pluginView.data().setPluginsEnabled({spec}, checked); @@ -319,7 +319,7 @@ public: private: void update() { - const ExtensionSystem::PluginSpec *spec = ExtensionsModel::pluginSpecForName(m_pluginName); + const ExtensionSystem::PluginSpec *spec = pluginSpecForName(m_pluginName); setVisible(spec != nullptr); if (spec == nullptr) return; diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index a4970d113c3..b2bc534fdf8 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -422,11 +422,13 @@ QLabel *tfLabel(const TextFormat &tf, bool singleLine) QGradientStops iconGradientStops(const QModelIndex &index) { - const bool isVendorExtension = index.data(RoleVendor).toString() == "The Qt Company Ltd"; - const QColor startColor = creatorColor(isVendorExtension ? Theme::Token_Gradient01_Start - : Theme::Token_Gradient02_Start); - const QColor endColor = creatorColor(isVendorExtension ? Theme::Token_Gradient01_End - : Theme::Token_Gradient02_End); + const PluginSpec *ps = pluginSpecForName(index.data(RoleName).toString()); + const bool greenGradient = ps != nullptr && ps->isEffectivelyEnabled(); + + const QColor startColor = creatorColor(greenGradient ? Theme::Token_Gradient01_Start + : Theme::Token_Gradient02_Start); + const QColor endColor = creatorColor(greenGradient ? Theme::Token_Gradient01_End + : Theme::Token_Gradient02_End); const QGradientStops gradient = { {0, startColor}, {1, endColor}, diff --git a/src/plugins/extensionmanager/extensionsmodel.cpp b/src/plugins/extensionmanager/extensionsmodel.cpp index 1d8fad89dfa..2500f8f73f6 100644 --- a/src/plugins/extensionmanager/extensionsmodel.cpp +++ b/src/plugins/extensionmanager/extensionsmodel.cpp @@ -390,7 +390,7 @@ void ExtensionsModel::setExtensionsJson(const QByteArray &json) endResetModel(); } -PluginSpec *ExtensionsModel::pluginSpecForName(const QString &pluginName) +PluginSpec *pluginSpecForName(const QString &pluginName) { return findOrDefault(PluginManager::plugins(), equal(&PluginSpec::name, pluginName)); } diff --git a/src/plugins/extensionmanager/extensionsmodel.h b/src/plugins/extensionmanager/extensionsmodel.h index 1fc86d3afde..68e7f9ea846 100644 --- a/src/plugins/extensionmanager/extensionsmodel.h +++ b/src/plugins/extensionmanager/extensionsmodel.h @@ -54,12 +54,13 @@ public: QVariant data(const QModelIndex &index, int role) const; void setExtensionsJson(const QByteArray &json); - static ExtensionSystem::PluginSpec *pluginSpecForName(const QString &pluginName); private: class ExtensionsModelPrivate *d = nullptr; }; +ExtensionSystem::PluginSpec *pluginSpecForName(const QString &pluginName); + #ifdef WITH_TESTS QObject *createExtensionsModelTest(); #endif From 11905967fe2053d81000831d08b384ccc662aef6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 26 Jun 2024 10:44:34 +0200 Subject: [PATCH 61/73] Process: Introduce DetachedChannelMode enum The default impl of Process::startDetached() forwards process channels. Make it optional by providing an additional argument of DetachedChannelMode type for Process::startDetached(). Change-Id: I6cb55377c21dfedacd53117756894d07e354e0fe Reviewed-by: hjk --- src/libs/utils/processenums.h | 5 +++++ src/libs/utils/qtcprocess.cpp | 16 +++++++++++----- src/libs/utils/qtcprocess.h | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/processenums.h b/src/libs/utils/processenums.h index 903bc8df9bf..e19321fcd04 100644 --- a/src/libs/utils/processenums.h +++ b/src/libs/utils/processenums.h @@ -41,6 +41,11 @@ enum class Channel { Error }; +enum class DetachedChannelMode { + Forward, + Discard +}; + enum class TextChannelMode { // Keep | Emit | Emit // raw | text | content diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 05111ef8efa..2a51e01071f 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -1317,12 +1317,18 @@ void Process::closeWriteChannel() d->sendControlSignal(ControlSignal::CloseWriteChannel); } -bool Process::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, qint64 *pid) +bool Process::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, + DetachedChannelMode channelMode, qint64 *pid) { - return QProcess::startDetached(cmd.executable().toUserOutput(), - cmd.splitArguments(), - workingDirectory.toUserOutput(), - pid); + QProcess process; + process.setProgram(cmd.executable().toUserOutput()); + process.setArguments(cmd.splitArguments()); + process.setWorkingDirectory(workingDirectory.toUserOutput()); + if (channelMode == DetachedChannelMode::Discard) { + process.setStandardOutputFile(QProcess::nullDevice()); + process.setStandardErrorFile(QProcess::nullDevice()); + } + return process.startDetached(pid); } void Process::setLowPriority() diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 3f043214f96..cc629fe127b 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -137,6 +137,7 @@ public: // Some of them could be aggregated in another public utils class. static bool startDetached(const CommandLine &cmd, const FilePath &workingDirectory = {}, + DetachedChannelMode channelMode = DetachedChannelMode::Forward, qint64 *pid = nullptr); // Starts the command and waits for finish. From 9cb4e8042a746227bb98f3092610058824355eae Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 25 Jun 2024 15:39:18 +0200 Subject: [PATCH 62/73] Doc: Replace \badcode with \code to show JSON highlighting ...in the online docs. Does not work in the helps. Change-Id: I6391ff40be2607eb026153deec418e9389954b7d Reviewed-by: Artem Sokolovskii Reviewed-by: Cristian Adam --- .../src/cmake/creator-projects-cmake-presets.qdoc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc index 41937eb6b92..02344e217b7 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc @@ -44,7 +44,7 @@ \c NOT_COMMON_VALUE is displayed in \uicontrol {Initial Parameters} and \c AN_ENVIRONMENT_FLAG in the environment configuration field. - \badcode + \code { "version": 1, "configurePresets": [ @@ -91,7 +91,7 @@ \li GNU gdb 11.2.0 for MinGW 11.2.0 64-bit debugger \endlist - \badcode + \code { "version": 1, "configurePresets": [ @@ -131,7 +131,7 @@ generator, add \c Debug and \c Release build steps, and specify the path to \c ninja.exe as a value of the \c CMAKE_MAKE_PROGRAM variable: - \badcode + \code { "version": 2, "configurePresets": [ @@ -180,7 +180,7 @@ For example: - \badcode + \code "generator": "Ninja Multi-Config", "toolset": { "value": "v142,host=x64", @@ -196,7 +196,7 @@ in the \c PATH, you might also have to specify the compiler to use in \c cacheVariables or \c environmentVariables: - \badcode + \code "generator": "Ninja Multi-Config", "toolset": { "value": "v142,host=x64", @@ -226,7 +226,7 @@ \li \c wine emulator \endlist - \badcode + \code { "version": 4, "configurePresets": [ @@ -262,7 +262,7 @@ if the \c hostSystemName equals \c Linux, the \c linux presets are used and if it equals \c Windows, the \c windows presets are used. - \badcode + \code { "version": 3, "configurePresets": [ From d6eee1e25072133183541cbf17ed9186a0268302 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 26 Jun 2024 15:17:25 +0200 Subject: [PATCH 63/73] Doc: Update supported CMake presets version to 5 Link to the presets docs for version 5, so that users won't accidentally use fields from newer versions. Task-number: QTCREATORBUG-30604 Change-Id: Iab548df768d55408dd018e97e2f5c9c1dfc3e594 Reviewed-by: Cristian Adam --- .../src/cmake/creator-projects-cmake-presets.qdoc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc index 02344e217b7..4e0160ba9eb 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc @@ -15,13 +15,14 @@ \c CMakeUserPresets.json has options for your local builds. Create the presets files in the format described in - \l{https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html} + \l{https://cmake.org/cmake/help/v3.24/manual/cmake-presets.7.html} {cmake-presets(7)} and store them in the project's root directory. You can then see them in the \l {Projects} view. - \QC supports presets up to version 3 (introduced in CMake 3.21), but does not - enforce version checking. It reads and uses all the fields from version 3 if - present. It does not support test presets. + \QC supports \e configure and \e build presets up to version 5 + (introduced in CMake 3.24), but does not enforce version checking. + It reads and uses all the fields from version 5 if present. + It does not support \e test presets. You can import the presets the first time you \l {Open projects} {open a project}, when no \c CMakeLists.txt.user file exists or you have From a81e4fb277b298de630132eb4e4e1b0d1b4a2b98 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 25 Jun 2024 10:34:55 +0200 Subject: [PATCH 64/73] Extensions: Edit UI text - Add dots to ends of messages - Replace "plugin" with "extension" in translatable text - Fix capitalization of headings and button labels - Change wording Change-Id: I24a3ca6de6a5a0a4509bab34ad2f50cbcf40c73a Reviewed-by: Eike Ziller Reviewed-by: Leena Miettinen --- .../extensionmanagerwidget.cpp | 12 ++++----- src/plugins/lua/bindings/fetch.cpp | 23 ++++++++-------- src/plugins/lua/bindings/install.cpp | 26 ++++++++++--------- src/plugins/lua/luaengine.cpp | 6 ++--- src/plugins/lua/luapluginspec.cpp | 6 ++--- 5 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index b62951529ee..a9761e8ebff 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -279,8 +279,8 @@ public: : QWidget(parent) { m_label = new InfoLabel; - m_checkBox = new QCheckBox(Tr::tr("Load on Start")); - m_restartButton = new Button(Tr::tr("Restart now"), Button::MediumPrimary); + m_checkBox = new QCheckBox(Tr::tr("Load on start")); + m_restartButton = new Button(Tr::tr("Restart Now"), Button::MediumPrimary); m_restartButton->setVisible(false); m_pluginView.hide(); @@ -667,9 +667,9 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url) struct StorageStruct { StorageStruct() { - progressDialog.reset(new QProgressDialog(Tr::tr("Downloading Plugin..."), - Tr::tr("Cancel"), 0, 0, - ICore::dialogParent())); + progressDialog.reset(new QProgressDialog( + Tr::tr("Downloading..."), Tr::tr("Cancel"), 0, 0, ICore::dialogParent())); + progressDialog->setWindowTitle(Tr::tr("Download Extension")); progressDialog->setWindowModality(Qt::ApplicationModal); progressDialog->setFixedSize(progressDialog->sizeHint()); progressDialog->setAutoClose(false); @@ -694,7 +694,7 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url) QMessageBox::warning( ICore::dialogParent(), Tr::tr("Download Error"), - Tr::tr("Could not download Plugin") + "\n\n" + storage->url.toString() + "\n\n" + Tr::tr("Cannot download extension") + "\n\n" + storage->url.toString() + "\n\n" + Tr::tr("Code: %1.").arg(query.reply()->error())); } }; diff --git a/src/plugins/lua/bindings/fetch.cpp b/src/plugins/lua/bindings/fetch.cpp index 22d1bc64cbd..6f5fd535612 100644 --- a/src/plugins/lua/bindings/fetch.cpp +++ b/src/plugins/lua/bindings/fetch.cpp @@ -59,7 +59,7 @@ void addFetchModule() LuaOptionsPage(Module *module) { setId("BB.Lua.Fetch"); - setDisplayName(Tr::tr("Network access")); + setDisplayName(Tr::tr("Network Access")); setCategory("ZY.Lua"); setDisplayCategory("Lua"); setCategoryIconPath(":/lua/images/settingscategory_lua.png"); @@ -176,8 +176,8 @@ void addFetchModule() // so we have to use a QMessageBox instead of the info bar auto msgBox = new QMessageBox( QMessageBox::Question, - Tr::tr("Allow Internet access"), - Tr::tr("The plugin \"%1\" would like to fetch from the following url:\n%2") + Tr::tr("Allow Internet Access"), + Tr::tr("Allow the extension \"%1\" to fetch from the following URL:\n%2") .arg(pluginName) .arg(url), QMessageBox::Yes | QMessageBox::No, @@ -205,14 +205,13 @@ void addFetchModule() Utils::InfoBarEntry entry{ Utils::Id::fromString("Fetch" + pluginName), - Tr::tr("The plugin \"%1\" would like to fetch data from the internet. Do " - "you want to allow this?") + Tr::tr("Allow the extension \"%1\" to fetch data from the internet?") .arg(pluginName)}; entry.setDetailsWidgetCreator([pluginName, url] { - const QString markdown = Tr::tr("The plugin \"**%1**\" would like to fetch " - "from the following url:\n\n") - .arg(pluginName) - + QString("* [%3](%3)").arg(url); + const QString markdown = Tr::tr("Allow the extension \"%1\" to fetch data" + "from the following URL:\n\n") + .arg("**" + pluginName + "**") + + QString("* [%1](%1)").arg(url); QLabel *list = new QLabel(); list->setTextFormat(Qt::TextFormat::MarkdownText); @@ -225,7 +224,7 @@ void addFetchModule() Core::ICore::infoBar()->removeInfo(Utils::Id::fromString("Fetch" + pluginName)); fetch(); }); - entry.addCustomButton(Tr::tr("Allow once"), [pluginName, fetch]() { + entry.addCustomButton(Tr::tr("Allow Once"), [pluginName, fetch]() { Core::ICore::infoBar()->removeInfo(Utils::Id::fromString("Fetch" + pluginName)); fetch(); }); @@ -311,8 +310,8 @@ void addFetchModule() }; checkPermission(url, actualFetch, [callback, pluginName]() { - callback(Tr::tr("Fetching is not allowed for the plugin \"%1\" (You can edit " - "permissions in Preferences => Lua)") + callback(Tr::tr("Fetching is not allowed for the extension \"%1\". (You can edit " + "permissions in Preferences > Lua.)") .arg(pluginName)); }); }; diff --git a/src/plugins/lua/bindings/install.cpp b/src/plugins/lua/bindings/install.cpp index a044ff2fb8d..076cf63b9fa 100644 --- a/src/plugins/lua/bindings/install.cpp +++ b/src/plugins/lua/bindings/install.cpp @@ -50,7 +50,7 @@ expected_str getPackageInfo(const FilePath &appDataPath) return make_unexpected(error.errorString()); if (!doc.isObject()) - return make_unexpected(Tr::tr("Package info is not an object")); + return make_unexpected(Tr::tr("Package info is not an object.")); return doc; } @@ -66,7 +66,7 @@ expected_str getInstalledPackageInfo(const FilePath &appDataPath, c if (root.contains(name)) { QJsonValue v = root[name]; if (!v.isObject()) - return make_unexpected(Tr::tr("Installed package info is not an object")); + return make_unexpected(Tr::tr("Installed package info is not an object.")); return v.toObject(); } @@ -86,12 +86,12 @@ expected_str getOrCreatePackageInfo(const FilePath &appDataPath) expected_str savePackageInfo(const FilePath &appDataPath, const QJsonDocument &doc) { if (!appDataPath.ensureWritableDir()) - return make_unexpected(Tr::tr("Could not create app data directory")); + return make_unexpected(Tr::tr("Cannot create app data directory.")); const FilePath packageInfoPath = appDataPath / "package.json"; return packageInfoPath.writeFileContents(doc.toJson()) .transform_error([](const QString &error) { - return Tr::tr("Could not write to package info: %1").arg(error); + return Tr::tr("Cannot write to package info: %1").arg(error); }) .transform([](qint64) { return; }); } @@ -147,7 +147,7 @@ static Group installRecipe( const auto size = reply->size(); const auto written = storage->write(reply->readAll()); if (written != size) - return emitResult(Tr::tr("Could not write to temporary file")); + return emitResult(Tr::tr("Cannot write to temporary file.")); storage->close(); return DoneResult::Success; }; @@ -169,7 +169,7 @@ static Group installRecipe( const auto onUnarchiverDone = [appDataPath, installOptionsIt, emitResult](DoneWith result) { if (result == DoneWith::Error) - return emitResult(Tr::tr("Unarchiving failed")); + return emitResult(Tr::tr("Unarchiving failed.")); if (result == DoneWith::Cancel) return DoneResult::Error; @@ -212,7 +212,7 @@ static Group installRecipe( } if (!storage->open(QIODevice::WriteOnly)) { - emitResult(Tr::tr("Could not open temporary file")); + emitResult(Tr::tr("Cannot open temporary file.")); return SetupResult::StopWithError; } return SetupResult::Continue; @@ -326,16 +326,17 @@ void addInstallModule() if (QApplication::activeModalWidget()) { auto msgBox = new QMessageBox( QMessageBox::Question, - Tr::tr("Install package"), + Tr::tr("Install Package"), msg, QMessageBox::Yes | QMessageBox::No, Core::ICore::dialogParent()); const QString details - = Tr::tr("The plugin \"%1\" would like to install the following " + = Tr::tr("The extension \"%1\" wants to install the following " "package(s):\n\n") .arg(pluginSpec->name) + Utils::transform(installOptionsList, [](const InstallOptions &options) { + //: %1 = package name, %2 = version, %3 = URL return QString("* %1 - %2 (from: %3)") .arg(options.name, options.version, options.url.toString()); }).join("\n"); @@ -363,11 +364,12 @@ void addInstallModule() entry.setCancelButtonInfo(denied); const QString details - = Tr::tr("The plugin \"**%1**\" would like to install the following " + = Tr::tr("The extension \"%1\" wants to install the following " "package(s):\n\n") - .arg(pluginSpec->name) + .arg("**" + pluginSpec->name + "**") // markdown bold + Utils::transform(installOptionsList, [](const InstallOptions &options) { - return QString("* %1 - %2 (from: [%3](%3))") + //: Markdown list item: %1 = package name, %2 = version, %3 = URL + return Tr::tr("* %1 - %2 (from: [%3](%3))") .arg(options.name, options.version, options.url.toString()); }).join("\n"); diff --git a/src/plugins/lua/luaengine.cpp b/src/plugins/lua/luaengine.cpp index 34faee83847..babfac698d5 100644 --- a/src/plugins/lua/luaengine.cpp +++ b/src/plugins/lua/luaengine.cpp @@ -164,7 +164,7 @@ expected_str LuaEngine::connectHooks( QString hookName = QStringList{path, k.as()}.join("."); auto it = d->m_hooks.find(hookName); if (it == d->m_hooks.end()) - return make_unexpected(QString("No hook named '%1' found").arg(hookName)); + return make_unexpected(Tr::tr("No hook with the name \"%1\" found.").arg(hookName)); else it.value()(v.as()); } @@ -265,7 +265,7 @@ expected_str LuaEngine::prepareSetup( auto pluginTable = result.get>(); if (!pluginTable) - return make_unexpected(Tr::tr("Script did not return a table")); + return make_unexpected(Tr::tr("Script did not return a table.")); auto hookTable = pluginTable->get>("hooks"); @@ -278,7 +278,7 @@ expected_str LuaEngine::prepareSetup( auto setupFunction = pluginTable->get_or("setup", {}); if (!setupFunction) - return make_unexpected(Tr::tr("Plugin info table did not contain a setup function")); + return make_unexpected(Tr::tr("Extension info table did not contain a setup function.")); return setupFunction; } diff --git a/src/plugins/lua/luapluginspec.cpp b/src/plugins/lua/luapluginspec.cpp index 3e6b1eb3edd..f00e48936bc 100644 --- a/src/plugins/lua/luapluginspec.cpp +++ b/src/plugins/lua/luapluginspec.cpp @@ -108,19 +108,19 @@ bool LuaPluginSpec::initializePlugin() = LuaEngine::instance().prepareSetup(*activeLuaState, *this); if (!setupResult) { - setError(Lua::Tr::tr("Failed to prepare plugin setup: %1").arg(setupResult.error())); + setError(Lua::Tr::tr("Cannot prepare extension setup: %1").arg(setupResult.error())); return false; } auto result = setupResult->call(); if (result.get_type() == sol::type::boolean && result.get() == false) { - setError(Lua::Tr::tr("Plugin setup function returned false")); + setError(Lua::Tr::tr("Extension setup function returned false.")); return false; } else if (result.get_type() == sol::type::string) { std::string error = result.get().what(); if (!error.empty()) { - setError(Lua::Tr::tr("Plugin setup function returned error: %1") + setError(Lua::Tr::tr("Extension setup function returned error: %1") .arg(QString::fromStdString(error))); return false; } From 6ffe1a8061af8f4dd3cd50aba1b9bca51ee4f0c5 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 26 Jun 2024 16:02:16 +0200 Subject: [PATCH 65/73] ExtensionBrowser: Delay fetching of json data from server The fetching is postponed until the extension manager is shown. This also adds a spinner which is shown during the fetching of the data. Change-Id: Id24ae772bcdfdf885ecfd5341d9a8d02f398c1a0 Reviewed-by: hjk --- .../extensionmanager/extensionsbrowser.cpp | 21 +++++++++++++++---- .../extensionmanager/extensionsbrowser.h | 2 ++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index b2bc534fdf8..13816ff5dd2 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -249,6 +250,7 @@ public: class ExtensionsBrowserPrivate { public: + bool dataFetched = false; ExtensionsModel *model; QLineEdit *searchBox; QListView *extensionsView; @@ -256,6 +258,7 @@ public: QSortFilterProxyModel *filterProxyModel; int columnsCount = 2; Tasking::TaskTreeRunner taskTreeRunner; + SpinnerSolution::Spinner *m_spinner; }; ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) @@ -311,6 +314,8 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) WelcomePageHelpers::setBackgroundColor(d->extensionsView->viewport(), Theme::Token_Background_Default); + d->m_spinner = new SpinnerSolution::Spinner(SpinnerSolution::SpinnerSize::Large, this); + auto updateModel = [this] { d->filterProxyModel->sort(0); @@ -324,8 +329,6 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) }; connect(PluginManager::instance(), &PluginManager::pluginsChanged, this, updateModel); - connect(PluginManager::instance(), &PluginManager::initializationDone, - this, &ExtensionsBrowser::fetchExtensions); connect(d->searchBox, &QLineEdit::textChanged, d->filterProxyModel, &QSortFilterProxyModel::setFilterWildcard); } @@ -362,6 +365,15 @@ int ExtensionsBrowser::extraListViewWidth() const + 1; // Needed } +void ExtensionsBrowser::showEvent(QShowEvent *event) +{ + if (!d->dataFetched) { + d->dataFetched = true; + fetchExtensions(); + } + QWidget::showEvent(event); +} + void ExtensionsBrowser::fetchExtensions() { #ifdef WITH_TESTS @@ -372,7 +384,7 @@ void ExtensionsBrowser::fetchExtensions() using namespace Tasking; - const auto onQuerySetup = [](NetworkQuery &query) { + const auto onQuerySetup = [this](NetworkQuery &query) { const QString host = "https://qc-extensions.qt.io"; const QString url = "%1/api/v1/search?request="; const QString requestTemplate @@ -382,10 +394,10 @@ void ExtensionsBrowser::fetchExtensions() .arg(QSysInfo::productType()) .arg(QSysInfo::productVersion()) .arg(QSysInfo::currentCpuArchitecture()); - query.setRequest(QNetworkRequest(QUrl::fromUserInput(request))); query.setNetworkAccessManager(NetworkAccessManager::instance()); qCDebug(browserLog).noquote() << "Sending request:" << request; + d->m_spinner->show(); }; const auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) { const QByteArray response = query.reply()->readAll(); @@ -396,6 +408,7 @@ void ExtensionsBrowser::fetchExtensions() qCDebug(browserLog).noquote() << response; d->model->setExtensionsJson({}); } + d->m_spinner->hide(); }; Group group { diff --git a/src/plugins/extensionmanager/extensionsbrowser.h b/src/plugins/extensionmanager/extensionsbrowser.h index b49bcfaba12..4e0b87c5936 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.h +++ b/src/plugins/extensionmanager/extensionsbrowser.h @@ -28,6 +28,8 @@ public: int extraListViewWidth() const; // Space for scrollbar, etc. + void showEvent(QShowEvent *event) override; + signals: void itemSelected(const QModelIndex ¤t, const QModelIndex &previous); From a53a72044ce1b867dff622b512b5b600153c2cee Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 25 Jun 2024 08:39:54 +0200 Subject: [PATCH 66/73] TextEditor: Allow to open all files with the text editor Sometimes the mime detection returns unexpected results and defines a textfile based on the ending as a binary file. We should at least make it possible for the user to open those files in the plain text editor. Fixes: QTCREATORBUG-31116 Change-Id: I3139a1013be9fa6f28654434229c62f7a8e79d21 Reviewed-by: Christian Stenger --- src/plugins/coreplugin/editormanager/ieditorfactory.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp index 74c35a7b5ca..0c0fc17a204 100644 --- a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp +++ b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp @@ -4,6 +4,7 @@ #include "ieditorfactory.h" #include "ieditorfactory_p.h" #include "editormanager.h" +#include "../coreconstants.h" #include #include @@ -36,6 +37,14 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, } return true; // continue }); + // Always offer the plain text editor as a fallback for the case that the mime type + // is not detected correctly. + if (auto plainTextEditorFactory = Utils::findOrDefault( + allFactories, + Utils::equal(&IEditorFactory::id, Utils::Id(Constants::K_DEFAULT_TEXT_EDITOR_ID)))) { + if (!matches.contains(plainTextEditorFactory)) + list->append(plainTextEditorFactory); + } } /*! From eeaf1e18e0d4692454afaa9859ae366289ec8cea Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 25 Jun 2024 14:32:25 +0200 Subject: [PATCH 67/73] LanguageClient: use uniform row height for call and type hierarchy Change-Id: If035d00766b50cb56ea42796d8399860394bf2d4 Reviewed-by: hjk --- src/plugins/languageclient/callandtypehierarchy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/languageclient/callandtypehierarchy.cpp b/src/plugins/languageclient/callandtypehierarchy.cpp index 43e47ddc00b..3d2e9eff144 100644 --- a/src/plugins/languageclient/callandtypehierarchy.cpp +++ b/src/plugins/languageclient/callandtypehierarchy.cpp @@ -267,6 +267,7 @@ public: m_view->setModel(&m_model); m_view->setActivationMode(SingleClickActivation); m_view->setItemDelegate(&m_delegate); + m_view->setUniformRowHeights(true); theWidget->setLayout(new QVBoxLayout); theWidget->layout()->addWidget(m_view); From 269fc1fd6bd2ff373efab8ce75cb2576943f7bff Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 25 Jun 2024 15:25:56 +0200 Subject: [PATCH 68/73] LanguageClient: optimize call and type hierarchy Trigger a fetch from the can fetch function in order to get whether the item has children. This information is used to show the expansion marker for items that have children, and not for items that have not been fetched yet. Change-Id: Ifc20588aa805368369e72fc8501244f64bbbc91d Reviewed-by: hjk Reviewed-by: Christian Kandeler --- src/plugins/languageclient/callandtypehierarchy.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/languageclient/callandtypehierarchy.cpp b/src/plugins/languageclient/callandtypehierarchy.cpp index 3d2e9eff144..8cfc3578c37 100644 --- a/src/plugins/languageclient/callandtypehierarchy.cpp +++ b/src/plugins/languageclient/callandtypehierarchy.cpp @@ -76,7 +76,12 @@ protected: } private: - bool canFetchMore() const override { return m_client && !m_fetchedChildren; } + bool canFetchMore() const override + { + if (m_client && !m_fetchedChildren) + const_cast(this)->fetchMore(); + return false; + } void fetchMore() override { @@ -96,8 +101,6 @@ private: appendChild(new HierarchyItem(getSourceItem(item), m_client)); } } - if (!hasChildren()) - update(); }); m_client->sendMessage(request); } From e20f33cd4cd7467b6f108a4167de6f31480dce1d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 26 Jun 2024 14:15:33 +0200 Subject: [PATCH 69/73] Fix various translatable strings Change-Id: I08e81f188a68c8e820f20a35249d1b318178a7b9 Reviewed-by: Leena Miettinen --- src/plugins/android/androidmanager.cpp | 4 +-- src/plugins/android/androidsdkmanager.cpp | 2 +- .../autotest/projectsettingswidget.cpp | 2 +- src/plugins/autotest/testsettings.cpp | 2 +- src/plugins/axivion/axivionoutputpane.cpp | 6 ++-- src/plugins/axivion/axivionsettings.cpp | 28 ++++++++++--------- .../clangformatglobalconfigwidget.cpp | 2 +- .../cmakeprojectmanager/presetsparser.cpp | 7 +++-- src/plugins/cppeditor/cppfilesettingspage.cpp | 2 +- src/plugins/modeleditor/elementtasks.cpp | 6 ++-- .../modeleditor/extpropertiesmview.cpp | 6 ++-- .../buildpropertiessettings.cpp | 2 +- .../projectexplorersettings.cpp | 3 +- src/plugins/remotelinux/linuxdevice.cpp | 12 +++++--- 14 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 9cca27242d0..dac4eb3c8e4 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -55,12 +55,12 @@ static std::optional documentElement(const FilePath &fileName) { QFile file(fileName.toString()); if (!file.open(QIODevice::ReadOnly)) { - MessageManager::writeDisrupting(Tr::tr("Cannot open: %1").arg(fileName.toUserOutput())); + MessageManager::writeDisrupting(Tr::tr("Cannot open \"%1\".").arg(fileName.toUserOutput())); return {}; } QDomDocument doc; if (!doc.setContent(file.readAll())) { - MessageManager::writeDisrupting(Tr::tr("Cannot parse: %1").arg(fileName.toUserOutput())); + MessageManager::writeDisrupting(Tr::tr("Cannot parse \"%1\".").arg(fileName.toUserOutput())); return {}; } return doc.documentElement(); diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 76b4b5db72a..47b1f4b1155 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -313,7 +313,7 @@ static GroupItem updateRecipe(const Storage &dialogStorage) const QStringList args = {"--update", sdkRootArg()}; QuestionProgressDialog *dialog = dialogStorage->m_dialog.get(); setupSdkProcess(args, &process, dialog, 0, 1); - dialog->appendMessage(Tr::tr("Updating installed packages....") + '\n', NormalMessageFormat); + dialog->appendMessage(Tr::tr("Updating installed packages...") + '\n', NormalMessageFormat); dialog->setProgress(0); }; const auto onDone = [dialogStorage](DoneWith result) { diff --git a/src/plugins/autotest/projectsettingswidget.cpp b/src/plugins/autotest/projectsettingswidget.cpp index b6347f52a70..01cbb33fd1d 100644 --- a/src/plugins/autotest/projectsettingswidget.cpp +++ b/src/plugins/autotest/projectsettingswidget.cpp @@ -69,7 +69,7 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project) m_pathFilters = new QTreeWidget; m_pathFilters->setHeaderHidden(true); m_pathFilters->setRootIsDecorated(false); - QLabel *filterLabel = new QLabel(Tr::tr("Wildcard expressions for filtering"), this); + QLabel *filterLabel = new QLabel(Tr::tr("Wildcard expressions for filtering:"), this); QPushButton *addFilter = new QPushButton(Tr::tr("Add"), this); QPushButton *removeFilter = new QPushButton(Tr::tr("Remove"), this); removeFilter->setEnabled(false); diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp index 42407ab9034..523a92499aa 100644 --- a/src/plugins/autotest/testsettings.cpp +++ b/src/plugins/autotest/testsettings.cpp @@ -35,7 +35,7 @@ TestSettings::TestSettings() useTimeout.setSettingsKey("UseTimeout"); useTimeout.setDefaultValue(false); - useTimeout.setLabelText(Tr::tr("Timeout")); + useTimeout.setLabelText(Tr::tr("Timeout:")); useTimeout.setToolTip(Tr::tr("Use a timeout while executing test cases.")); timeout.setSettingsKey("Timeout"); diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 644db7f5433..fa15362e32d 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -879,17 +879,17 @@ public: dashboardUrl.setQuery(search.toUrlQuery(QueryMode::FilterQuery)); QMenu *menu = new QMenu; - auto action = new QAction(Tr::tr("Open issue in Dashboard"), menu); + auto action = new QAction(Tr::tr("Open Issue in Dashboard"), menu); menu->addAction(action); QObject::connect(action, &QAction::triggered, menu, [issueBaseUrl] { QDesktopServices::openUrl(issueBaseUrl); }); - action = new QAction(Tr::tr("Open table in Dashboard"), menu); + action = new QAction(Tr::tr("Open Table in Dashboard"), menu); QObject::connect(action, &QAction::triggered, menu, [dashboardUrl] { QDesktopServices::openUrl(dashboardUrl); }); menu->addAction(action); - action = new QAction(Tr::tr("Copy Dashboard link to clipboard"), menu); + action = new QAction(Tr::tr("Copy Dashboard Link to Clipboard"), menu); QObject::connect(action, &QAction::triggered, menu, [dashboardUrl] { if (auto clipboard = QGuiApplication::clipboard()) clipboard->setText(dashboardUrl.toString()); diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index aaed7b93da1..9100b7c4e99 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -308,16 +308,17 @@ AxivionSettingsWidget::AxivionSettingsWidget() auto addButton = new QPushButton(Tr::tr("Add..."), this); m_edit = new QPushButton(Tr::tr("Edit..."), this); m_remove = new QPushButton(Tr::tr("Remove"), this); - Column { - Row { - Form { - Tr::tr("Default dashboard server"), m_dashboardServers, br - }, st, - Column { addButton, m_edit, st, m_remove }, + Column{ + Row{ + Form{Tr::tr("Default dashboard server:"), m_dashboardServers, br}, + st, + Column{addButton, m_edit, st, m_remove}, }, - Space(10), br, - Row { settings().highlightMarks }, st - }.attachTo(this); + Space(10), + br, + Row{settings().highlightMarks}, + st} + .attachTo(this); connect(addButton, &QPushButton::clicked, this, [this] { // add an empty item unconditionally @@ -357,10 +358,11 @@ void AxivionSettingsWidget::updateEnabledStates() void AxivionSettingsWidget::removeCurrentServerConfig() { const QString config = m_dashboardServers->currentData().value().displayString(); - if (QMessageBox::question(ICore::dialogParent(), Tr::tr("Remove Server Configuration"), - Tr::tr("Do you really want to remove the server configuration " - "\"%1\"?").arg(config)) - != QMessageBox::Yes) { + if (QMessageBox::question( + ICore::dialogParent(), + Tr::tr("Remove Server Configuration"), + Tr::tr("Remove the server configuration \"%1\"?").arg(config)) + != QMessageBox::Yes) { return; } m_dashboardServers->removeItem(m_dashboardServers->currentIndex()); diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index fdcceea62b4..052ed865151 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -110,7 +110,7 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(ICodeStylePreferenc // clang-format off Group globalSettingsGroupBox { bindTo(&globalSettingsGroupBoxWidget), - title(Tr::tr("ClangFormat Settings:")), + title(Tr::tr("ClangFormat Settings")), Column { m_useGlobalSettings, Form { diff --git a/src/plugins/cmakeprojectmanager/presetsparser.cpp b/src/plugins/cmakeprojectmanager/presetsparser.cpp index 35567b64a64..429c8958694 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.cpp +++ b/src/plugins/cmakeprojectmanager/presetsparser.cpp @@ -518,7 +518,7 @@ bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage m_presetsData.configurePresets, jsonFile.parentDir())) { errorMessage = ::CMakeProjectManager::Tr::tr( - "Invalid \"configurePresets\" section in %1 file") + "Invalid \"configurePresets\" section in file \"%1\".") .arg(jsonFile.fileName()); return false; } @@ -527,14 +527,15 @@ bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage if (!parseBuildPresets(root.value("buildPresets"), m_presetsData.buildPresets, jsonFile.parentDir())) { - errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"buildPresets\" section in %1 file.") + errorMessage = ::CMakeProjectManager::Tr::tr( + "Invalid \"buildPresets\" section in file \"%1\".") .arg(jsonFile.fileName()); return false; } // optional if (!parseVendor(root.value("vendor"), m_presetsData.vendor)) { - errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"vendor\" section in %1 file.") + errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"vendor\" section in file \"%1\".") .arg(jsonFile.fileName()); } diff --git a/src/plugins/cppeditor/cppfilesettingspage.cpp b/src/plugins/cppeditor/cppfilesettingspage.cpp index 70f17e9afe8..b9c64965a68 100644 --- a/src/plugins/cppeditor/cppfilesettingspage.cpp +++ b/src/plugins/cppeditor/cppfilesettingspage.cpp @@ -47,7 +47,7 @@ class HeaderGuardExpander : public MacroExpander public: HeaderGuardExpander(const FilePath &filePath) : m_filePath(filePath) { - setDisplayName(Tr::tr("Header file variables")); + setDisplayName(Tr::tr("Header File Variables")); registerFileVariables("Header", Tr::tr("Header file"), [this] { return m_filePath; }); diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp index 7bbdd7b3e0b..62e5b9bad72 100644 --- a/src/plugins/modeleditor/elementtasks.cpp +++ b/src/plugins/modeleditor/elementtasks.cpp @@ -447,8 +447,10 @@ void ElementTasks::openLinkedFile(const qmt::MElement *element) (void) Core::EditorManager::openEditor(filepath); } } else { - QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Opening File"), - Tr::tr("File %1 does not exist.").arg(filepath.toUserOutput())); + QMessageBox::critical( + Core::ICore::dialogParent(), + Tr::tr("Opening File"), + Tr::tr("File \"%1\" does not exist.").arg(filepath.toUserOutput())); } } } diff --git a/src/plugins/modeleditor/extpropertiesmview.cpp b/src/plugins/modeleditor/extpropertiesmview.cpp index b105554e6fc..27fcca34f34 100644 --- a/src/plugins/modeleditor/extpropertiesmview.cpp +++ b/src/plugins/modeleditor/extpropertiesmview.cpp @@ -257,8 +257,10 @@ void ExtPropertiesMView::onImagePathChanged(const QString &path) assignModelElement(m_diagramElements, SelectionSingle, image, &qmt::DObject::image, &qmt::DObject::setImage); } else { - QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Selecting Image"), - Tr::tr("Unable to read image file %1").arg(path)); + QMessageBox::critical( + Core::ICore::dialogParent(), + Tr::tr("Selecting Image"), + Tr::tr("Unable to read image file \"%1\".").arg(path)); } } } diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp index ebfe8782151..d5eb9bfc3aa 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.cpp +++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp @@ -57,7 +57,7 @@ BuildPropertiesSettings::BuildPropertiesSettings() buildDirectoryTemplate.setToolTip( Tr::tr("Template used to construct the default build directory.

" "The default value can be set using the environment variable " - "%1") + "%1.") .arg(Constants::QTC_DEFAULT_BUILD_DIRECTORY_TEMPLATE)); buildDirectoryTemplate.setUseResetButton(); diff --git a/src/plugins/projectexplorer/projectexplorersettings.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp index 3e36b84ab75..a45872eeff3 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.cpp +++ b/src/plugins/projectexplorer/projectexplorersettings.cpp @@ -310,10 +310,11 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget() { m_reaperTimeoutSpinBox = new QSpinBox; m_reaperTimeoutSpinBox->setMinimum(1); + //: Suffix for "seconds" m_reaperTimeoutSpinBox->setSuffix(Tr::tr("s")); m_reaperTimeoutSpinBox->setToolTip( Tr::tr("The amount of seconds to wait between a \"soft kill\" and a \"hard kill\" of a " - "running application")); + "running application.")); m_currentDirectoryRadioButton = new QRadioButton(Tr::tr("Current directory")); m_directoryRadioButton = new QRadioButton(Tr::tr("Directory")); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index d51df10bef4..3fd4f0db738 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -711,8 +711,11 @@ void SshProcessInterfacePrivate::start() auto linuxDevice = std::dynamic_pointer_cast(m_device); QTC_ASSERT(linuxDevice, handleDone(); return); if (linuxDevice->isDisconnected()) { - emit q->done({-1, QProcess::CrashExit, QProcess::FailedToStart, - Tr::tr("Device \"%1\" is disconnected").arg(linuxDevice->displayName())}); + emit q->done( + {-1, + QProcess::CrashExit, + QProcess::FailedToStart, + Tr::tr("Device \"%1\" is disconnected.").arg(linuxDevice->displayName())}); return; } linuxDevice->connectionAccess() @@ -1646,7 +1649,7 @@ private: const expected_str result = async.result(); if (result) emit progress( - Tr::tr("Created directory: %1\n").arg(iteratorParentDirs->toUserOutput())); + Tr::tr("Created directory: \"%1\".\n").arg(iteratorParentDirs->toUserOutput())); else emit progress(result.error()); }; @@ -1665,7 +1668,8 @@ private: ++counter; if (result) { - emit progress(Tr::tr("Copied %1/%2: %3 -> %4\n") + //: %1/%2 = progress in the form 4/15, %3 and %4 = source and target file paths + emit progress(Tr::tr("Copied %1/%2: \"%3\" -> \"%4\".\n") .arg(counter) .arg(m_setup.m_files.size()) .arg(iterator->m_source.toUserOutput()) From b94c51995d52b11a88c6f33bad62ec4d65793f03 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 26 Jun 2024 14:03:49 +0200 Subject: [PATCH 70/73] Python: Fix translatable string Word arithmetic does not work across languages. Provide explicit strings for the combinations. Change-Id: I95399f5d528405971d630a464e67a89766351162 Reviewed-by: David Schulz Reviewed-by: Leena Miettinen --- src/plugins/python/pipsupport.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 673dbdccf33..d7a2dbd645b 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -66,21 +66,16 @@ void PipInstallTask::run() emit finished(false); return; } - QString operation = Tr::tr("Install"); - QString operant; QStringList arguments = {"-m", "pip", "install"}; if (!m_requirementsFile.isEmpty()) { - operant = Tr::tr("Requirements"); arguments << "-r" << m_requirementsFile.toString(); } else { - for (const PipPackage &package : m_packages) { QString pipPackage = package.packageName; if (!package.version.isEmpty()) pipPackage += "==" + package.version; arguments << pipPackage; } - operant = m_packages.count() == 1 ? m_packages.first().displayName : Tr::tr("Packages"); } if (!m_targetPath.isEmpty()) { @@ -90,17 +85,27 @@ void PipInstallTask::run() arguments << "--user"; // add --user to global pythons, but skip it for venv pythons } - if (m_upgrade) { + if (m_upgrade) arguments << "--upgrade"; - operation = Tr::tr("Update"); + + QString operation; + if (!m_requirementsFile.isEmpty()) { + operation = m_upgrade ? Tr::tr("Update Requirements") : Tr::tr("Install Requirements"); + } else if (m_packages.count() == 1) { + //: %1 = package name + operation = m_upgrade ? Tr::tr("Update %1") + //: %1 = package name + : Tr::tr("Install %1"); + operation = operation.arg(m_packages.first().displayName); + } else { + operation = m_upgrade ? Tr::tr("Update Packages") : Tr::tr("Install Packages"); } m_process.setCommand({m_python, arguments}); m_process.setTerminalMode(m_silent ? TerminalMode::Off : TerminalMode::Run); m_process.start(); - const QString taskTitle = Tr::tr("%1 %2").arg(operation).arg(operant); - Core::ProgressManager::addTask(m_future.future(), taskTitle, pipInstallTaskId); + Core::ProgressManager::addTask(m_future.future(), operation, pipInstallTaskId); Core::MessageManager::writeSilently( Tr::tr("Running \"%1\" to install %2.") .arg(m_process.commandLine().toUserOutput(), packagesDisplayName())); From 8405b384a3f491750b50aeb0f90a286fa61069a2 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 26 Jun 2024 16:59:37 +0200 Subject: [PATCH 71/73] ExtensionManager: Introduce own SortFilterProxyModel We want to sort by type and then alphabetically. That requires a custom lessThan() implementation, thus a custom QSortFilterProxyModel. Will come handy for further filtering/sorting requirements in the future. Change-Id: Iaacd955015d56026e41d404dcf4781a1715dc55a Reviewed-by: hjk --- .../extensionmanager/extensionsbrowser.cpp | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 13816ff5dd2..d88e7f41d3e 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -247,6 +247,32 @@ public: } }; +class SortFilterProxyModel : public QSortFilterProxyModel +{ +public: + SortFilterProxyModel(QObject *parent = nullptr); + +protected: + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +}; + +SortFilterProxyModel::SortFilterProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ +} + +bool SortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + const ItemType leftType = left.data(RoleItemType).value(); + const ItemType rightType = right.data(RoleItemType).value(); + if (leftType != rightType) + return leftType < rightType; + + const QString leftName = left.data(RoleName).toString(); + const QString rightName = right.data(RoleName).toString(); + return leftName < rightName; +} + class ExtensionsBrowserPrivate { public: @@ -255,7 +281,7 @@ public: QLineEdit *searchBox; QListView *extensionsView; QItemSelectionModel *selectionModel = nullptr; - QSortFilterProxyModel *filterProxyModel; + SortFilterProxyModel *filterProxyModel; int columnsCount = 2; Tasking::TaskTreeRunner taskTreeRunner; SpinnerSolution::Spinner *m_spinner; @@ -277,7 +303,7 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) d->model = new ExtensionsModel(this); - d->filterProxyModel = new QSortFilterProxyModel(this); + d->filterProxyModel = new SortFilterProxyModel(this); d->filterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); d->filterProxyModel->setFilterRole(RoleSearchText); d->filterProxyModel->setSortRole(RoleItemType); From a48fcfecd4a858f340f347e56c7734f7584f2aa1 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 25 Jun 2024 11:45:16 +0200 Subject: [PATCH 72/73] ClangCodeModel: Prevent adding an already-present closing quote ... when doing completion for header includes. Fixes: QTCREATORBUG-31103 Change-Id: Ic2d4eb4abce4f6d0f7d08b0ff0f5e0f54669eb65 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdcompletion.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/clangcodemodel/clangdcompletion.cpp b/src/plugins/clangcodemodel/clangdcompletion.cpp index 44520d324de..b781c564887 100644 --- a/src/plugins/clangcodemodel/clangdcompletion.cpp +++ b/src/plugins/clangcodemodel/clangdcompletion.cpp @@ -359,8 +359,14 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, } // Avoid inserting characters that are already there + // For include file completions, also consider a possibly pre-existing + // closing quote or angle bracket. QTextCursor cursor = manipulator.textCursorAt(rangeStart); cursor.movePosition(QTextCursor::EndOfWord); + if (kind == CompletionItemKind::File && !textToBeInserted.isEmpty() + && textToBeInserted.right(1) == manipulator.textAt(cursor.position(), 1)) { + cursor.setPosition(cursor.position() + 1); + } const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos); if (currentPos < cursor.position() && textToBeInserted != textAfterCursor From be84c74cb9f6176f65de844aa1119bb9dcb2ba38 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 26 Jun 2024 08:38:51 +0200 Subject: [PATCH 73/73] ExtensionManager: Hide ExtensionManagerWidget class in .cpp And de-pimpl. Smaller overall interface and less indirections. Change-Id: If6a5c0824581a6478ad6e88410d97e23cc517a53 Reviewed-by: Alessandro Portale --- .../extensionmanagerplugin.cpp | 2 +- .../extensionmanagerwidget.cpp | 241 +++++++++--------- .../extensionmanager/extensionmanagerwidget.h | 16 +- 3 files changed, 126 insertions(+), 133 deletions(-) diff --git a/src/plugins/extensionmanager/extensionmanagerplugin.cpp b/src/plugins/extensionmanager/extensionmanagerplugin.cpp index 979a75ad291..e51cb0cbdda 100644 --- a/src/plugins/extensionmanager/extensionmanagerplugin.cpp +++ b/src/plugins/extensionmanager/extensionmanagerplugin.cpp @@ -50,7 +50,7 @@ public: using namespace Layouting; auto widget = Column { new StyledBar, - new ExtensionManagerWidget, + createExtensionManagerWidget(), noMargin, spacing(0), }.emerge(); diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index a9761e8ebff..c2dc396cece 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -399,166 +399,166 @@ private: QSignalMapper *m_signalMapper; }; -class ExtensionManagerWidgetPrivate +class ExtensionManagerWidget final : public Core::ResizeSignallingWidget { public: - QString currentItemName; - ExtensionsBrowser *extensionBrowser; - CollapsingWidget *secondaryDescriptionWidget; - HeadingWidget *headingWidget; - QWidget *primaryContent; - QWidget *secondaryContent; - QLabel *description; - QLabel *linksTitle; - QLabel *links; - QLabel *imageTitle; - QLabel *image; - QBuffer imageDataBuffer; - QMovie imageMovie; - QLabel *tagsTitle; - TagList *tags; - QLabel *platformsTitle; - QLabel *platforms; - QLabel *dependenciesTitle; - QLabel *dependencies; - QLabel *packExtensionsTitle; - QLabel *packExtensions; - PluginStatusWidget *pluginStatus; - PluginsData currentItemPlugins; - Tasking::TaskTreeRunner dlTaskTreeRunner; - Tasking::TaskTreeRunner imgTaskTreeRunner; + ExtensionManagerWidget(); + +private: + void updateView(const QModelIndex ¤t); + void fetchAndInstallPlugin(const QUrl &url); + void fetchAndDisplayImage(const QUrl &url); + + QString m_currentItemName; + ExtensionsBrowser *m_extensionBrowser; + CollapsingWidget *m_secondaryDescriptionWidget; + HeadingWidget *m_headingWidget; + QWidget *m_primaryContent; + QWidget *m_secondaryContent; + QLabel *m_description; + QLabel *m_linksTitle; + QLabel *m_links; + QLabel *m_imageTitle; + QLabel *m_image; + QBuffer m_imageDataBuffer; + QMovie m_imageMovie; + QLabel *m_tagsTitle; + TagList *m_tags; + QLabel *m_platformsTitle; + QLabel *m_platforms; + QLabel *m_dependenciesTitle; + QLabel *m_dependencies; + QLabel *m_packExtensionsTitle; + QLabel *m_packExtensions; + PluginStatusWidget *m_pluginStatus; + PluginsData m_currentItemPlugins; + Tasking::TaskTreeRunner m_dlTaskTreeRunner; + Tasking::TaskTreeRunner m_imgTaskTreeRunner; }; -ExtensionManagerWidget::ExtensionManagerWidget(QWidget *parent) - : ResizeSignallingWidget(parent) - , d(new ExtensionManagerWidgetPrivate) +ExtensionManagerWidget::ExtensionManagerWidget() { - d->extensionBrowser = new ExtensionsBrowser; + m_extensionBrowser = new ExtensionsBrowser; auto descriptionColumns = new QWidget; - d->secondaryDescriptionWidget = new CollapsingWidget; + m_secondaryDescriptionWidget = new CollapsingWidget; - d->headingWidget = new HeadingWidget; - d->description = tfLabel(contentTF, false); - d->description->setWordWrap(true); - d->linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information")); - d->links = tfLabel(contentTF, false); - d->links->setOpenExternalLinks(true); - d->imageTitle = sectionTitle(h6CapitalTF, {}); - d->image = new QLabel; - d->imageMovie.setDevice(&d->imageDataBuffer); + m_headingWidget = new HeadingWidget; + m_description = tfLabel(contentTF, false); + m_description->setWordWrap(true); + m_linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information")); + m_links = tfLabel(contentTF, false); + m_links->setOpenExternalLinks(true); + m_imageTitle = sectionTitle(h6CapitalTF, {}); + m_image = new QLabel; + m_imageMovie.setDevice(&m_imageDataBuffer); using namespace Layouting; auto primary = new QWidget; const auto spL = spacing(SpacingTokens::VPaddingL); Column { - d->description, - Column { d->linksTitle, d->links, spL }, - Column { d->imageTitle, d->image, spL }, + m_description, + Column { m_linksTitle, m_links, spL }, + Column { m_imageTitle, m_image, spL }, st, noMargin, spacing(SpacingTokens::ExVPaddingGapXl), }.attachTo(primary); - d->primaryContent = toScrollableColumn(primary); + m_primaryContent = toScrollableColumn(primary); - d->tagsTitle = sectionTitle(h6TF, Tr::tr("Tags")); - d->tags = new TagList; - d->platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms")); - d->platforms = tfLabel(contentTF, false); - d->dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies")); - d->dependencies = tfLabel(contentTF, false); - d->packExtensionsTitle = sectionTitle(h6TF, Tr::tr("Extensions in pack")); - d->packExtensions = tfLabel(contentTF, false); - d->pluginStatus = new PluginStatusWidget; + m_tagsTitle = sectionTitle(h6TF, Tr::tr("Tags")); + m_tags = new TagList; + m_platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms")); + m_platforms = tfLabel(contentTF, false); + m_dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies")); + m_dependencies = tfLabel(contentTF, false); + m_packExtensionsTitle = sectionTitle(h6TF, Tr::tr("Extensions in pack")); + m_packExtensions = tfLabel(contentTF, false); + m_pluginStatus = new PluginStatusWidget; auto secondary = new QWidget; const auto spXxs = spacing(SpacingTokens::VPaddingXxs); Column { sectionTitle(h6CapitalTF, Tr::tr("Extension details")), Column { - Column { d->tagsTitle, d->tags, spXxs }, - Column { d->platformsTitle, d->platforms, spXxs }, - Column { d->dependenciesTitle, d->dependencies, spXxs }, - Column { d->packExtensionsTitle, d->packExtensions, spXxs }, + Column { m_tagsTitle, m_tags, spXxs }, + Column { m_platformsTitle, m_platforms, spXxs }, + Column { m_dependenciesTitle, m_dependencies, spXxs }, + Column { m_packExtensionsTitle, m_packExtensions, spXxs }, spacing(SpacingTokens::VPaddingL), }, st, noMargin, spacing(SpacingTokens::ExVPaddingGapXl), }.attachTo(secondary); - d->secondaryContent = toScrollableColumn(secondary); + m_secondaryContent = toScrollableColumn(secondary); Row { WelcomePageHelpers::createRule(Qt::Vertical), Column { - d->secondaryContent, - d->pluginStatus, + m_secondaryContent, + m_pluginStatus, }, noMargin, spacing(0), - }.attachTo(d->secondaryDescriptionWidget); + }.attachTo(m_secondaryDescriptionWidget); Row { WelcomePageHelpers::createRule(Qt::Vertical), Row { Column { Column { - d->headingWidget, + m_headingWidget, customMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl), }, - d->primaryContent, + m_primaryContent, }, }, - d->secondaryDescriptionWidget, + m_secondaryDescriptionWidget, noMargin, spacing(0), }.attachTo(descriptionColumns); Row { Space(SpacingTokens::ExVPaddingGapXl), - d->extensionBrowser, + m_extensionBrowser, descriptionColumns, noMargin, spacing(0), }.attachTo(this); WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default); - connect(d->extensionBrowser, &ExtensionsBrowser::itemSelected, + connect(m_extensionBrowser, &ExtensionsBrowser::itemSelected, this, &ExtensionManagerWidget::updateView); connect(this, &ResizeSignallingWidget::resized, this, [this](const QSize &size) { const int intendedBrowserColumnWidth = size.width() - 580; - d->extensionBrowser->adjustToWidth(intendedBrowserColumnWidth); + m_extensionBrowser->adjustToWidth(intendedBrowserColumnWidth); const bool secondaryDescriptionVisible = size.width() > 970; const int secondaryDescriptionWidth = secondaryDescriptionVisible ? 264 : 0; - d->secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth); + m_secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth); }); - connect(d->headingWidget, &HeadingWidget::pluginInstallationRequested, this, [this](){ - fetchAndInstallPlugin(QUrl::fromUserInput(d->currentItemPlugins.constFirst().second)); + connect(m_headingWidget, &HeadingWidget::pluginInstallationRequested, this, [this](){ + fetchAndInstallPlugin(QUrl::fromUserInput(m_currentItemPlugins.constFirst().second)); }); - connect(d->tags, &TagList::tagSelected, d->extensionBrowser, &ExtensionsBrowser::setFilter); - connect(d->headingWidget, &HeadingWidget::vendorClicked, - d->extensionBrowser, &ExtensionsBrowser::setFilter); + connect(m_tags, &TagList::tagSelected, m_extensionBrowser, &ExtensionsBrowser::setFilter); + connect(m_headingWidget, &HeadingWidget::vendorClicked, + m_extensionBrowser, &ExtensionsBrowser::setFilter); updateView({}); } -ExtensionManagerWidget::~ExtensionManagerWidget() -{ - delete d; -} - void ExtensionManagerWidget::updateView(const QModelIndex ¤t) { - d->headingWidget->update(current); + m_headingWidget->update(current); const bool showContent = current.isValid(); - d->primaryContent->setVisible(showContent); - d->secondaryContent->setVisible(showContent); - d->headingWidget->setVisible(showContent); - d->pluginStatus->setVisible(showContent); + m_primaryContent->setVisible(showContent); + m_secondaryContent->setVisible(showContent); + m_headingWidget->setVisible(showContent); + m_pluginStatus->setVisible(showContent); if (!showContent) return; - d->currentItemName = current.data().toString(); + m_currentItemName = current.data().toString(); const bool isPack = current.data(RoleItemType) == ItemTypePack; - d->pluginStatus->setPluginName(isPack ? QString() : d->currentItemName); - d->currentItemPlugins = current.data(RolePlugins).value(); + m_pluginStatus->setPluginName(isPack ? QString() : m_currentItemName); + m_currentItemPlugins = current.data(RolePlugins).value(); auto toContentParagraph = [](const QString &text) { const QString pHtml = QString::fromLatin1("

") .arg(creatorColor(Theme::Token_Text_Default).name())); descriptionHtml.append(""); - d->description->setText(descriptionHtml); + m_description->setText(descriptionHtml); } - d->description->setVisible(hasDescription); + m_description->setVisible(hasDescription); const LinksData linksData = current.data(RoleDescriptionLinks).value(); const bool hasLinks = !linksData.isEmpty(); @@ -608,55 +608,55 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t) .arg(anchor); }); linksHtml = links.join("
"); - d->links->setText(toContentParagraph(linksHtml)); + m_links->setText(toContentParagraph(linksHtml)); } - d->linksTitle->setVisible(hasLinks); - d->links->setVisible(hasLinks); + m_linksTitle->setVisible(hasLinks); + m_links->setVisible(hasLinks); - d->imgTaskTreeRunner.reset(); - d->imageMovie.stop(); - d->imageDataBuffer.close(); - d->image->clear(); + m_imgTaskTreeRunner.reset(); + m_imageMovie.stop(); + m_imageDataBuffer.close(); + m_image->clear(); const ImagesData imagesData = current.data(RoleDescriptionImages).value(); const bool hasImages = !imagesData.isEmpty(); if (hasImages) { const ImagesData::Type &image = imagesData.constFirst(); // Only show one image - d->imageTitle->setText(image.first); + m_imageTitle->setText(image.first); fetchAndDisplayImage(image.second); } - d->imageTitle->setVisible(hasImages); - d->image->setVisible(hasImages); + m_imageTitle->setVisible(hasImages); + m_image->setVisible(hasImages); } { const QStringList tags = current.data(RoleTags).toStringList(); - d->tags->setTags(tags); + m_tags->setTags(tags); const bool hasTags = !tags.isEmpty(); - d->tagsTitle->setVisible(hasTags); - d->tags->setVisible(hasTags); + m_tagsTitle->setVisible(hasTags); + m_tags->setVisible(hasTags); const QStringList platforms = current.data(RolePlatforms).toStringList(); const bool hasPlatforms = !platforms.isEmpty(); if (hasPlatforms) - d->platforms->setText(toContentParagraph(platforms.join("
"))); - d->platformsTitle->setVisible(hasPlatforms); - d->platforms->setVisible(hasPlatforms); + m_platforms->setText(toContentParagraph(platforms.join("
"))); + m_platformsTitle->setVisible(hasPlatforms); + m_platforms->setVisible(hasPlatforms); const QStringList dependencies = current.data(RoleDependencies).toStringList(); const bool hasDependencies = !dependencies.isEmpty(); if (hasDependencies) - d->dependencies->setText(toContentParagraph(dependencies.join("
"))); - d->dependenciesTitle->setVisible(hasDependencies); - d->dependencies->setVisible(hasDependencies); + m_dependencies->setText(toContentParagraph(dependencies.join("
"))); + m_dependenciesTitle->setVisible(hasDependencies); + m_dependencies->setVisible(hasDependencies); const PluginsData plugins = current.data(RolePlugins).value(); const bool hasExtensions = isPack && !plugins.isEmpty(); if (hasExtensions) { const QStringList extensions = transform(plugins, &QPair::first); - d->packExtensions->setText(toContentParagraph(extensions.join("
"))); + m_packExtensions->setText(toContentParagraph(extensions.join("
"))); } - d->packExtensionsTitle->setVisible(hasExtensions); - d->packExtensions->setVisible(hasExtensions); + m_packExtensionsTitle->setVisible(hasExtensions); + m_packExtensions->setVisible(hasExtensions); } } @@ -717,7 +717,7 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url) onGroupDone(onPluginInstallation), }; - d->dlTaskTreeRunner.start(group); + m_dlTaskTreeRunner.start(group); } void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url) @@ -744,17 +744,17 @@ void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url) const auto onShowImage = [storage, this]() { if (storage->imageData.isEmpty()) return; - d->imageDataBuffer.setData(storage->imageData); - if (!d->imageDataBuffer.open(QIODevice::ReadOnly)) + m_imageDataBuffer.setData(storage->imageData); + if (!m_imageDataBuffer.open(QIODevice::ReadOnly)) return; - QImageReader reader(&d->imageDataBuffer); + QImageReader reader(&m_imageDataBuffer); const bool animated = reader.supportsAnimation(); if (animated) { - d->image->setMovie(&d->imageMovie); - d->imageMovie.start(); + m_image->setMovie(&m_imageMovie); + m_imageMovie.start(); } else { const QPixmap pixmap = QPixmap::fromImage(reader.read()); - d->image->setPixmap(pixmap); + m_image->setPixmap(pixmap); } }; @@ -764,7 +764,12 @@ void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url) onGroupDone(onShowImage), }; - d->imgTaskTreeRunner.start(group); + m_imgTaskTreeRunner.start(group); +} + +QWidget *createExtensionManagerWidget() +{ + return new ExtensionManagerWidget; } } // ExtensionManager::Internal diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.h b/src/plugins/extensionmanager/extensionmanagerwidget.h index dbc02daeca8..721f5adc956 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.h +++ b/src/plugins/extensionmanager/extensionmanagerwidget.h @@ -1,22 +1,10 @@ // Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include +#include namespace ExtensionManager::Internal { -class ExtensionManagerWidget final : public Core::ResizeSignallingWidget -{ -public: - explicit ExtensionManagerWidget(QWidget *parent = nullptr); - ~ExtensionManagerWidget(); - -private: - void updateView(const QModelIndex ¤t); - void fetchAndInstallPlugin(const QUrl &url); - void fetchAndDisplayImage(const QUrl &url); - - class ExtensionManagerWidgetPrivate *d = nullptr; -}; +QWidget *createExtensionManagerWidget(); } // ExtensionManager::Internal