From 898190bd21824b3a4c796cdb4071903e71a9c9d2 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 31 Jan 2024 17:16:38 +0100 Subject: [PATCH 01/82] Doc: Add brackets and quotes that are automatically inserted This works for single quotes, angle brackets, and square brackets, too. Task-number: QTCREATORBUG-30209 Change-Id: Icb07d87fe95ee8779ffc29f4623a7dfbdfca9e4d Reviewed-by: Eike Ziller --- .../src/editors/creator-code-completion.qdoc | 3 +-- .../src/howto/creator-only/creator-how-tos.qdoc | 12 +++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/qtcreator/src/editors/creator-code-completion.qdoc b/doc/qtcreator/src/editors/creator-code-completion.qdoc index 522565eecbd..4281f77b672 100644 --- a/doc/qtcreator/src/editors/creator-code-completion.qdoc +++ b/doc/qtcreator/src/editors/creator-code-completion.qdoc @@ -183,8 +183,7 @@ skipped when you type, and removed when you press \key Backspace. \if defined(qtcreator) - \sa {Complete CMake code}, - {Enclose selected code in curly braces, parentheses, or double quotes}, {Nim} + \sa {Complete CMake code}, {Enclose code in brackets or quotes}, {Nim} \endif \sa {Complete code}, {Snippets} diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc index 8de74cf8420..6c3fc7fd84e 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -288,16 +288,18 @@ \ingroup creator-how-to-edit - \title Enclose selected code in curly braces, parentheses, or double quotes + \title Enclose code in brackets or quotes - When you have selected code and enter one of the following opening - characters, the matching closing character is added automatically - at the end of the selection: + Select code and enter one of the following opening characters to add + the matching closing character at the end of the selection: \list - \li { \li ( + \li { + \li [ + \li < \li " + \li ' \endlist To specify whether to automatically insert matching characters, From 5ae401b92335a1f81e11e6e1246298602e2b383b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 6 Feb 2024 11:27:54 +0100 Subject: [PATCH 02/82] Aspect: Don't try to change value more than once When our window loses focus the editingFinished signal is triggered. This can happen multiple times (QTBUG-121983) if the result of the edit is a modal dialog and the user clicks outside our application. This would call editingFinished again, resulting in multiple message boxes being opened. (Easiest to reproduce is changing the build directory of a project which displays a message box confirming the change) This patch checks, via a recursion Guard, that the slot is not already in the process of being called. Change-Id: I5e61e1b57680f0b1f2483a81682e791bfb5c0867 Reviewed-by: hjk --- src/libs/utils/aspects.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 1e8ccbac71f..2098c68d1c0 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -7,6 +7,7 @@ #include "checkablemessagebox.h" #include "environment.h" #include "fancylineedit.h" +#include "guard.h" #include "iconbutton.h" #include "layoutbuilder.h" #include "passworddialog.h" @@ -1181,13 +1182,12 @@ void StringAspect::addToLayout(LayoutItem &parent) connect(lineEditDisplay, &FancyLineEdit::validChanged, this, &StringAspect::validChanged); bufferToGui(); if (isAutoApply() && d->m_autoApplyOnEditingFinished) { - connect(lineEditDisplay, - &FancyLineEdit::editingFinished, - this, - [this, lineEditDisplay] { - d->undoable.set(undoStack(), lineEditDisplay->text()); - handleGuiChanged(); - }); + connect(lineEditDisplay, &FancyLineEdit::editingFinished, this, [this, lineEditDisplay] { + if (lineEditDisplay->text() != d->undoable.get()) { + d->undoable.set(undoStack(), lineEditDisplay->text()); + handleGuiChanged(); + } + }); } else { connect(lineEditDisplay, &QLineEdit::textChanged, this, [this, lineEditDisplay] { d->undoable.set(undoStack(), lineEditDisplay->text()); @@ -1386,6 +1386,8 @@ public: bool m_autoApplyOnEditingFinished = false; bool m_allowPathFromDevice = true; bool m_validatePlaceHolder = false; + + Guard m_editFinishedGuard; }; FilePathAspect::FilePathAspect(AspectContainer *container) @@ -1559,8 +1561,12 @@ void FilePathAspect::addToLayout(Layouting::LayoutItem &parent) connect(d->m_pathChooserDisplay, &PathChooser::validChanged, this, &FilePathAspect::validChanged); bufferToGui(); if (isAutoApply() && d->m_autoApplyOnEditingFinished) { - connect(d->m_pathChooserDisplay, &PathChooser::editingFinished, - this, &FilePathAspect::handleGuiChanged); + connect(d->m_pathChooserDisplay, &PathChooser::editingFinished, this, [this] { + if (d->m_editFinishedGuard.isLocked()) + return; + GuardLocker lk(d->m_editFinishedGuard); + handleGuiChanged(); + }); connect(d->m_pathChooserDisplay, &PathChooser::browsingFinished, this, &FilePathAspect::handleGuiChanged); } else { From 91e72756fb4d4d72a7f3f6af80d72da5a662cf64 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 5 Feb 2024 15:40:06 +0100 Subject: [PATCH 03/82] CppEditor: Support wrapping strings in QByteArrayLiteral() Fixes: QTCREATORBUG-12995 Change-Id: I9c0136b93fcfde0d2326bbd2bd6dbd5e75ae97a8 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfixes.cpp | 33 ++++++++++++++----------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 74862772e5a..3465066c7fc 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -141,7 +141,8 @@ enum DefPos { inline bool isQtStringLiteral(const QByteArray &id) { - return id == "QLatin1String" || id == "QLatin1Literal" || id == "QStringLiteral"; + return id == "QLatin1String" || id == "QLatin1Literal" || id == "QStringLiteral" + || id == "QByteArrayLiteral"; } inline bool isQtStringTranslation(const QByteArray &id) @@ -1110,21 +1111,20 @@ enum ActionFlags { EncloseInQLatin1CharAction = 0x1, EncloseInQLatin1StringAction = 0x2, EncloseInQStringLiteralAction = 0x4, - EncloseActionMask = EncloseInQLatin1CharAction - | EncloseInQLatin1StringAction | EncloseInQStringLiteralAction, - TranslateTrAction = 0x8, - TranslateQCoreApplicationAction = 0x10, - TranslateNoopAction = 0x20, - TranslationMask = TranslateTrAction - | TranslateQCoreApplicationAction | TranslateNoopAction, - RemoveObjectiveCAction = 0x40, - ConvertEscapeSequencesToCharAction = 0x100, - ConvertEscapeSequencesToStringAction = 0x200, - SingleQuoteAction = 0x400, - DoubleQuoteAction = 0x800 + EncloseInQByteArrayLiteralAction = 0x8, + EncloseActionMask = EncloseInQLatin1CharAction | EncloseInQLatin1StringAction + | EncloseInQStringLiteralAction | EncloseInQByteArrayLiteralAction, + TranslateTrAction = 0x10, + TranslateQCoreApplicationAction = 0x20, + TranslateNoopAction = 0x40, + TranslationMask = TranslateTrAction | TranslateQCoreApplicationAction | TranslateNoopAction, + RemoveObjectiveCAction = 0x100, + ConvertEscapeSequencesToCharAction = 0x200, + ConvertEscapeSequencesToStringAction = 0x400, + SingleQuoteAction = 0x800, + DoubleQuoteAction = 0x1000 }; - /* Convert single-character string literals into character literals with some * special cases "a" --> 'a', "'" --> '\'', "\n" --> '\n', "\"" --> '"'. */ static QByteArray stringToCharEscapeSequences(const QByteArray &content) @@ -1160,6 +1160,8 @@ static QString stringLiteralReplacement(unsigned actions) return QLatin1String("QLatin1String"); if (actions & EncloseInQStringLiteralAction) return QLatin1String("QStringLiteral"); + if (actions & EncloseInQByteArrayLiteralAction) + return QLatin1String("QByteArrayLiteral"); if (actions & TranslateTrAction) return QLatin1String("tr"); if (actions & TranslateQCoreApplicationAction) @@ -1350,6 +1352,9 @@ void WrapStringLiteral::doMatch(const CppQuickFixInterface &interface, QuickFixO actions = EncloseInQStringLiteralAction | objectiveCActions; result << new WrapStringLiteralOp(interface, priority, actions, msgQtStringLiteralDescription(stringLiteralReplacement(actions)), literal); + actions = EncloseInQByteArrayLiteralAction | objectiveCActions; + result << new WrapStringLiteralOp(interface, priority, actions, + msgQtStringLiteralDescription(stringLiteralReplacement(actions)), literal); } } From be33c807a64a217c5e20b87d752087ba239a72e9 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 2 Feb 2024 08:48:30 +0100 Subject: [PATCH 04/82] ProjectExplorer: Remove PEPlugin::finishedInitialization() signal It was only used once in the debugger, connect more directly there. Change-Id: I96923a308adfd343daeab6574e097f24bf0654d5 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggerplugin.cpp | 6 ++++-- src/plugins/projectexplorer/projectexplorer.cpp | 4 ---- src/plugins/projectexplorer/projectexplorer.h | 4 ---- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index e49e429f775..d2647f3d7b9 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -787,9 +788,10 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) ICore::addAdditionalContext(debuggerNotRunning); m_arguments = arguments; - if (!m_arguments.isEmpty()) - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::finishedInitialization, + if (!m_arguments.isEmpty()) { + connect(SessionManager::instance(), &SessionManager::startupSessionRestored, this, &DebuggerPluginPrivate::parseCommandLineArguments); + } // Menus m_menu = ActionManager::createMenu(M_DEBUG_ANALYZER); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e8aa205abdc..4a9d1ef8aae 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1897,10 +1897,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er &ProjectWelcomePage::requestProject, m_instance, &ProjectExplorerPlugin::openProjectWelcomePage); - connect(SessionManager::instance(), - &SessionManager::startupSessionRestored, - m_instance, - &ProjectExplorerPlugin::finishedInitialization); dd->updateWelcomePage(); MacroExpander *expander = Utils::globalMacroExpander(); diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index eb33841dd9a..ffb5d1bcd3c 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -24,8 +24,6 @@ namespace Core { class OutputWindow; } // Core -namespace Utils { class CommandLine; } - namespace ProjectExplorer { class CustomParserSettings; class FolderNode; @@ -170,8 +168,6 @@ public: static Core::OutputWindow *buildSystemOutput(); signals: - void finishedInitialization(); - // Is emitted when a project has been added/removed, // or the file list of a specific project has changed. void fileListChanged(); From 2d37a7421f99ffba59c42eb0339258959e5855b6 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 7 Feb 2024 10:33:46 +0100 Subject: [PATCH 05/82] VCS: Simplify VcsEditor setup Create the editor parameter structures in-place, and also include the other two parameters in the struct to simplify the signature of the c'tor. Change-Id: Iff7d5ddf3096f4a3ed18e53265ae74806823af32 Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarplugin.cpp | 48 ++++------ src/plugins/clearcase/clearcaseplugin.cpp | 60 ++++++------- src/plugins/cvs/cvsplugin.cpp | 75 +++++++--------- src/plugins/fossil/fossilplugin.cpp | 49 ++++------- src/plugins/git/gitplugin.cpp | 98 ++++++++------------- src/plugins/mercurial/mercurialplugin.cpp | 48 ++++------ src/plugins/perforce/perforceplugin.cpp | 58 +++++------- src/plugins/subversion/subversionplugin.cpp | 34 +++---- src/plugins/vcsbase/vcsbaseeditor.cpp | 23 +++-- src/plugins/vcsbase/vcsbaseeditor.h | 7 +- 10 files changed, 198 insertions(+), 302 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index a3b9c22d0c6..14046d738f0 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -89,27 +89,6 @@ const char COMMIT[] = "Bazaar.Action.Commit"; const char UNCOMMIT[] = "Bazaar.Action.UnCommit"; const char CREATE_REPOSITORY[] = "Bazaar.Action.CreateRepository"; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, // type - Constants::FILELOG_ID, // id - Constants::FILELOG_DISPLAY_NAME, // display name - Constants::LOGAPP // mime type -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, - Constants::ANNOTATEAPP -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, - Constants::DIFFAPP -}; - class RevertDialog : public QDialog { public: @@ -220,23 +199,32 @@ public: FilePath m_submitRepository; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, // type + Constants::FILELOG_ID, // id + Constants::FILELOG_DISPLAY_NAME, // display name + Constants::LOGAPP,// mime type [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + Constants::ANNOTATELOG_ID, + Constants::ANNOTATELOG_DISPLAY_NAME, + Constants::ANNOTATEAPP, [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + Constants::DIFFLOG_ID, + Constants::DIFFLOG_DISPLAY_NAME, + Constants::DIFFAPP, [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; class UnCommitDialog : public QDialog diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 56949f65621..f07c2348592 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -99,26 +99,9 @@ const char CMD_ID_UPDATE_VIEW[] = "ClearCase.UpdateView"; const char CMD_ID_CHECKIN_ALL[] = "ClearCase.CheckInAll"; const char CMD_ID_STATUS[] = "ClearCase.Status"; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - "ClearCase File Log Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase File Log Editor"), // display_name - "text/vnd.qtcreator.clearcase.log" -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - "ClearCase Annotation Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Annotation Editor"), // display_name - "text/vnd.qtcreator.clearcase.annotation" -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - "ClearCase Diff Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Diff Editor"), // display_name - "text/x-patch" -}; +const char LOG_EDITOR_ID[] = "ClearCase File Log Editor"; +const char ANNOTATION_EDITOR_ID[] = "ClearCase Annotation Editor"; +const char DIFF_EDITOR_ID[] = "ClearCase Diff Editor"; static QString debugCodec(const QTextCodec *c) { @@ -311,23 +294,32 @@ public: ClearCaseSettingsPage m_settingsPage; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + LOG_EDITOR_ID, + QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase File Log Editor"), // display_name + "text/vnd.qtcreator.clearcase.log", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + ANNOTATION_EDITOR_ID, + QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Annotation Editor"), // display_name + "text/vnd.qtcreator.clearcase.annotation", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + DIFF_EDITOR_ID, + QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Diff Editor"), // display_name + "text/x-patch", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; #ifdef WITH_TESTS bool m_fakeClearTool = false; @@ -1218,7 +1210,7 @@ void ClearCasePluginPrivate::ccDiffWithPred(const FilePath &workingDir, const QS diffname = QDir::toNativeSeparators(files.first()); } const QString title = QString::fromLatin1("cc diff %1").arg(diffname); - IEditor *editor = showOutputInEditor(title, result, diffEditorParameters.id, source, codec); + IEditor *editor = showOutputInEditor(title, result, DIFF_EDITOR_ID, source, codec); setWorkingDirectory(editor, workingDir); VcsBaseEditor::tagEditor(editor, tag); auto diffEditorWidget = qobject_cast(editor->widget()); @@ -1299,7 +1291,7 @@ void ClearCasePluginPrivate::diffActivity() } m_diffPrefix.clear(); const QString title = QString::fromLatin1("%1.patch").arg(activity); - IEditor *editor = showOutputInEditor(title, result, diffEditorParameters.id, + IEditor *editor = showOutputInEditor(title, result, DIFF_EDITOR_ID, FilePath::fromString(activity), nullptr); setWorkingDirectory(editor, topLevel); } @@ -1461,7 +1453,7 @@ void ClearCasePluginPrivate::history(const FilePath &workingDir, const QString title = QString::fromLatin1("cc history %1").arg(id); const FilePath source = VcsBaseEditor::getSource(workingDir, files); IEditor *newEditor = showOutputInEditor(title, result.cleanedStdOut(), - logEditorParameters.id, source, codec); + LOG_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); if (enableAnnotationContextMenu) VcsBaseEditor::getVcsBaseEditor(newEditor)->setFileLogAnnotateEnabled(true); @@ -1564,7 +1556,7 @@ void ClearCasePluginPrivate::vcsAnnotateHelper(const FilePath &workingDir, const EditorManager::activateEditor(editor); } else { const QString title = QString::fromLatin1("cc annotate %1").arg(id); - IEditor *newEditor = showOutputInEditor(title, res, annotateEditorParameters.id, source, codec); + IEditor *newEditor = showOutputInEditor(title, res, ANNOTATION_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); VcsBaseEditor::gotoLineOfEditor(newEditor, lineNumber); } @@ -1598,7 +1590,7 @@ void ClearCasePluginPrivate::vcsDescribe(const FilePath &source, const QString & EditorManager::activateEditor(editor); } else { const QString title = QString::fromLatin1("cc describe %1").arg(id); - IEditor *newEditor = showOutputInEditor(title, description, diffEditorParameters.id, source, codec); + IEditor *newEditor = showOutputInEditor(title, description, DIFF_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); } } diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 61851d9e4ee..387e74e18fe 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -90,33 +90,10 @@ const char CVS_SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.cvs.submit"; const char CVSCOMMITEDITOR_ID[] = "CVS Commit Editor"; const char CVSCOMMITEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Commit Editor"); -const VcsBaseEditorParameters commandLogEditorParameters { - OtherContent, - "CVS Command Log Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Command Log Editor"), // display name - "text/vnd.qtcreator.cvs.commandlog" -}; - -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - "CVS File Log Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS File Log Editor"), // display name - "text/vnd.qtcreator.cvs.log" -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - "CVS Annotation Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Annotation Editor"), // display name - "text/vnd.qtcreator.cvs.annotation" -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - "CVS Diff Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Diff Editor"), // display name - "text/x-patch" -}; +const char CVS_COMMANDLOG_EDITOR_ID[] = "CVS Command Log Editor"; +const char CVS_FILELOG_EDITOR_ID[] = "CVS File Log Editor"; +const char CVS_ANNOTATION_EDITOR_ID[] = "CVS Annotation Editor"; +const char CVS_DIFF_EDITOR_ID[] = "CVS Diff Editor"; static inline bool messageBoxQuestion(const QString &title, const QString &question) { @@ -312,29 +289,41 @@ private: QAction *m_menuAction = nullptr; public: - VcsEditorFactory commandLogEditorFactory { - &commandLogEditorParameters, + VcsEditorFactory commandLogEditorFactory {{ + OtherContent, + CVS_COMMANDLOG_EDITOR_ID, + QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Command Log Editor"), // display name + "text/vnd.qtcreator.cvs.commandlog", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + CVS_FILELOG_EDITOR_ID, + QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS File Log Editor"), // display name + "text/vnd.qtcreator.cvs.log", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + CVS_ANNOTATION_EDITOR_ID, + QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Annotation Editor"), // display name + "text/vnd.qtcreator.cvs.annotation", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + CVS_DIFF_EDITOR_ID, + QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Diff Editor"), // display name + "text/x-patch", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; Utils::Id CvsPluginPrivate::id() const @@ -965,7 +954,7 @@ void CvsPluginPrivate::filelog(const FilePath &workingDir, } else { const QString title = QString::fromLatin1("cvs log %1").arg(id); IEditor *newEditor = showOutputInEditor(title, response.cleanedStdOut(), - logEditorParameters.id, source, codec); + CVS_FILELOG_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); if (enableAnnotationContextMenu) VcsBaseEditor::getVcsBaseEditor(newEditor)->setFileLogAnnotateEnabled(true); @@ -1105,7 +1094,7 @@ void CvsPluginPrivate::annotate(const FilePath &workingDir, const QString &file, } else { const QString title = QString::fromLatin1("cvs annotate %1").arg(id); IEditor *newEditor = showOutputInEditor(title, response.cleanedStdOut(), - annotateEditorParameters.id, source, codec); + CVS_ANNOTATION_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); VcsBaseEditor::gotoLineOfEditor(newEditor, lineNumber); } @@ -1119,7 +1108,7 @@ bool CvsPluginPrivate::status(const FilePath &topLevel, const QString &file, con const auto response = runCvs(topLevel, args); const bool ok = response.result() == ProcessResult::FinishedWithSuccess; if (ok) { - showOutputInEditor(title, response.cleanedStdOut(), commandLogEditorParameters.id, + showOutputInEditor(title, response.cleanedStdOut(), CVS_COMMANDLOG_EDITOR_ID, topLevel, nullptr); } return ok; @@ -1284,7 +1273,7 @@ bool CvsPluginPrivate::describe(const FilePath &repositoryPath, setDiffBaseDirectory(editor, repositoryPath); } else { const QString title = QString::fromLatin1("cvs describe %1").arg(commitId); - IEditor *newEditor = showOutputInEditor(title, output, diffEditorParameters.id, + IEditor *newEditor = showOutputInEditor(title, output, CVS_DIFF_EDITOR_ID, FilePath::fromString(entries.front().file), codec); VcsBaseEditor::tagEditor(newEditor, commitId); setDiffBaseDirectory(newEditor, repositoryPath); diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 46924462580..40138f281ba 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -77,28 +77,6 @@ protected: } }; -const VcsBaseEditorParameters fileLogParameters { - LogOutput, - Constants::FILELOG_ID, - Constants::FILELOG_DISPLAY_NAME, - Constants::LOGAPP -}; - -const VcsBaseEditorParameters annotateLogParameters { - AnnotateOutput, - Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, - Constants::ANNOTATEAPP -}; - -const VcsBaseEditorParameters diffParameters { - DiffOutput, - Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, - Constants::DIFFAPP -}; - - class FossilPluginPrivate final : public VersionControlBase { public: @@ -171,23 +149,32 @@ public: bool pullOrPush(SyncMode mode); // Variables - VcsEditorFactory fileLogFactory { - &fileLogParameters, + VcsEditorFactory fileLogFactory {{ + LogOutput, + Constants::FILELOG_ID, + Constants::FILELOG_DISPLAY_NAME, + Constants::LOGAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateLogFactory { - &annotateLogParameters, + VcsEditorFactory annotateLogFactory {{ + AnnotateOutput, + Constants::ANNOTATELOG_ID, + Constants::ANNOTATELOG_DISPLAY_NAME, + Constants::ANNOTATEAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffFactory { - &diffParameters, + VcsEditorFactory diffFactory {{ + DiffOutput, + Constants::DIFFLOG_ID, + Constants::DIFFLOG_DISPLAY_NAME, + Constants::DIFFAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; CommandLocator *m_commandLocator = nullptr; ActionContainer *m_fossilContainer = nullptr; diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index d72b397f6e0..c3ac447c570 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -132,48 +132,6 @@ public: static const QVersionNumber minimumRequiredVersion{1, 9}; -const VcsBaseEditorParameters svnLogEditorParameters { - OtherContent, - Git::Constants::GIT_SVN_LOG_EDITOR_ID, - Git::Constants::GIT_SVN_LOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.svnlog" -}; - -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - Git::Constants::GIT_LOG_EDITOR_ID, - Git::Constants::GIT_LOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.log" -}; - -const VcsBaseEditorParameters reflogEditorParameters { - LogOutput, - Git::Constants::GIT_REFLOG_EDITOR_ID, - Git::Constants::GIT_REFLOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.reflog" -}; - -const VcsBaseEditorParameters blameEditorParameters { - AnnotateOutput, - Git::Constants::GIT_BLAME_EDITOR_ID, - Git::Constants::GIT_BLAME_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.annotation" -}; - -const VcsBaseEditorParameters commitTextEditorParameters { - OtherContent, - Git::Constants::GIT_COMMIT_TEXT_EDITOR_ID, - Git::Constants::GIT_COMMIT_TEXT_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.commit" -}; - -const VcsBaseEditorParameters rebaseEditorParameters { - OtherContent, - Git::Constants::GIT_REBASE_EDITOR_ID, - Git::Constants::GIT_REBASE_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.rebase" -}; - // GitPlugin class GitPluginPrivate final : public VersionControlBase @@ -366,41 +324,59 @@ public: GitGrep gitGrep; - VcsEditorFactory svnLogEditorFactory { - &svnLogEditorParameters, + VcsEditorFactory svnLogEditorFactory {{ + OtherContent, + Git::Constants::GIT_SVN_LOG_EDITOR_ID, + Git::Constants::GIT_SVN_LOG_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.git.svnlog", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + Git::Constants::GIT_LOG_EDITOR_ID, + Git::Constants::GIT_LOG_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.git.log", [] { return new GitLogEditorWidgetT; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory reflogEditorFactory { - &reflogEditorParameters, - [] { return new GitLogEditorWidgetT; }, + VcsEditorFactory reflogEditorFactory {{ + LogOutput, + Git::Constants::GIT_REFLOG_EDITOR_ID, + Git::Constants::GIT_REFLOG_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.git.reflog", + [] { return new GitLogEditorWidgetT; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory blameEditorFactory { - &blameEditorParameters, + VcsEditorFactory blameEditorFactory {{ + AnnotateOutput, + Git::Constants::GIT_BLAME_EDITOR_ID, + Git::Constants::GIT_BLAME_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.git.annotation", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory commitTextEditorFactory { - &commitTextEditorParameters, + VcsEditorFactory commitTextEditorFactory {{ + OtherContent, + Git::Constants::GIT_COMMIT_TEXT_EDITOR_ID, + Git::Constants::GIT_COMMIT_TEXT_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.git.commit", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory rebaseEditorFactory { - &rebaseEditorParameters, + VcsEditorFactory rebaseEditorFactory {{ + OtherContent, + Git::Constants::GIT_REBASE_EDITOR_ID, + Git::Constants::GIT_REBASE_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.git.rebase", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; static GitPluginPrivate *dd = nullptr; diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 081a7a5e41c..bd691d47e4c 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -67,27 +67,6 @@ protected: } }; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - Constants::FILELOG_ID, - Constants::FILELOG_DISPLAY_NAME, - Constants::LOGAPP -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, - Constants::ANNOTATEAPP -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, - Constants::DIFFAPP -}; - class MercurialPluginPrivate final : public VcsBase::VersionControlBase { public: @@ -180,23 +159,32 @@ private: FilePath m_submitRepository; public: - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + Constants::FILELOG_ID, + Constants::FILELOG_DISPLAY_NAME, + Constants::LOGAPP, [this] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + Constants::ANNOTATELOG_ID, + Constants::ANNOTATELOG_DISPLAY_NAME, + Constants::ANNOTATEAPP, [this] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + Constants::DIFFLOG_ID, + Constants::DIFFLOG_DISPLAY_NAME, + Constants::DIFFAPP, [this] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; static MercurialPluginPrivate *dd = nullptr; diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 23d6071d7d5..7bca24a7be7 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -128,27 +128,6 @@ struct PerforceResponse QString stdErr; }; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - PERFORCE_LOG_EDITOR_ID, - PERFORCE_LOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.p4.log" -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - PERFORCE_ANNOTATION_EDITOR_ID, - PERFORCE_ANNOTATION_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.p4.annotation" -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - PERFORCE_DIFF_EDITOR_ID, - PERFORCE_DIFF_EDITOR_DISPLAY_NAME, - "text/x-patch" -}; - // Flags for runP4Cmd. enum RunFlags { @@ -324,23 +303,32 @@ public: ManagedDirectoryCache m_managedDirectoryCache; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + PERFORCE_LOG_EDITOR_ID, + PERFORCE_LOG_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.p4.log", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + PERFORCE_ANNOTATION_EDITOR_ID, + PERFORCE_ANNOTATION_EDITOR_DISPLAY_NAME, + "text/vnd.qtcreator.p4.annotation", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + PERFORCE_DIFF_EDITOR_ID, + PERFORCE_DIFF_EDITOR_DISPLAY_NAME, + "text/x-patch", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; static PerforcePluginPrivate *dd = nullptr; @@ -827,7 +815,7 @@ void PerforcePluginPrivate::annotate(const FilePath &workingDir, if (lineNumber < 1) lineNumber = VcsBaseEditor::lineNumberOfCurrentEditor(); IEditor *ed = showOutputInEditor(Tr::tr("p4 annotate %1").arg(id), - result.stdOut, annotateEditorParameters.id, + result.stdOut, PERFORCE_ANNOTATION_EDITOR_ID, source, codec); VcsBaseEditor::gotoLineOfEditor(ed, lineNumber); } @@ -878,7 +866,7 @@ void PerforcePluginPrivate::filelog(const FilePath &workingDir, const QString &f if (!result.error) { const FilePath source = VcsBaseEditor::getSource(workingDir, fileName); IEditor *editor = showOutputInEditor(Tr::tr("p4 filelog %1").arg(id), result.stdOut, - logEditorParameters.id, source, codec); + PERFORCE_LOG_EDITOR_ID, source, codec); if (enableAnnotationContextMenu) VcsBaseEditor::getVcsBaseEditor(editor)->setFileLogAnnotateEnabled(true); } @@ -900,7 +888,7 @@ void PerforcePluginPrivate::changelists(const FilePath &workingDir, const QStrin if (!result.error) { const FilePath source = VcsBaseEditor::getSource(workingDir, fileName); IEditor *editor = showOutputInEditor(Tr::tr("p4 changelists %1").arg(id), result.stdOut, - logEditorParameters.id, source, codec); + PERFORCE_LOG_EDITOR_ID, source, codec); VcsBaseEditor::gotoLineOfEditor(editor, 1); } } @@ -1376,7 +1364,7 @@ void PerforcePluginPrivate::p4Diff(const PerforceDiffParameters &p) } // Create new editor IEditor *editor = showOutputInEditor(Tr::tr("p4 diff %1").arg(id), result.stdOut, - diffEditorParameters.id, + PERFORCE_DIFF_EDITOR_ID, VcsBaseEditor::getSource(p.workingDir, p.files), codec); VcsBaseEditor::tagEditor(editor, tag); @@ -1400,7 +1388,7 @@ void PerforcePluginPrivate::vcsDescribe(const FilePath &source, const QString &n const PerforceResponse result = runP4Cmd(settings().topLevel(), args, CommandToWindow|StdErrToWindow|ErrorToWindow, {}, {}, codec); if (!result.error) - showOutputInEditor(Tr::tr("p4 describe %1").arg(n), result.stdOut, diffEditorParameters.id, source, codec); + showOutputInEditor(Tr::tr("p4 describe %1").arg(n), result.stdOut, PERFORCE_DIFF_EDITOR_ID, source, codec); } void PerforcePluginPrivate::cleanCommitMessageFile() diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index c70df10640d..a5f146bf3d6 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -85,20 +85,6 @@ const char CMD_ID_UPDATE[] = "Subversion.Update"; const char CMD_ID_COMMIT_PROJECT[] = "Subversion.CommitProject"; const char CMD_ID_DESCRIBE[] = "Subversion.Describe"; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - Constants::SUBVERSION_LOG_EDITOR_ID, - Constants::SUBVERSION_LOG_EDITOR_DISPLAY_NAME, - Constants::SUBVERSION_LOG_MIMETYPE -}; - -const VcsBaseEditorParameters blameEditorParameters { - AnnotateOutput, - Constants::SUBVERSION_BLAME_EDITOR_ID, - Constants::SUBVERSION_BLAME_EDITOR_DISPLAY_NAME, - Constants::SUBVERSION_BLAME_MIMETYPE -}; - static inline QString debugCodec(const QTextCodec *c) { return c ? QString::fromLatin1(c->name()) : QString::fromLatin1("Null codec"); @@ -276,17 +262,23 @@ private: QAction *m_menuAction = nullptr; public: - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + Constants::SUBVERSION_LOG_EDITOR_ID, + Constants::SUBVERSION_LOG_EDITOR_DISPLAY_NAME, + Constants::SUBVERSION_LOG_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory blameEditorFactory { - &blameEditorParameters, + VcsEditorFactory blameEditorFactory {{ + AnnotateOutput, + Constants::SUBVERSION_BLAME_EDITOR_ID, + Constants::SUBVERSION_BLAME_EDITOR_DISPLAY_NAME, + Constants::SUBVERSION_BLAME_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; @@ -853,7 +845,7 @@ void SubversionPluginPrivate::vcsAnnotateHelper(const FilePath &workingDir, cons } else { const QString title = QString::fromLatin1("svn annotate %1").arg(id); IEditor *newEditor = showOutputInEditor(title, response.cleanedStdOut(), - blameEditorParameters.id, source, codec); + Constants::SUBVERSION_BLAME_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); VcsBaseEditor::gotoLineOfEditor(newEditor, lineNumber); } diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 729ee682c4d..9dcee6e31c7 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -1653,30 +1653,27 @@ IEditor *VcsBaseEditor::locateEditorByTag(const QString &tag) \sa VcsBase::VcsBaseEditorWidget */ -VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters *parameters, - // Force copy, see QTCREATORBUG-13218 - const EditorWidgetCreator editorWidgetCreator, - std::function describeFunc) +VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters ¶meters) { - setId(parameters->id); - setDisplayName(Tr::tr(parameters->displayName)); - if (QLatin1String(parameters->mimeType) != QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE)) - addMimeType(QLatin1String(parameters->mimeType)); + setId(parameters.id); + setDisplayName(Tr::tr(parameters.displayName)); + if (QLatin1String(parameters.mimeType) != QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE)) + addMimeType(QLatin1String(parameters.mimeType)); setEditorActionHandlers(TextEditorActionHandler::None); setDuplicatedSupported(false); setDocumentCreator([parameters] { - auto document = new TextDocument(parameters->id); - document->setMimeType(QLatin1String(parameters->mimeType)); + auto document = new TextDocument(parameters.id); + document->setMimeType(QLatin1String(parameters.mimeType)); document->setSuspendAllowed(false); return document; }); - setEditorWidgetCreator([parameters=*parameters, editorWidgetCreator, describeFunc] { - auto widget = editorWidgetCreator(); + setEditorWidgetCreator([parameters] { + auto widget = parameters.editorWidgetCreator(); auto editorWidget = Aggregation::query(widget); - editorWidget->setDescribeFunc(describeFunc); + editorWidget->setDescribeFunc(parameters.describeFunc); editorWidget->setParameters(parameters); return widget; }); diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index b2a9a80cb32..703e49324d4 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -45,6 +45,8 @@ public: const char *id; const char *displayName; const char *mimeType; + std::function editorWidgetCreator; + std::function describeFunc; }; class VCSBASE_EXPORT DiffChunk @@ -289,10 +291,7 @@ public: class VCSBASE_EXPORT VcsEditorFactory : public TextEditor::TextEditorFactory { public: - VcsEditorFactory(const VcsBaseEditorParameters *parameters, - const EditorWidgetCreator editorWidgetCreator, - std::function describeFunc); - + explicit VcsEditorFactory(const VcsBaseEditorParameters ¶meters); ~VcsEditorFactory(); }; From 8ee97b1e02b935ecd7882a53be95ac710c939c4b Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Wed, 7 Feb 2024 10:09:02 +0100 Subject: [PATCH 06/82] QuickFix: Fix add definition for templated function in namespace - Fix add definition for templated/not templated function in templated class inside namespace Fixes: QTCREATORBUG-22076 Change-Id: I565cbdc8c6ab8d09727b4cd6f1c8fb45741c213f Reviewed-by: Christian Kandeler --- src/libs/cplusplus/TypePrettyPrinter.cpp | 6 ++-- src/plugins/cppeditor/cppquickfix_test.cpp | 39 ++++++++++++++++++++-- src/plugins/cppeditor/cppquickfix_test.h | 1 + 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 7ae1aa3397b..0e7ba193427 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -363,12 +363,11 @@ void TypePrettyPrinter::visit(Function *type) { bool showTemplateParameters = _overview->showTemplateParameters; QStringList nameParts = _name.split("::"); - int i = nameParts.length() - 1; Scope *s = type->enclosingScope(); if (s && s->asTemplate()) s = s->enclosingScope(); - for (; s && i >= 0; s = s->enclosingScope()) { + for (int i = nameParts.length() - 1; s && i >= 0; s = s->enclosingScope()) { if (s->asClass()) showTemplateParameters = true; @@ -433,7 +432,8 @@ void TypePrettyPrinter::visit(Function *type) } if (_overview->showEnclosingTemplate) { - for (Scope *s = type->enclosingScope(); s && i >= 0; s = s->enclosingScope()) { + for (auto [s, i] = std::tuple{type->enclosingScope(), nameParts.length() - 1}; s && i >= 0; + s = s->enclosingScope()) { if (Template *templ = s->asTemplate()) { QString templateScope = "template<"; const int paramCount = templ->templateParameterCount(); diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index b0064ab790a..dd4817ea0d5 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -5008,19 +5008,19 @@ void QuickfixTest::testInsertDefFromDeclTemplateClassAndTemplateFunction() "class Foo\n" "{\n" " template\n" - " void fun@c();\n" + " T fun@c(U u);\n" "};\n"; QByteArray expected = "template" "class Foo\n" "{\n" " template\n" - " void fun@c();\n" + " T fun@c(U u);\n" "};\n" "\n" "template\n" "template\n" - "void Foo::func()\n" + "T Foo::func(U u)\n" "{\n" "\n" "}\n"; @@ -5029,6 +5029,39 @@ void QuickfixTest::testInsertDefFromDeclTemplateClassAndTemplateFunction() QuickFixOperationTest(singleDocument(original, expected), &factory); } +void QuickfixTest::testInsertDefFromDeclTemplateClassAndFunctionInsideNamespace() +{ + QByteArray original = + "namespace N {\n" + "template" + "class Foo\n" + "{\n" + " template\n" + " T fun@c(U u);\n" + "};\n" + "}\n"; + QByteArray expected = + "namespace N {\n" + "template" + "class Foo\n" + "{\n" + " template\n" + " T fun@c(U u);\n" + "};\n" + "\n" + "template\n" + "template\n" + "T Foo::func(U u)\n" + "{\n" + "\n" + "}\n" + "\n" + "}\n"; + + InsertDefFromDecl factory; + QuickFixOperationTest(singleDocument(original, expected), &factory); +} + void QuickfixTest::testInsertDefFromDeclFunctionWithSignedUnsignedArgument() { QByteArray original; diff --git a/src/plugins/cppeditor/cppquickfix_test.h b/src/plugins/cppeditor/cppquickfix_test.h index cc589f1908a..ee64b9f10d4 100644 --- a/src/plugins/cppeditor/cppquickfix_test.h +++ b/src/plugins/cppeditor/cppquickfix_test.h @@ -137,6 +137,7 @@ private slots: void testInsertDefFromDeclTemplateClassWithValueParam(); void testInsertDefFromDeclTemplateFunction(); void testInsertDefFromDeclTemplateClassAndTemplateFunction(); + void testInsertDefFromDeclTemplateClassAndFunctionInsideNamespace(); void testInsertDefFromDeclFunctionWithSignedUnsignedArgument(); void testInsertDefFromDeclNotTriggeredForFriendFunc(); void testInsertDefFromDeclMinimalFunctionParameterType(); From 44c9074c0bc77b407b2a0e3ac57ac4432657f775 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Mon, 5 Feb 2024 16:05:55 +0100 Subject: [PATCH 07/82] ClangFormat: Move clangformat output to infolabel Move clangformat output to infolabel in clangformatconfigwidget to reduce noiziness in cli and to enhance the convenience of editing the .clang-format file. Fixes: QTCREATORBUG-30269 Change-Id: I78053bde9791122172f1d3d4ba712a9954ea9c4e Reviewed-by: Eike Ziller Reviewed-by: --- .../clangformat/clangformatbaseindenter.cpp | 2 +- .../clangformat/clangformatconfigwidget.cpp | 52 +++++++------------ src/plugins/clangformat/clangformatutils.cpp | 26 ++++++++-- src/plugins/clangformat/clangformatutils.h | 6 ++- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 9f9ea8ac94e..2de357b1124 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -849,7 +849,7 @@ clang::format::FormatStyle ClangFormatBaseIndenterPrivate::customSettingsStyle( return currentQtStyle(preferences); clang::format::FormatStyle currentSettingsStyle; - bool success = parseConfigurationFile(filePath, currentSettingsStyle); + const Utils::expected_str success = parseConfigurationFile(filePath, currentSettingsStyle); QTC_ASSERT(success, return currentQtStyle(preferences)); return currentSettingsStyle; diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index c546cc0d21f..98de3370228 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -105,8 +107,7 @@ private: Guard m_ignoreChanges; QLabel *m_clangVersion; - QLabel *m_clangFileIsCorrectText; - QLabel *m_clangFileIsCorrectIcon; + InfoLabel *m_clangFileIsCorrectText; ClangFormatIndenter *m_indenter; }; @@ -137,7 +138,7 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(TextEditor::ICodeStylePreferenc Column { m_clangVersion, Row { m_editorScrollArea, m_preview }, - Row {m_clangFileIsCorrectIcon, m_clangFileIsCorrectText, st} + Row {m_clangFileIsCorrectText, st} }.attachTo(this); connect(codeStyle, &TextEditor::ICodeStylePreferences::currentPreferencesChanged, @@ -194,46 +195,28 @@ void ClangFormatConfigWidget::initEditor(TextEditor::ICodeStylePreferences *code m_editorScrollArea->setWidget(m_editor->widget()); m_editorScrollArea->setWidgetResizable(true); - m_clangFileIsCorrectText = new QLabel(Tr::tr("Clang-Format is configured correctly.")); - QPalette paletteCorrect = m_clangFileIsCorrectText->palette(); - paletteCorrect.setColor(QPalette::WindowText, Qt::darkGreen); - m_clangFileIsCorrectText->setPalette(paletteCorrect); - - m_clangFileIsCorrectIcon = new QLabel(this); - m_clangFileIsCorrectIcon->setPixmap(Icons::OK.icon().pixmap(16, 16)); + m_clangFileIsCorrectText = new InfoLabel("", Utils::InfoLabel::Ok); + m_clangFileIsCorrectText->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + m_clangFileIsCorrectText->hide(); m_clangVersion = new QLabel(Tr::tr("Current ClangFormat version: %1.").arg(LLVM_VERSION_STRING), this); connect(m_editor->document(), &TextEditor::TextDocument::contentsChanged, this, [this] { clang::format::FormatStyle currentSettingsStyle; - const bool success + const Utils::expected_str success = parseConfigurationContent(m_editor->document()->contents().toStdString(), currentSettingsStyle); - QString text; - Qt::GlobalColor currentColor; - QPixmap pixmap; if (success) { - text = Tr::tr("Clang-Format is configured correctly."); - currentColor = Qt::darkGreen; - pixmap = Icons::OK.icon().pixmap(16, 16); - } else { - text = Tr::tr("Clang-Format is not configured correctly."); - currentColor = Qt::red; - pixmap = Icons::WARNING.icon().pixmap(16, 16); - } - - m_clangFileIsCorrectText->setText(text); - QPalette paletteCorrect = m_clangFileIsCorrectText->palette(); - paletteCorrect.setColor(QPalette::WindowText, currentColor); - m_clangFileIsCorrectText->setPalette(paletteCorrect); - m_clangFileIsCorrectIcon->setPixmap(pixmap); - - if (!success) + m_clangFileIsCorrectText->hide(); + m_indenter->setOverriddenStyle(currentSettingsStyle); + updatePreview(); return; - m_indenter->setOverriddenStyle(currentSettingsStyle); - updatePreview(); + } + m_clangFileIsCorrectText->show(); + m_clangFileIsCorrectText->setText(Tr::tr("Warning: ") + success.error()); + m_clangFileIsCorrectText->setType(Utils::InfoLabel::Warning); }); QShortcut *completionSC = new QShortcut(QKeySequence("Ctrl+Space"), this); @@ -347,8 +330,9 @@ void ClangFormatConfigWidget::apply() return; clang::format::FormatStyle currentSettingsStyle; - const bool success = parseConfigurationContent(m_editor->document()->contents().toStdString(), - currentSettingsStyle); + const Utils::expected_str success + = parseConfigurationContent(m_editor->document()->contents().toStdString(), + currentSettingsStyle); auto saveSettings = [this] { QString errorString; diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index b1e8090ece2..6d16ebe9aa1 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -19,6 +19,7 @@ #include #include +#include #include @@ -417,15 +418,30 @@ Utils::FilePath filePathToCurrentSettings(const TextEditor::ICodeStylePreference / QLatin1String(Constants::SETTINGS_FILE_NAME); } -bool parseConfigurationContent(const std::string &fileContent, clang::format::FormatStyle &style) +static QString s_errorMessage; +Utils::expected_str parseConfigurationContent(const std::string &fileContent, + clang::format::FormatStyle &style) { - style.Language = clang::format::FormatStyle::LK_Cpp; - const std::error_code error = parseConfiguration(fileContent, &style); + auto diagHandler = [](const llvm::SMDiagnostic &diag, void * /*context*/) { + s_errorMessage = QString::fromStdString(diag.getMessage().str()) + " " + + QString::number(diag.getLineNo()) + ":" + + QString::number(diag.getColumnNo()); + }; - return error.value() == static_cast(ParseError::Success); + style.Language = clang::format::FormatStyle::LK_Cpp; + const std::error_code error = parseConfiguration(llvm::MemoryBufferRef(fileContent, "YAML"), + &style, + false, + diagHandler, + nullptr); + + if (error) + return make_unexpected(s_errorMessage); + return {}; } -bool parseConfigurationFile(const Utils::FilePath &filePath, clang::format::FormatStyle &style) +Utils::expected_str parseConfigurationFile(const Utils::FilePath &filePath, + clang::format::FormatStyle &style) { return parseConfigurationContent(filePath.fileContents().value_or(QByteArray()).toStdString(), style); diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index a4ff429b3e8..019414b11f5 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -48,7 +48,9 @@ clang::format::FormatStyle currentQtStyle(const TextEditor::ICodeStylePreference Utils::FilePath filePathToCurrentSettings(const TextEditor::ICodeStylePreferences *codeStyle); -bool parseConfigurationContent(const std::string &fileContent, clang::format::FormatStyle &style); -bool parseConfigurationFile(const Utils::FilePath &filePath, clang::format::FormatStyle &style); +Utils::expected_str parseConfigurationContent(const std::string &fileContent, + clang::format::FormatStyle &style); +Utils::expected_str parseConfigurationFile(const Utils::FilePath &filePath, + clang::format::FormatStyle &style); } // ClangFormat From b9f546cf1bb7d867bb5f0a31ada0c5c670c52f6e Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 5 Feb 2024 16:15:52 +0100 Subject: [PATCH 08/82] ProjectExplorer: Add kitFilterText virtual method to ProjectImporter This way a project importer implementation can modify the filterText edit field from the Project setup page. Task-number: QTCREATORBUG-29535 Change-Id: I22b3d613ff84111b918c4a4447cd5656d7c593b9 Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectimporter.h | 1 + src/plugins/projectexplorer/targetsetuppage.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/projectimporter.h b/src/plugins/projectexplorer/projectimporter.h index 3e67f09c06d..2cca307d5b3 100644 --- a/src/plugins/projectexplorer/projectimporter.h +++ b/src/plugins/projectexplorer/projectimporter.h @@ -36,6 +36,7 @@ public: virtual const QList import(const Utils::FilePath &importPath, bool silent = false); virtual Utils::FilePaths importCandidates() = 0; virtual Target *preferredTarget(const QList &possibleTargets); + virtual QString kitFilterText() { return QString(); } bool isUpdating() const { return m_isUpdating; } diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 5e67d291323..a4af51996a4 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -569,8 +569,11 @@ void TargetSetupPagePrivate::doInitializePage() setupWidgets(); setupImports(); - selectAtLeastOneEnabledKit(); + const QString filterText = m_importer ? m_importer->kitFilterText() : QString{}; + kitFilterLineEdit->setText(filterText); + kitFilterLineEdit->filterChanged(filterText); + selectAtLeastOneEnabledKit(); updateVisibility(); } From 3b2a4fd3f2690dd97f076482d3d1bc05da1c6c1d Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 7 Feb 2024 15:41:18 +0100 Subject: [PATCH 09/82] Vcs: Remove VcsBaseEditorPrivate::m_describeFunc Use the new copy inside m_parameters instead. Change-Id: I85cddfd598fe8fc95af99c7c89dfdb5af49b137e Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/vcsbaseeditor.cpp | 10 ++-------- src/plugins/vcsbase/vcsbaseeditor.h | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 9dcee6e31c7..13b8e647fe5 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -563,7 +563,6 @@ public: VcsBaseEditorConfig *m_config = nullptr; QList m_textCursorHandlers; QPointer m_command; - VcsBaseEditorWidget::DescribeFunc m_describeFunc = nullptr; ProgressIndicator *m_progressIndicator = nullptr; bool m_fileLogAnnotateEnabled = false; bool m_mouseDragging = false; @@ -723,14 +722,10 @@ int VcsBaseEditorWidget::lineNumberDigits() const return digits; } -void VcsBaseEditorWidget::setDescribeFunc(DescribeFunc describeFunc) -{ - d->m_describeFunc = describeFunc; -} - void VcsBaseEditorWidget::finalizeInitialization() { - connect(this, &VcsBaseEditorWidget::describeRequested, this, d->m_describeFunc); + QTC_CHECK(d->m_parameters.describeFunc); + connect(this, &VcsBaseEditorWidget::describeRequested, this, d->m_parameters.describeFunc); init(); } @@ -1673,7 +1668,6 @@ VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters ¶meters) setEditorWidgetCreator([parameters] { auto widget = parameters.editorWidgetCreator(); auto editorWidget = Aggregation::query(widget); - editorWidget->setDescribeFunc(parameters.describeFunc); editorWidget->setParameters(parameters); return widget; }); diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index 703e49324d4..123f3ef9e40 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -147,8 +147,6 @@ public: void finalizeInitialization() override; // FIXME: Consolidate these into finalizeInitialization - void setDescribeFunc(DescribeFunc describeFunc); - // void virtual void init(); // void setParameters(const VcsBaseEditorParameters ¶meters); From ecc3879cf4d45cd807b524006ed1a354c8f619ff Mon Sep 17 00:00:00 2001 From: Dominik Holland Date: Wed, 7 Feb 2024 15:46:51 +0100 Subject: [PATCH 10/82] AppMan: Only allow Debugging/Profiling with a Linux kit Change-Id: I196fe6cc85065c3d9965f5fbb342f377bd221d95 Reviewed-by: hjk --- .../appmanagerrunconfiguration.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp index 2a5e20fa48b..77bddffb055 100644 --- a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp @@ -90,9 +90,10 @@ public: return !tis.isEmpty(); } - virtual bool filterTarget(const TargetInformation &ti) const + virtual bool filterTarget(Target *target, const TargetInformation &ti) const { - return !ti.manifest.supportsDebugging(); + return !ti.manifest.supportsDebugging() || + DeviceKitAspect::device(target->kit())->osType() != OsType::OsTypeLinux; } QList availableCreators(Target *target) const @@ -102,8 +103,8 @@ public: Qt::UniqueConnection); const auto buildTargets = TargetInformation::readFromProject(target); - const auto filteredTargets = Utils::filtered(buildTargets, [this](const TargetInformation &ti){ - return filterTarget(ti); + const auto filteredTargets = Utils::filtered(buildTargets, [this, target](const TargetInformation &ti) { + return filterTarget(target, ti); }); auto result = Utils::transform(filteredTargets, [this, target](const TargetInformation &ti) { @@ -143,9 +144,9 @@ public: addSupportedTargetDeviceType(Qdb::Constants::QdbLinuxOsType); } - virtual bool filterTarget(const TargetInformation &ti) const final + virtual bool filterTarget(Target *target, const TargetInformation &ti) const final { - return ti.manifest.supportsDebugging(); + return !AppManagerRunConfigurationFactory::filterTarget(target, ti); } }; From eb95794e679cca5e6ac51aef2a60a6811c7c46d9 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 8 Feb 2024 09:20:36 +0100 Subject: [PATCH 11/82] Debugger: Fix std string view dumper test for msvc Cdb always report the type name with all typedefs resolved so we have to check the original type name for cdb. Change-Id: Ib7166276075b18e011ea786a5d3468db0e24e9c0 Reviewed-by: Christian Stenger --- tests/auto/debugger/tst_dumpers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 698147c4194..69fcf3bcf2c 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -5313,8 +5313,8 @@ void tst_Dumpers::dumper_data() "&view, &u16view, basicview, u16basicview") - + Check("view", "\"test\"", "std::string_view") - + Check("u16view", "\"test\"", "std::u16string_view") + + Check("view", "\"test\"", TypeDef("std::basic_string_view >", "std::string_view")) + + Check("u16view", "\"test\"", TypeDef("std::basic_string_view >", "std::u16string_view")) + Check("basicview", "\"test\"", "std::basic_string_view >") + Check("u16basicview", "\"test\"", "std::basic_string_view >"); From 228f77afd1e1eee99e2d3e131d486c0e92ac54e0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 29 Jan 2024 18:13:17 +0100 Subject: [PATCH 12/82] QbsProjectManager: Support completion via qbs' LSP server Task-number: QBS-395 Change-Id: I2571dc46c9fb2867daeb3a5d00709337b12a750b Reviewed-by: Reviewed-by: David Schulz --- src/plugins/qbsprojectmanager/qbseditor.cpp | 179 +++++++++++++++++- .../codeassist/genericproposalmodel.h | 1 + 2 files changed, 172 insertions(+), 8 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbseditor.cpp b/src/plugins/qbsprojectmanager/qbseditor.cpp index 7eed6977a2c..08f6e0a8725 100644 --- a/src/plugins/qbsprojectmanager/qbseditor.cpp +++ b/src/plugins/qbsprojectmanager/qbseditor.cpp @@ -6,13 +6,23 @@ #include "qbslanguageclient.h" #include "qbsprojectmanagertr.h" +#include #include +#include +#include +#include +#include +#include #include #include +#include +#include + using namespace LanguageClient; using namespace QmlJSEditor; +using namespace TextEditor; using namespace Utils; namespace QbsProjectManager::Internal { @@ -26,11 +36,79 @@ private: bool inNextSplit = false) override; }; +class QbsCompletionAssistProcessor : public LanguageClientCompletionAssistProcessor +{ +public: + QbsCompletionAssistProcessor(Client *client); + +private: + QList generateCompletionItems( + const QList &items) const override; +}; + +class MergedCompletionAssistProcessor : public IAssistProcessor +{ +public: + MergedCompletionAssistProcessor(const AssistInterface *interface) : m_interface(interface) {} + ~MergedCompletionAssistProcessor(); + +private: + IAssistProposal *perform() override; + bool running() override { return m_started && (!m_qmlProposal || !m_qbsProposal); } + void checkFinished(); + + const AssistInterface * const m_interface; + std::unique_ptr m_qmlProcessor; + std::unique_ptr m_qbsProcessor; + std::optional m_qmlProposal; + std::optional m_qbsProposal; + bool m_started = false; +}; + +class QbsCompletionAssistProvider : public QmlJSCompletionAssistProvider +{ +private: + IAssistProcessor *createProcessor(const AssistInterface *interface) const override + { + return new MergedCompletionAssistProcessor(interface); + } +}; + +class QbsCompletionItem : public LanguageClientCompletionItem +{ +public: + using LanguageClientCompletionItem::LanguageClientCompletionItem; + +private: + QIcon icon() const override; +}; + +class MergedProposalModel : public GenericProposalModel +{ +public: + MergedProposalModel(const QList &sourceModels); +}; + +static Client *clientForDocument(const TextDocument *doc) +{ + if (!doc) + return nullptr; + const QList &candidates = LanguageClientManager::clientsSupportingDocument(doc); + for (Client * const candidate : candidates) { + if (const auto qbsClient = qobject_cast(candidate); + qbsClient && qbsClient->isActive() && qbsClient->documentOpen(doc)) { + return qbsClient; + } + } + return nullptr; +} + QbsEditorFactory::QbsEditorFactory() : QmlJSEditorFactory("QbsEditor.QbsEditor") { setDisplayName(Tr::tr("Qbs Editor")); setMimeTypes({Utils::Constants::QBS_MIMETYPE}); setEditorWidgetCreator([] { return new QbsEditorWidget; }); + setCompletionAssistProvider(new QbsCompletionAssistProvider); } void QbsEditorWidget::findLinkAt(const QTextCursor &cursor, const LinkHandler &processLinkCallback, @@ -43,18 +121,103 @@ void QbsEditorWidget::findLinkAt(const QTextCursor &cursor, const LinkHandler &p if (!self) return; const auto doc = self->textDocument(); - if (!doc) - return; - const QList &candidates = LanguageClientManager::clientsSupportingDocument(doc); - for (Client * const candidate : candidates) { - const auto qbsClient = qobject_cast(candidate); - if (!qbsClient || !qbsClient->isActive() || !qbsClient->documentOpen(doc)) - continue; - qbsClient->findLinkAt(doc, cursor, processLinkCallback, resolveTarget, + if (Client * const client = clientForDocument(doc)) { + client->findLinkAt(doc, cursor, processLinkCallback, resolveTarget, LinkTarget::SymbolDef); } }; QmlJSEditorWidget::findLinkAt(cursor, extendedCallback, resolveTarget, inNextSplit); } +MergedCompletionAssistProcessor::~MergedCompletionAssistProcessor() +{ + if (m_qmlProposal) + delete *m_qmlProposal; + if (m_qbsProposal) + delete *m_qbsProposal; +} + +IAssistProposal *MergedCompletionAssistProcessor::perform() +{ + m_started = true; + if (Client *const qbsClient = clientForDocument( + TextDocument::textDocumentForFilePath(m_interface->filePath()))) { + m_qbsProcessor.reset(new QbsCompletionAssistProcessor(qbsClient)); + m_qbsProcessor->setAsyncCompletionAvailableHandler([this](IAssistProposal *proposal) { + m_qbsProposal = proposal; + checkFinished(); + }); + m_qbsProcessor->start(std::make_unique(m_interface->cursor(), + m_interface->filePath(), + ExplicitlyInvoked)); + } else { + m_qbsProposal = nullptr; + } + m_qmlProcessor.reset(QmlJSCompletionAssistProvider().createProcessor(m_interface)); + m_qmlProcessor->setAsyncCompletionAvailableHandler([this](IAssistProposal *proposal) { + m_qmlProposal = proposal; + checkFinished(); + }); + const auto qmlJsIface = static_cast(m_interface); + return m_qmlProcessor->start( + std::make_unique(qmlJsIface->cursor(), + qmlJsIface->filePath(), + ExplicitlyInvoked, + qmlJsIface->semanticInfo())); +} + +void MergedCompletionAssistProcessor::checkFinished() +{ + if (running()) + return; + + QList sourceModels; + int basePosition = -1; + for (const IAssistProposal * const proposal : {*m_qmlProposal, *m_qbsProposal}) { + if (proposal) { + if (const auto model = proposal->model().dynamicCast()) + sourceModels << model; + if (basePosition == -1) + basePosition = proposal->basePosition(); + else + QTC_CHECK(basePosition == proposal->basePosition()); + } + } + setAsyncProposalAvailable( + new GenericProposal(basePosition >= 0 ? basePosition : m_interface->position(), + GenericProposalModelPtr(new MergedProposalModel(sourceModels)))); +} + +MergedProposalModel::MergedProposalModel(const QList &sourceModels) +{ + QList items; + for (const GenericProposalModelPtr &model : sourceModels) { + items << model->originalItems(); + model->loadContent({}); + } + loadContent(items); +} + +QbsCompletionAssistProcessor::QbsCompletionAssistProcessor(Client *client) + : LanguageClientCompletionAssistProcessor(client, nullptr, {}) +{} + +QList QbsCompletionAssistProcessor::generateCompletionItems( + const QList &items) const +{ + return Utils::transform>( + items, [](const LanguageServerProtocol::CompletionItem &item) { + return new QbsCompletionItem(item); + }); +} + +QIcon QbsCompletionItem::icon() const +{ + if (!item().detail()) { + return ProjectExplorer::DirectoryIcon( + ProjectExplorer::Constants::FILEOVERLAY_MODULES).icon(); + } + return CodeModelIcon::iconForType(CodeModelIcon::Property); +} + } // namespace QbsProjectManager::Internal diff --git a/src/plugins/texteditor/codeassist/genericproposalmodel.h b/src/plugins/texteditor/codeassist/genericproposalmodel.h index 610fab1a1fb..3107fae0d33 100644 --- a/src/plugins/texteditor/codeassist/genericproposalmodel.h +++ b/src/plugins/texteditor/codeassist/genericproposalmodel.h @@ -45,6 +45,7 @@ public: virtual int indexOf(const std::function &predicate) const; void loadContent(const QList &items); + const QList &originalItems() const { return m_originalItems; } bool isPerfectMatch(const QString &prefix) const; bool hasItemsToPropose(const QString &prefix, AssistReason reason) const; From 6deddd15c0a825baece0d13a9b40bf4b10cb8565 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 3 Feb 2024 02:32:16 +0100 Subject: [PATCH 13/82] ModelManagerSupport: Remove unused Ptr Change-Id: Ibdc81d1c6fecb808cbd7ca91f56a4869b6e26dc1 Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppmodelmanagersupport.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/cppeditor/cppmodelmanagersupport.h b/src/plugins/cppeditor/cppmodelmanagersupport.h index a43a1e0b02b..c2c463df59a 100644 --- a/src/plugins/cppeditor/cppmodelmanagersupport.h +++ b/src/plugins/cppeditor/cppmodelmanagersupport.h @@ -9,9 +9,6 @@ #include -#include -#include - #include namespace Core { class SearchResult; } @@ -29,9 +26,6 @@ class RefactoringEngineInterface; class CPPEDITOR_EXPORT ModelManagerSupport { -public: - using Ptr = QSharedPointer; - public: virtual ~ModelManagerSupport() = 0; From ba9ecc9b85be2bce74b9a947e11461a204190e9d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 3 Feb 2024 02:34:37 +0100 Subject: [PATCH 14/82] CppEditorOutline: Remove unused method Remove also unused include and forward declaration. Change-Id: I67d9ea45bc1073653b17faa3433f132a5e43f924 Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppeditoroutline.cpp | 6 ------ src/plugins/cppeditor/cppeditoroutline.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/plugins/cppeditor/cppeditoroutline.cpp b/src/plugins/cppeditor/cppeditoroutline.cpp index 05c521e0d31..d630a7ad1c6 100644 --- a/src/plugins/cppeditor/cppeditoroutline.cpp +++ b/src/plugins/cppeditor/cppeditoroutline.cpp @@ -150,12 +150,6 @@ QWidget *CppEditorOutline::widget() const return m_combo; } -QSharedPointer getDocument(const Utils::FilePath &filePath) -{ - const CPlusPlus::Snapshot snapshot = CppModelManager::snapshot(); - return snapshot.document(filePath); -} - void CppEditorOutline::updateNow() { m_combo->view()->expandAll(); diff --git a/src/plugins/cppeditor/cppeditoroutline.h b/src/plugins/cppeditor/cppeditoroutline.h index d73c0fc363d..b7ac18dd0f4 100644 --- a/src/plugins/cppeditor/cppeditoroutline.h +++ b/src/plugins/cppeditor/cppeditoroutline.h @@ -5,7 +5,6 @@ #include "cppoutlinemodel.h" -#include #include #include @@ -16,7 +15,6 @@ class QSortFilterProxyModel; class QTimer; QT_END_NAMESPACE -namespace TextEditor { class TextEditorWidget; } namespace Utils { class TreeViewComboBox; } namespace CppEditor { From b163044648d864046ce1c14245b14b356f24ab15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 26 Jan 2024 17:53:41 +0100 Subject: [PATCH 15/82] SquishTests: Update expected output in tst_git_clone Change-Id: Ia0a559ee8fb24d639b913dabc1b77dd4c2286fbb Reviewed-by: Christian Stenger --- tests/system/suite_tools/tst_git_clone/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/suite_tools/tst_git_clone/test.py b/tests/system/suite_tools/tst_git_clone/test.py index 42473264f7e..17ce84d7522 100644 --- a/tests/system/suite_tools/tst_git_clone/test.py +++ b/tests/system/suite_tools/tst_git_clone/test.py @@ -47,7 +47,7 @@ def verifyVersionControlView(targetDir, canceled): "Searching for target directory in clone log") test.verify(" ".join(["clone", "--progress", cloneUrl, cloneDir]) in vcsLog, "Searching for git parameters in clone log") - test.compare(canceled, " terminated abnormally" in vcsLog, + test.compare(canceled, " was canceled after " in vcsLog, "Searching for result in clone log") clickButton(waitForObject(":*Qt Creator.Clear_QToolButton")) From 31ca46ef2f26dcd5713b6ab53d64666fc49fac8b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 8 Feb 2024 10:00:29 +0200 Subject: [PATCH 16/82] VCS: Remove trailing dot in "running" message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The command should be copyable. Change-Id: Id44e8af81f32de3d9899293de504070011f896c2 Reviewed-by: André Hartmann --- src/plugins/vcsbase/vcsoutputwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index 4b6eab6fb17..e8738907b56 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -410,7 +410,7 @@ QString VcsOutputWindow::msgExecutionLogEntry(const FilePath &workingDir, const + ' ' + formatArguments(command.splitArguments()); if (workingDir.isEmpty()) return Tr::tr("Running: %1").arg(maskedCmdline) + '\n'; - return Tr::tr("Running in \"%1\": %2.").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; + return Tr::tr("Running in \"%1\": %2").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; } void VcsOutputWindow::appendShellCommandLine(const QString &text) From 70e013fd254bbc27eff82a2d64af1b3f882e0b56 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 8 Feb 2024 11:21:32 +0100 Subject: [PATCH 17/82] Git: Cleanup gitExecutable() Using expected removes a bunch of handling code. Change-Id: Id524912d82aa693fbb39c7e7fa34abd77153f92e Reviewed-by: Reviewed-by: Orgad Shaneh --- src/plugins/git/gitclient.cpp | 8 ++------ src/plugins/git/gitplugin.cpp | 8 +++----- src/plugins/git/gitsettings.cpp | 15 +++------------ src/plugins/git/gitsettings.h | 2 +- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 6f9224dda04..5523ba1b48a 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -929,7 +929,7 @@ void GitClient::requestReload(const QString &documentId, const FilePath &source, QTC_ASSERT(document, return); GitBaseDiffEditorController *controller = factory(document); QTC_ASSERT(controller, return); - controller->setVcsBinary(settings().gitExecutable()); + controller->setVcsBinary(settings().gitExecutable().value_or(FilePath{})); controller->setProcessEnvironment(processEnvironment()); controller->setWorkingDirectory(workingDirectory); @@ -2546,11 +2546,7 @@ bool GitClient::launchGitBash(const FilePath &workingDirectory) FilePath GitClient::vcsBinary() const { - bool ok; - Utils::FilePath binary = settings().gitExecutable(&ok); - if (!ok) - return {}; - return binary; + return settings().gitExecutable().value_or(FilePath{}); } // returns first line from log and removes it diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index c3ac447c570..993ea54fb49 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -409,11 +409,9 @@ void GitPluginPrivate::onApplySettings() { emit configurationChanged(); updateRepositoryBrowserAction(); - bool gitFoundOk; - QString errorMessage; - settings().gitExecutable(&gitFoundOk, &errorMessage); - if (!gitFoundOk) { - QTimer::singleShot(0, this, [errorMessage] { + const expected_str result = settings().gitExecutable(); + if (!result) { + QTimer::singleShot(0, this, [errorMessage = result.error()] { AsynchronousMessageBox::warning(Tr::tr("Git Settings"), errorMessage); }); } diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 43b0e8ae6c7..95938a41d88 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -164,14 +164,8 @@ GitSettings::GitSettings() readSettings(); } -FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const +expected_str GitSettings::gitExecutable() const { - // Locate binary in path if one is specified, otherwise default to pathless binary. - if (ok) - *ok = true; - if (errorMessage) - errorMessage->clear(); - if (tryResolve) { resolvedBinPath = binaryPath(); if (!resolvedBinPath.isAbsolutePath()) @@ -180,11 +174,8 @@ FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const } if (resolvedBinPath.isEmpty()) { - if (ok) - *ok = false; - if (errorMessage) - *errorMessage = Tr::tr("The binary \"%1\" could not be located in the path \"%2\"") - .arg(binaryPath().toUserOutput(), path()); + return make_unexpected(Tr::tr("The binary \"%1\" could not be located in the path \"%2\"") + .arg(binaryPath().toUserOutput(), path())); } return resolvedBinPath; } diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index f6ec650c2e8..2932cc78c0a 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -44,7 +44,7 @@ public: mutable Utils::FilePath resolvedBinPath; mutable bool tryResolve = true; - Utils::FilePath gitExecutable(bool *ok = nullptr, QString *errorMessage = nullptr) const; + Utils::expected_str gitExecutable() const; static QString trIgnoreWhitespaceChanges(); static QString trIgnoreLineMoves(); From 7b6543268885e66174938b0a0a7e932675d30de7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 8 Feb 2024 10:06:59 +0100 Subject: [PATCH 18/82] Wizard: Allow wizards to choose remote path Change-Id: Ia7b0184452e2c4e86d727fbc3880b2e27285ef5d Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/utils/projectintropage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp index b710e68723b..1f32cce6bcc 100644 --- a/src/libs/utils/projectintropage.cpp +++ b/src/libs/utils/projectintropage.cpp @@ -82,6 +82,7 @@ ProjectIntroPage::ProjectIntroPage(QWidget *parent) : d->m_pathChooser->setObjectName("baseFolder"); // used by Squish d->m_pathChooser->setExpectedKind(PathChooser::Directory); d->m_pathChooser->setDisabled(d->m_forceSubProject); + d->m_pathChooser->setAllowPathFromDevice(true); d->m_projectsDirectoryCheckBox = new QCheckBox(Tr::tr("Use as default project location")); d->m_projectsDirectoryCheckBox->setObjectName("projectsDirectoryCheckBox"); From 1cddc3d0b69ef07eedc6021ae4543d28488c3396 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 8 Feb 2024 11:07:40 +0100 Subject: [PATCH 19/82] TextEditor: fix applying empty list of format changes The block might have had some highlighting before the update, so compare the new ranges against the one from the layout and update the layout if the format ranges differ. Change-Id: Ia6a0025e74fa8941b1cccc00baa93d3d37cb9ff9 Reviewed-by: Artem Sokolovskii --- src/plugins/texteditor/syntaxhighlighterrunner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.cpp b/src/plugins/texteditor/syntaxhighlighterrunner.cpp index 0d5e32893ee..094e97e7a08 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.cpp +++ b/src/plugins/texteditor/syntaxhighlighterrunner.cpp @@ -185,7 +185,7 @@ void SyntaxHighlighterRunner::applyFormatRanges(const QListformats()) { TextDocumentLayout::FoldValidator foldValidator; foldValidator.setup(qobject_cast(m_document->documentLayout())); docBlock.layout()->setFormats(result.m_formatRanges); From cf7f9dffd5d0856bf3022590086d38f3f7e7f9b9 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Thu, 8 Feb 2024 11:05:00 +0100 Subject: [PATCH 20/82] Android: Fix Segfault when cancelling Android SDK installation Fixes: QTCREATORBUG-30246 Change-Id: I929779e4cd8c37c9d69bd7aaffe9ae5b9acb7435 Reviewed-by: Jarek Kobus Reviewed-by: Alessandro Portale --- src/plugins/android/androidsdkdownloader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androidsdkdownloader.cpp b/src/plugins/android/androidsdkdownloader.cpp index 6ff39dc4170..7246b5b9a3d 100644 --- a/src/plugins/android/androidsdkdownloader.cpp +++ b/src/plugins/android/androidsdkdownloader.cpp @@ -100,8 +100,8 @@ void AndroidSdkDownloader::downloadAndExtractSdk() m_progressDialog->setFixedSize(m_progressDialog->sizeHint()); m_progressDialog->setAutoClose(false); connect(m_progressDialog.get(), &QProgressDialog::canceled, this, [this] { - m_progressDialog.release()->deleteLater(); m_taskTreeRunner.reset(); + m_progressDialog.release()->deleteLater(); }); Storage> storage; @@ -116,6 +116,8 @@ void AndroidSdkDownloader::downloadAndExtractSdk() return; connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 received, qint64 max) { + if (!m_progressDialog) + return; m_progressDialog->setRange(0, max); m_progressDialog->setValue(received); }); From e3bbace6654ce0bfc3891066720084e8f7957a44 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 8 Feb 2024 13:45:47 +0100 Subject: [PATCH 21/82] TextEditor: fix double delete in synchronous syntax highlighter Change-Id: Ic4b9b78e5464613b9982814d771925d41f88bb25 Reviewed-by: Artem Sokolovskii --- .../texteditor/syntaxhighlighterrunner.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.cpp b/src/plugins/texteditor/syntaxhighlighterrunner.cpp index 094e97e7a08..68a1962f965 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.cpp +++ b/src/plugins/texteditor/syntaxhighlighterrunner.cpp @@ -33,20 +33,21 @@ public: const QString &mimeType, FontSettings fontSettings) { + m_highlighter = creator(); + m_highlighter->setFontSettings(fontSettings); + m_highlighter->setMimeType(mimeType); + if (async) { m_document = new QTextDocument(this); m_document->setDocumentLayout(new TextDocumentLayout(m_document)); + m_highlighter->setParent(m_document); } else { m_document = document; } - m_highlighter.reset(creator()); - m_highlighter->setFontSettings(fontSettings); m_highlighter->setDocument(m_document); - m_highlighter->setMimeType(mimeType); - m_highlighter->setParent(m_document); - connect(m_highlighter.get(), + connect(m_highlighter, &SyntaxHighlighter::resultsReady, this, &SyntaxHighlighterRunnerPrivate::resultsReady); @@ -102,7 +103,7 @@ public: void rehighlight() { m_highlighter->rehighlight(); } - std::unique_ptr m_highlighter; + SyntaxHighlighter *m_highlighter = nullptr; QTextDocument *m_document = nullptr; signals: @@ -118,7 +119,7 @@ SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighterCreator creato : d(new SyntaxHighlighterRunnerPrivate(creator, document, async, mimeType, fontSettings)) , m_document(document) { - m_useGenericHighlighter = qobject_cast(d->m_highlighter.get()); + m_useGenericHighlighter = qobject_cast(d->m_highlighter); if (async) { m_thread.emplace(); @@ -163,6 +164,7 @@ SyntaxHighlighterRunner::~SyntaxHighlighterRunner() m_thread->quit(); m_thread->wait(); } else { + delete d->m_highlighter; delete d; } } From 0422374e04cec9736454bec5fa576696fcd60f8e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 8 Feb 2024 13:46:12 +0100 Subject: [PATCH 22/82] TextEditor: remove unused function of syntax highlighter Change-Id: I9debd22730fcf2c9423beaaa5666ce282ed0bbe0 Reviewed-by: Artem Sokolovskii --- src/plugins/texteditor/syntaxhighlighter.cpp | 21 +++++--------------- src/plugins/texteditor/syntaxhighlighter.h | 2 -- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index 8c9cc194371..0ed00af389d 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -60,7 +60,6 @@ public: QList formats; QList> formatCategories; QTextCharFormat whitespaceFormat; - bool noAutomaticHighlighting = false; QString mimeType; }; @@ -345,12 +344,11 @@ void SyntaxHighlighter::setDocument(QTextDocument *doc) d->doc = doc; documentChanged(oldDoc, d->doc); if (d->doc) { - if (!d->noAutomaticHighlighting) { - connect(d->doc, &QTextDocument::contentsChange, this, &SyntaxHighlighter::reformatBlocks); - d->rehighlightPending = true; - QMetaObject::invokeMethod(this, &SyntaxHighlighter::delayedRehighlight, - Qt::QueuedConnection); - } + connect(d->doc, &QTextDocument::contentsChange, this, &SyntaxHighlighter::reformatBlocks); + d->rehighlightPending = true; + QMetaObject::invokeMethod(this, + &SyntaxHighlighter::delayedRehighlight, + Qt::QueuedConnection); d->foldValidator.setup(qobject_cast(doc->documentLayout())); } } @@ -846,15 +844,6 @@ FontSettings SyntaxHighlighter::fontSettings() const Q_D(const SyntaxHighlighter); return d->fontSettings; } -/*! - The syntax highlighter is not anymore reacting to the text document if \a noAutomatic is - \c true. -*/ -void SyntaxHighlighter::setNoAutomaticHighlighting(bool noAutomatic) -{ - Q_D(SyntaxHighlighter); - d->noAutomaticHighlighting = noAutomatic; -} /*! Creates text format categories for the text styles themselves, so the highlighter can diff --git a/src/plugins/texteditor/syntaxhighlighter.h b/src/plugins/texteditor/syntaxhighlighter.h index dbd57a45884..94cee8a65ef 100644 --- a/src/plugins/texteditor/syntaxhighlighter.h +++ b/src/plugins/texteditor/syntaxhighlighter.h @@ -53,8 +53,6 @@ public: virtual void setFontSettings(const TextEditor::FontSettings &fontSettings); TextEditor::FontSettings fontSettings() const; - void setNoAutomaticHighlighting(bool noAutomatic); - enum State { InProgress, Done From 98acd227345c6074922bd9c281ff1732879b63c1 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Thu, 8 Feb 2024 17:57:06 +0100 Subject: [PATCH 23/82] DiffEditor: Init some more members to nullptr Change-Id: Ia08c0ce5d6641533fe08f0a500f7439ec79882d8 Reviewed-by: Orgad Shaneh --- src/plugins/diffeditor/diffeditor.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/diffeditor/diffeditor.h b/src/plugins/diffeditor/diffeditor.h index e00a6e0fe49..60f7a772140 100644 --- a/src/plugins/diffeditor/diffeditor.h +++ b/src/plugins/diffeditor/diffeditor.h @@ -79,12 +79,12 @@ private: QComboBox *m_entriesComboBox = nullptr; QSpinBox *m_contextSpinBox = nullptr; QAction *m_contextSpinBoxAction = nullptr; - QAction *m_toggleSyncAction; - QAction *m_whitespaceButtonAction; - QAction *m_toggleDescriptionAction; - QAction *m_reloadAction; + QAction *m_toggleSyncAction = nullptr; + QAction *m_whitespaceButtonAction = nullptr; + QAction *m_toggleDescriptionAction = nullptr; + QAction *m_reloadAction = nullptr; QAction *m_contextLabelAction = nullptr; - QAction *m_viewSwitcherAction; + QAction *m_viewSwitcherAction = nullptr; QPair m_currentFileChunk; int m_currentViewIndex = -1; int m_currentDiffFileIndex = -1; From 7454f849014171134e620893f9afc4b7b3f05bf0 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 5 Feb 2024 13:49:27 +0100 Subject: [PATCH 24/82] CMakePM: When using presets only use presets for candidates Since the CMake presets is built upon Imports, when loading the presets it's better to only use the candidates from preset Kits and not any matching Kit that could handle the build directory. This makes working with CMake Presets a bit easier. Task-number: QTCREATORBUG-29535 Change-Id: I895e2e9162763e4cf3af5cdef5c9d5b228211fab Reviewed-by: Marcus Tillmanns --- .../cmakeprojectimporter.cpp | 35 ++++++++++++------- .../cmakeprojectimporter.h | 1 + 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 2d9631eb400..2ff01898cdc 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -147,20 +147,31 @@ static QString displayPresetName(const QString &presetName) FilePaths CMakeProjectImporter::importCandidates() { - FilePaths candidates; + FilePaths candidates = presetCandidates(); - candidates << scanDirectory(projectFilePath().absolutePath(), "build"); + if (candidates.isEmpty()) { + candidates << scanDirectory(projectFilePath().absolutePath(), "build"); - const QList kits = KitManager::kits(); - for (const Kit *k : kits) { - FilePath shadowBuildDirectory - = CMakeBuildConfiguration::shadowBuildDirectory(projectFilePath(), - k, - QString(), - BuildConfiguration::Unknown); - candidates << scanDirectory(shadowBuildDirectory.absolutePath(), QString()); + const QList kits = KitManager::kits(); + for (const Kit *k : kits) { + FilePath shadowBuildDirectory + = CMakeBuildConfiguration::shadowBuildDirectory(projectFilePath(), + k, + QString(), + BuildConfiguration::Unknown); + candidates << scanDirectory(shadowBuildDirectory.absolutePath(), QString()); + } } + const FilePaths finalists = Utils::filteredUnique(candidates); + qCInfo(cmInputLog) << "import candidates:" << finalists; + return finalists; +} + +FilePaths CMakeProjectImporter::presetCandidates() +{ + FilePaths candidates; + for (const auto &configPreset : m_project->presetsData().configurePresets) { if (configPreset.hidden.value()) continue; @@ -190,9 +201,7 @@ FilePaths CMakeProjectImporter::importCandidates() } } - const FilePaths finalists = Utils::filteredUnique(candidates); - qCInfo(cmInputLog) << "import candidates:" << finalists; - return finalists; + return candidates; } Target *CMakeProjectImporter::preferredTarget(const QList &possibleTargets) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h index ba8af4d61bc..e3b329e722f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h @@ -25,6 +25,7 @@ public: Utils::FilePaths importCandidates() final; ProjectExplorer::Target *preferredTarget(const QList &possibleTargets) final; + Utils::FilePaths presetCandidates(); private: QList examineDirectory(const Utils::FilePath &importPath, QString *warningMessage) const final; From 5328674479502660586d4fbc9757c494141bd8b3 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 8 Feb 2024 14:17:20 +0100 Subject: [PATCH 25/82] TextEditor: simplify SyntaxHighlighterRunner interface Change-Id: I6c8d51d8dccc91514c89267eac2cea66c87a871a Reviewed-by: Artem Sokolovskii Reviewed-by: Jarek Kobus --- .../texteditor/syntaxhighlighterrunner.cpp | 19 ++++++------------- .../texteditor/syntaxhighlighterrunner.h | 7 +------ src/plugins/texteditor/textdocument.cpp | 8 +++++--- .../highlighter/tst_highlighter.cpp | 5 ++--- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.cpp b/src/plugins/texteditor/syntaxhighlighterrunner.cpp index 68a1962f965..bf53d90561b 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.cpp +++ b/src/plugins/texteditor/syntaxhighlighterrunner.cpp @@ -27,16 +27,11 @@ class SyntaxHighlighterRunnerPrivate : public QObject { Q_OBJECT public: - SyntaxHighlighterRunnerPrivate(SyntaxHighlighterRunner::SyntaxHighlighterCreator creator, + SyntaxHighlighterRunnerPrivate(SyntaxHighlighter *highlighter, QTextDocument *document, - bool async, - const QString &mimeType, - FontSettings fontSettings) + bool async) + : m_highlighter(highlighter) { - m_highlighter = creator(); - m_highlighter->setFontSettings(fontSettings); - m_highlighter->setMimeType(mimeType); - if (async) { m_document = new QTextDocument(this); m_document->setDocumentLayout(new TextDocumentLayout(m_document)); @@ -111,12 +106,10 @@ signals: }; -SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighterCreator creator, +SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter, QTextDocument *document, - bool async, - const QString &mimeType, - const TextEditor::FontSettings &fontSettings) - : d(new SyntaxHighlighterRunnerPrivate(creator, document, async, mimeType, fontSettings)) + bool async) + : d(new SyntaxHighlighterRunnerPrivate(highlighter, document, async)) , m_document(document) { m_useGenericHighlighter = qobject_cast(d->m_highlighter); diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.h b/src/plugins/texteditor/syntaxhighlighterrunner.h index 7202ebf401d..ccb292ea086 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.h +++ b/src/plugins/texteditor/syntaxhighlighterrunner.h @@ -24,12 +24,7 @@ class TEXTEDITOR_EXPORT SyntaxHighlighterRunner : public QObject public: using SyntaxHighlighterCreator = std::function; - SyntaxHighlighterRunner( - SyntaxHighlighterCreator creator, - QTextDocument *document, - bool async, - const QString &mimeType, - const TextEditor::FontSettings &fontSettings = TextEditorSettings::fontSettings()); + SyntaxHighlighterRunner(SyntaxHighlighter *highlighter, QTextDocument *document, bool async); virtual ~SyntaxHighlighterRunner(); void setExtraFormats(const QMap> &formats); diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index a60c729ed4a..cb421f2bf7c 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -921,10 +921,12 @@ void TextDocument::resetSyntaxHighlighter(const std::functionm_highlighterRunner = new SyntaxHighlighterRunner(creator, + SyntaxHighlighter *highlighter = creator(); + highlighter->setFontSettings(TextEditorSettings::fontSettings()); + highlighter->setMimeType(mimeType()); + d->m_highlighterRunner = new SyntaxHighlighterRunner(highlighter, document(), - threaded && envValue, - mimeType()); + threaded && envValue); } void TextDocument::cleanWhitespace(const QTextCursor &cursor) diff --git a/tests/auto/texteditor/highlighter/tst_highlighter.cpp b/tests/auto/texteditor/highlighter/tst_highlighter.cpp index aaba61161bc..9044065a019 100644 --- a/tests/auto/texteditor/highlighter/tst_highlighter.cpp +++ b/tests/auto/texteditor/highlighter/tst_highlighter.cpp @@ -58,9 +58,8 @@ Last)"; doc = new QTextDocument(); doc->setPlainText(text); - - highlighterRunner = new SyntaxHighlighterRunner( - [this] { return new SyntaxHighlighter(doc, fontsettings); }, doc, false, {}, fontsettings); + auto highlighter = new SyntaxHighlighter(doc, fontsettings); + highlighterRunner = new SyntaxHighlighterRunner(highlighter, doc, false); } static const HighlightingResults &highlightingResults() From e073c54d0115c8f64145e4097406c2ee761675ec Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 8 Feb 2024 17:45:34 +0100 Subject: [PATCH 26/82] Terminal: Fix opening terminals on remote devices When the active project is on a remote device the working directory is set to its root directory. In this case we need to find the right shell binary from the remote device. Change-Id: I6b541273d23a8de5442ac041b28d81984ed5ef65 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalpane.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 111e6d2d992..096fffcba1f 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -106,6 +106,17 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) } } + if (parametersCopy.workingDirectory->needsDevice() && !parametersCopy.shellCommand) { + const FilePath shell = parametersCopy.workingDirectory->withNewPath( + parametersCopy.environment + .value_or(parametersCopy.workingDirectory->deviceEnvironment()) + .value_or("SHELL", "/bin/sh")); + if (!shell.isExecutableFile()) + parametersCopy.workingDirectory.reset(); + else + parametersCopy.shellCommand = CommandLine{shell, {}}; + } + const auto terminalWidget = new TerminalWidget(&m_tabWidget, parametersCopy); using namespace Constants; From f18dcf2202acbdb1573608e2f210d25407625c2c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 8 Feb 2024 14:41:02 +0100 Subject: [PATCH 27/82] TextEditor: Fix capitalization Change-Id: I220426e01c97eceab607e3b5c31bd8e294f48273 Reviewed-by: David Schulz --- src/plugins/texteditor/displaysettingspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index e46c5b7c5b4..b5435ed5e91 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -98,7 +98,7 @@ public: visualizeWhitespace = new QCheckBox(Tr::tr("&Visualize whitespace")); visualizeWhitespace->setToolTip(Tr::tr("Shows tabs and spaces.")); - highlightSelection = new QCheckBox(Tr::tr("&Highlight Selection")); + highlightSelection = new QCheckBox(Tr::tr("&Highlight selection")); highlightSelection->setToolTip(Tr::tr("Adds a colored background and a marker to the " "scrollbar to occurrences of the selected text.")); From a020c13e10b324775667b799fdee67c86a09d106 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 8 Feb 2024 15:15:56 +0100 Subject: [PATCH 28/82] Filepath: Fix operator<() Previously a QMap with FilePath as key would return wrong entries when comparing paths with and without scheme/host. Change-Id: Icc5d119a18c1b7a2fdab9c89f162c48859926523 Reviewed-by: Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 30 ++++++++++++---- tests/auto/utils/filepath/tst_filepath.cpp | 41 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 5678be86b2b..562f3247bd8 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -2334,12 +2334,30 @@ QTCREATOR_UTILS_EXPORT bool operator!=(const FilePath &first, const FilePath &se QTCREATOR_UTILS_EXPORT bool operator<(const FilePath &first, const FilePath &second) { - const int cmp = first.pathView().compare(second.pathView(), first.caseSensitivity()); - if (cmp != 0) - return cmp < 0; - if (first.host() != second.host()) - return first.host() < second.host(); - return first.scheme() < second.scheme(); + const bool firstNeedsDevice = first.needsDevice(); + const bool secondNeedsDevice = second.needsDevice(); + + // If either needs a device, we have to compare host and scheme first. + if (firstNeedsDevice || secondNeedsDevice) { + // Paths needing a device are "larger" than those not needing one. + if (firstNeedsDevice < secondNeedsDevice) + return true; + else if (firstNeedsDevice > secondNeedsDevice) + return false; + + // First we sort by scheme ... + const int s = first.scheme().compare(second.scheme()); + if (s != 0) + return s < 0; + + // than by host ... + const int h = first.host().compare(second.host()); + if (h != 0) + return h < 0; + } + + const int p = first.pathView().compare(second.pathView(), first.caseSensitivity()); + return p < 0; } QTCREATOR_UTILS_EXPORT bool operator<=(const FilePath &first, const FilePath &second) diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index 0cd0629609e..369fb6a2584 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -117,6 +117,11 @@ private slots: void isRootPath(); + void lessThan(); + void lessThan_data(); + + void asQMapKey(); + private: QTemporaryDir tempDir; QString rootPath; @@ -1666,6 +1671,42 @@ void tst_filepath::sort() QCOMPARE(sortedPaths, sorted); } +void tst_filepath::lessThan_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << FilePath() << FilePath() << false; + QTest::newRow("simple") << FilePath("/a") << FilePath("/b") << true; + QTest::newRow("simple-2") << FilePath("/a") << FilePath("/a") << false; + QTest::newRow("simple-3") << FilePath("/b") << FilePath("/a") << false; + + QTest::newRow("remote-vs-local") << FilePath("docker://1234/a") << FilePath("/a") << false; + QTest::newRow("local-vs-remote") << FilePath("/a") << FilePath("docker://1234/a") << true; + + QTest::newRow("remote-vs-local-2") << FilePath("docker://1234/a") << FilePath("/b") << false; + QTest::newRow("local-vs-remote-2") << FilePath("/a") << FilePath("docker://1234/b") << true; +} + +void tst_filepath::lessThan() +{ + QFETCH(FilePath, left); + QFETCH(FilePath, right); + QFETCH(bool, expected); + + QCOMPARE(left < right, expected); +} + +void tst_filepath::asQMapKey() +{ + QMap map; + map.insert(FilePath::fromString("/Users/mtillmanns/projects/qt/qtc-work/fsengine"), 1); + + QCOMPARE(map.contains(FilePath::fromString("ssh://marcus@mad-ubuntu-23.local/tmp/untitled")), + false); +} + void tst_filepath::isRootPath() { FilePath localRoot = FilePath::fromString(QDir::rootPath()); From 4e5692d62830292d35d80b06e173ddc3744cbffa Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 7 Feb 2024 17:15:49 +0100 Subject: [PATCH 29/82] Vcs: Use QString and Id in editor parameters instead of char * ... and use it to simplify the translation setup. Change-Id: Ibd386ede3ecfc351316bed53bc184954adbcaa74 Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/bazaar/bazaarplugin.cpp | 10 +++++----- src/plugins/bazaar/constants.h | 5 ----- src/plugins/clearcase/clearcaseconstants.h | 1 - src/plugins/clearcase/clearcaseplugin.cpp | 9 +++++---- src/plugins/cvs/cvsplugin.cpp | 12 ++++++------ src/plugins/fossil/constants.h | 12 ++---------- src/plugins/fossil/fossilplugin.cpp | 9 +++++---- src/plugins/git/gitconstants.h | 15 ++------------- src/plugins/git/gitplugin.cpp | 15 ++++++++------- src/plugins/mercurial/constants.h | 6 ------ src/plugins/mercurial/mercurialplugin.cpp | 9 +++++---- src/plugins/perforce/perforceplugin.cpp | 16 +++++----------- src/plugins/subversion/subversionconstants.h | 11 ++--------- src/plugins/subversion/subversionplugin.cpp | 7 ++++--- src/plugins/vcsbase/vcsbaseeditor.cpp | 8 ++++---- src/plugins/vcsbase/vcsbaseeditor.h | 6 +++--- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 8 ++++---- src/plugins/vcsbase/vcsbasesubmiteditor.h | 6 +++--- 18 files changed, 63 insertions(+), 102 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 14046d738f0..8ca92f83a1c 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +63,6 @@ namespace Bazaar::Internal { // Submit editor parameters const char COMMIT_ID[] = "Bazaar Commit Log Editor"; -const char COMMIT_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar Commit Log Editor"); const char COMMITMIMETYPE[] = "text/vnd.qtcreator.bazaar.commit"; // Menu items @@ -202,7 +202,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, // type Constants::FILELOG_ID, // id - Constants::FILELOG_DISPLAY_NAME, // display name + VcsBase::Tr::tr("Bazaar File Log Editor"), Constants::LOGAPP,// mime type [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) @@ -211,7 +211,7 @@ public: VcsEditorFactory annotateEditorFactory {{ AnnotateOutput, Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, + VcsBase::Tr::tr("Bazaar Annotation Editor"), Constants::ANNOTATEAPP, [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) @@ -220,7 +220,7 @@ public: VcsEditorFactory diffEditorFactory {{ DiffOutput, Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, + VcsBase::Tr::tr("Bazaar Diff Editor"), Constants::DIFFAPP, [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) @@ -480,7 +480,7 @@ BazaarPluginPrivate::BazaarPluginPrivate() setupVcsSubmitEditor(this, { COMMITMIMETYPE, COMMIT_ID, - COMMIT_DISPLAY_NAME, + VcsBase::Tr::tr("Bazaar Commit Log Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CommitEditor; } }); diff --git a/src/plugins/bazaar/constants.h b/src/plugins/bazaar/constants.h index e2cdb549bb3..9672d063442 100644 --- a/src/plugins/bazaar/constants.h +++ b/src/plugins/bazaar/constants.h @@ -3,8 +3,6 @@ #pragma once -#include - namespace Bazaar::Constants { const char BAZAAR[] = "bazaar"; @@ -23,15 +21,12 @@ const char ANNOTATE_CHANGESET_ID[] = "([.0-9]+)"; // Base editor parameters const char FILELOG_ID[] = "Bazaar File Log Editor"; -const char FILELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar File Log Editor"); const char LOGAPP[] = "text/vnd.qtcreator.bazaar.log"; const char ANNOTATELOG_ID[] = "Bazaar Annotation Editor"; -const char ANNOTATELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar Annotation Editor"); const char ANNOTATEAPP[] = "text/vnd.qtcreator.bazaar.annotation"; const char DIFFLOG_ID[] = "Bazaar Diff Editor"; -const char DIFFLOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar Diff Editor"); const char DIFFAPP[] = "text/x-patch"; // File status hint diff --git a/src/plugins/clearcase/clearcaseconstants.h b/src/plugins/clearcase/clearcaseconstants.h index fe42967e555..97d57eb9bda 100644 --- a/src/plugins/clearcase/clearcaseconstants.h +++ b/src/plugins/clearcase/clearcaseconstants.h @@ -11,7 +11,6 @@ namespace Constants { const char VCS_ID_CLEARCASE[] = "E.ClearCase"; const char CLEARCASE_SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.clearcase.submit"; const char CLEARCASECHECKINEDITOR_ID[] = "ClearCase Check In Editor"; -const char CLEARCASECHECKINEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Check In Editor"); const char TASK_INDEX[] = "ClearCase.Task.Index"; const char KEEP_ACTIVITY[] = "__KEEP__"; enum { debug = 0 }; diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index f07c2348592..f566b8223d4 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -297,7 +298,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, LOG_EDITOR_ID, - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase File Log Editor"), // display_name + VcsBase::Tr::tr("ClearCase File Log Editor"), // display_name "text/vnd.qtcreator.clearcase.log", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) @@ -306,7 +307,7 @@ public: VcsEditorFactory annotateEditorFactory {{ AnnotateOutput, ANNOTATION_EDITOR_ID, - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Annotation Editor"), // display_name + VcsBase::Tr::tr("ClearCase Annotation Editor"), // display_name "text/vnd.qtcreator.clearcase.annotation", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) @@ -315,7 +316,7 @@ public: VcsEditorFactory diffEditorFactory {{ DiffOutput, DIFF_EDITOR_ID, - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Diff Editor"), // display_name + VcsBase::Tr::tr("ClearCase Diff Editor"), // display_name "text/x-patch", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) @@ -732,7 +733,7 @@ ClearCasePluginPrivate::ClearCasePluginPrivate() setupVcsSubmitEditor(this, { Constants::CLEARCASE_SUBMIT_MIMETYPE, Constants::CLEARCASECHECKINEDITOR_ID, - Constants::CLEARCASECHECKINEDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("ClearCase Check In Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new ClearCaseSubmitEditor; } }); diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 387e74e18fe..4ca9dd83b39 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -88,7 +89,6 @@ const char CMD_ID_REPOSITORYUPDATE[] = "CVS.RepositoryUpdate"; const char CVS_SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.cvs.submit"; const char CVSCOMMITEDITOR_ID[] = "CVS Commit Editor"; -const char CVSCOMMITEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Commit Editor"); const char CVS_COMMANDLOG_EDITOR_ID[] = "CVS Command Log Editor"; const char CVS_FILELOG_EDITOR_ID[] = "CVS File Log Editor"; @@ -292,7 +292,7 @@ public: VcsEditorFactory commandLogEditorFactory {{ OtherContent, CVS_COMMANDLOG_EDITOR_ID, - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Command Log Editor"), // display name + VcsBase::Tr::tr("CVS Command Log Editor"), // display name "text/vnd.qtcreator.cvs.commandlog", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -301,7 +301,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, CVS_FILELOG_EDITOR_ID, - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS File Log Editor"), // display name + VcsBase::Tr::tr("CVS File Log Editor"), // display name "text/vnd.qtcreator.cvs.log", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -310,7 +310,7 @@ public: VcsEditorFactory annotateEditorFactory {{ AnnotateOutput, CVS_ANNOTATION_EDITOR_ID, - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Annotation Editor"), // display name + VcsBase::Tr::tr("CVS Annotation Editor"), // display name "text/vnd.qtcreator.cvs.annotation", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -319,7 +319,7 @@ public: VcsEditorFactory diffEditorFactory {{ DiffOutput, CVS_DIFF_EDITOR_ID, - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Diff Editor"), // display name + VcsBase::Tr::tr("CVS Diff Editor"), // display name "text/x-patch", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -449,7 +449,7 @@ CvsPluginPrivate::CvsPluginPrivate() setupVcsSubmitEditor(this, { CVS_SUBMIT_MIMETYPE, CVSCOMMITEDITOR_ID, - CVSCOMMITEDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("CVS Commit Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CvsSubmitEditor; }, }); diff --git a/src/plugins/fossil/constants.h b/src/plugins/fossil/constants.h index 6dd6bd4d048..558c8fc3ed4 100644 --- a/src/plugins/fossil/constants.h +++ b/src/plugins/fossil/constants.h @@ -3,10 +3,7 @@ #pragma once -#include - -namespace Fossil { -namespace Constants { +namespace Fossil::Constants { const char VCS_ID_FOSSIL[] = "I.Fossil"; @@ -31,20 +28,16 @@ const char DIFFFILE_ID_EXACT[] = "[+]{3} (.*)\\s*"; // match and capture //BaseEditorParameters const char FILELOG_ID[] = "Fossil File Log Editor"; -const char FILELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil File Log Editor"); const char LOGAPP[] = "text/vnd.qtcreator.fossil.log"; const char ANNOTATELOG_ID[] = "Fossil Annotation Editor"; -const char ANNOTATELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil Annotation Editor"); const char ANNOTATEAPP[] = "text/vnd.qtcreator.fossil.annotation"; const char DIFFLOG_ID[] = "Fossil Diff Editor"; -const char DIFFLOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil Diff Editor"); const char DIFFAPP[] = "text/x-patch"; //SubmitEditorParameters const char COMMIT_ID[] = "Fossil Commit Log Editor"; -const char COMMIT_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil Commit Log Editor"); const char COMMITMIMETYPE[] = "text/vnd.qtcreator.fossil.commit"; //menu items @@ -85,5 +78,4 @@ const char FSTATUS_UNKNOWN[] = "Unknown"; // Fossil Json Wizards const char WIZARD_PATH[] = ":/fossil/wizard"; -} // namespace Constants -} // namespace Fossil +} // Fossil::Constants diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 40138f281ba..b09ffda013b 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -152,7 +153,7 @@ public: VcsEditorFactory fileLogFactory {{ LogOutput, Constants::FILELOG_ID, - Constants::FILELOG_DISPLAY_NAME, + VcsBase::Tr::tr("Fossil File Log Editor"), Constants::LOGAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) @@ -161,7 +162,7 @@ public: VcsEditorFactory annotateLogFactory {{ AnnotateOutput, Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, + VcsBase::Tr::tr("Fossil Annotation Editor"), Constants::ANNOTATEAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) @@ -170,7 +171,7 @@ public: VcsEditorFactory diffFactory {{ DiffOutput, Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, + VcsBase::Tr::tr("Fossil Diff Editor"), Constants::DIFFAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) @@ -238,7 +239,7 @@ FossilPluginPrivate::FossilPluginPrivate() setupVcsSubmitEditor(this, { Constants::COMMITMIMETYPE, Constants::COMMIT_ID, - Constants::COMMIT_DISPLAY_NAME, + VcsBase::Tr::tr("Fossil Commit Log Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CommitEditor; } }); diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h index 32d456ca165..ecd966c77c9 100644 --- a/src/plugins/git/gitconstants.h +++ b/src/plugins/git/gitconstants.h @@ -3,30 +3,20 @@ #pragma once -#include - -namespace Git { -namespace Constants { +namespace Git::Constants { const char GIT_PLUGIN[] = "GitPlugin"; const char GIT_SVN_LOG_EDITOR_ID[] = "Git SVN Log Editor"; -const char GIT_SVN_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git SVN Log Editor"); const char GIT_LOG_EDITOR_ID[] = "Git Log Editor"; -const char GIT_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Log Editor"); const char GIT_REFLOG_EDITOR_ID[] = "Git Reflog Editor"; -const char GIT_REFLOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Reflog Editor"); const char GIT_BLAME_EDITOR_ID[] = "Git Annotation Editor"; -const char GIT_BLAME_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Annotation Editor"); const char GIT_COMMIT_TEXT_EDITOR_ID[] = "Git Commit Editor"; -const char GIT_COMMIT_TEXT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Commit Editor"); const char GIT_REBASE_EDITOR_ID[] = "Git Rebase Editor"; -const char GIT_REBASE_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Rebase Editor"); const char GIT_BRANCH_VIEW_ID[] = "Git Branches"; const char GIT_CONTEXT[] = "Git Context"; const char GITSUBMITEDITOR_ID[] = "Git Submit Editor"; -const char GITSUBMITEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Submit Editor"); const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.git.submit"; const char C_GITEDITORID[] = "Git Editor"; @@ -38,5 +28,4 @@ const char DEFAULT_COMMENT_CHAR = '#'; const char TEXT_MARK_CATEGORY_BLAME[] = "Git.Mark.Blame"; -} // namespace Constants -} // namespace Git +} // Git::Constants diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 993ea54fb49..9535f14128d 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -327,7 +328,7 @@ public: VcsEditorFactory svnLogEditorFactory {{ OtherContent, Git::Constants::GIT_SVN_LOG_EDITOR_ID, - Git::Constants::GIT_SVN_LOG_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git SVN Log Editor"), "text/vnd.qtcreator.git.svnlog", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) @@ -336,7 +337,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, Git::Constants::GIT_LOG_EDITOR_ID, - Git::Constants::GIT_LOG_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git Log Editor"), "text/vnd.qtcreator.git.log", [] { return new GitLogEditorWidgetT; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) @@ -345,7 +346,7 @@ public: VcsEditorFactory reflogEditorFactory {{ LogOutput, Git::Constants::GIT_REFLOG_EDITOR_ID, - Git::Constants::GIT_REFLOG_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git Reflog Editor"), "text/vnd.qtcreator.git.reflog", [] { return new GitLogEditorWidgetT; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) @@ -354,7 +355,7 @@ public: VcsEditorFactory blameEditorFactory {{ AnnotateOutput, Git::Constants::GIT_BLAME_EDITOR_ID, - Git::Constants::GIT_BLAME_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git Annotation Editor"), "text/vnd.qtcreator.git.annotation", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) @@ -363,7 +364,7 @@ public: VcsEditorFactory commitTextEditorFactory {{ OtherContent, Git::Constants::GIT_COMMIT_TEXT_EDITOR_ID, - Git::Constants::GIT_COMMIT_TEXT_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git Commit Editor"), "text/vnd.qtcreator.git.commit", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) @@ -372,7 +373,7 @@ public: VcsEditorFactory rebaseEditorFactory {{ OtherContent, Git::Constants::GIT_REBASE_EDITOR_ID, - Git::Constants::GIT_REBASE_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git Rebase Editor"), "text/vnd.qtcreator.git.rebase", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) @@ -931,7 +932,7 @@ GitPluginPrivate::GitPluginPrivate() setupVcsSubmitEditor(this, { Git::Constants::SUBMIT_MIMETYPE, Git::Constants::GITSUBMITEDITOR_ID, - Git::Constants::GITSUBMITEDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git Submit Editor"), VcsBaseSubmitEditorParameters::DiffRows, [] { return new GitSubmitEditor; }, }); diff --git a/src/plugins/mercurial/constants.h b/src/plugins/mercurial/constants.h index e38871e4aa7..ee2738dbcac 100644 --- a/src/plugins/mercurial/constants.h +++ b/src/plugins/mercurial/constants.h @@ -3,8 +3,6 @@ #pragma once -#include - namespace Mercurial::Constants { enum { debug = 0 }; @@ -23,20 +21,16 @@ const char DIFFIDENTIFIER[] = "^(?:diff --git a/|[+-]{3} (?:/dev/null|[ab]/(.+$) // Base editor parameters const char FILELOG_ID[] = "Mercurial File Log Editor"; -const char FILELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial File Log Editor"); const char LOGAPP[] = "text/vnd.qtcreator.mercurial.log"; const char ANNOTATELOG_ID[] = "Mercurial Annotation Editor"; -const char ANNOTATELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial Annotation Editor"); const char ANNOTATEAPP[] = "text/vnd.qtcreator.mercurial.annotation"; const char DIFFLOG_ID[] = "Mercurial Diff Editor"; -const char DIFFLOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial Diff Editor"); const char DIFFAPP[] = "text/x-patch"; // Submit editor parameters const char COMMIT_ID[] = "Mercurial Commit Log Editor"; -const char COMMIT_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial Commit Log Editor"); const char COMMITMIMETYPE[] = "text/vnd.qtcreator.mercurial.commit"; // File menu actions diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index bd691d47e4c..1fa1fc8155e 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -162,7 +163,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, Constants::FILELOG_ID, - Constants::FILELOG_DISPLAY_NAME, + VcsBase::Tr::tr("Mercurial File Log Editor"), Constants::LOGAPP, [this] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) @@ -171,7 +172,7 @@ public: VcsEditorFactory annotateEditorFactory {{ AnnotateOutput, Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, + VcsBase::Tr::tr("Mercurial Annotation Editor"), Constants::ANNOTATEAPP, [this] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) @@ -180,7 +181,7 @@ public: VcsEditorFactory diffEditorFactory {{ DiffOutput, Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, + VcsBase::Tr::tr("Mercurial Diff Editor"), Constants::DIFFAPP, [this] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) @@ -197,7 +198,7 @@ MercurialPluginPrivate::MercurialPluginPrivate() setupVcsSubmitEditor(this, { Constants::COMMITMIMETYPE, Constants::COMMIT_ID, - Constants::COMMIT_DISPLAY_NAME, + VcsBase::Tr::tr("Mercurial Commit Log Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CommitEditor; } }); diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 7bca24a7be7..42e2bbfcb18 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -62,16 +63,9 @@ const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.p4.submit"; const char PERFORCE_CONTEXT[] = "Perforce Context"; const char PERFORCE_SUBMIT_EDITOR_ID[] = "Perforce.SubmitEditor"; -const char PERFORCE_SUBMIT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce.SubmitEditor"); - const char PERFORCE_LOG_EDITOR_ID[] = "Perforce.LogEditor"; -const char PERFORCE_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce Log Editor"); - const char PERFORCE_DIFF_EDITOR_ID[] = "Perforce.DiffEditor"; -const char PERFORCE_DIFF_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce Diff Editor"); - const char PERFORCE_ANNOTATION_EDITOR_ID[] = "Perforce.AnnotationEditor"; -const char PERFORCE_ANNOTATION_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce Annotation Editor"); // Ensure adding "..." to relative paths which is p4's convention // for the current directory @@ -306,7 +300,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, PERFORCE_LOG_EDITOR_ID, - PERFORCE_LOG_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Perforce Log Editor"), "text/vnd.qtcreator.p4.log", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) @@ -315,7 +309,7 @@ public: VcsEditorFactory annotateEditorFactory {{ AnnotateOutput, PERFORCE_ANNOTATION_EDITOR_ID, - PERFORCE_ANNOTATION_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Perforce Annotation Editor"), "text/vnd.qtcreator.p4.annotation", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) @@ -324,7 +318,7 @@ public: VcsEditorFactory diffEditorFactory {{ DiffOutput, PERFORCE_DIFF_EDITOR_ID, - PERFORCE_DIFF_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Perforce Diff Editor"), "text/x-patch", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) @@ -343,7 +337,7 @@ PerforcePluginPrivate::PerforcePluginPrivate() setupVcsSubmitEditor(this, { SUBMIT_MIMETYPE, PERFORCE_SUBMIT_EDITOR_ID, - PERFORCE_SUBMIT_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Perforce.SubmitEditor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new PerforceSubmitEditor; }, }); diff --git a/src/plugins/subversion/subversionconstants.h b/src/plugins/subversion/subversionconstants.h index b0d6ce8f45a..2b834ed64ae 100644 --- a/src/plugins/subversion/subversionconstants.h +++ b/src/plugins/subversion/subversionconstants.h @@ -3,10 +3,7 @@ #pragma once -#include - -namespace Subversion { -namespace Constants { +namespace Subversion::Constants { const char SUBVERSION_PLUGIN[] = "SubversionPlugin"; @@ -16,16 +13,12 @@ enum { debug = 0 }; const char SUBVERSION_CONTEXT[] = "Subversion Context"; const char SUBVERSION_COMMIT_EDITOR_ID[] = "Subversion Commit Editor"; -const char SUBVERSION_COMMIT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Subversion Commit Editor"); const char SUBVERSION_SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.svn.submit"; const char SUBVERSION_LOG_EDITOR_ID[] = "Subversion File Log Editor"; -const char SUBVERSION_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Subversion File Log Editor"); const char SUBVERSION_LOG_MIMETYPE[] = "text/vnd.qtcreator.svn.log"; const char SUBVERSION_BLAME_EDITOR_ID[] = "Subversion Annotation Editor"; -const char SUBVERSION_BLAME_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Subversion Annotation Editor"); const char SUBVERSION_BLAME_MIMETYPE[] = "text/vnd.qtcreator.svn.annotation"; -} // namespace Constants -} // namespace Subversion +} // Subversion::Constants diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index a5f146bf3d6..95a774e1f83 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -265,7 +266,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, Constants::SUBVERSION_LOG_EDITOR_ID, - Constants::SUBVERSION_LOG_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Subversion File Log Editor"), Constants::SUBVERSION_LOG_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) @@ -274,7 +275,7 @@ public: VcsEditorFactory blameEditorFactory {{ AnnotateOutput, Constants::SUBVERSION_BLAME_EDITOR_ID, - Constants::SUBVERSION_BLAME_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Subversion Annotation Editor"), Constants::SUBVERSION_BLAME_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) @@ -480,7 +481,7 @@ SubversionPluginPrivate::SubversionPluginPrivate() setupVcsSubmitEditor(this, { Constants::SUBVERSION_SUBMIT_MIMETYPE, Constants::SUBVERSION_COMMIT_EDITOR_ID, - Constants::SUBVERSION_COMMIT_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Subversion Commit Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new SubversionSubmitEditor; }, }); diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 13b8e647fe5..d365be71569 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -1651,16 +1651,16 @@ IEditor *VcsBaseEditor::locateEditorByTag(const QString &tag) VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters ¶meters) { setId(parameters.id); - setDisplayName(Tr::tr(parameters.displayName)); - if (QLatin1String(parameters.mimeType) != QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE)) - addMimeType(QLatin1String(parameters.mimeType)); + setDisplayName(parameters.displayName); + if (parameters.mimeType != DiffEditor::Constants::DIFF_EDITOR_MIMETYPE) + addMimeType(parameters.mimeType); setEditorActionHandlers(TextEditorActionHandler::None); setDuplicatedSupported(false); setDocumentCreator([parameters] { auto document = new TextDocument(parameters.id); - document->setMimeType(QLatin1String(parameters.mimeType)); + document->setMimeType(parameters.mimeType); document->setSuspendAllowed(false); return document; }); diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index 123f3ef9e40..04e698f4eae 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -42,9 +42,9 @@ class VCSBASE_EXPORT VcsBaseEditorParameters { public: EditorContentType type; - const char *id; - const char *displayName; - const char *mimeType; + Utils::Id id; + QString displayName; + QString mimeType; std::function editorWidgetCreator; std::function describeFunc; }; diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 79dcddc3f95..4c29da91f2f 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -147,10 +147,10 @@ void VcsBaseSubmitEditor::setParameters(const VcsBaseSubmitEditorParameters &par { d->m_parameters = parameters; d->m_file.setId(parameters.id); - d->m_file.setMimeType(QLatin1String(parameters.mimeType)); + d->m_file.setMimeType(parameters.mimeType); setWidget(d->m_widget); - document()->setPreferredDisplayName(Tr::tr(d->m_parameters.displayName)); + document()->setPreferredDisplayName(d->m_parameters.displayName); // Message font according to settings CompletingTextEdit *descriptionEdit = d->m_widget->descriptionEdit(); @@ -643,8 +643,8 @@ public: .bindContextAction(&diffAction); setId(parameters.id); - setDisplayName(QLatin1String(parameters.displayName)); - addMimeType(QLatin1String(parameters.mimeType)); + setDisplayName(parameters.displayName); + addMimeType(parameters.mimeType); setEditorCreator([parameters, submitAction, diffAction, undoAction, redoAction] { VcsBaseSubmitEditor *editor = parameters.editorCreator(); editor->setParameters(parameters); diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h index 204ab9b6af5..b2eb958a792 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.h +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h @@ -28,9 +28,9 @@ class VcsBaseSubmitEditorPrivate; class VCSBASE_EXPORT VcsBaseSubmitEditorParameters { public: - const char *mimeType; - const char *id; - const char *displayName; + QString mimeType; + Utils::Id id; + QString displayName; enum DiffType { DiffRows, DiffFiles } diffType; std::function editorCreator; }; From 0d40cc509363d79ed516294ba819a63686e63c26 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 8 Feb 2024 18:59:51 +0100 Subject: [PATCH 30/82] CMakePM: Fix conan generators path using backslashes This can cause issues with CMake, since CMake uses slashes as directory separator. Fixes: QTCREATORBUG-30326 Change-Id: I0c03b3bcd32bddc99fb361eb8e6aaffd0b1f10b6 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/share/3rdparty/package-manager/auto-setup.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/src/share/3rdparty/package-manager/auto-setup.cmake b/src/share/3rdparty/package-manager/auto-setup.cmake index a2e30686f9f..628b69cc768 100644 --- a/src/share/3rdparty/package-manager/auto-setup.cmake +++ b/src/share/3rdparty/package-manager/auto-setup.cmake @@ -137,6 +137,7 @@ macro(qtc_auto_setup_conan) get_property(CONAN_INSTALL_SUCCESS GLOBAL PROPERTY CONAN_INSTALL_SUCCESS) if (CONAN_INSTALL_SUCCESS) get_property(CONAN_GENERATORS_FOLDER GLOBAL PROPERTY CONAN_GENERATORS_FOLDER) + file(TO_CMAKE_PATH \"\${CONAN_GENERATORS_FOLDER}\" CONAN_GENERATORS_FOLDER) file(WRITE \"${CMAKE_BINARY_DIR}/conan-dependencies/conan_paths.cmake\" \" list(PREPEND CMAKE_PREFIX_PATH \\\"\${CONAN_GENERATORS_FOLDER}\\\") list(PREPEND CMAKE_MODULE_PATH \\\"\${CONAN_GENERATORS_FOLDER}\\\") From 8869fefb72df0223415d69d312d09fd6df5c3451 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 6 Feb 2024 19:02:24 +0100 Subject: [PATCH 31/82] Doc: Describe changes to ClangFormat preferences Task-number: QTCREATORBUG-30209 Change-Id: Iff7587cca92c016f2f6ff5f40150d620f623a9b2 Reviewed-by: Reviewed-by: Artem Sokolovskii --- ...tcreator-code-style-built-in-indenter.webp | Bin 0 -> 13192 bytes ...reator-code-style-clang-format-global.webp | Bin 15310 -> 15316 bytes ...eator-code-style-clang-format-project.webp | Bin 10152 -> 10864 bytes ...eator-code-style-settings-edit-qtquick.png | Bin 12603 -> 0 bytes .../qtcreator-options-code-style-qml.png | Bin 11935 -> 0 bytes .../qtcreator-preferences-nim-code-style.webp | Bin 8204 -> 8764 bytes ...reator-preferences-qtquick-code-style.webp | Bin 0 -> 10320 bytes .../creator-preferences-cpp-code-style.qdoc | 56 +++++++++--------- .../creator-only/creator-preferences-nim.qdoc | 10 ++-- .../creator-projects-settings-code-style.qdoc | 32 +++++----- ...reator-preferences-qtquick-code-style.qdoc | 22 +++---- 11 files changed, 56 insertions(+), 64 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-code-style-built-in-indenter.webp delete mode 100644 doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png delete mode 100644 doc/qtcreator/images/qtcreator-options-code-style-qml.png create mode 100644 doc/qtcreator/images/qtcreator-preferences-qtquick-code-style.webp diff --git a/doc/qtcreator/images/qtcreator-code-style-built-in-indenter.webp b/doc/qtcreator/images/qtcreator-code-style-built-in-indenter.webp new file mode 100644 index 0000000000000000000000000000000000000000..f8eaa1dac52359273631db3e843815ccf46b21d5 GIT binary patch literal 13192 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 H8ZiR^?T#W# literal 10152 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

Blc#Sg&9gYVc>;dZFJBygFDAo8 z+}^Mx^9)doG9|++gRmNl&9Xo4U3;IQ?clo@_nJyT|hAhS0B#(G__5A$Ryz=@w@5U9*zdNS8)I7Uz zpnJ`$9dQDC4G+ahYwlpER=Ie{AI;da zM>;h2w(k79>GNImJAa&6I8prSY$dN9=59B#AOF9c@o!hclms`So9N z_211EQoolvLFSM%l3w3;-zVNwpUr#h|2f?ly=UAa>PbSP%9oew{8_zkgEJrJ6KKePuPX&Pj?hhOEyCda_AL%{5HGP{hyi zNSDn7!;Ri21!pE?U7RWQ@fBmX@pXB_?99CGPo^(3z5e~=o5I3v!~e(C^oR7KxgB@7 zn=DUsUG{M1N~x}jnYgWTy4*b zBr{$tvP`TLICsX=;YfS$LJ?I?r4Q{ptm%*gcjxu=i>6Q5zR(st&&6wLzy zDlvN$0(Dds#iz6U;?@vISz{3I5VIuI(>cfYOH=FjPfqI=dV5i+=BQbBMqQSm~r!Dno0}A66`2TVU8od(ontWQp*+xBJ zlcE~qow(zFME=(|JaRr3(KX>oncn&JkG4PB$x`H{loBqWV4%ra82zMelk9UIEmkd- zQ>;_j4VNmCN9|jm|g$S-vts^H12taTsG=eobCzb4}H?%blfgNyO!+MkfT$b@oW^P<{0NV?B$8T}sc=4Jxxr^b>lc z?@X`uY<)9{k*W4iibI~k?an!kQXw2uxMSruJSdb~a7R3CjX}H{OXlhoH{MAzL_c74 z41DOwx=N-&@06lenj_=`gSSWV%!7RQ~*FEFT|<=C0rLRCoJ> zRjLLR|C9aMw%J~s_9ae=&2xjn1NYNqc5>B9l}o%k1)|jgx=z&BFH!NxjSybP_@eCg zkN3>+yu=$^xeaF$I+Z#ZIb@B6AIrS${G; zQd+w&ZDmoy6aG#vem92}o{~a6uB2tF7z5WeF@|_p$g|GmIechSiloQX^*coatDGgD zR3B9Mwuj*(^IV1a*aJo{d9GV!v+d-&?r{3`BTGZa*UAwEGld(~C$-lt;m~8yYc)+= zdFJ1?2aOMZ6u5FYZ9gvb(J|R+Rk5W~)26fB4^=1loLIzAC@ID=QTkNb4;OW>##1G$ zQUWRiij};Wc5@qrP0=^dJH_=!`i7r?h+J0#*G<>cHWJG;N;2H1WQW{oYURx7dhQ}U zRbg&FtD|Ft#p;zt6SU)twHMu)B6pujSMK52Or{M%ykhrOS4-YAYVm(_rnBJhNu>u# z0m{Wn9HRM|Jgeqync+Jjf~&alfqU1Re5E^as!N&zZgMvsD5$YXlQ1YyesuWQk`NX) z-tD)PSF>-}pv||_M?k^g;bZPS3Ps8Hif6T~U087LK+poCxkZjo8=oIJQ|PH+=y;6l zGwUD8i2-3R?*C|849aURCmh6|D)om5SZz^0Wm=rnvC2;|M8HD8QO!9~X?3U31f6(e z?L{l!GuM|N$la+H5Rf*t{cQKqCl}sMIB6Fx_%Ud=DtG;(*ovcT(pro*!b z4iLi)g+FP;teR7FSaeFpbk^lx=CY;yo-I+7!6D_!x^k)J7Y5#G8rz!|a36cz=6P=c sgZSr}Y$-E&p3e?o{d$ru#qay^tEu-sfS6q>k$0APfz~O^+-?*D01YK~8~^|S diff --git a/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png b/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png deleted file mode 100644 index 34473e4bd89893c317f6e3e4f8d2fdd68e589f57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12603 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 diff --git a/doc/qtcreator/images/qtcreator-preferences-qtquick-code-style.webp b/doc/qtcreator/images/qtcreator-preferences-qtquick-code-style.webp new file mode 100644 index 0000000000000000000000000000000000000000..574f30dd64d5ea5c47a40fc3b752cbcd6008a462 GIT binary patch literal 10320 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 D^_}e_ literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc b/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc index 44622426af8..56e413b7e93 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -18,30 +18,39 @@ To specify global indentation settings for the C++ editor: \list 1 - \li Select \preferences > \uicontrol {C++}. + \li Go to \preferences > \uicontrol {C++}. \image qtcreator-code-style-clang-format-global.webp {Code Style preferences} \li In \uicontrol {Formatting mode}, select: \list \li \uicontrol {Indenting Only} to only indent code. \li \uicontrol {Full Formatting} to use the \key {Ctrl+I} keyboard shortcut to format code instead of indenting. - \li \uicontrol Disable to turn off ClangFormat. + \li \uicontrol {Use Built-In Indenter} to turn off ClangFormat. \endlist + \li Select \uicontrol {Ignore files greater than} to make parsing faster + by ignoring big files. Specify the maximum size of files to parse. \li To apply the formatting while you type, select \uicontrol {Format while typing}. \li To apply the formatting to the edited code when you save the file, select \uicontrol {Format edited code on file save}. \li To change the ClangFormat style globally for all projects, - select \uicontrol {Override ClangFormat configuration file}. - \li In the \uicontrol {Current settings} field, select the settings to - modify and click \uicontrol Copy. - \li Give a name to the settings and click \uicontrol OK. - \li Click \uicontrol Edit to set + select \uicontrol {Use custom settings}. + \li In \uicontrol {Custom settings}, select the settings to change, and + then select \uicontrol Copy. + \li Give a name to the settings, and select \uicontrol OK. + \li In \uicontrol ClangFormat, edit the \l{https://clang.llvm.org/docs/ClangFormatStyleOptions.html} - {ClangFormat Style Options}. + {ClangFormat Style Options}. The live preview shows how the + preferences change the indentation. + If you enter invalid values, you see warning messages. \endlist - In the other tabs, you can specify how to: + \section1 Using Built-In Indenter + + \image qtcreator-code-style-built-in-indenter.webp {Code Style preferences for built-in indenter} + + If you select \uicontrol {Use Built-In Indenter} in + \uicontrol {Formatting mode}, you can specify how to: \list \li Interpret the \key Tab and \key Backspace key presses. @@ -52,12 +61,9 @@ \li Bind pointers (*) and references (&) in types and declarations to identifiers, type names, or left or right \c const or \c volatile keywords. - \li Name getter functions. \endlist - Use the live preview to see how the preferences change the indentation. - - \section1 Specifying Settings for Content + \section2 Specifying Settings for Content You can indent public, protected, and private statements and declarations related to them within classes. @@ -67,24 +73,24 @@ \image qtcreator-code-style-content.png {Content preferences} - \section1 Specifying Settings for Braces + \section2 Specifying Settings for Braces You can indent class, namespace, enum and function declarations and code blocks. \image qtcreator-code-style-braces.png {Braces preferences} - \section1 Specifying Settings for Switch Statements + \section2 Specifying Settings for Switch Statements You can indent case or default statements, or statements or blocks related to them within switch statements. \image qtcreator-code-style-switch.png {Switch preferences} - \section1 Specifying Alignment + \section2 Specifying Alignment To align continuation lines to tokens after assignments, such as \c = or - \c +=, select the \uicontrol {Align after assignments} check box. You can + \c +=, select \uicontrol {Align after assignments}. You can specify additional settings for aligning continuation lines in the \uicontrol General tab. @@ -94,7 +100,7 @@ \image qtcreator-code-style-alignment.png {Alignment preferences} - \section1 Binding Pointers and References + \section2 Binding Pointers and References To bind pointers (\c *) and references (\c &) in types and declarations to identifiers, type names, or left or right \c const or \c volatile keywords, @@ -105,15 +111,6 @@ \image qtcreator-pointers-references.png {Pointers and References preferences} - \section1 Creating Project-Specific ClangFormat Files - - To override the \c {.clang-format} file for a particular project, create a - copy of the built-in style and edit its settings by selecting - \uicontrol Projects > \uicontrol {Project Settings} > - \uicontrol {Code Style} > \uicontrol Copy > \uicontrol Edit > - \uicontrol {ClangFormat} > - \uicontrol {Override ClangFormat configuration file}. - \section1 Creating ClangFormat Files from Command Line You can create \c {.clang-format} files that have the configuration @@ -124,5 +121,6 @@ clang-format -style=llvm -dump-config > .clang-format \endcode - \sa {Indent text or code}, {Behavior}, {Qt Quick Code Style}, {Nim} + \sa {Indent text or code}, {Specify code style}, {Behavior}, + {Qt Quick Code Style}, {Nim} */ diff --git a/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc b/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc index fa84ef87ca7..b5a62ae20c4 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc @@ -16,11 +16,11 @@ To specify preferences for the Nim editor (experimental): \list 1 - \li Select \preferences > \uicontrol Nim. - \li In the \uicontrol {Current settings} field, select the settings to - modify and click \uicontrol Copy. + \li Go to \preferences > \uicontrol Nim. + \li In \uicontrol {Custom settings}, select the settings to + modify, and then select \uicontrol Copy. \image qtcreator-preferences-nim-code-style.webp {Nim Code Style preferences} - \li Give a name to the settings and click \uicontrol OK. + \li Give a name to the settings, and select \uicontrol OK. \li Specify how to interpret the \key Tab key presses and how to align continuation lines. \li Select \uicontrol OK to save the settings. @@ -36,7 +36,7 @@ completion. To use Nimsuggest, you must install it on the development PC and enter the - path to the tool executable in the \uicontrol Path field. + path to the tool executable in \uicontrol Path. \image qtcreator-preferences-nim-tools.webp diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc index e60d5c49c52..88e0354aaa9 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -19,16 +19,15 @@ and editor the file opens in. \QC opens C++ files in \uicontrol Edit mode in the C++ code editor and QML files in the Qt Quick editor. - You can specify indentation for: + Specify indentation for: \list \li C++ files \li QML files \li Nim files - \li Other text files \endlist - You can specify code style either globally or separately for each project. + Specify code style either globally or separately for each project. You can specify several sets of code style settings and easily switch between them. In addition, you can import and export code style settings. @@ -36,31 +35,30 @@ \list 1 - \li Select \uicontrol Projects > \uicontrol {Project Settings} > + \li Go to \uicontrol Projects > \uicontrol {Project Settings} > \uicontrol {Code Style}. \image qtcreator-code-style-clang-format-project.webp {Code Style settings in Projects mode} - \li In the \uicontrol Language field, select \uicontrol C++, + \li In \uicontrol Language, select \uicontrol C++, \uicontrol {Qt Quick}, or \uicontrol Nim. - \li Deselect the \uicontrol {Use global settings} check box. + \li For C++, clear \uicontrol {Use global settings} to use the + \c {.clang-format} file for the project. - \li In the \uicontrol {Current settings} field, select the settings to modify - and click \uicontrol Copy. - - \li Give a name to the settings and click \uicontrol OK. - - \li Click \uicontrol Edit to specify a code style for the project. + \li To override the project's \c {.clang-format} file, + select \uicontrol {Use custom settings}. + \li In \uicontrol {Custom settings}, select the settings to use for the + project. \endlist In rare cases, ClangFormat can trip over a code construct and trigger a \QC crash. If that happens for your project, select - \uicontrol Disable as the formatting mode to switch - ClangFormat off for the project. If you can reproduce the crash, - please select \uicontrol Help > \uicontrol {Report Bug} to report - the bug and and attach the code that triggers the crash. + \uicontrol {Use Built-In Indenter} in \uicontrol {Formatting mode} to + turn off ClangFormat for the project. If you can reproduce the crash, + go to \uicontrol Help > \uicontrol {Report Bug} to report + the bug and attach the code that triggers the crash to the bug report. \sa {Indent text or code}, {Edit MIME types}, {C++ Code Style}, {Qt Quick Code Style}, {Nim} diff --git a/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc b/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc index 6ea13251620..70655b99edd 100644 --- a/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc +++ b/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc @@ -19,21 +19,17 @@ To specify QML code style globally: \list 1 - \li Select \preferences > \uicontrol {Qt Quick}. - \li In the \uicontrol {Current settings} field, select the settings to - modify and click \uicontrol Copy. - \image qtcreator-options-code-style-qml.png {QML Code Style preferences} - \li Give a name to the settings and click \uicontrol OK. - \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-qtquick.png {Edit Code Style dialog} + \li Go to \preferences > \uicontrol {Qt Quick} > \uicontrol {Code Style}. + \li In \uicontrol {Custom settings}, select the settings to + modify, and then select \uicontrol Copy. + \image qtcreator-preferences-qtquick-code-style.webp {Qt Quick Code Style preferences} + \li Give a name to the settings, and select \uicontrol OK. + \li Specify how to interpret the \key Tab key presses and how to align + continuation lines. + \li In \uicontrol {Line length}, set the maximum line length for + code lines. \endlist - You can specify how to interpret the \key Tab key presses and how to align - continuation lines. - - In \uicontrol {Line length}, you can adjust the maximum line length for - code lines. - To override the global preferences for a particular project, select \uicontrol Projects > \uicontrol {Code Style}. From 5a643b1c0a33daf8bac64e3c7688af8b80956dd4 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 8 Feb 2024 09:00:33 +0100 Subject: [PATCH 32/82] QtSupport: Mark remote Qt Versions Adds a postfix " (on ...)" to the default name of qt versions if they are located on a remote device. Makes it easier to distinguish Qt Versions Change-Id: I02208f49d5a1b6b22294b8cc29348455808f342f Reviewed-by: Leena Miettinen Reviewed-by: hjk Reviewed-by: --- src/plugins/qtsupport/baseqtversion.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 23a947c45f2..399efc3a1cd 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -382,9 +382,14 @@ QString QtVersion::defaultUnexpandedDisplayName() const } } - return detectionSource() == "PATH" ? - Tr::tr("Qt %{Qt:Version} in PATH (%2)").arg(location) : - Tr::tr("Qt %{Qt:Version} (%2)").arg(location); + QString result = detectionSource() == "PATH" + ? Tr::tr("Qt %{Qt:Version} in PATH (%2)").arg(location) + : Tr::tr("Qt %{Qt:Version} (%2)").arg(location); + + if (qmakeFilePath().needsDevice()) + result += QString(Tr::tr(" (on %1)")).arg(qmakeFilePath().host().toString()); + + return result; } QSet QtVersion::availableFeatures() const From 0b44cc5589a0fb94271131bfa2cddfc61b58bced Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 7 Feb 2024 16:13:22 +0100 Subject: [PATCH 33/82] Vcs: Hide topic cache in new IVersionControl pimpl Potentially more stable api long-term. Also simplifies the user side code a bit. Change-Id: I6913e27e2a5dc14907e72f252081cdbed34842a3 Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/coreplugin/iversioncontrol.cpp | 160 ++++++++++++-------- src/plugins/coreplugin/iversioncontrol.h | 38 ++--- src/plugins/fossil/fossilplugin.cpp | 25 +-- src/plugins/git/gitplugin.cpp | 28 +--- src/plugins/mercurial/mercurialplugin.cpp | 24 +-- src/plugins/subversion/subversionplugin.cpp | 35 +---- 6 files changed, 134 insertions(+), 176 deletions(-) diff --git a/src/plugins/coreplugin/iversioncontrol.cpp b/src/plugins/coreplugin/iversioncontrol.cpp index 4cbc8050a26..f70e4be492e 100644 --- a/src/plugins/coreplugin/iversioncontrol.cpp +++ b/src/plugins/coreplugin/iversioncontrol.cpp @@ -14,44 +14,40 @@ #include #include -/*! - \class Core::IVersionControl::TopicCache - \inheaderfile coreplugin/iversioncontrol.h - \inmodule QtCreator - - \brief The TopicCache class stores a cache which maps a directory to a topic. - - A VCS topic is typically the current active branch name, but it can also have other - values (for example the latest tag) when there is no active branch. - - It is displayed: - \list - \li In the project tree, next to each root project - corresponding to the project. - \li In the main window title - corresponding to the current active editor. - \endlist - - In order to enable topic display, an IVersionControl subclass needs to create - an instance of the TopicCache subclass with appropriate overrides for its - pure virtual functions, and pass this instance to IVersionControl's constructor. - - The cache tracks a file in the repository, which is expected to change when the - topic changes. When the file is modified, the cache is refreshed. - For example: for Git this file is typically /.git/HEAD - */ - -/*! - \fn Utils::FilePath Core::IVersionControl::TopicCache::trackFile(const Utils::FilePath &repository) - Returns the path to the file that invalidates the cache for \a repository when - the file is modified. - - \fn QString Core::IVersionControl::TopicCache::refreshTopic(const Utils::FilePath &repository) - Returns the current topic for \a repository. - */ - using namespace Utils; namespace Core { +namespace Internal { + +class TopicData +{ +public: + QDateTime timeStamp; + QString topic; +}; + +class IVersionControlPrivate +{ +public: + IVersionControl::FileTracker m_fileTracker; + IVersionControl::TopicRefresher m_topicRefresher; + QHash m_topicCache; +}; + +} // Internal + +IVersionControl::IVersionControl() + : d(new Internal::IVersionControlPrivate) +{ + Core::VcsManager::addVersionControl(this); +} + +IVersionControl::~IVersionControl() +{ + delete d; +} + QString IVersionControl::vcsOpenText() const { return Tr::tr("Open with VCS (%1)").arg(displayName()); @@ -111,24 +107,83 @@ IVersionControl::RepoUrl IVersionControl::getRepoUrl(const QString &location) co return RepoUrl(location); } -void IVersionControl::setTopicCache(TopicCache *topicCache) +FilePath IVersionControl::trackFile(const FilePath &repository) { - m_topicCache = topicCache; + QTC_ASSERT(d->m_fileTracker, return {}); + return d->m_fileTracker(repository); } +QString IVersionControl::refreshTopic(const FilePath &repository) +{ + QTC_ASSERT(d->m_topicRefresher, return {}); + return d->m_topicRefresher(repository); +} + +/*! + Returns the topic for repository under \a topLevel. + + A VCS topic is typically the current active branch name, but it can also have other + values (for example the latest tag) when there is no active branch. + + It is displayed: + \list + \li In the project tree, next to each root project - corresponding to the project. + \li In the main window title - corresponding to the current active editor. + \endlist + + In order to enable topic display, an IVersionControl subclass needs to create + an instance of the TopicCache subclass with appropriate overrides for its + pure virtual functions, and pass this instance to IVersionControl's constructor. + + The cache tracks a file in the repository, which is expected to change when the + topic changes. When the file is modified, the cache is refreshed. + For example: for Git this file is typically /.git/HEAD + + The base implementation features a cache. If the cache for \a topLevel is valid, + it will be used. Otherwise it will be refreshed using the items provided by + \c setTopicFileTracker() and \c setTopicRefresher(). + + \sa setTopicFileTracker(), setTopicRefresher(). + */ + QString IVersionControl::vcsTopic(const FilePath &topLevel) { - return m_topicCache ? m_topicCache->topic(topLevel) : QString(); + QTC_ASSERT(!topLevel.isEmpty(), return QString()); + Internal::TopicData &data = d->m_topicCache[topLevel]; + const FilePath file = trackFile(topLevel); + + if (file.isEmpty()) + return QString(); + const QDateTime lastModified = file.lastModified(); + if (lastModified == data.timeStamp) + return data.topic; + data.timeStamp = lastModified; + return data.topic = refreshTopic(topLevel); } -IVersionControl::IVersionControl() +/*! + Provides the \a fileTracker function object for use in \c vscTopic() cache handling. + + The parameter object takes a repository as input and returns the file + that should trigger topic refresh (e.g. .git/HEAD for Git). + + Modification of this file will invalidate the internal topic cache for the repository. +*/ + +void IVersionControl::setTopicFileTracker(const FileTracker &fileTracker) { - Core::VcsManager::addVersionControl(this); + d->m_fileTracker = fileTracker; } -IVersionControl::~IVersionControl() +/*! + Provides the \a topicRefresher function object for use in \c vscTopic() cache handling. + + The parameter object takes a repository as input and returns its current topic. + */ + +void IVersionControl::setTopicRefresher(const TopicRefresher &topicRefresher) { - delete m_topicCache; + d->m_topicRefresher = topicRefresher; } FilePaths IVersionControl::unmanagedFiles(const FilePaths &filePaths) const @@ -143,29 +198,6 @@ IVersionControl::OpenSupportMode IVersionControl::openSupportMode(const FilePath Q_UNUSED(filePath) return NoOpen; } - -IVersionControl::TopicCache::~TopicCache() = default; - -/*! - Returns the topic for repository under \a topLevel. - - If the cache for \a topLevel is valid, it will be used. Otherwise it will be refreshed. - */ -QString IVersionControl::TopicCache::topic(const FilePath &topLevel) -{ - QTC_ASSERT(!topLevel.isEmpty(), return QString()); - TopicData &data = m_cache[topLevel]; - const FilePath file = trackFile(topLevel); - - if (file.isEmpty()) - return QString(); - const QDateTime lastModified = file.lastModified(); - if (lastModified == data.timeStamp) - return data.topic; - data.timeStamp = lastModified; - return data.topic = refreshTopic(topLevel); -} - void IVersionControl::fillLinkContextMenu(QMenu *, const FilePath &, const QString &) { } diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index e97749ca1b2..31e35437770 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -8,16 +8,15 @@ #include #include -#include #include -#include #include -#include QT_FORWARD_DECLARE_CLASS(QMenu); namespace Core { +namespace Internal { class IVersionControlPrivate; } + class CORE_EXPORT IVersionControl : public QObject { Q_OBJECT @@ -43,28 +42,6 @@ public: OpenMandatory /*!< Files must always be opened by the VCS */ }; - class CORE_EXPORT TopicCache - { - public: - virtual ~TopicCache(); - QString topic(const Utils::FilePath &topLevel); - - protected: - virtual Utils::FilePath trackFile(const Utils::FilePath &repository) = 0; - virtual QString refreshTopic(const Utils::FilePath &repository) = 0; - - private: - class TopicData - { - public: - QDateTime timeStamp; - QString topic; - }; - - QHash m_cache; - - }; - IVersionControl(); ~IVersionControl() override; @@ -218,7 +195,14 @@ public: }; virtual RepoUrl getRepoUrl(const QString &location) const; - void setTopicCache(TopicCache *topicCache); + // Topic cache + using FileTracker = std::function; + Utils::FilePath trackFile(const Utils::FilePath &repository); + void setTopicFileTracker(const FileTracker &fileTracker); + + using TopicRefresher = std::function; + QString refreshTopic(const Utils::FilePath &repository); + void setTopicRefresher(const TopicRefresher &topicRefresher); signals: void repositoryChanged(const Utils::FilePath &repository); @@ -226,7 +210,7 @@ signals: void configurationChanged(); private: - TopicCache *m_topicCache = nullptr; + Internal::IVersionControlPrivate *d; }; } // namespace Core diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index b09ffda013b..25fcdfa923a 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -61,23 +61,6 @@ using namespace std::placeholders; namespace Fossil::Internal { -class FossilTopicCache final : public IVersionControl::TopicCache -{ -public: - FossilTopicCache() = default; - -protected: - FilePath trackFile(const FilePath &repository) final - { - return repository.pathAppended(Constants::FOSSILREPO); - } - - QString refreshTopic(const FilePath &repository) final - { - return fossilClient().synchronousTopic(repository); - } -}; - class FossilPluginPrivate final : public VersionControlBase { public: @@ -222,7 +205,13 @@ FossilPluginPrivate::FossilPluginPrivate() { Context context(Constants::FOSSIL_CONTEXT); - setTopicCache(new FossilTopicCache); + setTopicFileTracker([](const FilePath &repository) { + return repository.pathAppended(Constants::FOSSILREPO); + }); + setTopicRefresher([](const FilePath &repository) { + return fossilClient().synchronousTopic(repository); + }); + connect(&fossilClient(), &VcsBaseClient::changed, this, &FossilPluginPrivate::changed); m_commandLocator = new CommandLocator("Fossil", "fossil", "fossil", this); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 9535f14128d..915796bdbf0 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -382,25 +382,6 @@ public: static GitPluginPrivate *dd = nullptr; -class GitTopicCache : public IVersionControl::TopicCache -{ -public: - GitTopicCache() {} - -protected: - FilePath trackFile(const FilePath &repository) override - { - const FilePath gitDir = gitClient().findGitDirForRepository(repository); - return gitDir.isEmpty() ? FilePath() : gitDir / "HEAD"; - } - - QString refreshTopic(const FilePath &repository) override - { - emit dd->repositoryChanged(repository); - return gitClient().synchronousTopic(repository); - } -}; - GitPluginPrivate::~GitPluginPrivate() { cleanCommitMessageFile(); @@ -560,7 +541,14 @@ GitPluginPrivate::GitPluginPrivate() { dd = this; - setTopicCache(new GitTopicCache); + setTopicFileTracker([](const FilePath &repository) { + const FilePath gitDir = gitClient().findGitDirForRepository(repository); + return gitDir.isEmpty() ? FilePath() : gitDir / "HEAD"; + }); + setTopicRefresher([this](const FilePath &repository) { + emit repositoryChanged(repository); + return gitClient().synchronousTopic(repository); + }); m_fileActions.reserve(10); m_projectActions.reserve(10); diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 1fa1fc8155e..91c25139d9f 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -51,23 +51,6 @@ using namespace std::placeholders; namespace Mercurial::Internal { -class MercurialTopicCache : public Core::IVersionControl::TopicCache -{ -public: - MercurialTopicCache() = default; - -protected: - FilePath trackFile(const FilePath &repository) override - { - return repository.pathAppended(".hg/branch"); - } - - QString refreshTopic(const FilePath &repository) override - { - return mercurialClient().branchQuerySync(repository.toString()); - } -}; - class MercurialPluginPrivate final : public VcsBase::VersionControlBase { public: @@ -203,7 +186,12 @@ MercurialPluginPrivate::MercurialPluginPrivate() [] { return new CommitEditor; } }); - setTopicCache(new MercurialTopicCache); + setTopicFileTracker([](const FilePath &repository) { + return repository.pathAppended(".hg/branch"); + }); + setTopicRefresher([](const FilePath &repository) { + return mercurialClient().branchQuerySync(repository.toString()); + }); Core::Context context(Constants::MERCURIAL_CONTEXT); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 95a774e1f83..cab80c64d0d 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -126,24 +126,6 @@ static inline QStringList svnDirectories() return rc; } -class SubversionPluginPrivate; - -class SubversionTopicCache : public Core::IVersionControl::TopicCache -{ -public: - SubversionTopicCache(SubversionPluginPrivate *plugin) : - m_plugin(plugin) - { } - -protected: - FilePath trackFile(const FilePath &repository) override; - - QString refreshTopic(const FilePath &repository) override; - -private: - SubversionPluginPrivate *m_plugin; -}; - class SubversionPluginPrivate final : public VcsBase::VersionControlBase { public: @@ -312,7 +294,12 @@ SubversionPluginPrivate::SubversionPluginPrivate() { dd = this; - setTopicCache(new SubversionTopicCache(this)); + setTopicFileTracker([this](const FilePath &repository) { + return FilePath::fromString(monitorFile(repository)); + }); + setTopicRefresher([this](const FilePath &repository) { + return synchronousTopic(repository); + }); using namespace Constants; using namespace Core::Constants; @@ -1153,16 +1140,6 @@ VcsCommand *SubversionPluginPrivate::createInitialCheckoutCommand(const QString return command; } -FilePath SubversionTopicCache::trackFile(const FilePath &repository) -{ - return FilePath::fromString(m_plugin->monitorFile(repository)); -} - -QString SubversionTopicCache::refreshTopic(const FilePath &repository) -{ - return m_plugin->synchronousTopic(repository); -} - #ifdef WITH_TESTS From 3b5c377ce5d19531b15eb3969ee43620da77ca7f Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Thu, 8 Feb 2024 12:22:24 +0100 Subject: [PATCH 34/82] Debugger: Fix custom allocator dumper tests for GCC >= 13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC commit [1] commit 64c986b49558a7c356b85bda85195216936c29a3 Author: Jonathan Wakely Date: Wed Dec 14 15:21:32 2022 +0000 libstdc++: Diagnose broken allocator rebind members added a static_assert that caused the dumper tests using custom allocators to fail like this on Debian testing: DEBUG : tst_Dumpers::dumper(StdBasicString) qtc.debugger.dumpers: In file included from /usr/include/c++/13/ext/alloc_traits.h:34, from /usr/include/c++/13/bits/basic_string.h:39, from /usr/include/c++/13/string:54, from main.cpp:28: /usr/include/c++/13/bits/alloc_traits.h: In instantiation of ‘struct std::__allocator_traits_base::__rebind, char, void>’: /usr/include/c++/13/bits/alloc_traits.h:94:11: required by substitution of ‘template using std::__alloc_rebind = typename std::__allocator_traits_base::__rebind<_Alloc, _Up>::type [with _Alloc = myallocator; _Up = char]’ /usr/include/c++/13/bits/alloc_traits.h:228:8: required by substitution of ‘template template using std::allocator_traits< >::rebind_alloc = std::__alloc_rebind<_Alloc, _Tp> [with _Tp = char; _Alloc = myallocator]’ /usr/include/c++/13/ext/alloc_traits.h:126:65: required from ‘struct __gnu_cxx::__alloc_traits, char>::rebind’ /usr/include/c++/13/bits/basic_string.h:90:24: required from ‘class std::__cxx11::basic_string, myallocator >’ main.cpp:56:71: required from here /usr/include/c++/13/bits/alloc_traits.h:70:31: error: static assertion failed: allocator_traits::rebind_alloc must be A 70 | _Tp>::value, | ^~~~~ /usr/include/c++/13/bits/alloc_traits.h:70:31: note: ‘std::integral_constant::value’ evaluates to false make: *** [Makefile:506: main.o] Error 1 Override the rebind behavior of the custom allocator used in the tests to fix this. [1] https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=64c986b49558a7 Change-Id: I1cd8370e5f1601b710e28c251061291c65ac44ce Reviewed-by: hjk Reviewed-by: Qt CI Bot --- tests/auto/debugger/tst_dumpers.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 69fcf3bcf2c..613eb9c72bb 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -5264,7 +5264,12 @@ void tst_Dumpers::dumper_data() << Data("#include \n" "template\n" - "class myallocator : public std::allocator {};\n", + "class myallocator : public std::allocator {\n" + "template\n" + "struct rebind {\n" + "typedef myallocator<_Tp1> other;\n" + "};\n" + "};\n", "std::basic_string, myallocator> str(\"hello\");", @@ -5418,6 +5423,10 @@ void tst_Dumpers::dumper_data() "template\n" "class myallocator : public std::allocator {\n" "using std::allocator::allocator;\n" + "template\n" + "struct rebind {\n" + "typedef myallocator<_Tp1> other;\n" + "};\n" "};\n", "std::vector v0, v1;\n" From d9eeddfad156a8b10fa6877c4fbca4dd19d0a3fa Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Thu, 8 Feb 2024 14:40:24 +0100 Subject: [PATCH 35/82] Git: Fix upstream status for untracked branches Using HEAD is wrong as soon as the branch is not checked out. Instead the branch name must be used. Amends 960ac1adf4855ce73d36c265a6b08da0e478bd93 Change-Id: Id10b4012455ccb9b393404413a369f241edc098e Reviewed-by: Reviewed-by: Orgad Shaneh --- src/plugins/git/branchmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index fa9dee2cb37..14a59f0993b 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -914,7 +914,7 @@ void BranchModel::updateUpstreamStatus(BranchNode *node) process->setEnvironment(gitClient().processEnvironment()); QStringList parameters = {"rev-list", "--no-color", "--count"}; if (node->tracking.isEmpty()) - parameters += {"HEAD", "--not", "--remotes"}; + parameters += {node->fullRef(), "--not", "--remotes"}; else parameters += {"--left-right", node->fullRef() + "..." + node->tracking}; process->setCommand({gitClient().vcsBinary(), parameters}); From c22471d3161b4b4a1ded20fc11764050d22a020c Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sun, 11 Feb 2024 12:34:02 +0100 Subject: [PATCH 36/82] Git: Disable upstream status for Detached HEAD It was always zero as Detached HEAD is a special branch that is not actively queried. It can be enabled later, but the quick fix is to disable it. Change-Id: Ib191e1b5551a13bc4911184e12e06a0b4dc28ddf Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/git/branchmodel.cpp | 7 +++++-- src/plugins/git/gitclient.h | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 14a59f0993b..ed80feeb16a 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -318,9 +318,12 @@ QVariant BranchModel::data(const QModelIndex &index, int role) const if (!node->isLocal() || !node->isLeaf()) break; - res += ' ' + arrowUp + QString::number(node->status.ahead); + if (node->status.ahead >= 0) + res += ' ' + arrowUp + QString::number(node->status.ahead); + if (!node->tracking.isEmpty()) { - res += ' ' + arrowDown + QString::number(node->status.behind); + if (node->status.behind >= 0) + res += ' ' + arrowDown + QString::number(node->status.behind); res += " [" + node->tracking + ']'; } break; diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 3f8368c62eb..f0ed9ffc8eb 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -73,8 +73,8 @@ public: UpstreamStatus() = default; UpstreamStatus(int ahead, int behind) : ahead(ahead), behind(behind) {} - int ahead = 0; - int behind = 0; + int ahead = -1; + int behind = -1; }; struct Author { From e1f6ee8f761a4d6e82935b456915e9b496101812 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 7 Feb 2024 13:35:53 +0100 Subject: [PATCH 37/82] SquishTests: Do not wait for the BuildProgress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always fail to retrieve it nowadays, so just remove this. Change-Id: I616e40e22ed1da2782b766701ba4b5bd742e1133 Reviewed-by: Robert Löhning Reviewed-by: Jukka Nokso --- tests/system/shared/build_utils.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index 6a2904286a3..c26634f61db 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -40,12 +40,6 @@ def getBuildIssues(ignoreCodeModel=True): # lines within the Issues output # param expectedToFail can be used to tell this function if the build was expected to fail or not def checkLastBuild(expectedToFail=False): - try: - # can't use waitForObject() 'cause visible is always 0 - findObject("{type='ProjectExplorer::Internal::BuildProgress' unnamed='1' }") - except LookupError: - test.log("checkLastBuild called without a build") - return buildIssues = getBuildIssues() types = [i[1] for i in buildIssues] errors = types.count("1") From 35b7f868f52fa0f8a447d0a6dd31206c2c60fba2 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 1 Feb 2024 13:17:18 +0100 Subject: [PATCH 38/82] SquishTests: Remove firewall handling for Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handling the firewall from script is cumbersome and not worth the effort - remove all related code. Explicitly state the prerequisite of disabling notifications for the firewall. Change-Id: Icbe3075127eeb9a57724c334f0b52a24f8b08f59 Reviewed-by: Robert Löhning Reviewed-by: Reviewed-by: Jukka Nokso --- tests/system/README | 5 +- tests/system/shared/debugger.py | 66 ------------------- .../suite_debugger/tst_simple_debug/test.py | 5 +- 3 files changed, 2 insertions(+), 74 deletions(-) diff --git a/tests/system/README b/tests/system/README index 1174b181876..7dff67a84d0 100644 --- a/tests/system/README +++ b/tests/system/README @@ -63,10 +63,7 @@ started. On Windows, this has the following prerequisites: Either: * have no firewall at all enabled (sure that's a bad idea) Or: - * run Windows with English UI - * have the Windows Firewall enabled (no other firewalls are handled by the scripts) - * run the Squish tests with administrator privileges - * additionally the UAC should be disabled, too + * have notifications disabled for the firewall when an application tries to access network Otherwise you'll have some trouble with popping up dialogs from the firewall. If you're using a different firewall - try to figure out and add a rule for this. diff --git a/tests/system/shared/debugger.py b/tests/system/shared/debugger.py index bb6b4082b63..5ee31dec201 100644 --- a/tests/system/shared/debugger.py +++ b/tests/system/shared/debugger.py @@ -266,69 +266,3 @@ def verifyBreakPoint(bpToVerify): test.fatal("Expected a dict for bpToVerify - got '%s'" % className(bpToVerify)) return False -# helper to check whether win firewall is running or not -# this doesn't check for other firewalls! -def __isWinFirewallRunning__(): - if hasattr(__isWinFirewallRunning__, "fireWallState"): - return __isWinFirewallRunning__.fireWallState - if platform.system() not in ('Microsoft' 'Windows'): - __isWinFirewallRunning__.fireWallState = False - return False - result = getOutputFromCmdline(["netsh", "firewall", "show", "state"]) - for line in result.splitlines(): - if "Operational mode" in line: - __isWinFirewallRunning__.fireWallState = not "Disable" in line - return __isWinFirewallRunning__.fireWallState - return None - -# helper that can modify the win firewall to allow a program to communicate through it or delete it -# param addToFW defines whether to add (True) or delete (False) this program to/from the firewall -def __configureFW__(workingDir, projectName, isReleaseBuild, addToFW=True): - if isReleaseBuild == None: - if projectName[-4:] == ".exe": - projectName = projectName[:-4] - path = "%s%s%s" % (workingDir, os.sep, projectName) - elif isReleaseBuild: - path = "%s%s%s%srelease%s%s" % (workingDir, os.sep, projectName, os.sep, os.sep, projectName) - else: - path = "%s%s%s%sdebug%s%s" % (workingDir, os.sep, projectName, os.sep, os.sep, projectName) - if addToFW: - mode = "add" - enable = "ENABLE" - else: - mode = "delete" - enable = "" - projectName = "" - # Needs admin privileges on Windows 7 - # Using the deprecated "netsh firewall" because the newer - # "netsh advfirewall" would need admin privileges on Windows Vista, too. - return subprocess.call(["netsh", "firewall", mode, "allowedprogram", - "%s.exe" % path, projectName, enable]) - -# function to add a program to allow communication through the win firewall -# param workingDir this directory is the parent of the project folder -# param projectName this is the name of the project (the folder inside workingDir as well as the name for the executable) -# param isReleaseBuild should currently always be set to True (will later add debug build testing) -def allowAppThroughWinFW(workingDir, projectName, isReleaseBuild=True): - if not __isWinFirewallRunning__(): - return - # WinFirewall seems to run - hopefully no other - result = __configureFW__(workingDir, projectName, isReleaseBuild) - if result == 0: - test.log("Added %s to firewall" % projectName) - else: - test.fatal("Could not add %s as allowed program to win firewall" % projectName) - -# function to delete a (former added) program from the win firewall -# param workingDir this directory is the parent of the project folder -# param projectName this is the name of the project (the folder inside workingDir as well as the name for the executable) -# param isReleaseBuild should currently always be set to True (will later add debug build testing) -def deleteAppFromWinFW(workingDir, projectName, isReleaseBuild=True): - if not __isWinFirewallRunning__(): - return - # WinFirewall seems to run - hopefully no other - result = __configureFW__(workingDir, projectName, isReleaseBuild, False) - if result == 0: - test.log("Deleted %s from firewall" % projectName) - else: - test.warning("Could not delete %s as allowed program from win firewall" % (projectName)) diff --git a/tests/system/suite_debugger/tst_simple_debug/test.py b/tests/system/suite_debugger/tst_simple_debug/test.py index e6301f941c5..518ac1b23b9 100644 --- a/tests/system/suite_debugger/tst_simple_debug/test.py +++ b/tests/system/suite_debugger/tst_simple_debug/test.py @@ -36,7 +36,7 @@ def main(): for kit, config in availableConfigs: test.log("Selecting '%s' as build config" % config) verifyBuildConfig(kit, config, True, True, True) - # explicitly build before start debugging for adding the executable as allowed program to WinFW + # explicitly build before start debugging selectFromLocator("t rebuild", "Rebuild All Projects") waitForCompile(300000) if not checkCompile(): @@ -52,7 +52,6 @@ def main(): buildDir = os.path.join(str(waitForObject(":Qt Creator_Utils::BuildDirectoryLineEdit").text), "debug") switchViewTo(ViewConstants.EDIT) - allowAppThroughWinFW(buildDir, projectName, None) if not doSimpleDebugging(kit, config, expectedBreakpointsOrder): try: stopB = findObject(':Qt Creator.Stop_QToolButton') @@ -60,8 +59,6 @@ def main(): clickButton(stopB) except: pass - if platform.system() in ('Microsoft' 'Windows'): - deleteAppFromWinFW(buildDir, projectName, None) # close application output window of current run to avoid mixing older output on the next run ensureChecked(":Qt Creator_AppOutput_Core::Internal::OutputPaneToggleButton") clickButton(waitForObject("{type='CloseButton' unnamed='1' visible='1' " From 46fd19591f6cab76303a03f41d0b73d1cf91a806 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 2 Feb 2024 13:44:11 +0100 Subject: [PATCH 39/82] Squish: Fix missing impl for deleting shared scripts The action has been present for some time, but so far it had been unimplemented Change-Id: I798a144116ffeba60fb368430b30705ffc9b3f1c Reviewed-by: David Schulz --- src/plugins/squish/squishnavigationwidget.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index 95f37c67eaf..7921938c37a 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -47,6 +47,7 @@ private: void onRowsInserted(const QModelIndex &parent, int, int); void onRowsRemoved(const QModelIndex &parent, int, int); void onAddSharedFileTriggered(const QModelIndex &idx); + void onRemoveSharedFileTriggered(const QModelIndex &idx); void onRemoveSharedFolderTriggered(int row, const QModelIndex &parent); void onRemoveAllSharedFolderTriggered(); void onRecordTestCase(const QString &suiteName, const QString &testCase); @@ -161,6 +162,9 @@ void SquishNavigationWidget::contextMenuEvent(QContextMenuEvent *event) case SquishTestTreeItem::SquishSharedFile: { QAction *deleteSharedFile = new QAction(Tr::tr("Delete Shared File"), &menu); menu.addAction(deleteSharedFile); + connect(deleteSharedFile, &QAction::triggered, this, [this, idx] { + onRemoveSharedFileTriggered(idx); + }); break; } case SquishTestTreeItem::SquishSharedFolder: { @@ -325,6 +329,31 @@ void SquishNavigationWidget::onAddSharedFileTriggered(const QModelIndex &idx) m_view->edit(m_sortModel->mapFromSource(added)); } +void SquishNavigationWidget::onRemoveSharedFileTriggered(const QModelIndex &idx) +{ + const auto scriptFile = FilePath::fromVariant(idx.data(LinkRole)); + QTC_ASSERT(!scriptFile.isEmpty(), return); + + const QString detail = Tr::tr("Do you really want to delete \"%1\" permanently?") + .arg(scriptFile.toUserOutput()); + const QMessageBox::StandardButton pressed + = CheckableMessageBox::question(Core::ICore::dialogParent(), + Tr::tr("Remove Shared File"), + detail, + Key("RemoveSharedSquishScript")); + if (pressed != QMessageBox::Yes) + return; + + const QModelIndex &realIdx = m_sortModel->mapToSource(idx); + // close document silently if open + if (Core::IDocument *doc = Core::DocumentModel::documentForFilePath(scriptFile)) + Core::EditorManager::closeDocuments({doc}, false); + if (scriptFile.removeFile()) + m_model->removeTreeItem(realIdx.row(), realIdx.parent()); + else + SquishMessages::criticalMessage(Tr::tr("Failed to remove \"%1\".")); +} + void SquishNavigationWidget::onRemoveSharedFolderTriggered(int row, const QModelIndex &parent) { const auto folder = Utils::FilePath::fromVariant(m_sortModel->index(row, 0, parent).data(LinkRole)); From 6db80678214169d4406f48f813b07a452b140358 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Fri, 9 Feb 2024 09:48:56 +0100 Subject: [PATCH 40/82] ClangFormat: Fix warning readability message on dark theme Fixes: QTCREATORBUG-30339 Change-Id: I57291907656b379468a066a09e767b886f17d7a0 Reviewed-by: Reviewed-by: David Schulz --- .../clangformat/clangformatglobalconfigwidget.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index 973271b8c3c..7027511868e 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -68,7 +69,7 @@ private: QCheckBox *m_formatOnSave; QCheckBox *m_useCustomSettingsCheckBox; QCheckBox *m_useGlobalSettings; - QLabel *m_currentProjectLabel; + InfoLabel *m_currentProjectLabel; }; ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(ICodeStylePreferences *codeStyle, @@ -95,10 +96,10 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(ICodeStylePreferenc m_useGlobalSettings->hide(); m_useCustomSettings = ClangFormatSettings::instance().useCustomSettings(); - m_currentProjectLabel = new QLabel( + m_currentProjectLabel = new Utils::InfoLabel( Tr::tr("Please note that the current project includes a .clang-format file, which will be " - "used for code indenting and formatting.")); - m_currentProjectLabel->setStyleSheet("QLabel { color : red; }"); + "used for code indenting and formatting."), + Utils::InfoLabel::Warning); m_currentProjectLabel->setWordWrap(true); using namespace Layouting; From 439773252b3382b5c323156bb6534dacfb9f82e9 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 7 Feb 2024 16:50:27 +0100 Subject: [PATCH 41/82] Doc: Add Known Issues to \ingroup creator-reference It somehow fell out from there. Point to the Change Log command for viewing the changes. Task-number: QTCREATORBUG-29361 Change-Id: I59bc227e507495684f9d2cc9db19510481076d38 Reviewed-by: Eike Ziller Reviewed-by: --- .../overview/creator-only/creator-issues.qdoc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc b/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc index db2af2c5ebf..de7c8b45d3d 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -8,20 +8,22 @@ // ********************************************************************** /*! - \previouspage creator-how-tos.html \page creator-known-issues.html - \nextpage creator-glossary.html + \previouspage creator-reference.html + + \ingroup creator-reference \title Known Issues - This section lists known issues in \QC version \qtcversion. The development - team is aware of them, and therefore, you do not need to report them as - bugs. + \brief Known issues in \QC version \qtcversion. - For a list of fixed issues and added features, see the changelog file in - the \c{qtcreator\dist} folder or the \l{https://bugreports.qt.io} + The \QC development team is aware of the issues described here, and + therefore, you do not need to report them in the \l{https://bugreports.qt.io} {Qt Project Bug Tracker}. + For a list of fixed issues and added features, go to \uicontrol Help > + \uicontrol {Change Log}. + \section1 General Issues \list From 4d9fe5572d335099cacea8e65e6c0b861d0d1113 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 8 Feb 2024 18:14:46 +0100 Subject: [PATCH 42/82] Fix qbs build Include MsvcToolchain unconditionally, as in the CMake build. Change-Id: I01c9642ee74bb8f4476ba318512f4f441a823b93 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/projectexplorer.qbs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 3e5ee74e730..feab87da1ba 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -89,6 +89,7 @@ QtcPlugin { "makestep.cpp", "makestep.h", "miniprojecttargetselector.cpp", "miniprojecttargetselector.h", "msvcparser.cpp", "msvcparser.h", + "msvctoolchain.cpp", "msvctoolchain.h", "namedwidget.cpp", "namedwidget.h", "osparser.cpp", "osparser.h", "panelswidget.cpp", "panelswidget.h", @@ -230,15 +231,6 @@ QtcPlugin { files: ["*.png"] } - Group { - name: "WindowsToolChains" - condition: qbs.targetOS.contains("windows") || qtc.withPluginTests - files: [ - "msvctoolchain.cpp", - "msvctoolchain.h", - ] - } - QtcTestFiles { files: ["outputparser_test.h", "outputparser_test.cpp"] } From 354f50f258bf42cf1289fc98514fcb1841d89aa1 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 9 Feb 2024 15:18:40 +0100 Subject: [PATCH 43/82] CppEditor: Use a hidden friend to compare BaseEditorDocumentParser::Configuration Posh, and avoids an upcoming warning with C++20: /data/dev/creator/src/plugins/clangcodemodel/clangdclient.cpp:907:40: warning: C++20 says that these are ambiguous, even though the second is reversed: In file included from /data/dev/creator/src/plugins/clangcodemodel/clangdclient.h:6, from /data/dev/creator/src/plugins/clangcodemodel/clangdclient.cpp:4: /data/dev/creator/src/plugins/cppeditor/baseeditordocumentparser.h:37:14: note: candidate 1: 'bool CppEditor::BaseEditorDocumentParser::Configuration::operator==(const CppEditor::BaseEditorDocumentParser::Configuration&)' /data/dev/creator/src/plugins/cppeditor/baseeditordocumentparser.h:37:14: note: candidate 2: 'bool CppEditor::BaseEditorDocumentParser::Configuration::operator==(const CppEditor::BaseEditorDocumentParser::Configuration&)' (reversed) /data/dev/creator/src/plugins/cppeditor/baseeditordocumentparser.h:37:14: note: try making the operator a 'const' member function Change-Id: I98ed9d907b673b9353f540bab2ff7239e018b4f2 Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/baseeditordocumentparser.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/cppeditor/baseeditordocumentparser.h b/src/plugins/cppeditor/baseeditordocumentparser.h index 45f6b953990..dce82893848 100644 --- a/src/plugins/cppeditor/baseeditordocumentparser.h +++ b/src/plugins/cppeditor/baseeditordocumentparser.h @@ -34,11 +34,11 @@ public: QByteArray editorDefines; QString preferredProjectPartId; - bool operator==(const Configuration &other) + friend bool operator==(const Configuration &left, const Configuration &right) { - return usePrecompiledHeaders == other.usePrecompiledHeaders - && editorDefines == other.editorDefines - && preferredProjectPartId == other.preferredProjectPartId; + return left.usePrecompiledHeaders == right.usePrecompiledHeaders + && left.editorDefines == right.editorDefines + && left.preferredProjectPartId == right.preferredProjectPartId; } }; From c553d63a32f9df7fdc999421e353647c20b0fd91 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 8 Feb 2024 18:50:57 +0100 Subject: [PATCH 44/82] PE: Allow ProjectImporter to filter kits in TargetSetupPage Amends b9f546cf1bb7d867bb5f0a31ada0c5c670c52f6e Change-Id: Icf64f3cd751480c9fe2ae740f47954a62c252cc4 Reviewed-by: Marcus Tillmanns Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/projectexplorer/projectimporter.h | 2 +- src/plugins/projectexplorer/targetsetuppage.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/plugins/projectexplorer/projectimporter.h b/src/plugins/projectexplorer/projectimporter.h index 2cca307d5b3..6946054ca9e 100644 --- a/src/plugins/projectexplorer/projectimporter.h +++ b/src/plugins/projectexplorer/projectimporter.h @@ -36,7 +36,7 @@ public: virtual const QList import(const Utils::FilePath &importPath, bool silent = false); virtual Utils::FilePaths importCandidates() = 0; virtual Target *preferredTarget(const QList &possibleTargets); - virtual QString kitFilterText() { return QString(); } + virtual bool filter(Kit *) const { return true; } bool isUpdating() const { return m_isUpdating; } diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index a4af51996a4..72e77fd6644 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -304,6 +304,8 @@ void TargetSetupPagePrivate::setupWidgets(const QString &filterText) for (Kit *k : KitManager::sortedKits()) { if (!filterText.isEmpty() && !k->displayName().contains(filterText, Qt::CaseInsensitive)) continue; + if (m_importer && !m_importer->filter(k)) + continue; const auto widget = new TargetSetupWidget(k, m_projectPath); connect(widget, &TargetSetupWidget::selectedToggled, this, &TargetSetupPagePrivate::kitSelectionChanged); @@ -569,10 +571,6 @@ void TargetSetupPagePrivate::doInitializePage() setupWidgets(); setupImports(); - const QString filterText = m_importer ? m_importer->kitFilterText() : QString{}; - kitFilterLineEdit->setText(filterText); - kitFilterLineEdit->filterChanged(filterText); - selectAtLeastOneEnabledKit(); updateVisibility(); } From 87c67fc6d7193883edb9a0244296cd429f0473de Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 5 Feb 2024 16:23:22 +0100 Subject: [PATCH 45/82] CMakePM: Only display CMake preset Kits in the project setup page Fixes: QTCREATORBUG-29535 Change-Id: I87c16c24a8548efb4374af342947d342e19cc510 Reviewed-by: Marcus Tillmanns Reviewed-by: --- .../cmakeprojectimporter.cpp | 18 ++++++++++++++++++ .../cmakeprojectmanager/cmakeprojectimporter.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 2ff01898cdc..450d1540102 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -201,6 +201,8 @@ FilePaths CMakeProjectImporter::presetCandidates() } } + m_hasCMakePresets = !candidates.isEmpty(); + return candidates; } @@ -219,6 +221,22 @@ Target *CMakeProjectImporter::preferredTarget(const QList &possibleTar return ProjectImporter::preferredTarget(possibleTargets); } +bool CMakeProjectImporter::filter(ProjectExplorer::Kit *k) const +{ + if (!m_hasCMakePresets) + return true; + + const auto presetConfigItem = CMakeConfigurationKitAspect::cmakePresetConfigItem(k); + if (presetConfigItem.isNull()) + return false; + + const QString presetName = presetConfigItem.expandedValue(k); + return std::find_if(m_project->presetsData().configurePresets.cbegin(), + m_project->presetsData().configurePresets.cend(), + [&presetName](const auto &preset) { return presetName == preset.name; }) + != m_project->presetsData().configurePresets.cend(); +} + static CMakeConfig configurationFromPresetProbe( const FilePath &importPath, const FilePath &sourceDirectory, diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h index e3b329e722f..82e1835ba7b 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h @@ -24,6 +24,7 @@ public: Utils::FilePaths importCandidates() final; ProjectExplorer::Target *preferredTarget(const QList &possibleTargets) final; + bool filter(ProjectExplorer::Kit *k) const final; Utils::FilePaths presetCandidates(); private: @@ -48,6 +49,7 @@ private: const CMakeProject *m_project; Utils::TemporaryDirectory m_presetsTempDir; + bool m_hasCMakePresets = false; }; #ifdef WITH_TESTS From 44fa834f2b1433817cb6ef9537c1a528ae1a436f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 9 Feb 2024 10:30:57 +0100 Subject: [PATCH 46/82] Update qbs submodule to HEAD of 2.3 branch Change-Id: I13b506ee25d9f3668a8f995a7ddc3a95752780eb Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/shared/qbs | 2 +- src/src.qbs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 0d589c18b57..a04135ed738 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 0d589c18b570ce895cf3d6e69545439c2f68ebac +Subproject commit a04135ed738d5d65669441fad1593713c3ca2a89 diff --git a/src/src.qbs b/src/src.qbs index fb7532b03c9..95f2e96dcc5 100644 --- a/src/src.qbs +++ b/src/src.qbs @@ -34,6 +34,7 @@ Project { qbsBaseDir + "/share/share.qbs", qbsBaseDir + "/src/app/apps.qbs", qbsBaseDir + "/src/shared/bundledqt/bundledqt.qbs", + qbsBaseDir + "/src/shared/lsp/lsp.qbs", qbsBaseDir + "/src/shared/json/json.qbs", qbsBaseDir + "/src/shared/variant/variant.qbs", ] From e21b8e0c1d845962b55287f7ff7742ff680383a6 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 8 Feb 2024 17:40:18 +0100 Subject: [PATCH 47/82] Utils: Add FilePath constructor for TempFileSaver Change-Id: I15286be055bd69544e4283740bd0c3411573475c Reviewed-by: Reviewed-by: hjk --- src/libs/utils/fileutils.cpp | 28 ++++++++++++++++++++++++++++ src/libs/utils/fileutils.h | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 4530ea206b8..a2998e2f07d 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -238,6 +238,11 @@ bool FileSaver::finalize() } TempFileSaver::TempFileSaver(const QString &templ) +{ + initFromString(templ); +} + +void TempFileSaver::initFromString(const QString &templ) { m_file.reset(new QTemporaryFile{}); auto tempFile = static_cast(m_file.get()); @@ -253,6 +258,29 @@ TempFileSaver::TempFileSaver(const QString &templ) m_filePath = FilePath::fromString(tempFile->fileName()); } +TempFileSaver::TempFileSaver(const FilePath &templ) +{ + if (templ.isEmpty() || !templ.needsDevice()) { + initFromString(templ.path()); + } else { + expected_str result = templ.createTempFile(); + if (!result) { + m_errorString = Tr::tr("Cannot create temporary file %1: %2") + .arg(templ.toUserOutput(), result.error()); + m_hasError = true; + return; + } + + m_file.reset(new QFile(result->toFSPathString())); + if (!m_file->open(QIODevice::WriteOnly)) { + m_errorString = Tr::tr("Cannot create temporary file %1: %2") + .arg(result->toUserOutput(), m_file->errorString()); + m_hasError = true; + } + m_filePath = *result; + } +} + TempFileSaver::~TempFileSaver() { m_file.reset(); diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 316030b0397..b20f7568dbe 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -222,10 +222,14 @@ class QTCREATOR_UTILS_EXPORT TempFileSaver : public FileSaverBase { public: explicit TempFileSaver(const QString &templ = QString()); + explicit TempFileSaver(const FilePath &templ); ~TempFileSaver() override; void setAutoRemove(bool on) { m_autoRemove = on; } +protected: + void initFromString(const QString &templ); + private: bool m_autoRemove = true; }; From 291a893f5f5dbe0837ed145fb750417ee0f8475f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 8 Feb 2024 17:44:24 +0100 Subject: [PATCH 48/82] VCS: Allow remote vcs operations Both VcsBaseClient::vcsBinary() and VcsBaseClient::processEnvironment() get an additional parameter "FilePath target" to allow selecting binaries and environment based on where the repository is located. This allows to select e.g. a git binary on a remote device, and the environment of the remote device for each VCS operation. A bunch of file path operations are either fixed or ported to actually use FilePath correctly. Change-Id: I6afc645772fde3dff3ec19c13efe538e5888e952 Reviewed-by: hjk Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarplugin.cpp | 4 +- src/plugins/fossil/fossilclient.cpp | 12 ++-- src/plugins/fossil/fossilplugin.cpp | 13 +++-- src/plugins/git/branchmodel.cpp | 4 +- src/plugins/git/changeselectiondialog.cpp | 9 +-- src/plugins/git/gerrit/gerritmodel.cpp | 2 +- src/plugins/git/gerrit/gerritplugin.cpp | 4 +- src/plugins/git/gitclient.cpp | 54 ++++++++++-------- src/plugins/git/gitclient.h | 7 ++- src/plugins/git/gitgrep.cpp | 4 +- src/plugins/git/gitplugin.cpp | 37 ++++++------ src/plugins/git/mergetool.cpp | 2 +- src/plugins/mercurial/mercurialclient.cpp | 5 +- src/plugins/mercurial/mercurialplugin.cpp | 4 +- src/plugins/subversion/subversionclient.cpp | 6 +- src/plugins/subversion/subversionplugin.cpp | 4 +- src/plugins/vcsbase/vcsbaseclient.cpp | 63 ++++++++++++--------- src/plugins/vcsbase/vcsbaseclient.h | 8 ++- src/plugins/vcsbase/vcsbaseeditor.cpp | 2 +- src/plugins/vcsbase/vcsbaseplugin.cpp | 2 +- src/plugins/vcsbase/vcscommand.h | 8 ++- 21 files changed, 141 insertions(+), 113 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 8ca92f83a1c..9a75fbf3b3c 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -951,10 +951,10 @@ VcsCommand *BazaarPluginPrivate::createInitialCheckoutCommand(const QString &url args << m_client.vcsCommandString(BazaarClient::CloneCommand) << extraArgs << url << localName; - Environment env = m_client.processEnvironment(); + Environment env = m_client.processEnvironment(baseDirectory); env.set("BZR_PROGRESS_BAR", "text"); auto command = VcsBaseClient::createVcsCommand(baseDirectory, env); - command->addJob({m_client.vcsBinary(), args}, -1); + command->addJob({m_client.vcsBinary(baseDirectory), args}, -1); return command; } diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index e892978799e..d24935595a6 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -736,7 +736,7 @@ void FossilClient::annotate(const FilePath &workingDir, const QString &file, int lineNumber = -1; editor->setDefaultLineNumber(lineNumber); - enqueueJob(createCommand(workingDir, fossilEditor), args); + enqueueJob(createCommand(workingDir, fossilEditor), args, workingDir); } bool FossilClient::isVcsFileOrDirectory(const FilePath &filePath) const @@ -833,7 +833,7 @@ void FossilClient::view(const FilePath &source, const QString &id, const QString VcsBaseEditor::getCodec(source), "view", id); editor->setWorkingDirectory(workingDirectory); - enqueueJob(createCommand(workingDirectory, editor), args + extraOptions); + enqueueJob(createCommand(workingDirectory, editor), args + extraOptions, source); } class FossilLogHighlighter : QSyntaxHighlighter @@ -935,7 +935,7 @@ void FossilClient::log(const FilePath &workingDir, const QStringList &files, args << effectiveArgs; if (!files.isEmpty()) args << "--path" << files; - enqueueJob(createCommand(workingDir, fossilEditor), args); + enqueueJob(createCommand(workingDir, fossilEditor), args, workingDir); } void FossilClient::logCurrentFile(const FilePath &workingDir, const QStringList &files, @@ -989,7 +989,7 @@ void FossilClient::logCurrentFile(const FilePath &workingDir, const QStringList QStringList args(vcsCmdString); args << effectiveArgs << files; - enqueueJob(createCommand(workingDir, fossilEditor), args); + enqueueJob(createCommand(workingDir, fossilEditor), args, workingDir); } void FossilClient::revertFile(const FilePath &workingDir, @@ -1009,7 +1009,7 @@ void FossilClient::revertFile(const FilePath &workingDir, if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void FossilClient::revertAll(const FilePath &workingDir, const QString &revision, const QStringList &extraOptions) @@ -1033,7 +1033,7 @@ void FossilClient::revertAll(const FilePath &workingDir, const QString &revision if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(createCommand(workingDir), args); + enqueueJob(createCommand(workingDir), args, workingDir); } QString FossilClient::sanitizeFossilOutput(const QString &output) const diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 25fcdfa923a..c4ea13b4464 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -808,7 +808,7 @@ bool FossilPluginPrivate::managesFile(const FilePath &workingDirectory, const QS bool FossilPluginPrivate::isConfigured() const { - const FilePath binary = fossilClient().vcsBinary(); + const FilePath binary = fossilClient().vcsBinary({}); if (binary.isEmpty()) return false; @@ -927,7 +927,8 @@ VcsCommand *FossilPluginPrivate::createInitialCheckoutCommand(const QString &sou checkoutPath.createDir(); // Setup the wizard page command job - auto command = VcsBaseClient::createVcsCommand(checkoutPath, fossilClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(checkoutPath, + fossilClient().processEnvironment(checkoutPath)); if (!isLocalRepository && !cloneRepository.exists()) { @@ -963,7 +964,7 @@ VcsCommand *FossilPluginPrivate::createInitialCheckoutCommand(const QString &sou << extraOptions << sourceUrl << fossilFileNative; - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); } // check out the cloned repository file into the working copy directory; @@ -972,20 +973,20 @@ VcsCommand *FossilPluginPrivate::createInitialCheckoutCommand(const QString &sou QStringList args({"open", fossilFileNative}); if (!checkoutBranch.isEmpty()) args << checkoutBranch; - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); // set user default to admin user if specified if (!isLocalRepository && !adminUser.isEmpty()) { const QStringList args({ "user", "default", adminUser, "--user", adminUser}); - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); } // turn-off autosync if requested if (!isLocalRepository && disableAutosync) { const QStringList args({"settings", "autosync", "off"}); - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); } return command; diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index ed80feeb16a..99e6e010057 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -914,13 +914,13 @@ void BranchModel::updateUpstreamStatus(BranchNode *node) return; Process *process = new Process(node); - process->setEnvironment(gitClient().processEnvironment()); + process->setEnvironment(gitClient().processEnvironment(d->workingDirectory)); QStringList parameters = {"rev-list", "--no-color", "--count"}; if (node->tracking.isEmpty()) parameters += {node->fullRef(), "--not", "--remotes"}; else parameters += {"--left-right", node->fullRef() + "..." + node->tracking}; - process->setCommand({gitClient().vcsBinary(), parameters}); + process->setCommand({gitClient().vcsBinary(d->workingDirectory), parameters}); process->setWorkingDirectory(d->workingDirectory); connect(process, &Process::done, this, [this, process, node] { process->deleteLater(); diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp index cf991e6e938..12cc91eddb3 100644 --- a/src/plugins/git/changeselectiondialog.cpp +++ b/src/plugins/git/changeselectiondialog.cpp @@ -33,8 +33,8 @@ ChangeSelectionDialog::ChangeSelectionDialog(const FilePath &workingDirectory, I QWidget *parent) : QDialog(parent) { - m_gitExecutable = gitClient().vcsBinary(); - m_gitEnvironment = gitClient().processEnvironment(); + m_gitExecutable = gitClient().vcsBinary(workingDirectory); + m_gitEnvironment = gitClient().processEnvironment(workingDirectory); resize(550, 350); setWindowTitle(Tr::tr("Select a Git Commit")); @@ -209,8 +209,9 @@ void ChangeSelectionDialog::recalculateCompletion() return; Process *process = new Process(this); - process->setEnvironment(gitClient().processEnvironment()); - process->setCommand({gitClient().vcsBinary(), {"for-each-ref", "--format=%(refname:short)"}}); + process->setEnvironment(gitClient().processEnvironment(workingDir)); + process->setCommand( + {gitClient().vcsBinary(workingDir), {"for-each-ref", "--format=%(refname:short)"}}); process->setWorkingDirectory(workingDir); process->setUseCtrlCStub(true); connect(process, &Process::done, this, [this, process] { diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index b11458393e8..8af786ac5e5 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -266,7 +266,6 @@ QueryContext::QueryContext(const QString &query, m_output.append(m_process.readAllRawStandardOutput()); }); connect(&m_process, &Process::done, this, &QueryContext::processDone); - m_process.setEnvironment(Git::Internal::gitClient().processEnvironment()); m_timer.setInterval(timeOutMS); m_timer.setSingleShot(true); @@ -286,6 +285,7 @@ void QueryContext::start() VcsOutputWindow::appendCommand(m_process.workingDirectory(), commandLine); m_timer.start(); m_process.setCommand(commandLine); + m_process.setEnvironment(Git::Internal::gitClient().processEnvironment(m_binary)); auto progress = new Core::ProcessProgress(&m_process); progress->setDisplayName(Git::Tr::tr("Querying Gerrit")); m_process.start(); diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 802c921409a..3ef90358b9b 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -101,7 +101,7 @@ FetchContext::FetchContext(const std::shared_ptr &change, VcsBase::VcsOutputWindow::append(QString::fromLocal8Bit(m_process.readAllRawStandardOutput())); }); m_process.setWorkingDirectory(repository); - m_process.setEnvironment(gitClient().processEnvironment()); + m_process.setEnvironment(gitClient().processEnvironment(repository)); } void FetchContext::start() @@ -279,7 +279,7 @@ QString GerritPlugin::branch(const FilePath &repository) void GerritPlugin::fetch(const std::shared_ptr &change, int mode) { // Locate git. - const Utils::FilePath git = gitClient().vcsBinary(); + const Utils::FilePath git = gitClient().vcsBinary(m_dialog->repositoryPath()); if (git.isEmpty()) { VcsBase::VcsOutputWindow::appendError(Git::Tr::tr("Git is not available.")); return; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 5523ba1b48a..eb857c46859 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -827,15 +827,12 @@ FilePath GitClient::findRepositoryForDirectory(const FilePath &directory) const { if (directory.isEmpty() || directory.endsWith("/.git") || directory.path().contains("/.git/")) return {}; - // QFileInfo is outside loop, because it is faster this way - QFileInfo fileInfo; FilePath parent; for (FilePath dir = directory; !dir.isEmpty(); dir = dir.parentDir()) { const FilePath gitName = dir.pathAppended(GIT_DIRECTORY); if (!gitName.exists()) continue; // parent might exist - fileInfo.setFile(gitName.toString()); - if (fileInfo.isFile()) + if (gitName.isFile()) return dir; if (gitName.pathAppended("config").exists()) return dir; @@ -929,8 +926,8 @@ void GitClient::requestReload(const QString &documentId, const FilePath &source, QTC_ASSERT(document, return); GitBaseDiffEditorController *controller = factory(document); QTC_ASSERT(controller, return); - controller->setVcsBinary(settings().gitExecutable().value_or(FilePath{})); - controller->setProcessEnvironment(processEnvironment()); + controller->setVcsBinary(vcsBinary(workingDirectory)); + controller->setProcessEnvironment(processEnvironment(workingDirectory)); controller->setWorkingDirectory(workingDirectory); using namespace std::placeholders; @@ -1047,9 +1044,8 @@ void GitClient::log(const FilePath &workingDirectory, const QString &fileName, const QString title = Tr::tr("Git Log \"%1\"").arg(msgArg); const Id editorId = Git::Constants::GIT_LOG_EDITOR_ID; const FilePath sourceFile = VcsBaseEditor::getSource(workingDir, fileName); - GitEditorWidget *editor = static_cast( - createVcsEditor(editorId, title, sourceFile, - encoding(EncodingLogOutput), "logTitle", msgArg)); + GitEditorWidget *editor = static_cast(createVcsEditor( + editorId, title, sourceFile, encoding(EncodingLogOutput, sourceFile), "logTitle", msgArg)); VcsBaseEditorConfig *argWidget = editor->editorConfig(); if (!argWidget) { argWidget = new GitLogArgumentsWidget(!fileName.isEmpty(), editor); @@ -2089,9 +2085,9 @@ bool GitClient::synchronousApplyPatch(const FilePath &workingDirectory, return false; } -Environment GitClient::processEnvironment() const +Environment GitClient::processEnvironment(const FilePath &appliedTo) const { - Environment environment = VcsBaseClientImpl::processEnvironment(); + Environment environment; environment.prependOrSetPath(settings().path()); if (HostOsInfo::isWindowsHost() && settings().winSetHomeEnvironment()) { QString homePath; @@ -2103,7 +2099,7 @@ Environment GitClient::processEnvironment() const environment.set("HOME", homePath); } environment.set("GIT_EDITOR", m_disableEditor ? "true" : m_gitQtcEditor); - return environment; + return environment.appliedToEnvironment(appliedTo.deviceEnvironment()); } bool GitClient::beginStashScope(const FilePath &workingDirectory, const QString &command, @@ -2387,7 +2383,7 @@ QStringList GitClient::synchronousRepositoryBranches(const QString &repositoryUR void GitClient::launchGitK(const FilePath &workingDirectory, const QString &fileName) const { - tryLaunchingGitK(processEnvironment(), workingDirectory, fileName); + tryLaunchingGitK(processEnvironment(workingDirectory), workingDirectory, fileName); } void GitClient::launchRepositoryBrowser(const FilePath &workingDirectory) const @@ -2420,7 +2416,7 @@ void GitClient::tryLaunchingGitK(const Environment &env, const QString &fileName, GitClient::GitKLaunchTrial trial) const { - const FilePath gitBinDirectory = gitBinDir(trial, vcsBinary().parentDir()); + const FilePath gitBinDirectory = gitBinDir(trial, vcsBinary(workingDirectory).parentDir()); FilePath binary = gitBinDirectory.pathAppended("gitk").withExecutableSuffix(); QStringList arguments; if (HostOsInfo::isWindowsHost()) { @@ -2469,7 +2465,7 @@ void GitClient::handleGitKFailedToStart(const Environment &env, GitKLaunchTrial nextTrial = None; - if (oldTrial == Bin && vcsBinary().parentDir().fileName() == "bin") { + if (oldTrial == Bin && vcsBinary(workingDirectory).parentDir().fileName() == "bin") { nextTrial = ParentOfBin; } else if (oldTrial != SystemPath && !Environment::systemEnvironment().searchInPath("gitk").isEmpty()) { @@ -2486,7 +2482,7 @@ void GitClient::handleGitKFailedToStart(const Environment &env, bool GitClient::launchGitGui(const FilePath &workingDirectory) { bool success = true; - FilePath gitBinary = vcsBinary(); + FilePath gitBinary = vcsBinary(workingDirectory); if (gitBinary.isEmpty()) { success = false; } else { @@ -2501,7 +2497,7 @@ bool GitClient::launchGitGui(const FilePath &workingDirectory) { FilePath GitClient::gitBinDirectory() const { - const QString git = vcsBinary().toString(); + const QString git = vcsBinary({}).toString(); if (git.isEmpty()) return {}; @@ -2529,7 +2525,7 @@ FilePath GitClient::gitBinDirectory() const bool GitClient::launchGitBash(const FilePath &workingDirectory) { bool success = true; - const FilePath git = vcsBinary(); + const FilePath git = vcsBinary(workingDirectory); if (git.isEmpty()) { success = false; @@ -2544,8 +2540,18 @@ bool GitClient::launchGitBash(const FilePath &workingDirectory) return success; } -FilePath GitClient::vcsBinary() const +FilePath GitClient::vcsBinary(const FilePath &forDirectory) const { + if (forDirectory.needsDevice()) { + auto it = m_gitExecutableCache.find(forDirectory.withNewPath({})); + if (it == m_gitExecutableCache.end()) { + const FilePath gitBin = forDirectory.withNewPath("git").searchInPath(); + it = m_gitExecutableCache.insert(forDirectory.withNewPath({}), + gitBin.isExecutableFile() ? gitBin : FilePath{}); + } + + return it.value(); + } return settings().gitExecutable().value_or(FilePath{}); } @@ -2753,7 +2759,7 @@ bool GitClient::addAndCommit(const FilePath &repositoryDirectory, const GitSubmitEditorPanelData &data, CommitType commitType, const QString &amendSHA1, - const QString &messageFile, + const FilePath &messageFile, SubmitFileModel *model) { const QString renameSeparator = " -> "; @@ -2817,7 +2823,7 @@ bool GitClient::addAndCommit(const FilePath &repositoryDirectory, if (commitType == FixupCommit) { arguments << "--fixup" << amendSHA1; } else { - arguments << "-F" << QDir::toNativeSeparators(messageFile); + arguments << "-F" << messageFile.nativePath(); if (commitType == AmendCommit) arguments << "--amend"; const QString &authorString = data.authorString(); @@ -3243,7 +3249,7 @@ void GitClient::vcsExecAbortable(const FilePath &workingDirectory, const QString command->addFlags(RunFlags::ShowStdOut | RunFlags::ShowSuccessMessage); // For rebase, Git might request an editor (which means the process keeps running until the // user closes it), so run without timeout. - command->addJob({vcsBinary(), arguments}, isRebase ? 0 : vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, isRebase ? 0 : vcsTimeoutS()); const QObject *actualContext = context ? context : this; connect(command, &VcsCommand::done, actualContext, [=] { const CommandResult result = CommandResult(*command); @@ -3461,7 +3467,7 @@ QFuture GitClient::gitVersion() const // Do not execute repeatedly if that fails (due to git // not being installed) until settings are changed. - const FilePath newGitBinary = vcsBinary(); + const FilePath newGitBinary = vcsBinary({}); const bool needToRunGit = m_gitVersionForBinary != newGitBinary && !newGitBinary.isEmpty(); if (needToRunGit) { auto proc = new Process(const_cast(this)); @@ -3476,7 +3482,7 @@ QFuture GitClient::gitVersion() const proc->deleteLater(); }); - proc->setEnvironment(processEnvironment()); + proc->setEnvironment(processEnvironment(newGitBinary)); proc->setCommand({newGitBinary, {"--version"}}); proc->start(); } else { diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index f0ed9ffc8eb..823aae6736d 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -123,7 +123,7 @@ public: GitClient(); ~GitClient(); - Utils::FilePath vcsBinary() const override; + Utils::FilePath vcsBinary(const Utils::FilePath &forDirectory) const override; QFuture gitVersion() const; void vcsExecAbortable(const Utils::FilePath &workingDirectory, const QStringList &arguments, @@ -295,7 +295,7 @@ public: const GitSubmitEditorPanelData &data, CommitType commitType, const QString &amendSHA1, - const QString &messageFile, + const Utils::FilePath &messageFile, VcsBase::SubmitFileModel *model); enum StatusResult { StatusChanged, StatusUnchanged, StatusFailed }; @@ -318,7 +318,7 @@ public: QStringList synchronousRepositoryBranches(const QString &repositoryURL, const Utils::FilePath &workingDirectory = {}) const; - Utils::Environment processEnvironment() const override; + Utils::Environment processEnvironment(const Utils::FilePath &appliedTo) const override; bool beginStashScope(const Utils::FilePath &workingDirectory, const QString &command, StashFlag flag = Default, PushAction pushAction = NoPush); @@ -395,6 +395,7 @@ private: mutable Utils::FilePath m_gitVersionForBinary; mutable QVersionNumber m_cachedGitVersion; + mutable QMap m_gitExecutableCache; QString m_gitQtcEditor; QMap m_stashInfo; diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 2f1f0bda49a..5675fe0f484 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -134,8 +134,8 @@ static void runGitGrep(QPromise &promise, const FileFindParam const GitGrepParameters &gitParameters) { const auto setupProcess = [¶meters, gitParameters](Process &process) { - const FilePath vcsBinary = gitClient().vcsBinary(); - const Environment environment = gitClient().processEnvironment(); + const FilePath vcsBinary = gitClient().vcsBinary(parameters.searchDir); + const Environment environment = gitClient().processEnvironment(vcsBinary); QStringList arguments = { "-c", "color.grep.match=bold red", diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 915796bdbf0..966abc40b8c 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -281,7 +281,7 @@ public: const Context &context); void updateRepositoryBrowserAction(); - IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd); + IEditor *openSubmitEditor(const FilePath &fileName, const CommitData &cd); void cleanCommitMessageFile(); void cleanRepository(const FilePath &directory); void applyPatch(const FilePath &workingDirectory, QString file = {}); @@ -319,7 +319,7 @@ public: BranchViewFactory m_branchViewFactory; QPointer m_remoteDialog; FilePath m_submitRepository; - QString m_commitMessageFileName; + FilePath m_commitMessageFileName; InstantBlame m_instantBlame; @@ -402,7 +402,7 @@ void GitPluginPrivate::onApplySettings() void GitPluginPrivate::cleanCommitMessageFile() { if (!m_commitMessageFileName.isEmpty()) { - QFile::remove(m_commitMessageFileName); + m_commitMessageFileName.removeFile(); m_commitMessageFileName.clear(); } } @@ -986,8 +986,12 @@ void GitPluginPrivate::blameFile() const FilePath fileName = state.currentFile().canonicalPath(); FilePath topLevel; VcsManager::findVersionControlForDirectory(fileName.parentDir(), &topLevel); - gitClient().annotate(topLevel, fileName.relativeChildPath(topLevel).toString(), - lineNumber, {}, extraOptions, firstLine); + gitClient().annotate(topLevel, + fileName.relativeChildPath(topLevel).path(), + lineNumber, + {}, + extraOptions, + firstLine); } void GitPluginPrivate::logProject() @@ -1247,7 +1251,9 @@ void GitPluginPrivate::startCommit(CommitType commitType) m_submitRepository = data.panelInfo.repository; // Start new temp file with message template - TempFileSaver saver; + TempFileSaver saver( + data.panelInfo.repository.tmpDir().value_or(data.panelInfo.repository.withNewPath("")) + / "commit-msg.XXXXXX"); // Keep the file alive, else it removes self and forgets its name saver.setAutoRemove(false); saver.write(commitTemplate.toLocal8Bit()); @@ -1255,7 +1261,7 @@ void GitPluginPrivate::startCommit(CommitType commitType) VcsOutputWindow::appendError(saver.errorString()); return; } - m_commitMessageFileName = saver.filePath().toString(); + m_commitMessageFileName = saver.filePath(); openSubmitEditor(m_commitMessageFileName, data); } @@ -1284,10 +1290,9 @@ void GitPluginPrivate::instantBlameOnce() m_instantBlame.once(); } -IEditor *GitPluginPrivate::openSubmitEditor(const QString &fileName, const CommitData &cd) +IEditor *GitPluginPrivate::openSubmitEditor(const FilePath &fileName, const CommitData &cd) { - IEditor *editor = EditorManager::openEditor(FilePath::fromString(fileName), - Constants::GITSUBMITEDITOR_ID); + IEditor *editor = EditorManager::openEditor(fileName, Constants::GITSUBMITEDITOR_ID); auto submitEditor = qobject_cast(editor); QTC_ASSERT(submitEditor, return nullptr); setSubmitEditor(submitEditor); @@ -1320,10 +1325,9 @@ bool GitPluginPrivate::activateCommit() QTC_ASSERT(editorDocument, return true); // Submit editor closing. Make it write out the commit message // and retrieve files - const QFileInfo editorFile = editorDocument->filePath().toFileInfo(); - const QFileInfo changeFile(m_commitMessageFileName); + // Paranoia! - if (editorFile.absoluteFilePath() != changeFile.absoluteFilePath()) + if (!editorDocument->filePath().isSameFile(m_commitMessageFileName)) return true; auto model = qobject_cast(editor->fileModel()); @@ -1700,7 +1704,7 @@ bool GitPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) const bool GitPluginPrivate::isConfigured() const { - return !gitClient().vcsBinary().isEmpty(); + return !gitClient().vcsBinary({}).isEmpty(); } bool GitPluginPrivate::supportsOperation(Operation operation) const @@ -1765,9 +1769,10 @@ VcsCommand *GitPluginPrivate::createInitialCheckoutCommand(const QString &url, QStringList args = {"clone", "--progress"}; args << extraArgs << url << localName; - auto command = VcsBaseClient::createVcsCommand(baseDirectory, gitClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(baseDirectory, + gitClient().processEnvironment(baseDirectory)); command->addFlags(RunFlags::SuppressStdErr); - command->addJob({gitClient().vcsBinary(), args}, -1); + command->addJob({gitClient().vcsBinary(baseDirectory), args}, -1); return command; } diff --git a/src/plugins/git/mergetool.cpp b/src/plugins/git/mergetool.cpp index 8829c445180..d0a102c9df4 100644 --- a/src/plugins/git/mergetool.cpp +++ b/src/plugins/git/mergetool.cpp @@ -37,7 +37,7 @@ void MergeTool::start(const FilePath &workingDirectory, const QStringList &files { QStringList arguments; arguments << "mergetool" << "-y" << files; - const CommandLine cmd = {gitClient().vcsBinary(), arguments}; + const CommandLine cmd = {gitClient().vcsBinary(workingDirectory), arguments}; VcsOutputWindow::appendCommand(workingDirectory, cmd); m_process.setCommand(cmd); m_process.setWorkingDirectory(workingDirectory); diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 81228964229..fd568c9741f 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -273,7 +273,7 @@ void MercurialClient::incoming(const FilePath &repositoryRoot, const QString &re VcsBaseEditorWidget *editor = createVcsEditor(Constants::DIFFLOG_ID, title, repositoryRoot, VcsBaseEditor::getCodec(repositoryRoot), "incoming", id); - enqueueJob(createCommand(FilePath::fromString(repository), editor), args); + enqueueJob(createCommand(FilePath::fromString(repository), editor), args, repositoryRoot); } void MercurialClient::outgoing(const FilePath &repositoryRoot) @@ -286,7 +286,7 @@ void MercurialClient::outgoing(const FilePath &repositoryRoot) VcsBaseEditorWidget *editor = createVcsEditor(Constants::DIFFLOG_ID, title, repositoryRoot, VcsBaseEditor::getCodec(repositoryRoot), "outgoing", repositoryRoot.toString()); - enqueueJob(createCommand(repositoryRoot, editor), args); + enqueueJob(createCommand(repositoryRoot, editor), args, repositoryRoot); } void MercurialClient::annotate(const Utils::FilePath &workingDir, const QString &file, @@ -424,7 +424,6 @@ void MercurialClient::requestReload(const QString &documentId, const FilePath &s QTC_ASSERT(document, return); auto controller = new MercurialDiffEditorController(document, args); controller->setVcsBinary(settings().binaryPath()); - controller->setProcessEnvironment(processEnvironment()); controller->setWorkingDirectory(workingDirectory); VcsBase::setSource(document, sourceCopy); diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 91c25139d9f..8e4d90f045c 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -736,7 +736,9 @@ VcsCommand *MercurialPluginPrivate::createInitialCheckoutCommand(const QString & { QStringList args; args << QLatin1String("clone") << extraArgs << url << localName; - auto command = VcsBaseClient::createVcsCommand(baseDirectory, mercurialClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(baseDirectory, + mercurialClient().processEnvironment( + baseDirectory)); command->addJob({settings().binaryPath(), args}, -1); return command; } diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 4f378731d4b..e30abd5bc81 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -57,7 +57,7 @@ bool SubversionClient::doCommit(const FilePath &repositoryRoot, const QString &commitMessageFile, const QStringList &extraOptions) const { - CommandLine args{vcsBinary()}; + CommandLine args{vcsBinary(repositoryRoot)}; args << vcsCommandString(CommitCommand) << extraOptions << AddAuthOptions() @@ -117,7 +117,7 @@ QString SubversionClient::synchronousTopic(const FilePath &repository) const { QStringList args; - QString svnVersionBinary = vcsBinary().toString(); + QString svnVersionBinary = vcsBinary(repository).toString(); int pos = svnVersionBinary.lastIndexOf('/'); if (pos < 0) svnVersionBinary.clear(); @@ -237,7 +237,7 @@ SubversionDiffEditorController *SubversionClient::findOrCreateDiffEditor(const Q if (!controller) { controller = new SubversionDiffEditorController(document); controller->setVcsBinary(settings().binaryPath()); - controller->setProcessEnvironment(processEnvironment()); + controller->setProcessEnvironment(processEnvironment(workingDirectory)); controller->setWorkingDirectory(workingDirectory); } VcsBase::setSource(document, source); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index cab80c64d0d..fc9d5ed1222 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -1135,7 +1135,9 @@ VcsCommand *SubversionPluginPrivate::createInitialCheckoutCommand(const QString args << SubversionClient::AddAuthOptions(); args << Subversion::Constants::NON_INTERACTIVE_OPTION << extraArgs << url << localName; - auto command = VcsBaseClient::createVcsCommand(baseDirectory, subversionClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(baseDirectory, + subversionClient().processEnvironment( + baseDirectory)); command->addJob(args, -1); return command; } diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index ea2ddcadc5d..81a816c0099 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -61,15 +61,18 @@ VcsBaseClientImpl::VcsBaseClientImpl(VcsBaseSettings *baseSettings) this, &VcsBaseClientImpl::saveSettings); } -FilePath VcsBaseClientImpl::vcsBinary() const +FilePath VcsBaseClientImpl::vcsBinary(const Utils::FilePath &forDirectory) const { + if (forDirectory.needsDevice()) + return {}; + return m_baseSettings->binaryPath(); } VcsCommand *VcsBaseClientImpl::createCommand(const FilePath &workingDirectory, VcsBaseEditorWidget *editor) const { - auto cmd = createVcsCommand(workingDirectory, processEnvironment()); + auto cmd = createVcsCommand(workingDirectory, processEnvironment(workingDirectory)); if (editor) { editor->setCommand(cmd); connect(cmd, &VcsCommand::done, editor, [editor, cmd] { @@ -88,24 +91,24 @@ void VcsBaseClientImpl::setupCommand(Utils::Process &process, const FilePath &workingDirectory, const QStringList &args) const { - process.setEnvironment(processEnvironment()); + process.setEnvironment(workingDirectory.deviceEnvironment()); process.setWorkingDirectory(workingDirectory); - process.setCommand({vcsBinary(), args}); + process.setCommand({vcsBinary(workingDirectory), args}); process.setUseCtrlCStub(true); } -void VcsBaseClientImpl::enqueueJob(VcsCommand *cmd, const QStringList &args, +void VcsBaseClientImpl::enqueueJob(VcsCommand *cmd, + const QStringList &args, + const Utils::FilePath &forDirectory, const ExitCodeInterpreter &interpreter) const { - cmd->addJob({vcsBinary(), args}, vcsTimeoutS(), {}, interpreter); + cmd->addJob({vcsBinary(forDirectory), args}, vcsTimeoutS(), {}, interpreter); cmd->start(); } -Environment VcsBaseClientImpl::processEnvironment() const +Environment VcsBaseClientImpl::processEnvironment(const FilePath &appliedTo) const { - Environment environment = Environment::systemEnvironment(); - VcsBase::setProcessEnvironment(&environment); - return environment; + return appliedTo.deviceEnvironment(); } QStringList VcsBaseClientImpl::splitLines(const QString &s) @@ -129,14 +132,18 @@ QString VcsBaseClientImpl::stripLastNewline(const QString &in) CommandResult VcsBaseClientImpl::vcsSynchronousExec(const FilePath &workingDir, const QStringList &args, RunFlags flags, int timeoutS, QTextCodec *codec) const { - return vcsSynchronousExec(workingDir, {vcsBinary(), args}, flags, timeoutS, codec); + return vcsSynchronousExec(workingDir, {vcsBinary(workingDir), args}, flags, timeoutS, codec); } CommandResult VcsBaseClientImpl::vcsSynchronousExec(const FilePath &workingDir, const CommandLine &cmdLine, RunFlags flags, int timeoutS, QTextCodec *codec) const { - return VcsCommand::runBlocking(workingDir, processEnvironment(), cmdLine, flags, - timeoutS > 0 ? timeoutS : vcsTimeoutS(), codec); + return VcsCommand::runBlocking(workingDir, + processEnvironment(workingDir), + cmdLine, + flags, + timeoutS > 0 ? timeoutS : vcsTimeoutS(), + codec); } void VcsBaseClientImpl::resetCachedVcsInfo(const FilePath &workingDir) @@ -166,7 +173,7 @@ void VcsBaseClientImpl::vcsExecWithHandler(const FilePath &workingDirectory, VcsCommand *command = createCommand(workingDirectory); command->addFlags(additionalFlags); command->setCodec(codec); - command->addJob({vcsBinary(), arguments}, vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, vcsTimeoutS()); if (handler) { const QObject *actualContext = context ? context : this; connect(command, &VcsCommand::done, actualContext, [command, handler] { @@ -182,7 +189,7 @@ void VcsBaseClientImpl::vcsExec(const FilePath &workingDirectory, { VcsCommand *command = createCommand(workingDirectory); command->addFlags(additionalFlags); - command->addJob({vcsBinary(), arguments}, vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, vcsTimeoutS()); command->start(); } @@ -192,7 +199,7 @@ void VcsBaseClientImpl::vcsExecWithEditor(const Utils::FilePath &workingDirector { VcsCommand *command = createCommand(workingDirectory, editor); command->setCodec(editor->codec()); - command->addJob({vcsBinary(), arguments}, vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, vcsTimeoutS()); command->start(); } @@ -350,7 +357,7 @@ void VcsBaseClient::annotate(const Utils::FilePath &workingDir, const QString &f VcsCommand *cmd = createCommand(workingDir, editor); editor->setDefaultLineNumber(lineNumber); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::diff(const FilePath &workingDir, const QStringList &files) @@ -387,7 +394,7 @@ void VcsBaseClient::diff(const FilePath &workingDir, const QStringList &files) : VcsBaseEditor::getCodec(source); VcsCommand *command = createCommand(workingDir, editor); command->setCodec(codec); - enqueueJob(command, args, exitCodeInterpreter(DiffCommand)); + enqueueJob(command, args, workingDir, exitCodeInterpreter(DiffCommand)); } void VcsBaseClient::log(const FilePath &workingDir, @@ -421,7 +428,7 @@ void VcsBaseClient::log(const FilePath &workingDir, } } - CommandLine args{vcsBinary(), {vcsCmdString}}; + CommandLine args{vcsBinary(workingDir), {vcsCmdString}}; if (addAuthOptions) addAuthOptions(args); if (editorConfig) @@ -448,7 +455,7 @@ void VcsBaseClient::revertFile(const FilePath &workingDir, if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::revertAll(const FilePath &workingDir, @@ -464,7 +471,7 @@ void VcsBaseClient::revertAll(const FilePath &workingDir, if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::status(const FilePath &workingDir, @@ -475,7 +482,7 @@ void VcsBaseClient::status(const FilePath &workingDir, args << extraOptions << file; VcsCommand *cmd = createCommand(workingDir); cmd->addFlags(RunFlags::ShowStdOut); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::emitParsedStatus(const FilePath &repository, const QStringList &extraOptions) @@ -484,7 +491,7 @@ void VcsBaseClient::emitParsedStatus(const FilePath &repository, const QStringLi args << extraOptions; VcsCommand *cmd = createCommand(repository); connect(cmd, &VcsCommand::done, this, [this, cmd] { statusParser(cmd->cleanedStdOut()); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, repository); } QString VcsBaseClient::vcsCommandString(VcsCommandTag cmd) const @@ -525,7 +532,7 @@ void VcsBaseClient::import(const FilePath &repositoryRoot, { QStringList args(vcsCommandString(ImportCommand)); args << extraOptions << files; - enqueueJob(createCommand(repositoryRoot), args); + enqueueJob(createCommand(repositoryRoot), args, repositoryRoot); } void VcsBaseClient::view(const FilePath &source, @@ -541,7 +548,7 @@ void VcsBaseClient::view(const FilePath &source, VcsBaseEditor::getCodec(source), "view", id); const FilePath workingDirPath = source.isFile() ? source.absolutePath() : source; - enqueueJob(createCommand(workingDirPath, editor), args); + enqueueJob(createCommand(workingDirPath, editor), args, source); } void VcsBaseClient::update(const FilePath &repositoryRoot, const QString &revision, @@ -554,7 +561,7 @@ void VcsBaseClient::update(const FilePath &repositoryRoot, const QString &revisi if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(repositoryRoot.toString()); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, repositoryRoot); } void VcsBaseClient::commit(const FilePath &repositoryRoot, @@ -576,12 +583,12 @@ void VcsBaseClient::commit(const FilePath &repositoryRoot, cmd->addFlags(RunFlags::ShowStdOut); if (!commitMessageFile.isEmpty()) connect(cmd, &VcsCommand::done, [commitMessageFile] { QFile(commitMessageFile).remove(); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, repositoryRoot); } QString VcsBaseClient::vcsEditorTitle(const QString &vcsCmd, const QString &sourceId) const { - return vcsBinary().baseName() + QLatin1Char(' ') + vcsCmd + QLatin1Char(' ') + return vcsBinary({}).baseName() + QLatin1Char(' ') + vcsCmd + QLatin1Char(' ') + FilePath::fromString(sourceId).fileName(); } diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index f1db56ebeb9..99b818b59b7 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -41,7 +41,7 @@ public: explicit VcsBaseClientImpl(VcsBaseSettings *baseSettings); ~VcsBaseClientImpl() override = default; - virtual Utils::FilePath vcsBinary() const; + virtual Utils::FilePath vcsBinary(const Utils::FilePath &forDirectory) const; int vcsTimeoutS() const; static VcsCommand *createVcsCommand(const Utils::FilePath &defaultWorkingDir, @@ -59,10 +59,12 @@ public: const Utils::FilePath &workingDirectory, const QStringList &args) const; - void enqueueJob(VcsCommand *cmd, const QStringList &args, + void enqueueJob(VcsCommand *cmd, + const QStringList &args, + const Utils::FilePath &forDirectory, const ExitCodeInterpreter &interpreter = {}) const; - virtual Utils::Environment processEnvironment() const; + virtual Utils::Environment processEnvironment(const Utils::FilePath &appliedTo) const; // VCS functionality: virtual void annotate(const Utils::FilePath &workingDir, const QString &file, diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index d365be71569..b10758233a0 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -1327,7 +1327,7 @@ bool VcsBaseEditor::gotoLineOfEditor(IEditor *e, int lineNumber) // ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file'). FilePath VcsBaseEditor::getSource(const FilePath &workingDirectory, const QString &fileName) { - return workingDirectory.pathAppended(fileName); + return workingDirectory.resolvePath(fileName); } FilePath VcsBaseEditor::getSource(const FilePath &workingDirectory, const QStringList &fileNames) diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index ee2ea428137..b506f0ed380 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -374,7 +374,7 @@ FilePath VcsBasePluginState::currentFileDirectory() const QString VcsBasePluginState::relativeCurrentFile() const { QTC_ASSERT(hasFile(), return {}); - return data->m_state.currentFile.relativeChildPath(data->m_state.currentFileTopLevel).toString(); + return data->m_state.currentFile.relativeChildPath(data->m_state.currentFileTopLevel).path(); } QString VcsBasePluginState::currentPatchFile() const diff --git a/src/plugins/vcsbase/vcscommand.h b/src/plugins/vcsbase/vcscommand.h index e9975dcb140..62711395445 100644 --- a/src/plugins/vcsbase/vcscommand.h +++ b/src/plugins/vcsbase/vcscommand.h @@ -82,9 +82,11 @@ public: void setProgressParser(const Core::ProgressParser &parser); static CommandResult runBlocking(const Utils::FilePath &workingDirectory, - const Utils::Environment &environmentconst, - const Utils::CommandLine &command, RunFlags flags, - int timeoutS, QTextCodec *codec); + const Utils::Environment &environment, + const Utils::CommandLine &command, + RunFlags flags, + int timeoutS, + QTextCodec *codec); void cancel(); QString cleanedStdOut() const; From 0afe354952416e55193ce908e7018ec982ef9dcd Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Thu, 8 Feb 2024 10:29:35 +0100 Subject: [PATCH 49/82] Android: Update Android Stidio jdk detection Fixes: QTCREATORBUG-28866 Fixes: QTCREATORBUG-30322 Change-Id: Id7908301a6c6acb540e6a7d575cc6b8b95cdf5d6 Reviewed-by: Alessandro Portale --- src/plugins/android/androidconfigurations.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 2b0bd9492e0..21a20ff645c 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1479,9 +1479,12 @@ FilePath AndroidConfig::getJdkPath() // Look for Android Studio's jdk first const FilePath androidStudioSdkPath = androidStudioPath(); if (!androidStudioSdkPath.isEmpty()) { - const FilePath androidStudioSdkJrePath = androidStudioSdkPath / "jre"; - if (androidStudioSdkJrePath.exists()) - jdkHome = androidStudioSdkJrePath; + const QStringList allVersions{"jbr", "jre"}; + for (const QString &version : allVersions) { + const FilePath androidStudioSdkJbrPath = androidStudioSdkPath / version; + if (androidStudioSdkJbrPath.exists()) + return androidStudioSdkJbrPath; + } } if (jdkHome.isEmpty()) { From 7f1e16172a6a8a0a66c8505df80fcf156a26f894 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 9 Feb 2024 18:02:51 +0100 Subject: [PATCH 50/82] CMakePM: Traverse the whole inheritance tree for Presets Regarding QTCREATORBUG-30288, before this change I was getting on macOS presets for Linux and Windows. Fixes: QTCREATORBUG-30236 Fixes: QTCREATORBUG-30288 Change-Id: I4772ab7d14dec857b68164d4c24e6e904f20c88b Reviewed-by: Alessandro Portale --- .../cmakeprojectmanager/cmakeproject.cpp | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 3a79e4a376e..7318c7a791f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -89,6 +89,21 @@ PresetsData CMakeProject::presetsData() const return m_presetsData; } +template +static QStringList recursiveInheritsList(const T &presetsHash, const QStringList &inheritsList) +{ + QStringList result; + for (const QString &inheritFrom : inheritsList) { + result << inheritFrom; + if (presetsHash.contains(inheritFrom)) { + auto item = presetsHash[inheritFrom]; + if (item.inherits) + result << recursiveInheritsList(presetsHash, item.inherits.value()); + } + } + return result; +} + Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakePresetsData, Internal::PresetsData &cmakeUserPresetsData) { @@ -135,12 +150,14 @@ Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakeP if (!p.inherits) continue; - for (const QString &inheritFromName : p.inherits.value()) { - if (presetsHash.contains(inheritFromName)) { - p.inheritFrom(presetsHash[inheritFromName]); + const QStringList inheritsList = recursiveInheritsList(presetsHash, + p.inherits.value()); + Utils::reverseForeach(inheritsList, [&presetsHash, &p](const QString &inheritFrom) { + if (presetsHash.contains(inheritFrom)) { + p.inheritFrom(presetsHash[inheritFrom]); presetsHash[p.name] = p; } - } + }); } }; From 4aaf7f2689d6879d953cd7fe32b4905cc6c191f7 Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Wed, 7 Feb 2024 20:16:21 +0100 Subject: [PATCH 51/82] Debugger: Add debugging helper for std::tuple Add debugging helper for std::tuple and add a corresponding dumper test for it. With this in place, the std::tuple variable and its elements in the "tuple.cpp" sample program from QTCREATORBUG-25865 are shown as expected on both, Linux (libstdc++) with GDB or LLDB and with an MSVC build with CDB on Windows. A debugging helper for libc++ had already been added in commit 34ff9c97e60fffda06c3cb5bc87eae7491b0025f. Task-number: QTCREATORBUG-25865 Change-Id: I24b3d36b5daa26fd4fcb073c4df79015dfe752fc Reviewed-by: hjk --- share/qtcreator/debugger/stdtypes.py | 30 ++++++++++++++++++++++++++++ tests/auto/debugger/tst_dumpers.cpp | 12 +++++++++++ 2 files changed, 42 insertions(+) diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index 1c98c767258..bc4bb84dcbb 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -697,6 +697,36 @@ def qdump__std__pair(d, value): d.putValue('(%s, %s)' % (key, value)) +def qdumpHelper_get_tuple_elements(d, tuple, value_typename, value_member): + """ + Helper method that returns the elements of a tuple. + """ + elems = [] + other_members = [] + for member in tuple.members(True): + if not member.type.templateArguments(): + continue + if member.type.name.startswith(value_typename): + elems.append(member[value_member]) + else: + other_members.append(member) + for member in other_members: + sub_elems = qdumpHelper_get_tuple_elements(d, member, value_typename, value_member) + elems = elems + sub_elems + return elems + + +def qdump__std__tuple(d, value): + if d.isMsvcTarget(): + elems = qdumpHelper_get_tuple_elements(d, value, "std::_Tuple_val", "_Val") + else: + elems = qdumpHelper_get_tuple_elements(d, value, "std::_Head_base", "_M_head_impl") + d.putItemCount(len(elems)) + with Children(d): + for elem in elems: + d.putSubItem(0, elem) + + def qform__std__unordered_map(): return [DisplayFormat.CompactMap] diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 613eb9c72bb..1cf8f1bbf2f 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -5348,6 +5348,18 @@ void tst_Dumpers::dumper_data() + Check("v.0", "[0]", "\"foo\"", "std::string"); + QTest::newRow("StdTuple") + << Data("#include \n", + + "std::tuple tuple = std::make_tuple(123, std::string(\"hello\"), 456);\n", + + "&tuple") + + + Check("tuple.0", "[0]", "123", "int") + + Check("tuple.1", "[1]", "\"hello\"", "std::string") + + Check("tuple.2", "[2]", "456", "int"); + + QTest::newRow("StdValArray") << Data("#include \n" "#include \n", From 1726d8a0c831cc3a5edf760b9579a3307299343c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 12 Feb 2024 11:01:03 +0100 Subject: [PATCH 52/82] Welcome: Fix font sizes Fixes: QTCREATORBUG-30305 Change-Id: Ib00bd75c091c6caadd110aaf8e2c12abcbe16cea Reviewed-by: Eike Ziller --- src/plugins/coreplugin/iwelcomepage.cpp | 1 - src/plugins/coreplugin/welcomepagehelper.cpp | 3 --- src/plugins/projectexplorer/projectwelcomepage.cpp | 2 -- src/plugins/welcome/welcomeplugin.cpp | 1 - 4 files changed, 7 deletions(-) diff --git a/src/plugins/coreplugin/iwelcomepage.cpp b/src/plugins/coreplugin/iwelcomepage.cpp index 50f8499708f..3eb63d80312 100644 --- a/src/plugins/coreplugin/iwelcomepage.cpp +++ b/src/plugins/coreplugin/iwelcomepage.cpp @@ -175,7 +175,6 @@ void WelcomePageButton::setSize(Size size) const int hMargin = size == SizeSmall ? 12 : 26; const int vMargin = size == SizeSmall ? 2 : 4; d->m_layout->setContentsMargins(hMargin, vMargin, hMargin, vMargin); - d->m_label->setFont(size == SizeSmall ? font() : StyleHelper::uiFont(StyleHelper::UiElementH2)); } void WelcomePageButton::setWithAccentColor(bool withAccent) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 37874a9e46f..44fc75270dd 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -87,7 +87,6 @@ SearchBox::SearchBox(QWidget *parent) m_lineEdit = new FancyLineEdit; m_lineEdit->setFiltering(true); m_lineEdit->setFrame(false); - m_lineEdit->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); m_lineEdit->setMinimumHeight(33); m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); @@ -806,7 +805,6 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetContentsMargins(0, ItemGap, 0, 0); - sectionLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); auto scrollArea = qobject_cast(widget(0)); auto vbox = qobject_cast(scrollArea->widget()->layout()); @@ -877,7 +875,6 @@ void SectionedGridView::zoomInSection(const Section §ion) noMargin }.emerge(); sectionLabel->setContentsMargins(0, ItemGap, 0, 0); - sectionLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); auto gridView = new GridView(zoomedInWidget); gridView->setItemDelegate(m_itemDelegate); diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 11d27bf441b..45524bdb169 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -583,11 +583,9 @@ public: manageSessionsButton->setOnClicked([] { SessionManager::showSessionManager(); }); auto sessionsLabel = new QLabel(this); - sessionsLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); sessionsLabel->setText(Tr::tr("Sessions")); auto recentProjectsLabel = new QLabel(this); - recentProjectsLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); recentProjectsLabel->setText(Tr::tr("Projects")); auto sessionsList = new TreeView(this, "Sessions"); diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index b7161fcb0dc..0590823ea63 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -245,7 +245,6 @@ public: vbox->addItem(newVBox); auto newLabel = new QLabel(Tr::tr("New to Qt?"), mainWidget); - newLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); newLabel->setAlignment(Qt::AlignHCenter); newVBox->addWidget(newLabel); From dbc68fe3aacb0ad8d6d318b758721b5580a5e14c Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Feb 2024 12:44:05 +0100 Subject: [PATCH 53/82] BinEditor: Allow selections beyond offset 2^31 Fixes: QTCREATORBUG-30282 Change-Id: I18c6ee313b07d3e0606b7fc1e661ef6c90e026e9 Reviewed-by: Marcus Tillmanns --- src/plugins/bineditor/bineditorwidget.cpp | 16 ++++++++-------- src/plugins/bineditor/bineditorwidget.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/bineditor/bineditorwidget.cpp b/src/plugins/bineditor/bineditorwidget.cpp index 1d4765b3ca1..a79f2b80c40 100644 --- a/src/plugins/bineditor/bineditorwidget.cpp +++ b/src/plugins/bineditor/bineditorwidget.cpp @@ -581,13 +581,13 @@ void BinEditorWidget::updateLines() updateLines(m_cursorPosition, m_cursorPosition); } -void BinEditorWidget::updateLines(int fromPosition, int toPosition) +void BinEditorWidget::updateLines(qint64 fromPosition, qint64 toPosition) { - int topLine = verticalScrollBar()->value(); - int firstLine = qMin(fromPosition, toPosition) / m_bytesPerLine; - int lastLine = qMax(fromPosition, toPosition) / m_bytesPerLine; - int y = (firstLine - topLine) * m_lineHeight; - int h = (lastLine - firstLine + 1 ) * m_lineHeight; + const qint64 topLine = verticalScrollBar()->value(); + const qint64 firstLine = qMin(fromPosition, toPosition) / m_bytesPerLine; + const qint64 lastLine = qMax(fromPosition, toPosition) / m_bytesPerLine; + const int y = (firstLine - topLine) * m_lineHeight; + const int h = (lastLine - firstLine + 1 ) * m_lineHeight; viewport()->update(0, y, viewport()->width(), h); } @@ -800,7 +800,7 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) int foundPatternAt = findPattern(patternData, patternDataHex, patternOffset, patternOffset, &matchLength); - int selStart, selEnd; + qint64 selStart, selEnd; if (m_cursorPosition >= m_anchorPosition) { selStart = m_anchorPosition; selEnd = m_cursorPosition; @@ -1006,7 +1006,7 @@ qint64 BinEditorWidget::cursorPosition() const void BinEditorWidget::setCursorPosition(qint64 pos, MoveMode moveMode) { pos = qMin(m_size - 1, qMax(qint64(0), pos)); - int oldCursorPosition = m_cursorPosition; + qint64 oldCursorPosition = m_cursorPosition; m_lowNibble = false; m_cursorPosition = pos; diff --git a/src/plugins/bineditor/bineditorwidget.h b/src/plugins/bineditor/bineditorwidget.h index 2ad78e51310..17d2de8beda 100644 --- a/src/plugins/bineditor/bineditorwidget.h +++ b/src/plugins/bineditor/bineditorwidget.h @@ -198,7 +198,7 @@ private: bool inTextArea(const QPoint &pos) const; QRect cursorRect() const; void updateLines(); - void updateLines(int fromPosition, int toPosition); + void updateLines(qint64 fromPosition, qint64 toPosition); void ensureCursorVisible(); void setBlinkingCursorEnabled(bool enable); From ff85a58ce50b7b8f71fba723862f211283d9ffd7 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Feb 2024 12:56:21 +0100 Subject: [PATCH 54/82] BinEditor: Use 64bit positions in a few more places This fixes drawing of search hits across the 2^31 boundary. Searching itself is still buggy. Change-Id: Icac1722e2693585aa7afe62076ccec9459c18f3a Reviewed-by: Marcus Tillmanns --- src/plugins/bineditor/bineditorplugin.cpp | 8 +-- src/plugins/bineditor/bineditorwidget.cpp | 83 ++++++++++++----------- src/plugins/bineditor/bineditorwidget.h | 16 ++--- 3 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 5410385f9df..f3a5ed9879f 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -79,7 +79,7 @@ public: m_widget->highlightSearchResults(QByteArray()); } - int find(const QByteArray &pattern, int pos, FindFlags findFlags, bool *wrapped) + qint64 find(const QByteArray &pattern, qint64 pos, FindFlags findFlags, bool *wrapped) { if (wrapped) *wrapped = false; @@ -88,7 +88,7 @@ public: return pos; } - int res = m_widget->find(pattern, pos, Utils::textDocumentFlagsForFindFlags(findFlags)); + qint64 res = m_widget->find(pattern, pos, Utils::textDocumentFlagsForFindFlags(findFlags)); if (res < 0) { pos = (findFlags & FindBackward) ? -1 : 0; res = m_widget->find(pattern, pos, Utils::textDocumentFlagsForFindFlags(findFlags)); @@ -111,7 +111,7 @@ public: if (m_contPos == -1) m_contPos = m_incrementalStartPos; bool wrapped; - int found = find(pattern, m_contPos, findFlags, &wrapped); + qint64 found = find(pattern, m_contPos, findFlags, &wrapped); if (wrapped != m_incrementalWrappedState && (found >= 0)) { m_incrementalWrappedState = wrapped; showWrapIndicator(m_widget); @@ -147,7 +147,7 @@ public: m_contPos = m_widget->selectionStart()-1; } bool wrapped; - int found = find(pattern, m_contPos, findFlags, &wrapped); + qint64 found = find(pattern, m_contPos, findFlags, &wrapped); if (wrapped) showWrapIndicator(m_widget); Result result; diff --git a/src/plugins/bineditor/bineditorwidget.cpp b/src/plugins/bineditor/bineditorwidget.cpp index a79f2b80c40..da6efc69f88 100644 --- a/src/plugins/bineditor/bineditorwidget.cpp +++ b/src/plugins/bineditor/bineditorwidget.cpp @@ -592,9 +592,9 @@ void BinEditorWidget::updateLines(qint64 fromPosition, qint64 toPosition) viewport()->update(0, y, viewport()->width(), h); } -int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const +qint64 BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const { - int trailing = pattern.size(); + qint64 trailing = pattern.size(); if (trailing > m_blockSize) return -1; @@ -603,7 +603,7 @@ int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool ca QByteArrayMatcher matcher(pattern); qint64 block = from / m_blockSize; - const int end = qMin(from + SearchStride, m_size); + const qint64 end = qMin(from + SearchStride, m_size); while (from < end) { if (!requestDataAt(block * m_blockSize)) return -1; @@ -615,7 +615,7 @@ int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool ca if (!caseSensitive) buffer = buffer.toLower(); - int pos = matcher.indexIn(buffer, from - (block * m_blockSize) + trailing); + qint64 pos = matcher.indexIn(buffer, from - (block * m_blockSize) + trailing); if (pos >= 0) return pos + block * m_blockSize - trailing; ++block; @@ -624,9 +624,9 @@ int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool ca return end == m_size ? -1 : -2; } -int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const +qint64 BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const { - int trailing = pattern.size(); + qint64 trailing = pattern.size(); if (trailing > m_blockSize) return -1; @@ -635,10 +635,10 @@ int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, boo if (from == -1) from = m_size; - int block = from / m_blockSize; - const int lowerBound = qMax(qint64(0), from - SearchStride); + qint64 block = from / m_blockSize; + const qint64 lowerBound = qMax(0, from - SearchStride); while (from > lowerBound) { - if (!requestDataAt(qint64(block) * m_blockSize)) + if (!requestDataAt(block * m_blockSize)) return -1; QByteArray data = blockData(block); char *b = buffer.data(); @@ -648,18 +648,19 @@ int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, boo if (!caseSensitive) buffer = buffer.toLower(); - int pos = buffer.lastIndexOf(pattern, from - (block * m_blockSize)); + qint64 pos = buffer.lastIndexOf(pattern, from - (block * m_blockSize)); if (pos >= 0) return pos + block * m_blockSize; --block; - from = qint64(block) * m_blockSize + (m_blockSize-1) + trailing; + from = block * m_blockSize + (m_blockSize-1) + trailing; } return lowerBound == 0 ? -1 : -2; } -int BinEditorWidget::find(const QByteArray &pattern_arg, qint64 from, - QTextDocument::FindFlags findFlags) +qint64 BinEditorWidget::find(const QByteArray &pattern_arg, + qint64 from, + QTextDocument::FindFlags findFlags) { if (pattern_arg.isEmpty()) return 0; @@ -672,14 +673,14 @@ int BinEditorWidget::find(const QByteArray &pattern_arg, qint64 from, pattern = pattern.toLower(); bool backwards = (findFlags & QTextDocument::FindBackward); - int found = backwards ? dataLastIndexOf(pattern, from, caseSensitiveSearch) - : dataIndexOf(pattern, from, caseSensitiveSearch); + qint64 found = backwards ? dataLastIndexOf(pattern, from, caseSensitiveSearch) + : dataIndexOf(pattern, from, caseSensitiveSearch); - int foundHex = -1; + qint64 foundHex = -1; QByteArray hexPattern = calculateHexPattern(pattern_arg); if (!hexPattern.isEmpty()) { foundHex = backwards ? dataLastIndexOf(hexPattern, from) - : dataIndexOf(hexPattern, from); + : dataIndexOf(hexPattern, from); } qint64 pos = foundHex == -1 || (found >= 0 && (foundHex == -2 || found < foundHex)) @@ -695,15 +696,16 @@ int BinEditorWidget::find(const QByteArray &pattern_arg, qint64 from, return pos; } -int BinEditorWidget::findPattern(const QByteArray &data, const QByteArray &dataHex, - int from, int offset, int *match) +qint64 BinEditorWidget::findPattern(const QByteArray &data, const QByteArray &dataHex, + qint64 from, qint64 offset, qint64 *match) { if (m_searchPattern.isEmpty()) return -1; - int normal = m_searchPattern.isEmpty() - ? -1 : data.indexOf(m_searchPattern, from - offset); - int hex = m_searchPatternHex.isEmpty() - ? -1 : dataHex.indexOf(m_searchPatternHex, from - offset); + + qint64 normal = m_searchPattern.isEmpty() + ? -1 : data.indexOf(m_searchPattern, from - offset); + qint64 hex = m_searchPatternHex.isEmpty() + ? -1 : dataHex.indexOf(m_searchPatternHex, from - offset); if (normal >= 0 && (hex < 0 || normal < hex)) { if (match) @@ -787,10 +789,10 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) painter.fillRect(e->rect() & r, palette().alternateBase()); } - int matchLength = 0; + qint64 matchLength = 0; QByteArray patternData, patternDataHex; - int patternOffset = qMax(0, topLine*m_bytesPerLine - m_searchPattern.size()); + qint64 patternOffset = qMax(0, topLine * m_bytesPerLine - m_searchPattern.size()); if (!m_searchPattern.isEmpty()) { patternData = dataMid(patternOffset, m_numVisibleLines * m_bytesPerLine + (topLine*m_bytesPerLine - patternOffset)); patternDataHex = patternData; @@ -798,7 +800,7 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) patternData = patternData.toLower(); } - int foundPatternAt = findPattern(patternData, patternDataHex, patternOffset, patternOffset, &matchLength); + qint64 foundPatternAt = findPattern(patternData, patternDataHex, patternOffset, patternOffset, &matchLength); qint64 selStart, selEnd; if (m_cursorPosition >= m_anchorPosition) { @@ -817,13 +819,13 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) painter.setPen(palette().text().color()); const QFontMetrics &fm = painter.fontMetrics(); - for (int i = 0; i <= m_numVisibleLines; ++i) { + for (qint64 i = 0; i <= m_numVisibleLines; ++i) { qint64 line = topLine + i; if (line >= m_numLines) break; const quint64 lineAddress = m_baseAddr + line * m_bytesPerLine; - int y = i * m_lineHeight + m_ascent; + qint64 y = i * m_lineHeight + m_ascent; if (y - m_ascent > e->rect().bottom()) break; if (y + m_descent < e->rect().top()) @@ -1377,33 +1379,34 @@ void BinEditorWidget::keyPressEvent(QKeyEvent *e) break; case Qt::Key_PageUp: case Qt::Key_PageDown: { - int line = qMax(qint64(0), m_cursorPosition / m_bytesPerLine - verticalScrollBar()->value()); + qint64 line = qMax(qint64(0), m_cursorPosition / m_bytesPerLine - verticalScrollBar()->value()); verticalScrollBar()->triggerAction(e->key() == Qt::Key_PageUp ? QScrollBar::SliderPageStepSub : QScrollBar::SliderPageStepAdd); if (!ctrlPressed) setCursorPosition((verticalScrollBar()->value() + line) * m_bytesPerLine + m_cursorPosition % m_bytesPerLine, moveMode); - } break; - + break; + } case Qt::Key_Home: { - int pos; + qint64 pos; if (ctrlPressed) pos = 0; else - pos = m_cursorPosition/m_bytesPerLine * m_bytesPerLine; + pos = m_cursorPosition / m_bytesPerLine * m_bytesPerLine; setCursorPosition(pos, moveMode); - } break; + break; + } case Qt::Key_End: { - int pos; + qint64 pos; if (ctrlPressed) pos = m_size; else - pos = m_cursorPosition/m_bytesPerLine * m_bytesPerLine + 15; + pos = m_cursorPosition / m_bytesPerLine * m_bytesPerLine + 15; setCursorPosition(pos, moveMode); - } break; - default: + break; + } + default: { if (m_readOnly) break; - { QString text = e->text(); for (int i = 0; i < text.length(); ++i) { QChar c = text.at(i); @@ -1499,7 +1502,7 @@ void BinEditorWidget::highlightSearchResults(const QByteArray &pattern, QTextDoc viewport()->update(); } -void BinEditorWidget::changeData(int position, uchar character, bool highNibble) +void BinEditorWidget::changeData(qint64 position, uchar character, bool highNibble) { if (!requestDataAt(position)) return; diff --git a/src/plugins/bineditor/bineditorwidget.h b/src/plugins/bineditor/bineditorwidget.h index 17d2de8beda..aab235fb453 100644 --- a/src/plugins/bineditor/bineditorwidget.h +++ b/src/plugins/bineditor/bineditorwidget.h @@ -79,7 +79,7 @@ public: void setReadOnly(bool); bool isReadOnly() const; - int find(const QByteArray &pattern, qint64 from = 0, QTextDocument::FindFlags findFlags = {}); + qint64 find(const QByteArray &pattern, qint64 from = 0, QTextDocument::FindFlags findFlags = {}); void selectAll(); void clear(); @@ -90,8 +90,8 @@ public: Core::IEditor *editor() const { return m_ieditor; } void setEditor(Core::IEditor *ieditor) { m_ieditor = ieditor; } - int selectionStart() const { return qMin(m_anchorPosition, m_cursorPosition); } - int selectionEnd() const { return qMax(m_anchorPosition, m_cursorPosition); } + qint64 selectionStart() const { return qMin(m_anchorPosition, m_cursorPosition); } + qint64 selectionEnd() const { return qMax(m_anchorPosition, m_cursorPosition); } bool event(QEvent*) override; @@ -146,8 +146,8 @@ private: QByteArray m_lowerBlock; qint64 m_size = 0; - int dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; - int dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; + qint64 dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; + qint64 dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; bool requestDataAt(qint64 pos) const; bool requestOldDataAt(qint64 pos) const; @@ -202,10 +202,10 @@ private: void ensureCursorVisible(); void setBlinkingCursorEnabled(bool enable); - void changeData(int position, uchar character, bool highNibble = false); + void changeData(qint64 position, uchar character, bool highNibble = false); - int findPattern(const QByteArray &data, const QByteArray &dataHex, - int from, int offset, int *match); + qint64 findPattern(const QByteArray &data, const QByteArray &dataHex, + qint64 from, qint64 offset, qint64 *match); void drawItems(QPainter *painter, int x, int y, const QString &itemString); void drawChanges(QPainter *painter, int x, int y, const char *changes); From 844e005363ac85728b7b73bc82ac8683f3915415 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Feb 2024 14:31:34 +0100 Subject: [PATCH 55/82] BinEditor: Use a few more qint64 instead of int Change-Id: I4907cba425fd213cc2411d20919ff67e2dce71c4 Reviewed-by: Marcus Tillmanns --- src/plugins/bineditor/bineditorwidget.cpp | 28 +++++++++++------------ src/plugins/bineditor/bineditorwidget.h | 6 ++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/plugins/bineditor/bineditorwidget.cpp b/src/plugins/bineditor/bineditorwidget.cpp index da6efc69f88..90e6855ef76 100644 --- a/src/plugins/bineditor/bineditorwidget.cpp +++ b/src/plugins/bineditor/bineditorwidget.cpp @@ -238,16 +238,16 @@ bool BinEditorWidget::requestOldDataAt(qint64 pos) const char BinEditorWidget::dataAt(qint64 pos, bool old) const { - qint64 block = pos / m_blockSize; - int offset = static_cast(pos - block * m_blockSize); + const qint64 block = pos / m_blockSize; + const qint64 offset = pos - block * m_blockSize; return blockData(block, old).at(offset); } void BinEditorWidget::changeDataAt(qint64 pos, char c) { - qint64 block = pos / m_blockSize; + const qint64 block = pos / m_blockSize; BlockMap::iterator it = m_modifiedData.find(block); - int offset = static_cast(pos - block * m_blockSize); + const qint64 offset = pos - block * m_blockSize; if (it != m_modifiedData.end()) { it.value()[offset] = c; } else { @@ -262,7 +262,7 @@ void BinEditorWidget::changeDataAt(qint64 pos, char c) d->announceChangedData(m_baseAddr + pos, QByteArray(1, c)); } -QByteArray BinEditorWidget::dataMid(qint64 from, int length, bool old) const +QByteArray BinEditorWidget::dataMid(qint64 from, qint64 length, bool old) const { qint64 end = from + length; qint64 block = from / m_blockSize; @@ -1464,9 +1464,9 @@ void BinEditorWidget::zoomF(float delta) void BinEditorWidget::copy(bool raw) { - int selStart = selectionStart(); - int selEnd = selectionEnd(); - const int selectionLength = selEnd - selStart + 1; + const qint64 selStart = selectionStart(); + const qint64 selEnd = selectionEnd(); + const qint64 selectionLength = selEnd - selStart + 1; if (selectionLength >> 22) { QMessageBox::warning(this, Tr::tr("Copying Failed"), Tr::tr("You cannot copy more than 4 MB of binary data.")); @@ -1482,7 +1482,7 @@ void BinEditorWidget::copy(bool raw) QString hexString; const char * const hex = "0123456789abcdef"; hexString.reserve(3 * data.size()); - for (int i = 0; i < data.size(); ++i) { + for (qint64 i = 0; i < data.size(); ++i) { const uchar val = static_cast(data[i]); hexString.append(QLatin1Char(hex[val >> 4])).append(QLatin1Char(hex[val & 0xf])).append(QLatin1Char(' ')); } @@ -1575,8 +1575,8 @@ void BinEditorWidget::redo() void BinEditorWidget::contextMenuEvent(QContextMenuEvent *event) { - const int selStart = selectionStart(); - const int byteCount = selectionEnd() - selStart + 1; + const qint64 selStart = selectionStart(); + const qint64 byteCount = selectionEnd() - selStart + 1; QPointer contextMenu(new QMenu(this)); @@ -1720,12 +1720,12 @@ void BinEditorWidget::asDouble(qint64 offset, double &value, bool old) const value = *f; } -void BinEditorWidget::asIntegers(qint64 offset, int count, quint64 &bigEndianValue, - quint64 &littleEndianValue, bool old) const +void BinEditorWidget::asIntegers(qint64 offset, qint64 count, quint64 &bigEndianValue, + quint64 &littleEndianValue, bool old) const { bigEndianValue = littleEndianValue = 0; const QByteArray &data = dataMid(offset, count, old); - for (int pos = 0; pos < data.size(); ++pos) { + for (qint64 pos = 0; pos < data.size(); ++pos) { const quint64 val = static_cast(data.at(pos)) & 0xff; littleEndianValue += val << (pos * 8); bigEndianValue += val << ((count - pos - 1) * 8); diff --git a/src/plugins/bineditor/bineditorwidget.h b/src/plugins/bineditor/bineditorwidget.h index aab235fb453..5fb6f2a3fbd 100644 --- a/src/plugins/bineditor/bineditorwidget.h +++ b/src/plugins/bineditor/bineditorwidget.h @@ -154,12 +154,12 @@ private: char dataAt(qint64 pos, bool old = false) const; char oldDataAt(qint64 pos) const; void changeDataAt(qint64 pos, char c); - QByteArray dataMid(qint64 from, int length, bool old = false) const; + QByteArray dataMid(qint64 from, qint64 length, bool old = false) const; QByteArray blockData(qint64 block, bool old = false) const; QPoint offsetToPos(qint64 offset) const; - void asIntegers(qint64 offset, int count, quint64 &bigEndianValue, quint64 &littleEndianValue, - bool old = false) const; + void asIntegers(qint64 offset, qint64 count, quint64 &bigEndianValue, quint64 &littleEndianValue, + bool old = false) const; void asFloat(qint64 offset, float &value, bool old) const; void asDouble(qint64 offset, double &value, bool old) const; QString toolTip(const QHelpEvent *helpEvent) const; From f8383a44aac32355300f8a057df211e001f9dc9f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 12 Feb 2024 13:55:56 +0100 Subject: [PATCH 56/82] Axivion: Tweak fetch for issues Fetch issues for all kinds of issues instead of just style violations. Change-Id: I23508ae3c051cabab644f359daec4924034cb65c Reviewed-by: Andreas Loth Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionplugin.cpp | 95 +++++++++------------------ src/plugins/axivion/axivionplugin.h | 6 ++ 2 files changed, 38 insertions(+), 63 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 26f5196a9ad..efdfa620789 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -53,21 +53,6 @@ using namespace Utils; namespace Axivion::Internal { -class Issue -{ -public: - QString id; - QString state; - QString errorNumber; - QString message; - QString entity; - QString filePath; - QString severity; - int lineNumber = 0; -}; - -using Issues = QList; - QIcon iconForIssue(const QString &prefix) { static QHash prefixToIcon; @@ -154,7 +139,7 @@ public: void onDocumentOpened(IDocument *doc); void onDocumentClosed(IDocument * doc); void clearAllMarks(); - void handleIssuesForFile(const Issues &issues); + void handleIssuesForFile(const Dto::FileViewDto &fileView); void fetchIssueInfo(const QString &id); NetworkAccessManager m_networkAccessManager; @@ -173,16 +158,16 @@ static AxivionPluginPrivate *dd = nullptr; class AxivionTextMark : public TextMark { public: - AxivionTextMark(const FilePath &filePath, const Issue &issue) - : TextMark(filePath, issue.lineNumber, {Tr::tr("Axivion"), AxivionTextMarkId}) + AxivionTextMark(const FilePath &filePath, const Dto::LineMarkerDto &issue) + : TextMark(filePath, issue.startLine, {Tr::tr("Axivion"), AxivionTextMarkId}) { - const QString markText = issue.entity.isEmpty() ? issue.message - : issue.entity + ": " + issue.message; - setToolTip(issue.errorNumber + " " + markText); - setIcon(iconForIssue("SV")); // FIXME adapt to the issue + const QString markText = issue.description; + const QString id = issue.kind + QString::number(issue.id.value_or(-1)); + setToolTip(id + markText); + setIcon(iconForIssue(issue.kind)); setPriority(TextMark::NormalPriority); setLineAnnotation(markText); - setActionsProvider([id = issue.id] { + setActionsProvider([id] { auto action = new QAction; action->setIcon(Utils::Icons::INFO.icon()); action->setToolTip(Tr::tr("Show rule details")); @@ -495,6 +480,17 @@ Group issueTableRecipe(const IssueListSearch &search, const IssueTableHandler &h return fetchDataRecipe(url, handler); } +Group lineMarkerRecipe(const Utils::FilePath &filePath, const LineMarkerHandler &handler) +{ + QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? + QTC_ASSERT(!filePath.isEmpty(), return {}); // TODO: Call handler with unexpected? + + const QString fileName = QString::fromUtf8(QUrl::toPercentEncoding(filePath.path())); + const QUrl url = urlForProject(dd->m_currentProjectInfo.value().name + '/') + .resolved(QString("files?filename=" + fileName)); + return fetchDataRecipe(url, handler); +} + Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler) { QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? @@ -569,7 +565,7 @@ void AxivionPluginPrivate::fetchIssueInfo(const QString &id) dd->m_axivionOutputPane.updateAndShowRule(QString::fromUtf8(fixedHtml)); }; - m_issueInfoRunner.start(issueHtmlRecipe(QString("SV") + id, ruleHandler)); + m_issueInfoRunner.start(issueHtmlRecipe(id, ruleHandler)); } void AxivionPluginPrivate::handleOpenedDocs() @@ -591,41 +587,16 @@ void AxivionPluginPrivate::onDocumentOpened(IDocument *doc) if (!doc || !m_currentProjectInfo || !m_project || !m_project->isKnownFile(doc->filePath())) return; - IssueListSearch search; - search.kind = "SV"; - search.filter_path = doc->filePath().relativeChildPath(m_project->projectDirectory()).path(); - search.limit = 0; + const FilePath filePath = doc->filePath().relativeChildPath(m_project->projectDirectory()); + QTC_ASSERT(!filePath.isEmpty(), return); - const auto issuesHandler = [this](const Dto::IssueTableDto &dto) { - Issues issues; - const std::vector> &rows = dto.rows; - for (const auto &row : rows) { - Issue issue; - for (auto it = row.cbegin(); it != row.cend(); ++it) { - if (it->first == "id") - issue.id = anyToSimpleString(it->second); - else if (it->first == "state") - issue.state = anyToSimpleString(it->second); - else if (it->first == "errorNumber") - issue.errorNumber = anyToSimpleString(it->second); - else if (it->first == "message") - issue.message = anyToSimpleString(it->second); - else if (it->first == "entity") - issue.entity = anyToSimpleString(it->second); - else if (it->first == "path") - issue.filePath = anyToSimpleString(it->second); - else if (it->first == "severity") - issue.severity = anyToSimpleString(it->second); - else if (it->first == "line") - issue.lineNumber = anyToSimpleString(it->second).toInt(); - } - issues << issue; - } - handleIssuesForFile(issues); + const auto handler = [this](const Dto::FileViewDto &data) { + if (data.lineMarkers.empty()) + return; + handleIssuesForFile(data); }; - TaskTree *taskTree = new TaskTree; - taskTree->setRecipe(issueTableRecipe(search, issuesHandler)); + taskTree->setRecipe(lineMarkerRecipe(filePath, handler)); m_docMarksTrees.insert_or_assign(doc, std::unique_ptr(taskTree)); connect(taskTree, &TaskTree::done, this, [this, doc] { const auto it = m_docMarksTrees.find(doc); @@ -653,24 +624,22 @@ void AxivionPluginPrivate::onDocumentClosed(IDocument *doc) } } -void AxivionPluginPrivate::handleIssuesForFile(const Issues &issues) +void AxivionPluginPrivate::handleIssuesForFile(const Dto::FileViewDto &fileView) { - if (issues.isEmpty()) + if (fileView.lineMarkers.empty()) return; Project *project = ProjectManager::startupProject(); if (!project) return; - const FilePath filePath = project->projectDirectory() - .pathAppended(issues.first().filePath); + const FilePath filePath = project->projectDirectory().pathAppended(fileView.fileName); - const Id axivionId(AxivionTextMarkId); - for (const Issue &issue : issues) { + for (const Dto::LineMarkerDto &marker : std::as_const(fileView.lineMarkers)) { // FIXME the line location can be wrong (even the whole issue could be wrong) // depending on whether this line has been changed since the last axivion run and the // current state of the file - some magic has to happen here - new AxivionTextMark(filePath, issue); + new AxivionTextMark(filePath, marker); } } diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index a8090c6b7a6..1d5245a5034 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -19,6 +19,8 @@ namespace ProjectExplorer { class Project; } namespace Tasking { class Group; } +namespace Utils { class FilePath; } + namespace Axivion::Internal { struct IssueListSearch @@ -57,6 +59,10 @@ Tasking::Group tableInfoRecipe(const QString &prefix, const TableInfoHandler &ha using IssueTableHandler = std::function; Tasking::Group issueTableRecipe(const IssueListSearch &search, const IssueTableHandler &handler); +// TODO: Wrap into expected_str<>? +using LineMarkerHandler = std::function; +Tasking::Group lineMarkerRecipe(const Utils::FilePath &filePath, const LineMarkerHandler &handler); + using HtmlHandler = std::function; Tasking::Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler); From 8313190ee960d5eb97623b29249ac567ded66e47 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 13 Feb 2024 09:13:31 +0100 Subject: [PATCH 57/82] Terminal: Fix nullopt access Change-Id: I758dadc481b3ebe6b7274ab0dde52ec5f2d7dfa3 Reviewed-by: hjk --- src/plugins/terminal/terminalpane.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 096fffcba1f..16486387134 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -106,7 +106,8 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) } } - if (parametersCopy.workingDirectory->needsDevice() && !parametersCopy.shellCommand) { + if (parametersCopy.workingDirectory && parametersCopy.workingDirectory->needsDevice() + && !parametersCopy.shellCommand) { const FilePath shell = parametersCopy.workingDirectory->withNewPath( parametersCopy.environment .value_or(parametersCopy.workingDirectory->deviceEnvironment()) From acb449bb2bc84f75e3ec0aeecdd1641ab3ce89f7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 12 Feb 2024 11:52:13 +0100 Subject: [PATCH 58/82] TextEditor: Fix a leak of CompletionAssistProvider The c'tor of QmlJSEditorFactory allocates QmlJSCompletionAssistProvider and sets it via setCompletionAssistProvider. The QbsEditorFactory subclass allocates QbsCompletionAssistProvider and overrides the previous one via setCompletionAssistProvider. So, the old one was leaking. Use std::unique_ptr to ensure the ownership. Change-Id: I6fb7da2b97c50919e422482c858d3503403b788d Reviewed-by: David Schulz --- src/plugins/texteditor/texteditor.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 1ed6d0db513..e50311b1371 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -25,7 +25,6 @@ #include "refactoroverlay.h" #include "snippets/snippetoverlay.h" #include "storagesettings.h" -#include "syntaxhighlighter.h" #include "tabsettings.h" #include "textdocument.h" #include "textdocumentlayout.h" @@ -9425,7 +9424,7 @@ public: TextEditorFactory::SyntaxHighLighterCreator m_syntaxHighlighterCreator; CommentDefinition m_commentDefinition; QList m_hoverHandlers; // owned - CompletionAssistProvider * m_completionAssistProvider = nullptr; // owned + std::unique_ptr m_completionAssistProvider; // owned std::unique_ptr m_textEditorActionHandler; bool m_useGenericHighlighter = false; bool m_duplicatedSupported = true; @@ -9445,7 +9444,6 @@ TextEditorFactory::TextEditorFactory() TextEditorFactory::~TextEditorFactory() { qDeleteAll(d->m_hoverHandlers); - delete d->m_completionAssistProvider; delete d; } @@ -9472,8 +9470,9 @@ void TextEditorFactory::setEditorCreator(const EditorCreator &creator) if (d->m_syntaxHighlighterCreator) doc->resetSyntaxHighlighter(d->m_syntaxHighlighterCreator); - doc->setCompletionAssistProvider(d->m_completionAssistProvider ? d->m_completionAssistProvider - : &basicSnippetProvider); + doc->setCompletionAssistProvider(d->m_completionAssistProvider + ? d->m_completionAssistProvider.get() + : &basicSnippetProvider); return d->createEditorHelper(doc); }); @@ -9511,7 +9510,7 @@ void TextEditorFactory::addHoverHandler(BaseHoverHandler *handler) void TextEditorFactory::setCompletionAssistProvider(CompletionAssistProvider *provider) { - d->m_completionAssistProvider = provider; + d->m_completionAssistProvider.reset(provider); } void TextEditorFactory::setCommentDefinition(CommentDefinition definition) From 9c4bd40f7c21c13f993368d3e64bdb90da4ecc25 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Feb 2024 16:36:10 +0100 Subject: [PATCH 59/82] Debugger: Fix Qml debugger rampdown when not fully started Fixes: QTCREATORBUG-30355 Change-Id: I3e7c1ef56db1fe48f5b571d21f89d20b7936cfb7 Reviewed-by: David Schulz --- src/plugins/debugger/qml/qmlengine.cpp | 15 ++------------- src/plugins/debugger/qml/qmlengine.h | 1 - 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 7c907678aed..d271d15c5a5 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -208,7 +208,6 @@ public: bool unpausedEvaluate = false; bool contextEvaluate = false; bool supportChangeBreakpoint = false; - bool hasQuit = false; QTimer connectionTimer; QmlDebug::QDebugMessageClient *msgClient = nullptr; @@ -380,7 +379,7 @@ void QmlEngine::beginConnection() void QmlEngine::connectionStartupFailed() { - if (d->hasQuit) + if (isDying()) return; if (d->retryOnConnectFail) { @@ -502,8 +501,7 @@ void QmlEngine::startProcess() void QmlEngine::stopProcess() { - if (d->process.isRunning()) - d->process.close(); + d->process.close(); } void QmlEngine::shutdownInferior() @@ -937,15 +935,6 @@ bool QmlEngine::hasCapability(unsigned cap) const | AddWatcherCapability;*/ } -void QmlEngine::quitDebugger() -{ - d->automaticConnect = false; - d->retryOnConnectFail = false; - d->hasQuit = true; - stopProcess(); - closeConnection(); -} - void QmlEngine::doUpdateLocals(const UpdateParameters ¶ms) { d->updateLocals(params.qmlFocusOnFrame); diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 2006ce081ff..7c609e12496 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -91,7 +91,6 @@ private: bool companionPreventsActions() const override; bool hasCapability(unsigned) const override; - void quitDebugger() override; void doUpdateLocals(const UpdateParameters ¶ms) override; Core::Context languageContext() const override; From 231e7da7617dbe2ff1811d5dc9f4de8c542a1596 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 11 Feb 2024 12:53:52 +0100 Subject: [PATCH 60/82] Axivion: Drop known namespace specifiers Add more "using namespace". Change-Id: Ib207d14c79c692eb87d52cbc95917539c88f0536 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionoutputpane.cpp | 10 +++--- src/plugins/axivion/axivionplugin.cpp | 4 +-- .../axivion/axivionprojectsettings.cpp | 32 +++++++++---------- src/plugins/axivion/axivionsettings.cpp | 23 ++++++------- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index ec5ae042292..a9fb3a4e3f4 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -35,6 +35,8 @@ #include +using namespace Core; +using namespace ProjectExplorer; using namespace Tasking; using namespace Utils; @@ -199,11 +201,11 @@ public: if (role == BaseTreeView::ItemActivatedRole && !m_links.isEmpty()) { // TODO for now only simple - just the first.. Link link = m_links.first(); - ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); + Project *project = ProjectManager::startupProject(); FilePath baseDir = project ? project->projectDirectory() : FilePath{}; link.targetFilePath = baseDir.resolvePath(link.targetFilePath); if (link.targetFilePath.exists()) - Core::EditorManager::openEditorAt(link); + EditorManager::openEditorAt(link); return true; } return StaticTreeItem::setData(column, value, role); @@ -591,7 +593,7 @@ void IssuesWidget::fetchMoreIssues() } AxivionOutputPane::AxivionOutputPane(QObject *parent) - : Core::IOutputPane(parent) + : IOutputPane(parent) { setId("Axivion"); setDisplayName(Tr::tr("Axivion")); @@ -702,7 +704,7 @@ void AxivionOutputPane::updateAndShowRule(const QString &ruleHtml) browser->setText(ruleHtml); if (!ruleHtml.isEmpty()) { m_outputWidget->setCurrentIndex(2); - popup(Core::IOutputPane::NoModeSwitch); + popup(IOutputPane::NoModeSwitch); } } } diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index efdfa620789..8d2b869963f 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -169,7 +169,7 @@ public: setLineAnnotation(markText); setActionsProvider([id] { auto action = new QAction; - action->setIcon(Utils::Icons::INFO.icon()); + action->setIcon(Icons::INFO.icon()); action->setToolTip(Tr::tr("Show rule details")); QObject::connect(action, &QAction::triggered, dd, [id] { dd->fetchIssueInfo(id); }); return QList{action}; @@ -480,7 +480,7 @@ Group issueTableRecipe(const IssueListSearch &search, const IssueTableHandler &h return fetchDataRecipe(url, handler); } -Group lineMarkerRecipe(const Utils::FilePath &filePath, const LineMarkerHandler &handler) +Group lineMarkerRecipe(const FilePath &filePath, const LineMarkerHandler &handler) { QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? QTC_ASSERT(!filePath.isEmpty(), return {}); // TODO: Call handler with unexpected? diff --git a/src/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp index a3e3e3f3bc6..14d47eca53a 100644 --- a/src/plugins/axivion/axivionprojectsettings.cpp +++ b/src/plugins/axivion/axivionprojectsettings.cpp @@ -33,7 +33,7 @@ const char PSK_PROJECTNAME[] = "Axivion.ProjectName"; class AxivionProjectSettingsHandler : public QObject { public: - AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project) + AxivionProjectSettings *projectSettings(Project *project) { auto &settings = m_axivionProjectSettings[project]; if (!settings) @@ -47,7 +47,7 @@ public: m_axivionProjectSettings.clear(); } - QHash m_axivionProjectSettings; + QHash m_axivionProjectSettings; }; static AxivionProjectSettingsHandler &projectSettingsHandler() @@ -58,17 +58,15 @@ static AxivionProjectSettingsHandler &projectSettingsHandler() // AxivionProjectSettings -AxivionProjectSettings::AxivionProjectSettings(ProjectExplorer::Project *project) +AxivionProjectSettings::AxivionProjectSettings(Project *project) : m_project{project} { load(); - connect(project, &ProjectExplorer::Project::settingsLoaded, - this, &AxivionProjectSettings::load); - connect(project, &ProjectExplorer::Project::aboutToSaveSettings, - this, &AxivionProjectSettings::save); + connect(project, &Project::settingsLoaded, this, &AxivionProjectSettings::load); + connect(project, &Project::aboutToSaveSettings, this, &AxivionProjectSettings::save); } -AxivionProjectSettings *AxivionProjectSettings::projectSettings(ProjectExplorer::Project *project) +AxivionProjectSettings *AxivionProjectSettings::projectSettings(Project *project) { return projectSettingsHandler().projectSettings(project); } @@ -90,10 +88,10 @@ void AxivionProjectSettings::save() // AxivionProjectSettingsWidget -class AxivionProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget +class AxivionProjectSettingsWidget : public ProjectSettingsWidget { public: - explicit AxivionProjectSettingsWidget(ProjectExplorer::Project *project); + explicit AxivionProjectSettingsWidget(Project *project); private: void fetchProjects(); @@ -109,11 +107,11 @@ private: QPushButton *m_fetchProjects = nullptr; QPushButton *m_link = nullptr; QPushButton *m_unlink = nullptr; - Utils::InfoLabel *m_infoLabel = nullptr; + InfoLabel *m_infoLabel = nullptr; TaskTreeRunner m_taskTreeRunner; }; -AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Project *project) +AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(Project *project) : m_projectSettings(projectSettingsHandler().projectSettings(project)) { setUseGlobalSettingsCheckBoxVisible(false); @@ -132,7 +130,7 @@ AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Proj verticalLayout->addWidget(new QLabel(Tr::tr("Dashboard projects:"))); verticalLayout->addWidget(m_dashboardProjects); - m_infoLabel = new Utils::InfoLabel(this); + m_infoLabel = new InfoLabel(this); m_infoLabel->setVisible(false); verticalLayout->addWidget(m_infoLabel); @@ -171,7 +169,7 @@ void AxivionProjectSettingsWidget::fetchProjects() const auto onDashboardInfo = [this](const expected_str &info) { if (!info) { m_infoLabel->setText(info.error()); - m_infoLabel->setType(Utils::InfoLabel::Error); + m_infoLabel->setType(InfoLabel::Error); m_infoLabel->setVisible(true); } else { for (const QString &project : info->projects) @@ -234,19 +232,19 @@ void AxivionProjectSettingsWidget::updateEnabledStates() if (!hasDashboardSettings) { m_infoLabel->setText(Tr::tr("Incomplete or misconfigured settings.")); - m_infoLabel->setType(Utils::InfoLabel::NotOk); + m_infoLabel->setType(InfoLabel::NotOk); m_infoLabel->setVisible(true); } } -class AxivionProjectPanelFactory : public ProjectExplorer::ProjectPanelFactory +class AxivionProjectPanelFactory : public ProjectPanelFactory { public: AxivionProjectPanelFactory() { setPriority(250); setDisplayName(Tr::tr("Axivion")); - setCreateWidgetFunction([](ProjectExplorer::Project *project) { + setCreateWidgetFunction([](Project *project) { return new AxivionProjectSettingsWidget(project); }); } diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index d85178df544..3d95673b9c0 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -20,11 +20,12 @@ #include #include +using namespace Core; using namespace Utils; namespace Axivion::Internal { -AxivionServer::AxivionServer(const Utils::Id &id, const QString &dashboard, +AxivionServer::AxivionServer(const Id &id, const QString &dashboard, const QString &description, const QString &token) : id(id) , dashboard(dashboard) @@ -68,17 +69,17 @@ AxivionServer AxivionServer::fromJson(const QJsonObject &json) const QJsonValue token = json.value("token"); if (token == QJsonValue::Undefined) return invalidServer; - return { Utils::Id::fromString(id.toString()), dashboard.toString(), + return { Id::fromString(id.toString()), dashboard.toString(), description.toString(), token.toString() }; } -static Utils::FilePath tokensFilePath() +static FilePath tokensFilePath() { - return Utils::FilePath::fromString(Core::ICore::settings()->fileName()).parentDir() + return FilePath::fromString(ICore::settings()->fileName()).parentDir() .pathAppended("qtcreator/axivion.json"); } -static void writeTokenFile(const Utils::FilePath &filePath, const AxivionServer &server) +static void writeTokenFile(const FilePath &filePath, const AxivionServer &server) { QJsonDocument doc; doc.setObject(server.toJson()); @@ -87,11 +88,11 @@ static void writeTokenFile(const Utils::FilePath &filePath, const AxivionServer filePath.setPermissions(QFile::ReadUser | QFile::WriteUser); } -static AxivionServer readTokenFile(const Utils::FilePath &filePath) +static AxivionServer readTokenFile(const FilePath &filePath) { if (!filePath.exists()) return {}; - Utils::expected_str contents = filePath.fileContents(); + expected_str contents = filePath.fileContents(); if (!contents) return {}; const QJsonDocument doc = QJsonDocument::fromJson(*contents); @@ -120,7 +121,7 @@ AxivionSettings::AxivionSettings() void AxivionSettings::toSettings() const { writeTokenFile(tokensFilePath(), server); - Utils::AspectContainer::writeSettings(); + AspectContainer::writeSettings(); } // AxivionSettingsPage @@ -214,7 +215,7 @@ AxivionServer DashboardSettingsWidget::dashboardServer() const if (m_id.isValid()) result.id = m_id; else - result.id = m_mode == Edit ? Utils::Id::fromName(QUuid::createUuid().toByteArray()) : m_id; + result.id = m_mode == Edit ? Id::fromName(QUuid::createUuid().toByteArray()) : m_id; result.dashboard = m_dashboardUrl(); result.description = m_description(); result.token = m_token(); @@ -234,7 +235,7 @@ bool DashboardSettingsWidget::isValid() const return !m_token().isEmpty() && !m_description().isEmpty() && isUrlValid(m_dashboardUrl()); } -class AxivionSettingsWidget : public Core::IOptionsPageWidget +class AxivionSettingsWidget : public IOptionsPageWidget { public: AxivionSettingsWidget(); @@ -299,7 +300,7 @@ void AxivionSettingsWidget::showEditServerDialog() // AxivionSettingsPage -class AxivionSettingsPage : public Core::IOptionsPage +class AxivionSettingsPage : public IOptionsPage { public: AxivionSettingsPage() From d8a6654717fe78179ace126b9a419ad06e250e08 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 12 Feb 2024 16:56:29 +0100 Subject: [PATCH 61/82] Doc: Describe Vanished Targets in Projects mode sidebar Task-number: QTCREATORBUG-30209 Change-Id: Ia4a05d18262e97ea6fbfc03fb6874662ac67bec5 Reviewed-by: Christian Kandeler Reviewed-by: Eike Ziller --- .../images/qtcreator-project-kits.png | Bin 40239 -> 0 bytes .../images/qtcreator-projects-kits.webp | Bin 9292 -> 13522 bytes .../qtcreator-projects-vanished-targets.webp | Bin 0 -> 7114 bytes .../creator-projects-settings-overview.qdoc | 44 +++++++++++++----- 4 files changed, 32 insertions(+), 12 deletions(-) delete mode 100644 doc/qtcreator/images/qtcreator-project-kits.png create mode 100644 doc/qtcreator/images/qtcreator-projects-vanished-targets.webp diff --git a/doc/qtcreator/images/qtcreator-project-kits.png b/doc/qtcreator/images/qtcreator-project-kits.png deleted file mode 100644 index 16bf3a0dad0b403c757530a6081d078ea6b7a3b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40239 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ó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 literal 9292 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 AdjJ3c diff --git a/doc/qtcreator/images/qtcreator-projects-vanished-targets.webp b/doc/qtcreator/images/qtcreator-projects-vanished-targets.webp new file mode 100644 index 0000000000000000000000000000000000000000..f4acd354b1c9f12a5c30a97981fbdf4964671868 GIT binary patch literal 7114 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc index 458e21c0a0d..27ff2fccff9 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc @@ -112,21 +112,13 @@ lists the kits that are compatible with your project. To activate one or more kits, click them. - \image qtcreator-project-kits.png {List of kits in Projects mode sidebar} + \image qtcreator-projects-kits.webp {List of kits in Projects mode sidebar} The list displays kits from \preferences > \uicontrol Kits. Warning and error icons indicate that the kit configuration is not suitable for the project type. To view the warning and error messages, move the mouse pointer over the kit name. - In the list of kits, you may see entries described as \e {Replacement for - }. \QC generates them to save your project-specific settings, - such as custom build flags or run configuration arguments that would - disappear if the corresponding kits were simply removed when you remove - Qt versions while updating your Qt installation. You can modify the kit - configuration to use a currently installed Qt version and save the kit - under a new name. - \section1 Manage kits To modify kit configuration or to \l{Add kits}{add kits} to the list or to @@ -134,10 +126,11 @@ Each kit consists of a set of values that define one environment, such as a \l{glossary-device}{device}, \l{Add compilers}{compiler}, - \l{Add debuggers}{debugger}, and \l{Add Qt versions}{Qt version}. + \l{Add debuggers}{debugger}, and \l{Add Qt versions}{Qt version}, as well + as steps for building, deploying, and running applications. - To copy the build and run settings for a kit to another kit, select - \uicontrol {Copy Steps from Other Kit} in the context menu. + To copy the build, deploy, and run steps from another kit, select + \uicontrol {Copy Steps from Another Kit} in the context menu. To deactivate a kit, select \uicontrol {Disable Kit for Project} in the context menu. @@ -148,5 +141,32 @@ To import an existing build for the project, select \uicontrol {Import Existing Build}. + \section1 Copy custom settings from vanished targets + + \QC creates a list of \uicontrol {Vanished Targets} to save project-specific + settings, such as custom build flags or run configuration arguments, that + would disappear if \QOI removes the corresponding kits when you update your + Qt installation. + + \image qtcreator-projects-vanished-targets.webp {Vanished Targets in Projects} + + Go to one of the following options in the context menu to restore the + project's settings: + + \list + \li \uicontrol {Create a New Kit} creates a new kit with the same name + for the same device type, with the original build, deploy, and run + steps. Other kit settings are not restored. + \li \uicontrol {Copy Steps to Another Kit} copies the build, deploy, and + run steps to another kit. + \endlist + + To remove vanished targets, go to \uicontrol {Remove Vanished Target} or + \uicontrol {Remove All Vanished Targets} in the context menu. + + \note Since version 13.0, \QC does not create \e {replacement kits}, but you + might still see them listed for existing projects. You can copy the build, + deploy, and run steps from them to other kits. + \sa {Add kits}, {Configuring Projects}, {kits-tab}{Kits} */ From 39527bbcad1b933a49c3d1d13e8daee7d4772646 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 9 Feb 2024 14:36:36 +0100 Subject: [PATCH 62/82] ProjectExplorer: Get rid of mysterious "keep size" mode ... in MiniProjectTargetSelector. It's unclear what the intention was, but the effect was that the widget was growing after every project switch. Fixes: QTCREATORBUG-28954 Change-Id: Iea83243194c08ebb3caf78bc058774f17f23eced Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../miniprojecttargetselector.cpp | 53 +++++-------------- .../miniprojecttargetselector.h | 2 +- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 82e4c5b1813..bbf2b8be1dd 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -746,14 +746,10 @@ MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorActi bool MiniProjectTargetSelector::event(QEvent *event) { - if (event->type() == QEvent::LayoutRequest) { - doLayout(true); + if (event->type() == QEvent::ShortcutOverride + && static_cast(event)->key() == Qt::Key_Escape) { + event->accept(); return true; - } else if (event->type() == QEvent::ShortcutOverride) { - if (static_cast(event)->key() == Qt::Key_Escape) { - event->accept(); - return true; - } } return QWidget::event(event); } @@ -856,7 +852,7 @@ QVector MiniProjectTargetSelector::listWidgetWidths(int minSize, int maxSiz } } -void MiniProjectTargetSelector::doLayout(bool keepSize) +void MiniProjectTargetSelector::doLayout() { // An unconfigured project shows empty build/deploy/run sections // if there's a configured project in the seesion @@ -867,15 +863,12 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) m_kitAreaWidget->move(0, 0); - int oldSummaryLabelY = m_summaryLabel->y(); - int kitAreaHeight = m_kitAreaWidget->isVisibleTo(this) ? m_kitAreaWidget->sizeHint().height() : 0; // 1. Calculate the summary label height int summaryLabelY = 1 + kitAreaHeight; int summaryLabelHeight = 0; - int oldSummaryLabelHeight = m_summaryLabel->height(); bool onlySummary = false; // Count the number of lines int visibleLineCount = m_projectListWidget->isVisibleTo(this) ? 0 : 1; @@ -894,9 +887,6 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) summaryLabelHeight = m_summaryLabel->sizeHint().height(); } - if (keepSize && oldSummaryLabelHeight > summaryLabelHeight) - summaryLabelHeight = oldSummaryLabelHeight; - m_summaryLabel->move(0, summaryLabelY); // Height to be aligned with side bar button @@ -915,16 +905,13 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) maxItemCount = qMax(maxItemCount, m_listWidgets[i]->maxCount()); int titleWidgetsHeight = m_titleWidgets.first()->height(); - if (keepSize) { - heightWithoutKitArea = height() - oldSummaryLabelY + 1; - } else { - // Clamp the size of the listwidgets to be at least as high as the sidebar button - // and at most half the height of the entire Qt Creator window. - heightWithoutKitArea = summaryLabelHeight - + qBound(alignedWithActionHeight, - maxItemCount * 30 + bottomMargin + titleWidgetsHeight, - Core::ICore::mainWindow()->height() / 2); - } + + // Clamp the size of the listwidgets to be at least as high as the sidebar button + // and at most half the height of the entire Qt Creator window. + heightWithoutKitArea = summaryLabelHeight + + qBound(alignedWithActionHeight, + maxItemCount * 30 + bottomMargin + titleWidgetsHeight, + Core::ICore::mainWindow()->height() / 2); int titleY = summaryLabelY + summaryLabelHeight; int listY = titleY + titleWidgetsHeight; @@ -933,15 +920,6 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) // list widget widths int minWidth = qMax(m_summaryLabel->sizeHint().width(), 250); minWidth = qMax(minWidth, m_kitAreaWidget->sizeHint().width()); - if (keepSize) { - // Do not make the widget smaller then it was before - int oldTotalListWidgetWidth = m_projectListWidget->isVisibleTo(this) ? - m_projectListWidget->width() : 0; - for (int i = TARGET; i < LAST; ++i) - oldTotalListWidgetWidth += m_listWidgets[i]->width(); - minWidth = qMax(minWidth, oldTotalListWidgetWidth); - } - QVector widths = listWidgetWidths(minWidth, Core::ICore::mainWindow()->width() * 0.9); const int runColumnWidth = widths[RUN] == -1 ? 0 : RunColumnWidth; @@ -969,10 +947,7 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) m_kitAreaWidget->resize(x - 1, kitAreaHeight); newGeometry.setSize({x, heightWithoutKitArea + kitAreaHeight}); } else { - if (keepSize) - heightWithoutKitArea = height() - oldSummaryLabelY + 1; - else - heightWithoutKitArea = qMax(summaryLabelHeight + bottomMargin, alignedWithActionHeight); + heightWithoutKitArea = qMax(summaryLabelHeight + bottomMargin, alignedWithActionHeight); m_summaryLabel->resize(m_summaryLabel->sizeHint().width(), heightWithoutKitArea - bottomMargin); m_kitAreaWidget->resize(m_kitAreaWidget->sizeHint()); newGeometry.setSize({m_summaryLabel->width() + 1, heightWithoutKitArea + kitAreaHeight}); @@ -1359,7 +1334,7 @@ void MiniProjectTargetSelector::activeRunConfigurationChanged(RunConfiguration * void MiniProjectTargetSelector::setVisible(bool visible) { - doLayout(false); + doLayout(); QWidget::setVisible(visible); m_projectAction->setChecked(visible); if (visible) { @@ -1554,7 +1529,7 @@ void MiniProjectTargetSelector::updateSummary() } if (summary != m_summaryLabel->text()) { m_summaryLabel->setText(summary); - doLayout(false); + doLayout(); } } diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.h b/src/plugins/projectexplorer/miniprojecttargetselector.h index e28828ef4a5..81f98c4a451 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.h +++ b/src/plugins/projectexplorer/miniprojecttargetselector.h @@ -74,7 +74,7 @@ private: void paintEvent(QPaintEvent *) override; void mousePressEvent(QMouseEvent *) override; - void doLayout(bool keepSize); + void doLayout(); QVector listWidgetWidths(int minSize, int maxSize); QWidget *createTitleLabel(const QString &text); From e8ad29d3affd115573d7ee7a5621a6ca6e168911 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 9 Feb 2024 14:34:48 +0100 Subject: [PATCH 63/82] LinuxDevice: Add disconnected state Change-Id: Ic2c909e3375a9fb025a335c1ca65621fa031d000 Reviewed-by: Christian Kandeler Reviewed-by: --- src/libs/utils/devicefileaccess.cpp | 93 ++++++++++++++ src/libs/utils/devicefileaccess.h | 2 + .../devicesupport/devicesettingspage.cpp | 3 + .../projectexplorer/devicesupport/idevice.cpp | 2 +- .../projectexplorer/devicesupport/idevice.h | 6 +- src/plugins/remotelinux/linuxdevice.cpp | 120 +++++++++++++++++- src/plugins/remotelinux/linuxdevice.h | 10 ++ src/plugins/remotelinux/linuxdevicetester.cpp | 65 +++++++--- 8 files changed, 278 insertions(+), 23 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 0486ece19e9..39bdc736e09 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -878,52 +878,73 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const // UnixDeviceAccess +static Utils::unexpected make_unexpected_disconnected() +{ + return make_unexpected(Tr::tr("Device is not connected")); +} + UnixDeviceFileAccess::~UnixDeviceFileAccess() = default; bool UnixDeviceFileAccess::runInShellSuccess(const CommandLine &cmdLine, const QByteArray &stdInData) const { + if (disconnected()) + return false; return runInShell(cmdLine, stdInData).exitCode == 0; } bool UnixDeviceFileAccess::isExecutableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-x", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; if (filePath.isRootPath()) return true; @@ -933,12 +954,16 @@ bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const bool UnixDeviceFileAccess::isSymLink(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-h", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const { + if (disconnected()) + return false; const QStringList args = statArgs(filePath, "%h", "%l"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong() > 1; @@ -946,29 +971,39 @@ bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const bool UnixDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"touch", {path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::createDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"mkdir", {"-p", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::exists(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-e", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::removeFile(const FilePath &filePath) const { + if (disconnected()) + return false; return runInShellSuccess({"rm", {filePath.path()}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const { + if (disconnected()) + return false; QTC_ASSERT(filePath.path().startsWith('/'), return false); const QString path = filePath.cleanPath().path(); @@ -989,6 +1024,8 @@ bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString * expected_str UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { + if (disconnected()) + return make_unexpected_disconnected(); const RunResult result = runInShell( {"cp", {filePath.path(), target.path()}, OsType::OsTypeLinux}); @@ -1003,11 +1040,17 @@ expected_str UnixDeviceFileAccess::copyFile(const FilePath &filePath, bool UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const { + if (disconnected()) + return false; + return runInShellSuccess({"mv", {filePath.path(), target.path()}, OsType::OsTypeLinux}); } FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const { + if (disconnected()) + return {}; + const RunResult result = runInShell( {"readlink", {"-n", "-e", filePath.path()}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); @@ -1018,6 +1061,9 @@ expected_str UnixDeviceFileAccess::fileContents(const FilePath &file qint64 limit, qint64 offset) const { + if (disconnected()) + return make_unexpected_disconnected(); + QStringList args = {"if=" + filePath.path()}; if (limit > 0 || offset > 0) { const qint64 gcd = std::gcd(limit, offset); @@ -1045,6 +1091,9 @@ expected_str UnixDeviceFileAccess::writeFileContents(const FilePath &fil const QByteArray &data, qint64 offset) const { + if (disconnected()) + return make_unexpected_disconnected(); + QStringList args = {"of=" + filePath.path()}; if (offset != 0) { args.append("bs=1"); @@ -1061,6 +1110,9 @@ expected_str UnixDeviceFileAccess::writeFileContents(const FilePath &fil expected_str UnixDeviceFileAccess::createTempFile(const FilePath &filePath) { + if (disconnected()) + return make_unexpected_disconnected(); + if (!m_hasMkTemp.has_value()) m_hasMkTemp = runInShellSuccess({"which", {"mktemp"}, OsType::OsTypeLinux}); @@ -1120,6 +1172,9 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const { + if (disconnected()) + return {}; + const RunResult result = runInShell( {"stat", {"-L", "-c", "%Y", filePath.path()}, OsType::OsTypeLinux}); qint64 secs = result.stdOut.toLongLong(); @@ -1131,6 +1186,9 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const { + if (disconnected()) + return {}; + return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) << "-L" << filePath.path(); @@ -1138,6 +1196,9 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const { + if (disconnected()) + return {}; + QStringList args = statArgs(filePath, "%a", "%p"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1161,6 +1222,9 @@ QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) c bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions perms) const { + if (disconnected()) + return false; + const int flags = int(perms); return runInShellSuccess( {"chmod", {QString::number(flags, 16), filePath.path()}, OsType::OsTypeLinux}); @@ -1168,6 +1232,9 @@ bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permi qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const { + if (disconnected()) + return -1; + const QStringList args = statArgs(filePath, "%s", "%z"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong(); @@ -1175,12 +1242,18 @@ qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const qint64 UnixDeviceFileAccess::bytesAvailable(const FilePath &filePath) const { + if (disconnected()) + return -1; + const RunResult result = runInShell({"df", {"-k", filePath.path()}, OsType::OsTypeLinux}); return FileUtils::bytesAvailableFromDFOutput(result.stdOut); } QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const { + if (disconnected()) + return {}; + const QStringList args = statArgs(filePath, "%D:%i", "%d:%i"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1192,6 +1265,9 @@ QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const { + if (disconnected()) + return {}; + if (filePath.path() == "/") // TODO: Add FilePath::isRoot() { const FilePathInfo r{4096, @@ -1218,6 +1294,9 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, const FileFilter &filter, const FilePath::IterateDirCallback &callBack) const { + if (disconnected()) + return false; + QTC_CHECK(filePath.isAbsolutePath()); CommandLine cmdLine{"find", filter.asFindArguments(filePath.path()), OsType::OsTypeLinux}; @@ -1290,6 +1369,9 @@ void UnixDeviceFileAccess::findUsingLs(const QString ¤t, QStringList *found, const QString &start) const { + if (disconnected()) + return; + const RunResult result = runInShell( {"ls", {"-1", "-a", "-p", "--", current}, OsType::OsTypeLinux}); const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts); @@ -1349,6 +1431,9 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, const FilePath::IterateDirCallback &callBack, const FileFilter &filter) const { + if (disconnected()) + return; + // We try to use 'find' first, because that can filter better directly. // Unfortunately, it's not installed on all devices by default. if (m_tryUseFind) { @@ -1366,9 +1451,17 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, Environment UnixDeviceFileAccess::deviceEnvironment() const { + if (disconnected()) + return {}; + const RunResult result = runInShell({"env", {}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); return Environment(out.split('\n', Qt::SkipEmptyParts), OsTypeLinux); } +bool UnixDeviceFileAccess::disconnected() const +{ + return false; +} + } // namespace Utils diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 5b7c766a8a7..ba484541275 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -188,6 +188,8 @@ protected: QStringList *found, const QString &start) const; + virtual bool disconnected() const; + private: bool iterateWithFind(const FilePath &filePath, const FileFilter &filter, diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp index 3d2e86d445f..a7405ef46e2 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp @@ -312,6 +312,9 @@ void DeviceSettingsWidget::testDevice() dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setModal(true); dlg->show(); + connect(dlg, &QObject::destroyed, this, [this, id = device->id()] { + handleDeviceUpdated(id); + }); } void DeviceSettingsWidget::handleDeviceUpdated(Id id) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 9a79347da13..0fcdae1c918 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -593,7 +593,7 @@ QString IDevice::deviceStateToString() const QPixmap IDevice::deviceStateIcon() const { - switch (d->deviceState) { + switch (deviceState()) { case IDevice::DeviceReadyToUse: return Icons::DEVICE_READY_INDICATOR.pixmap(); case IDevice::DeviceConnected: return Icons::DEVICE_CONNECTED_INDICATOR.pixmap(); case IDevice::DeviceDisconnected: return Icons::DEVICE_DISCONNECTED_INDICATOR.pixmap(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index c494387de46..6434b5b6dde 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -105,7 +105,7 @@ public: virtual ~IDevice(); - Ptr clone() const; + virtual Ptr clone() const; DeviceSettings *settings() const; @@ -154,9 +154,9 @@ public: virtual DeviceProcessSignalOperation::Ptr signalOperation() const; enum DeviceState { DeviceReadyToUse, DeviceConnected, DeviceDisconnected, DeviceStateUnknown }; - DeviceState deviceState() const; + virtual DeviceState deviceState() const; void setDeviceState(const DeviceState state); - QString deviceStateToString() const; + virtual QString deviceStateToString() const; QPixmap deviceStateIcon() const; static Utils::Id typeFromMap(const Utils::Store &map); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index a835ef30be7..80b33c215f5 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -21,12 +21,15 @@ #include #include #include +#include #include +#include #include #include #include #include +#include #include #include #include @@ -292,6 +295,8 @@ public: Environment deviceEnvironment() const override; + bool disconnected() const override; + LinuxDevicePrivate *m_dev; }; @@ -307,7 +312,7 @@ public: explicit LinuxDevicePrivate(LinuxDevice *parent); ~LinuxDevicePrivate(); - bool setupShell(); + bool setupShell(const SshParameters &sshParameters); RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); void attachToSharedConnection(SshConnectionHandle *connectionHandle, @@ -319,6 +324,10 @@ public: void checkOsType(); void queryOsType(std::function run); + void setDisconnected(bool disconnected); + bool disconnected() const; + bool checkDisconnectedWithWarning(); + LinuxDevice *q = nullptr; QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; @@ -327,6 +336,7 @@ public: QReadWriteLock m_environmentCacheLock; std::optional m_environmentCache; + bool m_disconnected = false; }; void LinuxDevicePrivate::invalidateEnvironmentCache() @@ -358,14 +368,24 @@ Environment LinuxDevicePrivate::getEnvironment() RunResult LinuxDeviceFileAccess::runInShell(const CommandLine &cmdLine, const QByteArray &stdInData) const { + if (disconnected()) + return {-1, {}, Tr::tr("Device is disconnected.").toUtf8()}; return m_dev->runInShell(cmdLine, stdInData); } Environment LinuxDeviceFileAccess::deviceEnvironment() const { + if (disconnected()) + return {}; + return m_dev->getEnvironment(); } +bool LinuxDeviceFileAccess::disconnected() const +{ + return m_dev->checkDisconnectedWithWarning(); +} + // SshProcessImpl class SshProcessInterfacePrivate : public QObject @@ -1023,6 +1043,15 @@ LinuxDevice::~LinuxDevice() delete d; } +IDevice::Ptr LinuxDevice::clone() const +{ + IDevice::Ptr clone = IDevice::clone(); + Ptr linuxClone = std::dynamic_pointer_cast(clone); + QTC_ASSERT(linuxClone, return clone); + linuxClone->d->setDisconnected(d->disconnected()); + return clone; +} + IDeviceWidget *LinuxDevice::createWidget() { return new Internal::GenericLinuxDeviceConfigurationWidget(shared_from_this()); @@ -1106,15 +1135,31 @@ void LinuxDevicePrivate::queryOsType(std::function_setOsType(OsTypeLinux); } +void LinuxDevicePrivate::setDisconnected(bool disconnected) +{ + if (disconnected == m_disconnected) + return; + + m_disconnected = disconnected; + + if (m_disconnected) + m_handler->closeShell(); + +} + +bool LinuxDevicePrivate::disconnected() const +{ + return m_disconnected; +} + void LinuxDevicePrivate::checkOsType() { queryOsType([this](const CommandLine &cmd) { return runInShell(cmd); }); } // Call me with shell mutex locked -bool LinuxDevicePrivate::setupShell() +bool LinuxDevicePrivate::setupShell(const SshParameters &sshParameters) { - const SshParameters sshParameters = q->sshParameters(); if (m_handler->isRunning(sshParameters)) return true; @@ -1126,8 +1171,12 @@ bool LinuxDevicePrivate::setupShell() }, Qt::BlockingQueuedConnection, &ok); if (ok) { + setDisconnected(false); queryOsType([this](const CommandLine &cmd) { return m_handler->runInShell(cmd); }); + } else { + setDisconnected(true); } + return ok; } @@ -1135,11 +1184,43 @@ RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArra { QMutexLocker locker(&m_shellMutex); DEBUG(cmd.toUserOutput()); - const bool isSetup = setupShell(); + if (checkDisconnectedWithWarning()) + return {}; + const bool isSetup = setupShell(q->sshParameters()); + if (checkDisconnectedWithWarning()) + return {}; QTC_ASSERT(isSetup, return {}); return m_handler->runInShell(cmd, data); } +bool LinuxDevicePrivate::checkDisconnectedWithWarning() +{ + if (!disconnected()) + return false; + + QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = q->id(), name = q->displayName()] { + if (!Core::ICore::infoBar()->canInfoBeAdded(id)) + return; + const QString warnStr + = Tr::tr("Device \"%1\" is currently marked as disconnected.").arg(name); + InfoBarEntry info(id, warnStr, InfoBarEntry::GlobalSuppression::Enabled); + info.setDetailsWidgetCreator([] { + const auto label = new QLabel(Tr::tr( + "The device was not available when trying to connect previously.
" + "No further connection attempts will be made until the device is manually reset " + "by running a successful connection test via the " + "
settings page.")); + label->setWordWrap(true); + QObject::connect(label, &QLabel::linkActivated, [] { + Core::ICore::showOptionsDialog(ProjectExplorer::Constants::DEVICE_SETTINGS_PAGE_ID); + }); + return label; + }); + Core::ICore::infoBar()->addInfo(info); + }); + return true; +} + void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters) { @@ -1522,6 +1603,37 @@ void LinuxDevice::checkOsType() d->checkOsType(); } +IDevice::DeviceState LinuxDevice::deviceState() const +{ + if (isDisconnected()) + return DeviceDisconnected; + return IDevice::deviceState(); +} + +QString LinuxDevice::deviceStateToString() const +{ + if (isDisconnected()) + return Tr::tr("Device is considered unconnected. Re-run device test to reset state."); + return IDevice::deviceStateToString(); +} + +bool LinuxDevice::isDisconnected() const +{ + return d->disconnected(); +} +void LinuxDevice::setDisconnected(bool disconnected) +{ + d->setDisconnected(disconnected); +} + +QFuture LinuxDevice::tryToConnect() +{ + return Utils::asyncRun([this] { + QMutexLocker locker(&d->m_shellMutex); + return d->setupShell(sshParameters()); + }); +} + namespace Internal { class LinuxDeviceFactory final : public IDeviceFactory diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index a6625cdea2d..0bb2468eacb 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -20,6 +20,8 @@ public: static Ptr create() { return Ptr(new LinuxDevice); } + IDevice::Ptr clone() const override; + ProjectExplorer::IDeviceWidget *createWidget() override; bool canCreateProcessModel() const override { return true; } @@ -42,6 +44,14 @@ public: class LinuxDevicePrivate *connectionAccess() const; void checkOsType() override; + DeviceState deviceState() const override; + QString deviceStateToString() const override; + + bool isDisconnected() const; + void setDisconnected(bool disconnected); + + QFuture tryToConnect(); + protected: LinuxDevice(); diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 3d6c41cd657..f279bc0c382 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -3,6 +3,7 @@ #include "linuxdevicetester.h" +#include "linuxdevice.h" #include "remotelinuxtr.h" #include @@ -17,6 +18,8 @@ #include #include +#include + using namespace ProjectExplorer; using namespace Tasking; using namespace Utils; @@ -43,9 +46,13 @@ public: const Storage &storage) const; GroupItem transferTasks() const; GroupItem commandTasks() const; + void runCommandTests(); + + bool isRunning() const { return m_connectionTest || m_taskTreeRunner.isRunning(); } GenericLinuxDeviceTester *q = nullptr; - IDevice::Ptr m_device; + LinuxDevice::Ptr m_device; + QFutureWatcher *m_connectionTest = nullptr; TaskTreeRunner m_taskTreeRunner; QStringList m_extraCommands; QList m_extraTests; @@ -276,6 +283,20 @@ GroupItem GenericLinuxDeviceTesterPrivate::commandTasks() const return root; } +void GenericLinuxDeviceTesterPrivate::runCommandTests() +{ + const Group root { + echoTask("Hello"), // No quoting necessary + echoTask("Hello Remote World!"), // Checks quoting, too. + unameTask(), + gathererTask(), + transferTasks(), + m_extraTests, + commandTasks() + }; + m_taskTreeRunner.start(root); +} + } // namespace Internal using namespace Internal; @@ -302,26 +323,40 @@ void GenericLinuxDeviceTester::setExtraTests(const QList &extraTests) void GenericLinuxDeviceTester::testDevice(const IDevice::Ptr &deviceConfiguration) { - QTC_ASSERT(!d->m_taskTreeRunner.isRunning(), return); + QTC_ASSERT(!d->isRunning(), return); - d->m_device = deviceConfiguration; + emit progressMessage(Tr::tr("Connecting to device...")); - const Group root { - d->echoTask("Hello"), // No quoting necessary - d->echoTask("Hello Remote World!"), // Checks quoting, too. - d->unameTask(), - d->gathererTask(), - d->transferTasks(), - d->m_extraTests, - d->commandTasks() - }; - d->m_taskTreeRunner.start(root); + d->m_device = std::static_pointer_cast(deviceConfiguration); + + d->m_connectionTest = new QFutureWatcher(this); + d->m_connectionTest->setFuture(d->m_device->tryToConnect()); + + connect(d->m_connectionTest, &QFutureWatcher::finished, this, [this] { + const bool success = d->m_connectionTest->result(); + d->m_connectionTest->deleteLater(); + d->m_connectionTest = nullptr; + if (success) { + emit progressMessage(Tr::tr("Connected. Now doing extended checks.\n")); + d->runCommandTests(); + } else { + emit errorMessage( + Tr::tr("Basic connectivity test failed, device is considered unusable.")); + emit finished(TestFailure); + } + }); } void GenericLinuxDeviceTester::stopTest() { - QTC_ASSERT(d->m_taskTreeRunner.isRunning(), return); - d->m_taskTreeRunner.reset(); + QTC_ASSERT(d->isRunning(), return); + if (d->m_connectionTest) { + d->m_connectionTest->disconnect(); + d->m_connectionTest->cancel(); + d->m_connectionTest = nullptr; + } else { + d->m_taskTreeRunner.reset(); + } emit finished(TestFailure); } From 15b308c62152214f4acd4061d837ff48ac083112 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 13 Feb 2024 12:31:03 +0100 Subject: [PATCH 64/82] Update change log for 13.0.0 beta and add JIRA links Change-Id: I949f60c547058592d92b0d1a7475ae1b85867304 Reviewed-by: Leena Miettinen --- dist/changelog/changes-13.0.0.md | 97 +++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/dist/changelog/changes-13.0.0.md b/dist/changelog/changes-13.0.0.md index bd3fc5e3d51..793e47e97f2 100644 --- a/dist/changelog/changes-13.0.0.md +++ b/dist/changelog/changes-13.0.0.md @@ -34,18 +34,18 @@ General dock area * Added the option to show file paths relative to the active project to the search results view - (QTCREATORBUG-29462) + ([QTCREATORBUG-29462](https://bugreports.qt.io/browse/QTCREATORBUG-29462)) * Added a `Current` button for selecting the directory of the current document for searching in `Files in File System` * Added `Copy to Clipboard` to the `About Qt Creator` dialog - (QTCREATORBUG-29886) + ([QTCREATORBUG-29886](https://bugreports.qt.io/browse/QTCREATORBUG-29886)) Editing ------- * Made syntax highlighting asynchronous * Fixed that `Shift+Tab` did not always unindent - (QTCREATORBUG-29742) + ([QTCREATORBUG-29742](https://bugreports.qt.io/browse/QTCREATORBUG-29742)) * Fixed that `Surround text selection with brackets` did nothing for `<` * Fixed following links without a file name in documents without a file name @@ -53,34 +53,39 @@ Editing * Added the `Move Definition Here` refactoring action that moves an existing function definition to its declaration - (QTCREATORBUG-9515) + ([QTCREATORBUG-9515](https://bugreports.qt.io/browse/QTCREATORBUG-9515)) +* Added the `Enclose in QByteArrayLiteral` refactoring action + ([QTCREATORBUG-12995](https://bugreports.qt.io/browse/QTCREATORBUG-12995)) * Enabled the completion inside comments and strings by falling back to the built-in code model - (QTCREATORBUG-20828) + ([QTCREATORBUG-20828](https://bugreports.qt.io/browse/QTCREATORBUG-20828)) * Improved the position of headers inserted by refactoring operations - (QTCREATORBUG-21826) + ([QTCREATORBUG-21826](https://bugreports.qt.io/browse/QTCREATORBUG-21826)) * Improved the coding style settings by separating Clang Format and other coding style settings, and using a plain text editor for custom Clang Format settings * Fixed that the class wizards used the class name for the include guard instead of the file name - (QTCREATORBUG-30140) + ([QTCREATORBUG-30140](https://bugreports.qt.io/browse/QTCREATORBUG-30140)) * Fixed that renaming classes did not change the include directive for the renamed header in the source file - (QTCREATORBUG-30154) + ([QTCREATORBUG-30154](https://bugreports.qt.io/browse/QTCREATORBUG-30154)) * Fixed issues with refactoring template functions - (QTCREATORBUG-29408) + ([QTCREATORBUG-29408](https://bugreports.qt.io/browse/QTCREATORBUG-29408)) +* Fixed the `Add Definition` refactoring action for member functions of a + template class in a namespace + ([QTCREATORBUG-22076](https://bugreports.qt.io/browse/QTCREATORBUG-22076)) * Clangd * Fixed that `Follow Symbol Under Cursor` only worked for exact matches - (QTCREATORBUG-29814) + ([QTCREATORBUG-29814](https://bugreports.qt.io/browse/QTCREATORBUG-29814)) ### QML * Added navigation from QML components to the C++ code in the project - (QTCREATORBUG-28086) + ([QTCREATORBUG-28086](https://bugreports.qt.io/browse/QTCREATORBUG-28086)) * Added a button for launching the QML Preview on the current document to the editor tool bar * Added color previews when hovering Qt color functions - (QTCREATORBUG-29966) + ([QTCREATORBUG-29966](https://bugreports.qt.io/browse/QTCREATORBUG-29966)) ### Python @@ -95,7 +100,7 @@ Editing ### Widget Designer * Fixed the indentation of the code that is inserted by `Go to slot` - (QTCREATORBUG-11730) + ([QTCREATORBUG-11730](https://bugreports.qt.io/browse/QTCREATORBUG-11730)) ### Compiler Explorer @@ -108,6 +113,10 @@ Editing endings) to the tool bar * Added support for following links to the text editor +### Binary Files + +* Fixed issues with large addresses + Projects -------- @@ -115,41 +124,62 @@ Projects was configured for kits that have vanished, as a replacement for the automatic creation of "Replacement" kits * Added the status of devices to the device lists - (QTCREATORBUG-20941) + ([QTCREATORBUG-20941](https://bugreports.qt.io/browse/QTCREATORBUG-20941)) * Added the `Preferences > Build & Run > General > Application environment` option for globally modifying the environment for all run configurations - (QTCREATORBUG-29530) + ([QTCREATORBUG-29530](https://bugreports.qt.io/browse/QTCREATORBUG-29530)) * Added a file wizard for Qt translation (`.ts`) files - (QTCREATORBUG-29775) + ([QTCREATORBUG-29775](https://bugreports.qt.io/browse/QTCREATORBUG-29775)) * Increased the maximum width of the target selector - (QTCREATORBUG-30038) + ([QTCREATORBUG-30038](https://bugreports.qt.io/browse/QTCREATORBUG-30038)) * Fixed that the `Left` cursor key did not always collapse the current item - (QTBUG-118515) + ([QTBUG-118515](https://bugreports.qt.io/browse/QTBUG-118515)) * Fixed inconsistent folder hierarchies in the project tree - (QTCREATORBUG-29923) + ([QTCREATORBUG-29923](https://bugreports.qt.io/browse/QTCREATORBUG-29923)) ### CMake * Added support for custom output parsers for the configuration of projects - (QTCREATORBUG-29992) + ([QTCREATORBUG-29992](https://bugreports.qt.io/browse/QTCREATORBUG-29992)) * Made cache variables available even if project configuration failed +* CMake Presets + * Fixed `Reload CMake Presets` if the project was not configured yet + ([QTCREATORBUG-30238](https://bugreports.qt.io/browse/QTCREATORBUG-30238)) + * Fixed that kits were accumulating on the project setup page + ([QTCREATORBUG-29535](https://bugreports.qt.io/browse/QTCREATORBUG-29535)) + * Fixed that `binaryDir` was not handled for all presets + ([QTCREATORBUG-30236](https://bugreports.qt.io/browse/QTCREATORBUG-30236)) + * Fixed a freeze with nested presets + ([QTCREATORBUG-30288](https://bugreports.qt.io/browse/QTCREATORBUG-30288)) +* Conan + * Fixed that backslashes were wrongly used for paths on Windows + ([QTCREATORBUG-30326](https://bugreports.qt.io/browse/QTCREATORBUG-30326)) + +### Qbs + +* Added support for code completion with the Qbs language server + (QBS-395) ### Python * Added `Generate Kit` to the Python interpreter preferences for generating a Python kit with this interpreter * Added the target setup page when loading unconfigured Python projects +* Added a `requirements.txt` file to the application wizard * Fixed that the same Python interpreter could be auto-detected multiple times under different names Debugging --------- +* Added a `dr` locator filter for debugging a project + ### C++ +* Added a pretty printer for `std::tuple` * Fixed that breakpoints were not hit while the message dialog about missing debug information was shown - (QTCREATORBUG-30168) + ([QTCREATORBUG-30168](https://bugreports.qt.io/browse/QTCREATORBUG-30168)) ### Debug Adapter Protocol @@ -161,7 +191,7 @@ Analyzer ### Clang * Added `Edit Checks as Strings` for Clazy - (QTCREATORBUG-24846) + ([QTCREATORBUG-24846](https://bugreports.qt.io/browse/QTCREATORBUG-24846)) ### Axivion @@ -171,16 +201,19 @@ Terminal -------- * Added `Select All` to the context menu - (QTCREATORBUG-29922) + ([QTCREATORBUG-29922](https://bugreports.qt.io/browse/QTCREATORBUG-29922)) * Fixed the startup performance on Windows - (QTCREATORBUG-29840) + ([QTCREATORBUG-29840](https://bugreports.qt.io/browse/QTCREATORBUG-29840)) * Fixed the integration of the `fish` shell * Fixed that `Ctrl+W` closed the terminal even when shortcuts were blocked - (QTCREATORBUG-30070) + ([QTCREATORBUG-30070](https://bugreports.qt.io/browse/QTCREATORBUG-30070)) +* Fixed issues with Windows Powershell Version Control Systems ----------------------- +* Added support for remote version control operations + ### Git * Added the upstream status for untracked branches to `Branches` view @@ -195,22 +228,27 @@ Test Integration Platforms --------- +### Windows + +* Fixed Clang compiler ABI detection for WOA64 + ([QTCREATORBUG-30060](https://bugreports.qt.io/browse/QTCREATORBUG-30060)) + ### Android * Add support for target-based android-build directories (??? is that ready? Qt 6.8+ ???) - (QTBUG-117443) + ([QTBUG-117443](https://bugreports.qt.io/browse/QTBUG-117443)) ### iOS * Fixed the detection of iOS 17 devices * Fixed deployment and running applications for iOS 17 devices (application output, debugging, and profiling are not supported) - (QTCREATORBUG-29682) + ([QTCREATORBUG-29682](https://bugreports.qt.io/browse/QTCREATORBUG-29682)) ### Remote Linux * Fixed that debugging unnecessarily downloaded files from the remote system - (QTCREATORBUG-29614) + ([QTCREATORBUG-29614](https://bugreports.qt.io/browse/QTCREATORBUG-29614)) Credits for these changes go to: -------------------------------- @@ -238,6 +276,7 @@ Esa Törmänen Fabian Kosmale Friedemann Kleint Henning Gruendl +Ilya Kulakov Jaroslaw Kobus Johanna Vanhatapio Karim Abdelrahman @@ -249,6 +288,7 @@ Marcus Tillmanns Mathias Hasselmann Mats Honkamaa Mehdi Salem +Michael Weghorn Miikka Heikkinen Mitch Curtis Olivier De Cannière @@ -257,6 +297,7 @@ Pranta Dastider Robert Löhning Sami Shalayel Samuel Jose Raposo Vieira Mira +Samuel Mira Serg Kryvonos Shrief Gabr Sivert Krøvel From 5937f1b78e96c85c2c7bad4cfb24a4c73e6d519f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 13 Feb 2024 11:22:11 +0100 Subject: [PATCH 65/82] Update qbs submodule to HEAD of 2.3 branch Change-Id: Ideb5c401beb5f512e47ab3e6f7c32fe6e7edda1e Reviewed-by: 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 a04135ed738..a30e54c2e7f 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit a04135ed738d5d65669441fad1593713c3ca2a89 +Subproject commit a30e54c2e7fb7d9735a364497914a5df452dd1ad From f905ad1aa648c4b1c31fcfb2a77dfe241ec2eb1f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 13 Feb 2024 10:22:33 +0100 Subject: [PATCH 66/82] Terminal: Fix handling stub timeout Change-Id: Idaf18ac404d878382d5912793a667200bd7fe6f9 Reviewed-by: Reviewed-by: hjk --- src/libs/utils/terminalinterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index de3f57145cc..0d5a3be0203 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -420,6 +420,7 @@ void TerminalInterface::start() connect(d->stubConnectTimeoutTimer.get(), &QTimer::timeout, this, [this] { killInferiorProcess(); killStubProcess(); + emitFinished(-1, QProcess::ExitStatus::CrashExit); }); d->stubConnectTimeoutTimer->setSingleShot(true); d->stubConnectTimeoutTimer->start(10000); From 4cd5bdc4f6a7ab1578854fb7b0dc3b68c4e5da85 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 13 Feb 2024 09:17:34 +0100 Subject: [PATCH 67/82] LinuxDevice: Show warning if terminal open fails Change-Id: Ifb7a628e7d3f253d834cf8e6503db087def64e0f Reviewed-by: hjk --- src/plugins/remotelinux/linuxdevice.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 80b33c215f5..b166b702d34 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1007,7 +1007,7 @@ LinuxDevice::LinuxDevice() setOpenTerminal([this](const Environment &env, const FilePath &workingDir) -> expected_str { - Process proc; + Process *proc = new Process; // If we will not set any environment variables, we can leave out the shell executable // as the "ssh ..." call will automatically launch the default shell if there are @@ -1015,11 +1015,19 @@ LinuxDevice::LinuxDevice() // specify the shell executable. const QString shell = env.hasChanges() ? env.value_or("SHELL", "/bin/sh") : QString(); - proc.setCommand({filePath(shell), {}}); - proc.setTerminalMode(TerminalMode::Detached); - proc.setEnvironment(env); - proc.setWorkingDirectory(workingDir); - proc.start(); + proc->setCommand({filePath(shell), {}}); + proc->setTerminalMode(TerminalMode::Run); + proc->setEnvironment(env); + proc->setWorkingDirectory(workingDir); + proc->start(); + + QObject::connect(proc, &Process::done, proc, [proc](){ + if (proc->exitCode() != 0){ + qCWarning(linuxDeviceLog) << proc->exitMessage(); + Core::MessageManager::writeFlashing(proc->exitMessage()); + } + proc->deleteLater(); + }); return {}; }); From e7670dd9dbc69273f67b1c49b063a2762e9b8f9c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 11 Feb 2024 17:10:08 +0100 Subject: [PATCH 68/82] Axivion: Simplify string constructions Change-Id: I6dfefbcba47486a16f793c46c281c7f0fb2e888d Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/axivion/axivionplugin.cpp | 49 +++++++++++---------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 8d2b869963f..cd8fca0a0c5 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -266,8 +266,8 @@ static QUrl urlForProject(const QString &projectName) } static constexpr int httpStatusCodeOk = 200; -static const QLatin1String jsonContentType{ "application/json" }; -static const QLatin1String htmlContentType{ "text/html" }; +constexpr char s_htmlContentType[] = "text/html"; +constexpr char s_jsonContentType[] = "application/json"; static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) { @@ -284,15 +284,11 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::functioncredentials); - const QByteArray ua = QByteArrayLiteral("Axivion") - + QCoreApplication::applicationName().toUtf8() - + QByteArrayLiteral("Plugin/") - + QCoreApplication::applicationVersion().toUtf8(); - request.setRawHeader(QByteArrayLiteral("X-Axivion-User-Agent"), ua); + request.setRawHeader("Accept", s_htmlContentType); + request.setRawHeader("Authorization", storage->credentials); + const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); + request.setRawHeader("X-Axivion-User-Agent", ua); query.setRequest(request); query.setNetworkAccessManager(&dd->m_networkAccessManager); }; @@ -307,11 +303,10 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::functionreadAll()); return DoneResult::Success; } - return DoneResult::Error; }; @@ -340,22 +335,19 @@ static Group fetchDataRecipe(const QUrl &url, storage->credentials = QByteArrayLiteral("AxToken ") + settings().server.token.toUtf8(); }; - const auto onQuerySetup = [storage, url](NetworkQuery &query) { + const auto onNetworkQuerySetup = [storage, url](NetworkQuery &query) { QNetworkRequest request(url); - request.setRawHeader(QByteArrayLiteral("Accept"), - QByteArray(jsonContentType.data(), jsonContentType.size())); - request.setRawHeader(QByteArrayLiteral("Authorization"), - storage->credentials); - const QByteArray ua = QByteArrayLiteral("Axivion") - + QCoreApplication::applicationName().toUtf8() - + QByteArrayLiteral("Plugin/") - + QCoreApplication::applicationVersion().toUtf8(); - request.setRawHeader(QByteArrayLiteral("X-Axivion-User-Agent"), ua); + request.setRawHeader("Accept", s_jsonContentType); + request.setRawHeader("Authorization", storage->credentials); + const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); + request.setRawHeader("X-Axivion-User-Agent", ua); query.setRequest(request); query.setNetworkAccessManager(&dd->m_networkAccessManager); + return SetupResult::Continue; }; - const auto onQueryDone = [storage, url](const NetworkQuery &query, DoneWith doneWith) { + const auto onNetworkQueryDone = [storage, url](const NetworkQuery &query, DoneWith doneWith) { QNetworkReply *reply = query.reply(); const QNetworkReply::NetworkError error = reply->error(); const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -366,13 +358,13 @@ static Group fetchDataRecipe(const QUrl &url, .trimmed() .toLower(); if (doneWith == DoneWith::Success && statusCode == httpStatusCodeOk - && contentType == jsonContentType) { + && contentType == s_jsonContentType) { storage->serializableData = reply->readAll(); return DoneResult::Success; } const auto getError = [&]() -> Error { - if (contentType == jsonContentType) { + if (contentType == s_jsonContentType) { try { return DashboardError(reply->url(), statusCode, reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(), @@ -389,8 +381,7 @@ static Group fetchDataRecipe(const QUrl &url, return NetworkError(reply->url(), error, reply->errorString()); }; - MessageManager::writeFlashing( - QStringLiteral("Axivion: %1").arg(getError().message())); + MessageManager::writeFlashing(QStringLiteral("Axivion: %1").arg(getError().message())); return DoneResult::Error; }; @@ -411,7 +402,7 @@ static Group fetchDataRecipe(const QUrl &url, const Group recipe { storage, Sync(onCredentialSetup), - NetworkQueryTask(onQuerySetup, onQueryDone), + NetworkQueryTask(onNetworkQuerySetup, onNetworkQueryDone), AsyncTask(onDeserializeSetup, onDeserializeDone) }; From 5d8cf8ce09a8b47dd40cb1c43fe7980dc939b5e0 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 13 Feb 2024 14:21:42 +0100 Subject: [PATCH 69/82] Doc: Describe setting environment variables for run configurations ...in Preferences > Build & Run > General > Application environment > Change. Task-number: QTCREATORBUG-30209 Change-Id: Idd58652b25ef6cfebf7bfda1a237f4c661b4c3b6 Reviewed-by: Christian Kandeler --- ...creator-projects-settings-environment.qdoc | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc index 6a883e8666d..3f200320fc1 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc @@ -87,7 +87,25 @@ To run in a clean system environment, select \uicontrol {Clean Environment}. - \section2 Run on devices + \section2 Set the environment for all run configurations + + To set environment variables for running and debugging applications, so + that they don't affect \QC itself, set environment variables for run + configurations of all projects: + + \list 1 + \li Go to \preferences > \uicontrol {Build & Run} > \uicontrol General. + \li Select \uicontrol Change in \uicontrol {Application environment}. + \li Set environment variables in \uicontrol {Edit Environment}. + \image qtcreator-edit-environment.webp {Edit Environment dialog} + \endlist + + For example, set \c QT_FORCE_STDERR_LOGGING=1 to see application output + in \l {Application Output} instead of a journal or system log. + + Or, set \c QT_MESSAGE_PATTERN to add information to debugging messages. + + \section2 Use device environment When running on a mobile device connected to the development host, \QC fetches information about the \uicontrol {Device Environment} from the device. From 322dcd2c456dffeac1bf24496af77030776893f7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 13 Feb 2024 17:00:04 +0100 Subject: [PATCH 70/82] CppEditor: Re-add function decl/def switch handler Was accidentally removed in 3771eb196b066314d427d7343cb1d4c6e2c5d6a4. Fixes: QTCREATORBUG-30363 Change-Id: Ifef1266b144d2eb5b7b69ff3e721f781b4455e96 Reviewed-by: hjk --- src/plugins/cppeditor/cppeditorplugin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index b68c739f82e..c9185e372c1 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -323,6 +323,10 @@ void CppEditorPlugin::addPerSymbolActions() switchDeclDef.setTouchBarText(Tr::tr("Decl/Def", "text on macOS touch bar")); switchDeclDef.addToContainers(menus, Constants::G_SYMBOL); switchDeclDef.addToContainer(Core::Constants::TOUCH_BAR, Core::Constants::G_TOUCHBAR_NAVIGATION); + switchDeclDef.addOnTriggered(this, [] { + if (CppEditorWidget *editorWidget = currentCppEditorWidget()) + editorWidget->switchDeclarationDefinition(/*inNextSplit*/ false); + }); ActionBuilder openDeclDefSplit(this, Constants::OPEN_DECLARATION_DEFINITION_IN_NEXT_SPLIT); openDeclDefSplit.setText(Tr::tr("Open Function Declaration/Definition in Next Split")); From fc9863c768f17454c1cde2fd0395a70eb59342ad Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 13 Feb 2024 17:45:38 +0100 Subject: [PATCH 71/82] NetworkQuery: Support more operations Make it possible to PUT, POST and DELETE. Add setWriteData() method, to be used with PUT and POST. Change-Id: I99da38b60120b7efdab391db9b4d638f17d555df Reviewed-by: hjk --- src/libs/solutions/tasking/networkquery.cpp | 15 ++++++++++++++- src/libs/solutions/tasking/networkquery.h | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libs/solutions/tasking/networkquery.cpp b/src/libs/solutions/tasking/networkquery.cpp index b02bb9cea1c..335f79afd94 100644 --- a/src/libs/solutions/tasking/networkquery.cpp +++ b/src/libs/solutions/tasking/networkquery.cpp @@ -19,7 +19,20 @@ void NetworkQuery::start() emit done(DoneResult::Error); return; } - m_reply.reset(m_manager->get(m_request)); + switch (m_operation) { + case NetworkOperation::Get: + m_reply.reset(m_manager->get(m_request)); + break; + case NetworkOperation::Put: + m_reply.reset(m_manager->put(m_request, m_writeData)); + break; + case NetworkOperation::Post: + m_reply.reset(m_manager->post(m_request, m_writeData)); + break; + case NetworkOperation::Delete: + m_reply.reset(m_manager->deleteResource(m_request)); + break; + } connect(m_reply.get(), &QNetworkReply::finished, this, [this] { disconnect(m_reply.get(), &QNetworkReply::finished, this, nullptr); emit done(toDoneResult(m_reply->error() == QNetworkReply::NoError)); diff --git a/src/libs/solutions/tasking/networkquery.h b/src/libs/solutions/tasking/networkquery.h index bf08bd1e7b5..dd099dc7a88 100644 --- a/src/libs/solutions/tasking/networkquery.h +++ b/src/libs/solutions/tasking/networkquery.h @@ -22,6 +22,8 @@ namespace Tasking { // is independent on Qt::Network. // Possibly, it could be placed inside Qt::Network library, as a wrapper around QNetworkReply. +enum class NetworkOperation { Get, Put, Post, Delete }; + class TASKING_EXPORT NetworkQuery final : public QObject { Q_OBJECT @@ -29,6 +31,8 @@ class TASKING_EXPORT NetworkQuery final : public QObject public: ~NetworkQuery(); void setRequest(const QNetworkRequest &request) { m_request = request; } + void setOperation(NetworkOperation operation) { m_operation = operation; } + void setWriteData(const QByteArray &data) { m_writeData = data; } void setNetworkAccessManager(QNetworkAccessManager *manager) { m_manager = manager; } QNetworkReply *reply() const { return m_reply.get(); } void start(); @@ -39,6 +43,8 @@ signals: private: QNetworkRequest m_request; + NetworkOperation m_operation = NetworkOperation::Get; + QByteArray m_writeData; // Used by Put and Post QNetworkAccessManager *m_manager = nullptr; std::unique_ptr m_reply; }; From 02d930b210686b6e33e197cce3d4cdd092073afa Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 13:46:49 +0100 Subject: [PATCH 72/82] Debugger: Improve display of elided string data This was not adding the length before. The problem that the size is suddenly off by a factor of two for QString as elision counts bytes is still present. Change-Id: Ibcb595dc2d9aaa73b3feec955b4d14613307797f Reviewed-by: David Schulz --- src/plugins/debugger/watchhandler.cpp | 40 ++++++++++++--------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index eef0ba5a3ba..651c86bf2d6 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -818,14 +818,24 @@ static QString formattedValue(const WatchItem *item) return reformatInteger(integer, format, item->size, false); } - if (item->elided) { - QString v = item->value; - v.chop(1); - QString len = item->elided > 0 ? QString::number(item->elided) : "unknown length"; - return quoteUnprintable(v) + "\"... (" + len + ')'; + const int maxLength = settings().displayStringLimit(); + QString v = quoteUnprintable(item->value); + + if (v.endsWith('"')) { + if (item->elided) { + v.chop(1); + v.append("...\""); + } + int len = item->elided ? item->elided : item->value.length() - 2; + v += QString(" (%1)").arg(len > 0 ? QString::number(len) : "unknown length"); + return v; } - return quoteUnprintable(item->value); + if (v.size() > maxLength) { + v.truncate(maxLength); + v += QLatin1String("..."); + } + return v; } // Get a pointer address from pointer values reported by the debugger. @@ -886,18 +896,6 @@ QVariant WatchItem::editValue() const return QVariant(quoteUnprintable(stringValue)); } -// Truncate value for item view, maintaining quotes. -static QString truncateValue(QString v) -{ - enum { maxLength = 512 }; - if (v.size() < maxLength) - return v; - const bool isQuoted = v.endsWith('"'); // check for 'char* "Hallo"' - v.truncate(maxLength); - v += QLatin1String(isQuoted ? "...\"" : "..."); - return v; -} - static QString displayName(const WatchItem *item) { QString result; @@ -939,13 +937,9 @@ static QString displayName(const WatchItem *item) return result; } - void WatchItem::updateValueCache() const { - QString formatted = truncateValue(formattedValue(this)); - if (formatted.endsWith('"')) - formatted.append(QString(" (%1)").arg(this->value.length() - 2)); - valueCache = formatted; + valueCache = formattedValue(this); valueCache = watchModel(this)->removeNamespaces(valueCache); if (valueCache.isEmpty() && this->address) valueCache += QString::fromLatin1("@0x" + QByteArray::number(this->address, 16)); From a26aff7afd17b1f7ddda917ad07e1c1a9292ec9d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 14:58:56 +0100 Subject: [PATCH 73/82] Debugger: Report full sizes instead of the elide setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More direct communication of the meaning. Use 'length' when talking about things like string lengths, and 'size' for sizes in bytes. Task-number:  QTCREATORBUG-30065 Change-Id: Ifed84a5dab4ed890973c1abf4d427655eb50a61a Reviewed-by: David Schulz --- share/qtcreator/debugger/creatortypes.py | 4 +- share/qtcreator/debugger/dumper.py | 179 +++++++++++------------ share/qtcreator/debugger/qttypes.py | 169 +++++++++++---------- src/plugins/debugger/watchdata.cpp | 8 +- src/plugins/debugger/watchdata.h | 2 +- src/plugins/debugger/watchhandler.cpp | 10 +- 6 files changed, 184 insertions(+), 188 deletions(-) diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py index 24c16ce0094..ba5b53450b0 100644 --- a/share/qtcreator/debugger/creatortypes.py +++ b/share/qtcreator/debugger/creatortypes.py @@ -204,7 +204,7 @@ def qdump__CPlusPlus__Internal__Value(d, value): def qdump__Utils__FilePath(d, value): data, path_len, scheme_len, host_len = d.split("{@QString}IHH", value) - elided, enc = d.encodeStringHelper(data, d.displayStringLimit) + length, enc = d.encodeStringHelper(data, d.displayStringLimit) # enc is concatenated path + scheme + host if scheme_len: scheme_pos = path_len * 4 @@ -221,7 +221,7 @@ def qdump__Utils__FilePath(d, value): val += path_enc else: val = enc - d.putValue(val, "utf16", elided=elided) + d.putValue(val, "utf16", length=length) d.putPlainChildren(value) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 1fd42848d4e..ad25ad2dbeb 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -44,15 +44,15 @@ class ReportItem(): subsequent better guesses during a putItem() run. """ - def __init__(self, value=None, encoding=None, priority=-100, elided=None): + def __init__(self, value=None, encoding=None, priority=-100, length=None): self.value = value self.priority = priority self.encoding = encoding - self.elided = elided + self.length = length def __str__(self): - return 'Item(value: %s, encoding: %s, priority: %s, elided: %s)' \ - % (self.value, self.encoding, self.priority, self.elided) + return 'Item(value: %s, encoding: %s, priority: %s, length: %s)' \ + % (self.value, self.encoding, self.priority, self.length) class Timer(): @@ -349,8 +349,8 @@ class DumperBase(): else: if self.currentValue.encoding is not None: self.put('valueencoded="%s",' % self.currentValue.encoding) - if self.currentValue.elided: - self.put('valueelided="%s",' % self.currentValue.elided) + if self.currentValue.length: + self.put('valuelen="%s",' % self.currentValue.length) self.put('value="%s",' % self.currentValue.value) except: pass @@ -376,7 +376,7 @@ class DumperBase(): b = bytes(bytearray.fromhex(value)) value = codecs.decode(b, 'utf-16') self.put('"%s"' % value) - if self.currentValue.elided: + if self.currentValue.length: self.put('...') if self.currentType.value: @@ -545,40 +545,40 @@ class DumperBase(): # assume no Qt 3 support by default return False - # Clamps size to limit. - def computeLimit(self, size, limit): + # Clamps length to limit. + def computeLimit(self, length, limit=0): if limit == 0: limit = self.displayStringLimit - if limit is None or size <= limit: - return 0, size - return size, limit + if limit is None or length <= limit: + return length + return limit def vectorData(self, value): if self.qtVersion() >= 0x060000: - data, size, alloc = self.qArrayData(value) + data, length, alloc = self.qArrayData(value) elif self.qtVersion() >= 0x050000: vector_data_ptr = self.extractPointer(value) if self.ptrSize() == 4: - (ref, size, alloc, offset) = self.split('IIIp', vector_data_ptr) + (ref, length, alloc, offset) = self.split('IIIp', vector_data_ptr) else: - (ref, size, alloc, pad, offset) = self.split('IIIIp', vector_data_ptr) + (ref, length, alloc, pad, offset) = self.split('IIIIp', vector_data_ptr) alloc = alloc & 0x7ffffff data = vector_data_ptr + offset else: vector_data_ptr = self.extractPointer(value) - (ref, alloc, size) = self.split('III', vector_data_ptr) + (ref, alloc, length) = self.split('III', vector_data_ptr) data = vector_data_ptr + 16 - self.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000) - return data, size + self.check(0 <= length and length <= alloc and alloc <= 1000 * 1000 * 1000) + return data, length def qArrayData(self, value): if self.qtVersion() >= 0x60000: - dd, data, size = self.split('ppp', value) + dd, data, length = self.split('ppp', value) if dd: _, _, alloc = self.split('iip', dd) else: # fromRawData - alloc = size - return data, size, alloc + alloc = length + return data, length, alloc return self.qArrayDataHelper(self.extractPointer(value)) def qArrayDataHelper(self, array_data_ptr): @@ -586,10 +586,10 @@ class DumperBase(): if self.qtVersion() >= 0x050000: # QTypedArray: # - QtPrivate::RefCount ref - # - int size + # - int length # - uint alloc : 31, capacityReserved : 1 # - qptrdiff offset - (ref, size, alloc, offset) = self.split('IIpp', array_data_ptr) + (ref, length, alloc, offset) = self.split('IIpp', array_data_ptr) alloc = alloc & 0x7ffffff data = array_data_ptr + offset if self.ptrSize() == 4: @@ -599,43 +599,42 @@ class DumperBase(): elif self.qtVersion() >= 0x040000: # Data: # - QBasicAtomicInt ref; - # - int alloc, size; + # - int alloc, length; # - [padding] # - char *data; if self.ptrSize() == 4: - (ref, alloc, size, data) = self.split('IIIp', array_data_ptr) + (ref, alloc, length, data) = self.split('IIIp', array_data_ptr) else: - (ref, alloc, size, pad, data) = self.split('IIIIp', array_data_ptr) + (ref, alloc, length, pad, data) = self.split('IIIIp', array_data_ptr) else: # Data: # - QShared count; # - QChar *unicode # - char *ascii # - uint len: 30 - (dummy, dummy, dummy, size) = self.split('IIIp', array_data_ptr) - size = self.extractInt(array_data_ptr + 3 * self.ptrSize()) & 0x3ffffff - alloc = size # pretend. + (dummy, dummy, dummy, length) = self.split('IIIp', array_data_ptr) + length = self.extractInt(array_data_ptr + 3 * self.ptrSize()) & 0x3ffffff + alloc = length # pretend. data = self.extractPointer(array_data_ptr + self.ptrSize()) - return data, size, alloc + return data, length, alloc def encodeStringHelper(self, value, limit): - data, size, alloc = self.qArrayData(value) + data, length, alloc = self.qArrayData(value) if alloc != 0: - self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000) - elided, shown = self.computeLimit(2 * size, 2 * limit) - return elided, self.readMemory(data, shown) + self.check(0 <= length and length <= alloc and alloc <= 100 * 1000 * 1000) + shown = self.computeLimit(2 * length, 2 * limit) + return length, self.readMemory(data, shown) def encodeByteArrayHelper(self, value, limit): - data, size, alloc = self.qArrayData(value) + data, length, alloc = self.qArrayData(value) if alloc != 0: - self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000) - elided, shown = self.computeLimit(size, limit) - return elided, self.readMemory(data, shown) + self.check(0 <= length and length <= alloc and alloc <= 100 * 1000 * 1000) + shown = self.computeLimit(length, limit) + return length, self.readMemory(data, shown) - def putCharArrayValue(self, data, size, charSize, + def putCharArrayValue(self, data, length, charSize, displayFormat=DisplayFormat.Automatic): - bytelen = size * charSize - elided, shown = self.computeLimit(bytelen, self.displayStringLimit) + shown = self.computeLimit(length, self.displayStringLimit) mem = self.readMemory(data, shown) if charSize == 1: if displayFormat in (DisplayFormat.Latin1String, DisplayFormat.SeparateLatin1String): @@ -650,13 +649,13 @@ class DumperBase(): encodingType = 'ucs4' #childType = 'int' - self.putValue(mem, encodingType, elided=elided) + self.putValue(mem, encodingType, length=length) if displayFormat in ( DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String, DisplayFormat.Separate): - elided, shown = self.computeLimit(bytelen, 100000) + shown = self.computeLimit(length, 100000) self.putDisplay(encodingType + ':separate', self.readMemory(data, shown)) def putCharArrayHelper(self, data, size, charType, @@ -676,15 +675,15 @@ class DumperBase(): return self.hexencode(bytes(self.readRawMemory(addr, size))) def encodeByteArray(self, value, limit=0): - elided, data = self.encodeByteArrayHelper(value, limit) + _, data = self.encodeByteArrayHelper(value, limit) return data def putByteArrayValue(self, value): - elided, data = self.encodeByteArrayHelper(value, self.displayStringLimit) - self.putValue(data, 'latin1', elided=elided) + length, data = self.encodeByteArrayHelper(value, self.displayStringLimit) + self.putValue(data, 'latin1', length=length) def encodeString(self, value, limit=0): - elided, data = self.encodeStringHelper(value, limit) + _, data = self.encodeStringHelper(value, limit) return data def encodedUtf16ToUtf8(self, s): @@ -730,8 +729,8 @@ class DumperBase(): return inner def putStringValue(self, value): - elided, data = self.encodeStringHelper(value, self.displayStringLimit) - self.putValue(data, 'utf16', elided=elided) + length, data = self.encodeStringHelper(value, self.displayStringLimit) + self.putValue(data, 'utf16', length=length) def putPtrItem(self, name, value): with SubItem(self, name): @@ -900,12 +899,12 @@ class DumperBase(): if not self.isInt(thing): raise RuntimeError('Expected an integral value, got %s' % type(thing)) - def readToFirstZero(self, base, tsize, maximum): + def readToFirstZero(self, base, typesize, maximum): self.checkIntType(base) - self.checkIntType(tsize) + self.checkIntType(typesize) self.checkIntType(maximum) - code = self.packCode + (None, 'b', 'H', None, 'I')[tsize] + code = self.packCode + (None, 'b', 'H', None, 'I')[typesize] #blob = self.readRawMemory(base, 1) blob = bytes() while maximum > 1: @@ -916,8 +915,8 @@ class DumperBase(): maximum = int(maximum / 2) self.warn('REDUCING READING MAXIMUM TO %s' % maximum) - #DumperBase.warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, tsize, maximum)) - for i in range(0, maximum, tsize): + #DumperBase.warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, typesize, maximum)) + for i in range(0, maximum, typesize): t = struct.unpack_from(code, blob, i)[0] if t == 0: return 0, i, self.hexencode(blob[:i]) @@ -925,9 +924,9 @@ class DumperBase(): # Real end is unknown. return -1, maximum, self.hexencode(blob[:maximum]) - def encodeCArray(self, p, tsize, limit): - elided, shown, blob = self.readToFirstZero(p, tsize, limit) - return elided, blob + def encodeCArray(self, p, typesize, limit): + length, shown, blob = self.readToFirstZero(p, typesize, limit) + return length, blob def putItemCount(self, count, maximum=1000000000): # This needs to override the default value, so don't use 'put' directly. @@ -1043,12 +1042,12 @@ class DumperBase(): self.currentType.value = typish.name self.currentType.priority = priority - def putValue(self, value, encoding=None, priority=0, elided=None): + def putValue(self, value, encoding=None, priority=0, length=None): # Higher priority values override lower ones. - # elided = 0 indicates all data is available in value, + # length = None indicates all data is available in value, # otherwise it's the true length. if priority >= self.currentValue.priority: - self.currentValue = ReportItem(value, encoding, priority, elided) + self.currentValue = ReportItem(value, encoding, priority, length) def putSpecialValue(self, encoding, value='', children=None): self.putValue(value, encoding) @@ -1226,13 +1225,13 @@ class DumperBase(): return False - def putSimpleCharArray(self, base, size=None): - if size is None: - elided, shown, data = self.readToFirstZero(base, 1, self.displayStringLimit) + def putSimpleCharArray(self, base, length=None): + if length is None: + length, shown, data = self.readToFirstZero(base, 1, self.displayStringLimit) else: - elided, shown = self.computeLimit(int(size), self.displayStringLimit) + shown = self.computeLimit(length) data = self.readMemory(base, shown) - self.putValue(data, 'latin1', elided=elided) + self.putValue(data, 'latin1', length=length) def putDisplay(self, editFormat, value): self.putField('editformat', editFormat) @@ -1248,8 +1247,8 @@ class DumperBase(): if targetType.name in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'): # Use UTF-8 as default for char *. self.putType(typeName) - (elided, shown, data) = self.readToFirstZero(ptr, 1, limit) - self.putValue(data, 'utf8', elided=elided) + (length, shown, data) = self.readToFirstZero(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) if self.isExpanded(): self.putArrayData(ptr, shown, innerType) return True @@ -1257,55 +1256,55 @@ class DumperBase(): if targetType.name in ('wchar_t', 'WCHAR'): self.putType(typeName) charSize = self.lookupType('wchar_t').size() - (elided, data) = self.encodeCArray(ptr, charSize, limit) + (length, data) = self.encodeCArray(ptr, charSize, limit) if charSize == 2: - self.putValue(data, 'utf16', elided=elided) + self.putValue(data, 'utf16', length=length) else: - self.putValue(data, 'ucs4', elided=elided) + self.putValue(data, 'ucs4', length=length) return True if displayFormat == DisplayFormat.Latin1String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'latin1', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) return True if displayFormat == DisplayFormat.SeparateLatin1String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'latin1', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) self.putDisplay('latin1:separate', data) return True if displayFormat == DisplayFormat.Utf8String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'utf8', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) return True if displayFormat == DisplayFormat.SeparateUtf8String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'utf8', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) self.putDisplay('utf8:separate', data) return True if displayFormat == DisplayFormat.Local8BitString: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'local8bit', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'local8bit', length=length) return True if displayFormat == DisplayFormat.Utf16String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 2, limit) - self.putValue(data, 'utf16', elided=elided) + (length, data) = self.encodeCArray(ptr, 2, limit) + self.putValue(data, 'utf16', length=length) return True if displayFormat == DisplayFormat.Ucs4String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 4, limit) - self.putValue(data, 'ucs4', elided=elided) + (length, data) = self.encodeCArray(ptr, 4, limit) + self.putValue(data, 'ucs4', length=length) return True return False @@ -2577,17 +2576,17 @@ class DumperBase(): def extractQStringFromQDataStream(self, buf, offset): """ Read a QString from the stream """ - size = struct.unpack_from('!I', buf, offset)[0] + length = struct.unpack_from('!I', buf, offset)[0] offset += 4 - string = buf[offset:offset + size].decode('utf-16be') - return (string, offset + size) + string = buf[offset:offset + length].decode('utf-16be') + return (string, offset + length) def extractQByteArrayFromQDataStream(self, buf, offset): """ Read a QByteArray from the stream """ - size = struct.unpack_from('!I', buf, offset)[0] + length = struct.unpack_from('!I', buf, offset)[0] offset += 4 - string = buf[offset:offset + size].decode('latin1') - return (string, offset + size) + string = buf[offset:offset + length].decode('latin1') + return (string, offset + length) def extractIntFromQDataStream(self, buf, offset): """ Read an int from the stream """ diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index b08f60a9bb3..06e7d473254 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -28,46 +28,46 @@ def qform__QByteArray(): def qedit__QByteArray(d, value, data): d.call('void', value, 'resize', str(len(data))) - (base, size, alloc) = d.stringData(value) + (base, length, alloc) = d.stringData(value) d.setValues(base, 'char', [ord(c) for c in data]) def qdump__QByteArray(d, value): if d.qtVersion() >= 0x60000: - dd, data, size = value.split('ppi') + dd, data, length = value.split('ppi') if dd: _, _, alloc = d.split('iii', dd) else: # fromRawData - alloc = size + alloc = length else: - data, size, alloc = d.qArrayData(value) + data, length, alloc = d.qArrayData(value) - d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000)) - if size > 0: + d.check(alloc == 0 or (0 <= length and length <= alloc and alloc <= 100000000)) + if length > 0: d.putExpandable() - elided, shown = d.computeLimit(size, d.displayStringLimit) + shown = d.computeLimit(length, d.displayStringLimit) p = d.readMemory(data, shown) displayFormat = d.currentItemFormat() if displayFormat == DisplayFormat.Automatic or displayFormat == DisplayFormat.Latin1String: - d.putValue(p, 'latin1', elided=elided) + d.putValue(p, 'latin1', length=length) elif displayFormat == DisplayFormat.SeparateLatin1String: - d.putValue(p, 'latin1', elided=elided) + d.putValue(p, 'latin1', length=length) d.putDisplay('latin1:separate', d.encodeByteArray(value, limit=100000)) elif displayFormat == DisplayFormat.Utf8String: - d.putValue(p, 'utf8', elided=elided) + d.putValue(p, 'utf8', length=length) elif displayFormat == DisplayFormat.SeparateUtf8String: - d.putValue(p, 'utf8', elided=elided) + d.putValue(p, 'utf8', length=length) d.putDisplay('utf8:separate', d.encodeByteArray(value, limit=100000)) if d.isExpanded(): - d.putArrayData(data, size, d.charType()) + d.putArrayData(data, length, d.charType()) #def qdump__QArrayData(d, value): -# data, size, alloc = d.qArrayDataHelper(value.address()) -# d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000)) -# d.putValue(d.readMemory(data, size), 'latin1') +# data, length, alloc = d.qArrayDataHelper(value.address()) +# d.check(alloc == 0 or (0 <= length and length <= alloc and alloc <= 100000000)) +# d.putValue(d.readMemory(data, length), 'latin1') # d.putPlainChildren(value) @@ -81,10 +81,10 @@ def qdump__QBitArray(d, value): else: data, basize, _ = d.qArrayData(value['d']) unused = d.extractByte(data) if data else 0 - size = basize * 8 - unused - d.putItemCount(size) + length = basize * 8 - unused + d.putItemCount(length) if d.isExpanded(): - with Children(d, size, maxNumChild=10000): + with Children(d, length, maxNumChild=10000): for i in d.childRange(): q = data + 1 + int(i / 8) with SubItem(d, i): @@ -1621,17 +1621,17 @@ def qdumpHelper_QSet45(d, value): ptrSize = d.ptrSize() dptr = d.extractPointer(value) - (fakeNext, buckets, ref, size, nodeSize, userNumBits, numBits, numBuckets) = \ + (fakeNext, buckets, ref, length, nodeSize, userNumBits, numBits, numBuckets) = \ d.split('ppiiihhi', dptr) - d.check(0 <= size and size <= 100 * 1000 * 1000) + d.check(0 <= length and length <= 100 * 1000 * 1000) d.check(-1 <= ref and ref < 100000) - d.putItemCount(size) + d.putItemCount(length) if d.isExpanded(): keyType = value.type[0] isShort = d.qtVersion() < 0x050000 and keyType.name == 'int' - with Children(d, size, childType=keyType): + with Children(d, length, childType=keyType): node = hashDataFirstNode() for i in d.childRange(): if isShort: @@ -1714,15 +1714,15 @@ def qdump__QStack(d, value): def qdump__QPolygonF(d, value): - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QPointF')) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QPointF')) def qdump__QPolygon(d, value): - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QPoint')) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QPoint')) def qdump__QGraphicsPolygonItem(d, value): @@ -1741,14 +1741,14 @@ def qdump__QGraphicsPolygonItem(d, value): offset = 328 if d.isMsvcTarget() else 320 else: offset = 308 - data, size = d.vectorData(dptr + offset) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QPointF')) + data, length = d.vectorData(dptr + offset) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QPointF')) def qedit__QString(d, value, data): d.call('void', value, 'resize', str(len(data))) - (base, size, alloc) = d.stringData(value) + (base, length, alloc) = d.stringData(value) d.setValues(base, 'short', [ord(c) for c in data]) @@ -1758,14 +1758,14 @@ def qform__QString(): def qdump__QString(d, value): d.putStringValue(value) - data, size, _ = d.stringData(value) + data, length, _ = d.stringData(value) displayFormat = d.currentItemFormat() if displayFormat == DisplayFormat.Separate: d.putDisplay('utf16:separate', d.encodeString(value, limit=100000)) - if (size > 0): + if (length > 0): d.putExpandable() if d.isExpanded(): - d.putArrayData(data, size, d.createType('@QChar')) + d.putArrayData(data, length, d.createType('@QChar')) def qdump__QSettingsKey(d, value): @@ -1774,8 +1774,8 @@ def qdump__QSettingsKey(d, value): def qdump__QStaticStringData(d, value): - size = value.type[0] - (ref, size, alloc, pad, offset, data) = value.split('iii@p%ss' % (2 * size)) + length = value.type[0] + (ref, length, alloc, pad, offset, data) = value.split('iii@p%ss' % (2 * length)) d.putValue(d.hexencode(data), 'utf16') d.putPlainChildren(value) @@ -1788,28 +1788,28 @@ def qdump__QTypedArrayData(d, value): def qdump__QStringData(d, value): - (ref, size, alloc, pad, offset) = value.split('III@p') - elided, shown = d.computeLimit(size, d.displayStringLimit) + (ref, length, alloc, pad, offset) = value.split('III@p') + shown = d.computeLimit(length, d.displayStringLimit) data = d.readMemory(value.address() + offset, shown * 2) - d.putValue(data, 'utf16', elided=elided) + d.putValue(data, 'utf16', length=length) d.putPlainChildren(value) def qdump__QAnyStringView(d, value): - data, size = value.split('pp') + data, length = value.split('pp') bits = d.ptrSize() * 8 - 2 - tag = size >> bits - size = size & (2**bits - 1) - elided, shown = d.computeLimit(size, d.displayStringLimit) + tag = length >> bits + length = length & (2**bits - 1) + shown = d.computeLimit(length, d.displayStringLimit) if tag == 0: mem = d.readMemory(data, shown) - d.putValue(mem, 'utf8', elided=elided) + d.putValue(mem, 'utf8', length=length) elif tag == 1: mem = d.readMemory(data, shown) - d.putValue(mem, 'latin1', elided=elided) + d.putValue(mem, 'latin1', length=length) elif tag == 2: mem = d.readMemory(data, shown * 2) - d.putValue(mem, 'utf16', elided=elided) + d.putValue(mem, 'utf16', length=length) else: d.putSpecialValue('empty') d.putPlainChildren(value) @@ -1825,16 +1825,15 @@ def qdump__QStringView(d, value): if idata == 0: d.putValue('(null)') return - size = value['m_size'] - isize = size.integer() - elided, shown = d.computeLimit(isize, d.displayStringLimit) + length = value['m_size'].integer() + shown = d.computeLimit(length, d.displayStringLimit) mem = d.readMemory(idata, shown * 2) - d.putValue(mem, 'utf16', elided=elided) + d.putValue(mem, 'utf16', length=length) if d.currentItemFormat() == DisplayFormat.Separate: d.putDisplay('utf16:separate', mem) d.putExpandable() if d.isExpanded(): - d.putArrayData(idata, isize, d.createType('char16_t')) + d.putArrayData(idata, length, d.createType('char16_t')) def qdump__QHashedString(d, value): @@ -1848,12 +1847,12 @@ def qdump__QQmlRefCount(d, value): def qdump__QStringRef(d, value): - (stringptr, pos, size) = value.split('pii') + (stringptr, pos, length) = value.split('pii') if stringptr == 0: d.putValue('(null)') return data, ssize, alloc = d.stringData(d.createValue(stringptr, '@QString')) - d.putValue(d.readMemory(data + 2 * pos, 2 * size), 'utf16') + d.putValue(d.readMemory(data + 2 * pos, 2 * length), 'utf16') d.putPlainChildren(value) @@ -1937,7 +1936,7 @@ def qdump__QUrl(d, value): userNameEnc = d.encodeString(userName) hostEnc = d.encodeString(host) - elided, pathEnc = d.encodeStringHelper(path, d.displayStringLimit) + length, pathEnc = d.encodeStringHelper(path, d.displayStringLimit) url = d.encodeString(scheme) url += '3a002f002f00' # '://' if len(userNameEnc): @@ -1946,7 +1945,7 @@ def qdump__QUrl(d, value): if port >= 0: url += '3a00' + ''.join(['%02x00' % ord(c) for c in str(port)]) url += pathEnc - d.putValue(url, 'utf16', elided=elided) + d.putValue(url, 'utf16', length=length) displayFormat = d.currentItemFormat() if displayFormat == DisplayFormat.Separate: @@ -2162,7 +2161,7 @@ def qdumpHelper__QVariant6(d, value): qdumpHelper_QVariant_0(d, value) return - revision, alignment, size, flags, variantType, metaObjectPtr, name = \ + revision, alignment, length, flags, variantType, metaObjectPtr, name = \ d.split('HHIIIpp', metaTypeInterface) # Well-known simple type. @@ -2241,7 +2240,7 @@ def qdumpHelper__QVariant45(d, value): base1 = d.extractPointer(value) #DumperBase.warn('BASE 1: %s %s' % (base1, innert)) base = d.extractPointer(base1) - #DumperBase.warn('SIZE 1: %s' % size) + #DumperBase.warn('SIZE 1: %s' % length) val = d.createValue(base, innerType) else: #DumperBase.warn('DIRECT ITEM 1: %s' % innerType) @@ -2268,7 +2267,7 @@ def qdumpHelper__QVariant45(d, value): d.putSpecialValue('notcallable') return None ptr = p.pointer() - (elided, blob) = d.encodeCArray(ptr, 1, 100) + (_, blob) = d.encodeCArray(ptr, 1, 100) innerType = d.hexdecode(blob) # Prefer namespaced version. @@ -2303,34 +2302,34 @@ def qform__QVector(): def qdump__QVector(d, value): if d.qtVersion() >= 0x060000: - data, size = d.listData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType(value.type.ltarget[0])) + data, length = d.listData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType(value.type.ltarget[0])) # g++ 9.3 does not add the template parameter list to the debug info. # Fake it for the common case: if value.type.name == d.qtNamespace() + "QVector": d.putBetterType(value.type.name + '<' + value.type.ltarget[0].name + '>') else: - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType(value.type[0])) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType(value.type[0])) if False: def qdump__QObjectConnectionList(d, value): - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QObjectPrivate::ConnectionList')) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QObjectPrivate::ConnectionList')) def qdump__QVarLengthArray(d, value): if d.qtVersion() >= 0x060000: - cap, size, data = value.split('QQp') + cap, length, data = value.split('QQp') else: - cap, size, data = value.split('iip') - d.check(0 <= size) - d.putItemCount(size) - d.putPlotData(data, size, value.type[0]) + cap, length, data = value.split('iip') + d.check(0 <= length) + d.putItemCount(length) + d.putPlotData(data, length, value.type[0]) def qdump__QSharedPointer(d, value): @@ -2401,20 +2400,20 @@ def qdump__QXmlAttributes(d, value): def qdump__QXmlStreamStringRef(d, value): s = value['m_string'] - (data, size, alloc) = d.stringData(s) + (data, length, alloc) = d.stringData(s) data += 2 * int(value['m_position']) - size = int(value['m_size']) - s = d.readMemory(data, 2 * size) + length = int(value['m_size']) + s = d.readMemory(data, 2 * length) d.putValue(s, 'utf16') d.putPlainChildren(value) def qdump__QXmlStreamAttribute(d, value): s = value['m_name']['m_string'] - (data, size, alloc) = d.stringData(s) + (data, length, alloc) = d.stringData(s) data += 2 * int(value['m_name']['m_position']) - size = int(value['m_name']['m_size']) - s = d.readMemory(data, 2 * size) + length = int(value['m_name']['m_size']) + s = d.readMemory(data, 2 * length) d.putValue(s, 'utf16') d.putPlainChildren(value) @@ -2505,8 +2504,8 @@ def qdump__QV4__ExecutionContext(d, value): def qdump__QQmlSourceLocation(d, value): (sourceFile, line, col) = value.split('pHH') - (data, size, alloc) = d.stringData(value) - d.putValue(d.readMemory(data, 2 * size), 'utf16') + (data, length, alloc) = d.stringData(value) + d.putValue(d.readMemory(data, 2 * length), 'utf16') d.putField('valuesuffix', ':%s:%s' % (line, col)) d.putPlainChildren(value) @@ -3345,9 +3344,7 @@ def qdump__QJsonValue(d, value): return if t == 3: d.putType('QJsonValue (String)') - string = value.split('{@QString}')[0] - elided, base = d.encodeString(string, d.displayStringLimit) - d.putValue(base, 'utf16', elided=elided) + d.putStringValue(value.split('{@QString}')[0]) return if t == 4: d.putType('QJsonValue (Array)') @@ -3472,9 +3469,9 @@ def qdumpHelper_QCbor_string(d, container_ptr, element_index, is_bytes): bytedata_len = d.extractInt(bytedata) bytedata_data = bytedata + 4 # sizeof(QtCbor::ByteData) header part - elided, shown = d.computeLimit(bytedata_len, d.displayStringLimit) + shown = d.computeLimit(bytedata_len, d.displayStringLimit) res = d.readMemory(bytedata_data, shown) - d.putValue(res, enc, elided=elided) + d.putValue(res, enc, length=bytedata_len) def qdumpHelper_QCborArray_valueAt(d, container_ptr, elements_data_ptr, idx, bytedata, is_cbor): diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 8d0af0e4d31..120ce756122 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -151,8 +151,8 @@ QString WatchItem::toString() const if (!value.isEmpty()) str << "value=\"" << value << doubleQuoteComma; - if (elided) - str << "valueelided=\"" << elided << doubleQuoteComma; + if (valuelen) + str << "valuelen=\"" << valuelen << doubleQuoteComma; if (!editvalue.isEmpty()) str << "editvalue=\"<...>\","; @@ -300,9 +300,9 @@ void WatchItem::parseHelper(const GdbMi &input, bool maySort) if (mi.isValid()) id = mi.toInt(); - mi = input["valueelided"]; + mi = input["valuelen"]; if (mi.isValid()) - elided = mi.toInt(); + valuelen = mi.toInt(); mi = input["bitpos"]; if (mi.isValid()) diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index bb2e458bcd3..672ded5e7c6 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -72,7 +72,7 @@ public: uint bitsize = 0; // Size in case of bit fields uint autoDerefCount = 0; // number of levels of automatic dereferencing that has taken place (for pointer types) uint variablesReference = 0;// reference to the variable in the variables request DAP related - int elided = 0; // Full size if value was cut off, -1 if cut on unknown size, 0 otherwise + int valuelen = 0; // -1 if cut on unknown size, full size otherwise int arrayIndex = -1; // -1 if not an array member uchar sortGroup = 0; // 0 - ordinary member, 1 - vptr, 2 - base class bool wantsChildren = false; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 651c86bf2d6..841dc4d0156 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -822,12 +822,12 @@ static QString formattedValue(const WatchItem *item) QString v = quoteUnprintable(item->value); if (v.endsWith('"')) { - if (item->elided) { + if (item->valuelen > maxLength) { v.chop(1); v.append("...\""); } - int len = item->elided ? item->elided : item->value.length() - 2; - v += QString(" (%1)").arg(len > 0 ? QString::number(len) : "unknown length"); + if (item->valuelen > 0) + v += QString(" (%1)").arg(item->valuelen); return v; } @@ -1297,7 +1297,7 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const // FIXME: Forcing types is not implemented yet. //if (idx.column() == 2) // return editable; // Watcher types can be set by force. - if (column == ValueColumn && item->valueEditable && !item->elided) + if (column == ValueColumn && item->valueEditable && item->valuelen >= 0) return editable; // Watcher values are sometimes editable. } } else if (item->isLocal()) { @@ -1305,7 +1305,7 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const return notEditable; if (isRunning && !m_engine->hasCapability(AddWatcherWhileRunningCapability)) return notEditable; - if (column == ValueColumn && item->valueEditable && !item->elided) + if (column == ValueColumn && item->valueEditable && item->valuelen >= 0) return editable; // Locals values are sometimes editable. if (column == ValueColumn && item->arrayIndex >= 0) return editable; From 7b57ae31f6338fdb3faa7403a1a1f4c7e0f22caa Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 13 Feb 2024 15:04:20 +0100 Subject: [PATCH 74/82] Avoid automatic creation of performance data related .json files Amends 1a84ae038df0757f44d890ad3d5b2e055d5dda7e which enabled building the Nanotrace library by default. The part that is used for startup performance logging is only enabled at runtime with the `-trace` command line argument, but some logging using the "hr" variant was automatically created. Disable that part at compile time by default. Fixes: QTCREATORBUG-30331 Change-Id: I8add207c760bfe2dde52534f55feb7b637ccb600 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- src/libs/nanotrace/CMakeLists.txt | 7 ++++++- src/libs/nanotrace/nanotracehr.h | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libs/nanotrace/CMakeLists.txt b/src/libs/nanotrace/CMakeLists.txt index f2fa830e2d3..8652a817985 100644 --- a/src/libs/nanotrace/CMakeLists.txt +++ b/src/libs/nanotrace/CMakeLists.txt @@ -3,7 +3,6 @@ add_qtc_library(Nanotrace SOURCES nanotraceglobals.h nanotrace.cpp nanotrace.h - nanotracehr.cpp nanotracehr.h PUBLIC_DEPENDS Qt::Core Qt::Gui PROPERTIES CXX_VISIBILITY_PRESET default @@ -16,3 +15,9 @@ extend_qtc_library(Nanotrace CONDITION DESIGN_STUDIO_USE_NANOTRACE PUBLIC_DEFINES NANOTRACE_DESIGNSTUDIO_ENABLED ) + +option(NANOTRACEHR_ENABLED "Enables collecting high resolution performance data" OFF) +extend_qtc_library(Nanotrace + SOURCES + nanotracehr.cpp nanotracehr.h +) diff --git a/src/libs/nanotrace/nanotracehr.h b/src/libs/nanotrace/nanotracehr.h index d49e12a87a0..74b1381b064 100644 --- a/src/libs/nanotrace/nanotracehr.h +++ b/src/libs/nanotrace/nanotracehr.h @@ -34,7 +34,7 @@ enum class Tracing { IsDisabled, IsEnabled }; constexpr Tracing tracingStatus() { -#ifdef NANOTRACE_ENABLED +#ifdef NANOTRACEHR_ENABLED return Tracing::IsEnabled; #else return Tracing::IsDisabled; @@ -1569,7 +1569,7 @@ template Tracer(typename Category::ArgumentType name, Category &category, Arguments &&...) -> Tracer; -#ifdef NANOTRACE_ENABLED +#ifdef NANOTRACEHR_ENABLED class GlobalTracer { public: From 321b2454771f29e8d1ef085b637564a01acdb042 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 6 Feb 2024 16:58:52 +0100 Subject: [PATCH 75/82] Doc: Describe Help > About Qt Creator > Copy and Close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the instructions for contacting Qt from the front page to a how-to topic. Task-number: QTCREATORBUG-30209 Change-Id: I4f4083927ad54bdca555e1825f817f494e30e860 Reviewed-by: André Hartmann Reviewed-by: hjk --- .../creator-how-to-contact-qt.qdoc | 49 +++++++++++++++++++ doc/qtcreator/src/qtcreator.qdoc | 17 +------ 2 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 doc/qtcreator/src/howto/creator-only/creator-how-to-contact-qt.qdoc diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-to-contact-qt.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-to-contact-qt.qdoc new file mode 100644 index 00000000000..93b8844f240 --- /dev/null +++ b/doc/qtcreator/src/howto/creator-only/creator-how-to-contact-qt.qdoc @@ -0,0 +1,49 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page creator-how-to-contact-qt.html + \previouspage creator-how-tos.html + + \ingroup creator-how-to-use + + \title Contact Qt + + To report bugs and tell us what you think about \QC and Qt, + go to \uicontrol Help. + + \section1 Report bugs and suggest improvements + + To report bugs and add suggestions for improvement to the + \l{https://bugreports.qt.io/}{Qt Project Bug Tracker}, + go to \uicontrol Help > \uicontrol {Report Bug}. + + To copy information about your \QC version that you can paste to the bug + report, go to \uicontrol Help > \uicontrol {About \QC} and select + \uicontrol {Copy and Close}. + + To copy detailed information about your system that you can paste to the bug + report, go to \uicontrol Help > \uicontrol {System Information} and select + \uicontrol {Copy to Clipboard}. + + To get commercial Qt support, go to \uicontrol Help > + \uicontrol {Commercial Qt Support} and create a service request. + To check your licenses and services, go to \uicontrol Help > + \uicontrol {Qt Account}. + + \section1 Give feedback + + To rate \QC and send us feedback, go to \uicontrol Help > + \uicontrol {Give Feedback}. + + Or, give feedback from your Qt account. + + \section1 Join discussions + + To join the \l{https://lists.qt-project.org/listinfo/qt-creator} + {\QC mailing list} or \l{https://web.libera.chat/#qt-creator} + {#qt-creator} channel on Libera.Chat IRC, go to \uicontrol Help > + \uicontrol Contact. + + \sa {Pasting and Fetching Code Snippets}, {Technical Support} +*/ diff --git a/doc/qtcreator/src/qtcreator.qdoc b/doc/qtcreator/src/qtcreator.qdoc index 840ef3805bc..7c2d8ce775e 100644 --- a/doc/qtcreator/src/qtcreator.qdoc +++ b/doc/qtcreator/src/qtcreator.qdoc @@ -86,6 +86,7 @@ \endlist \li \b {\l{Reference}} \list + \li \l {Acknowledgements} \li \l {Build Systems} \li \l {Command-Line Options} \li \l {Custom Wizards} @@ -94,21 +95,5 @@ \li \l {Supported Platforms} \li \l {Reference}{See More...} \endlist - \row - \li {4,1} \b {Contact Us} - \list - \li To report bugs and suggestions to the - \l{https://bugreports.qt.io/}{Qt Project Bug Tracker}, - select \uicontrol Help > \uicontrol {Report Bug}. - \li To copy and paste detailed information about your - system to the bug report, select \uicontrol Help > - \uicontrol {System Information}. - \li To join the \l{https://lists.qt-project.org/listinfo/qt-creator} - {\QC mailing list} or \l{https://web.libera.chat/#qt-creator} - {#qt-creator} channel on Libera.Chat IRC, select - \uicontrol Help > \uicontrol Contact. - \li For credits and a list of third-party libraries, see - \l {Acknowledgements}. - \endlist \endtable */ From 52f970930033b1fad155b30c5b945e52f4f1258f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 12 Feb 2024 09:37:45 +0100 Subject: [PATCH 76/82] QtKeychain: Build lib with qbs Change-Id: Ief16859fd26b130aef474c6caae64f2faacbe7f3 Reviewed-by: Christian Kandeler --- src/libs/3rdparty/qtkeychain/qtkeychain.qbs | 86 +++++++++++++++++++++ src/libs/libs.qbs | 1 + 2 files changed, 87 insertions(+) create mode 100644 src/libs/3rdparty/qtkeychain/qtkeychain.qbs diff --git a/src/libs/3rdparty/qtkeychain/qtkeychain.qbs b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs new file mode 100644 index 00000000000..4a532363f0b --- /dev/null +++ b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs @@ -0,0 +1,86 @@ +QtcLibrary { + name: "qtkeychain" + + property bool useWinCredentialsStore: qbs.targetOS.contains("windows") + + Depends { name: "cpp" } + Depends { name: "Qt.core" } + Depends { name: "Qt.dbus"; condition: qbs.targetOS.contains("linux") } + Depends { name: "libsecret-1"; required: false } + + cpp.defines: base.concat(["QTKEYCHAIN_LIBRARY"]) + + Properties { + condition: useWinCredentialsStore + cpp.defines: outer.concat(["USE_CREDENTIAL_STORE=1"]) + cpp.dynamicLibraries: ["advapi32"] + } + + Properties { + condition: qbs.targetOS.contains("windows") && !useWinCredentialsStore + cpp.dynamicLibraries: ["crypt32"] + } + + Properties { + condition: qbs.targetOS.contains("macos") + cpp.frameworks: [ "Foundation", "Security" ] + } + + files: [ + "keychain.cpp", + "keychain.h", + "keychain_p.h", + "qkeychain_export.h", + ] + + Group { + name: "qtkeychain Windows files" + condition: qbs.targetOS.contains("windows") + files: [ + "keychain_win.cpp", + "plaintextstore_p.h", + ] + + Group { + name: "qtkeychain Windows no credentials store" + condition: !product.useWinCredentialsStore + files: [ "plaintextstore.cpp" ] + } + } + + Group { + name: "qtkeychain macOS files" + condition: qbs.targetOS.contains("macos") + files: [ "keychain_apple.mm" ] + } + + Group { + name: "qtkeychain Linux files" + condition: qbs.targetOS.contains("linux") + + Group { + name: "qtkeychain libsecret support" + condition: "libsecret-1".present + cpp.defines: outer.concat(["HAVE_LIBSECRET=1"]) + } + Group { + name: "dbus sources" + fileTags: "qt.dbus.interface" + files: ["org.kde.KWallet.xml"] + } + + Group { + name: "qtkeychain dbus support" + cpp.defines: outer.concat(["KEYCHAIN_DBUS=1"]) + files: [ + "gnomekeyring.cpp", + "gnomekeyring_p.h", + "keychain_unix.cpp", + "libsecret.cpp", + "libsecret_p.h", + "plaintextstore.cpp", + "plaintextstore_p.h", + ] + } + } +} diff --git a/src/libs/libs.qbs b/src/libs/libs.qbs index ffc3017cba0..a6426d4ae47 100644 --- a/src/libs/libs.qbs +++ b/src/libs/libs.qbs @@ -26,6 +26,7 @@ Project { "utils/utils.qbs", "3rdparty/libptyqt/ptyqt.qbs", "3rdparty/libvterm/vterm.qbs", + "3rdparty/qtkeychain/qtkeychain.qbs", "3rdparty/syntax-highlighting/syntax-highlighting.qbs", "3rdparty/winpty/winpty.qbs", "3rdparty/yaml-cpp/yaml-cpp.qbs", From 0d1831b4629a1ff062be22d66515a00857c75b82 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 14 Feb 2024 11:49:30 +0100 Subject: [PATCH 77/82] Mercurial: Remove unused lambda captures Change-Id: I5b308dc57b10624d140ed506a17ed41b3ec49491 Reviewed-by: Orgad Shaneh --- src/plugins/mercurial/mercurialplugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 8e4d90f045c..76c8f2ba8c8 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -148,7 +148,7 @@ public: Constants::FILELOG_ID, VcsBase::Tr::tr("Mercurial File Log Editor"), Constants::LOGAPP, - [this] { return new MercurialEditorWidget; }, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) }}; @@ -157,7 +157,7 @@ public: Constants::ANNOTATELOG_ID, VcsBase::Tr::tr("Mercurial Annotation Editor"), Constants::ANNOTATEAPP, - [this] { return new MercurialEditorWidget; }, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) }}; @@ -166,7 +166,7 @@ public: Constants::DIFFLOG_ID, VcsBase::Tr::tr("Mercurial Diff Editor"), Constants::DIFFAPP, - [this] { return new MercurialEditorWidget; }, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) }}; }; From 090fd0e5f5de4ccdf59eb3e520112f69bfd2ea0c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 17:15:28 +0100 Subject: [PATCH 78/82] Utils: Merge NamesValueModel and EnvironmentModel (1/2) The abstraction is nowhere used (anymore?) In order to keep the diff small, this here merges environmentmodel.{h,cpp} into namevaluemodel.{h,cpp} which will be renamed back to env* in a second step. Change-Id: I1e7c14012ec3d3f54d8557f4b737a59ede2283e7 Reviewed-by: Christian Kandeler --- src/libs/utils/CMakeLists.txt | 1 - src/libs/utils/environmentfwd.h | 3 - src/libs/utils/environmentmodel.cpp | 20 ------- src/libs/utils/environmentmodel.h | 19 ------- src/libs/utils/namevaluemodel.cpp | 56 ++++++++++--------- src/libs/utils/namevaluemodel.h | 17 +++--- src/libs/utils/namevaluevalidator.cpp | 2 +- src/libs/utils/namevaluevalidator.h | 6 +- src/libs/utils/utils.qbs | 2 - .../projectexplorer/environmentwidget.cpp | 2 +- 10 files changed, 42 insertions(+), 86 deletions(-) delete mode 100644 src/libs/utils/environmentmodel.cpp delete mode 100644 src/libs/utils/environmentmodel.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 9f11f3fc83c..dc3322456e5 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -44,7 +44,6 @@ add_qtc_library(Utils environment.cpp environment.h environmentdialog.cpp environmentdialog.h environmentfwd.h - environmentmodel.cpp environmentmodel.h execmenu.cpp execmenu.h expected.h externalterminalprocessimpl.cpp externalterminalprocessimpl.h diff --git a/src/libs/utils/environmentfwd.h b/src/libs/utils/environmentfwd.h index 8a2c444cc42..deb78279b5c 100644 --- a/src/libs/utils/environmentfwd.h +++ b/src/libs/utils/environmentfwd.h @@ -19,7 +19,4 @@ class PreprocessorMacroDictionary; using PreprocessorMacroItem = NameValueItem; using PreprocessorMacroItems = NameValueItems; -class NameValueModel; -class EnvironmentModel; - } // namespace Utils diff --git a/src/libs/utils/environmentmodel.cpp b/src/libs/utils/environmentmodel.cpp deleted file mode 100644 index 13329597846..00000000000 --- a/src/libs/utils/environmentmodel.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "environmentmodel.h" - -#include "environment.h" - -namespace Utils { - -Environment EnvironmentModel::baseEnvironment() const -{ - return Environment(baseNameValueDictionary()); -} - -void EnvironmentModel::setBaseEnvironment(const Environment &env) -{ - setBaseNameValueDictionary(env.toDictionary()); -} - -} // namespace Utils diff --git a/src/libs/utils/environmentmodel.h b/src/libs/utils/environmentmodel.h deleted file mode 100644 index 82bf98d43f5..00000000000 --- a/src/libs/utils/environmentmodel.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "utils_global.h" - -#include "namevaluemodel.h" - -namespace Utils { - -class QTCREATOR_UTILS_EXPORT EnvironmentModel : public NameValueModel -{ -public: - Environment baseEnvironment() const; - void setBaseEnvironment(const Environment &env); -}; - -} // namespace Utils diff --git a/src/libs/utils/namevaluemodel.cpp b/src/libs/utils/namevaluemodel.cpp index 57327c4ebed..400824763f8 100644 --- a/src/libs/utils/namevaluemodel.cpp +++ b/src/libs/utils/namevaluemodel.cpp @@ -4,6 +4,7 @@ #include "namevaluemodel.h" #include "algorithm.h" +#include "environment.h" #include "hostosinfo.h" #include "namevaluedictionary.h" #include "namevalueitem.h" @@ -20,7 +21,7 @@ namespace Utils { namespace Internal { -class NameValueModelPrivate +class EnvironmentModelPrivate { public: void updateResultNameValueDictionary() @@ -78,21 +79,22 @@ public: } // namespace Internal -NameValueModel::NameValueModel(QObject *parent) +EnvironmentModel::EnvironmentModel(QObject *parent) : QAbstractTableModel(parent) - , d(std::make_unique()) + , d(std::make_unique()) {} -NameValueModel::~NameValueModel() = default; +EnvironmentModel::~EnvironmentModel() = default; -QString NameValueModel::indexToVariable(const QModelIndex &index) const +QString EnvironmentModel::indexToVariable(const QModelIndex &index) const { const auto it = std::next(d->m_resultNameValueDictionary.constBegin(), index.row()); return d->m_resultNameValueDictionary.key(it); } -void NameValueModel::setBaseNameValueDictionary(const NameValueDictionary &dictionary) +void EnvironmentModel::setBaseEnvironment(const Environment &env) { + const NameValueDictionary dictionary = env.toDictionary(); if (d->m_baseNameValueDictionary == dictionary) return; beginResetModel(); @@ -101,14 +103,14 @@ void NameValueModel::setBaseNameValueDictionary(const NameValueDictionary &dicti endResetModel(); } -int NameValueModel::rowCount(const QModelIndex &parent) const +int EnvironmentModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return d->m_resultNameValueDictionary.size(); } -int NameValueModel::columnCount(const QModelIndex &parent) const +int EnvironmentModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; @@ -116,17 +118,17 @@ int NameValueModel::columnCount(const QModelIndex &parent) const return 2; } -bool NameValueModel::changes(const QString &name) const +bool EnvironmentModel::changes(const QString &name) const { return d->findInChanges(name) >= 0; } -const NameValueDictionary &NameValueModel::baseNameValueDictionary() const +Environment EnvironmentModel::baseEnvironment() const { - return d->m_baseNameValueDictionary; + return Environment(d->m_baseNameValueDictionary); } -QVariant NameValueModel::data(const QModelIndex &index, int role) const +QVariant EnvironmentModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); @@ -176,13 +178,13 @@ QVariant NameValueModel::data(const QModelIndex &index, int role) const return QVariant(); } -Qt::ItemFlags NameValueModel::flags(const QModelIndex &index) const +Qt::ItemFlags EnvironmentModel::flags(const QModelIndex &index) const { Q_UNUSED(index) return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } -QVariant NameValueModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant EnvironmentModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical || role != Qt::DisplayRole) return QVariant(); @@ -192,7 +194,7 @@ QVariant NameValueModel::headerData(int section, Qt::Orientation orientation, in /// ***************** /// Utility functions /// ***************** -QModelIndex NameValueModel::variableToIndex(const QString &name) const +QModelIndex EnvironmentModel::variableToIndex(const QString &name) const { int row = d->findInResult(name); if (row == -1) @@ -200,7 +202,7 @@ QModelIndex NameValueModel::variableToIndex(const QString &name) const return index(row, 0); } -bool NameValueModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || role != Qt::EditRole) return false; @@ -262,12 +264,12 @@ bool NameValueModel::setData(const QModelIndex &index, const QVariant &value, in return false; } -QModelIndex NameValueModel::addVariable() +QModelIndex EnvironmentModel::addVariable() { return addVariable(NameValueItem("NEWVAR", "VALUE")); } -QModelIndex NameValueModel::addVariable(const NameValueItem &item) +QModelIndex EnvironmentModel::addVariable(const NameValueItem &item) { // Return existing index if the name is already in the result set: int pos = d->findInResult(item.name); @@ -298,7 +300,7 @@ QModelIndex NameValueModel::addVariable(const NameValueItem &item) return index(insertPos, 0, QModelIndex()); } -void NameValueModel::resetVariable(const QString &name) +void EnvironmentModel::resetVariable(const QString &name) { int rowInChanges = d->findInChanges(name); if (rowInChanges < 0) @@ -323,7 +325,7 @@ void NameValueModel::resetVariable(const QString &name) } } -void NameValueModel::unsetVariable(const QString &name) +void EnvironmentModel::unsetVariable(const QString &name) { // This does not change the number of rows as we will display a // in place of the original variable! @@ -347,7 +349,7 @@ void NameValueModel::unsetVariable(const QString &name) emit userChangesChanged(); } -void NameValueModel::toggleVariable(const QModelIndex &idx) +void EnvironmentModel::toggleVariable(const QModelIndex &idx) { const QString name = indexToVariable(idx); const auto newIt = d->m_resultNameValueDictionary.constFind(name); @@ -371,28 +373,28 @@ void NameValueModel::toggleVariable(const QModelIndex &idx) emit userChangesChanged(); } -bool NameValueModel::isUnset(const QString &name) +bool EnvironmentModel::isUnset(const QString &name) { const int pos = d->findInChanges(name); return pos == -1 ? false : d->m_items.at(pos).operation == NameValueItem::Unset; } -bool NameValueModel::isEnabled(const QString &name) const +bool EnvironmentModel::isEnabled(const QString &name) const { return d->m_resultNameValueDictionary.isEnabled(d->m_resultNameValueDictionary.constFind(name)); } -bool NameValueModel::canReset(const QString &name) +bool EnvironmentModel::canReset(const QString &name) { return d->m_baseNameValueDictionary.hasKey(name); } -NameValueItems NameValueModel::userChanges() const +NameValueItems EnvironmentModel::userChanges() const { return d->m_items; } -void NameValueModel::setUserChanges(const NameValueItems &items) +void EnvironmentModel::setUserChanges(const NameValueItems &items) { NameValueItems filtered = Utils::filtered(items, [](const NameValueItem &i) { return i.name != "export " && !i.name.contains('='); @@ -421,7 +423,7 @@ void NameValueModel::setUserChanges(const NameValueItems &items) emit userChangesChanged(); } -bool NameValueModel::currentEntryIsPathList(const QModelIndex ¤t) const +bool EnvironmentModel::currentEntryIsPathList(const QModelIndex ¤t) const { if (!current.isValid()) return false; diff --git a/src/libs/utils/namevaluemodel.h b/src/libs/utils/namevaluemodel.h index 84c1f2cece9..55f53ed59e6 100644 --- a/src/libs/utils/namevaluemodel.h +++ b/src/libs/utils/namevaluemodel.h @@ -13,17 +13,15 @@ namespace Utils { -namespace Internal { -class NameValueModelPrivate; -} +namespace Internal { class EnvironmentModelPrivate; } -class QTCREATOR_UTILS_EXPORT NameValueModel : public QAbstractTableModel +class QTCREATOR_UTILS_EXPORT EnvironmentModel : public QAbstractTableModel { Q_OBJECT public: - explicit NameValueModel(QObject *parent = nullptr); - ~NameValueModel() override; + explicit EnvironmentModel(QObject *parent = nullptr); + ~EnvironmentModel() override; int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; @@ -34,6 +32,9 @@ public: Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Environment baseEnvironment() const; + void setBaseEnvironment(const Environment &env); + QModelIndex addVariable(); QModelIndex addVariable(const NameValueItem &item); void resetVariable(const QString &name); @@ -45,8 +46,6 @@ public: QString indexToVariable(const QModelIndex &index) const; QModelIndex variableToIndex(const QString &name) const; bool changes(const QString &key) const; - const NameValueDictionary &baseNameValueDictionary() const; - void setBaseNameValueDictionary(const NameValueDictionary &dictionary); NameValueItems userChanges() const; void setUserChanges(const NameValueItems &items); bool currentEntryIsPathList(const QModelIndex ¤t) const; @@ -59,7 +58,7 @@ signals: void focusIndex(const QModelIndex &index); private: - std::unique_ptr d; + std::unique_ptr d; }; } // namespace Utils diff --git a/src/libs/utils/namevaluevalidator.cpp b/src/libs/utils/namevaluevalidator.cpp index ef2ccbc9a08..e64c1528939 100644 --- a/src/libs/utils/namevaluevalidator.cpp +++ b/src/libs/utils/namevaluevalidator.cpp @@ -10,7 +10,7 @@ namespace Utils { NameValueValidator::NameValueValidator(QWidget *parent, - NameValueModel *model, + EnvironmentModel *model, QTreeView *view, const QModelIndex &index, const QString &toolTipText) diff --git a/src/libs/utils/namevaluevalidator.h b/src/libs/utils/namevaluevalidator.h index bf0f1b27f74..e06560f1896 100644 --- a/src/libs/utils/namevaluevalidator.h +++ b/src/libs/utils/namevaluevalidator.h @@ -16,13 +16,13 @@ QT_END_NAMESPACE namespace Utils { -class NameValueModel; +class EnvironmentModel; class QTCREATOR_UTILS_EXPORT NameValueValidator : public QValidator { public: NameValueValidator(QWidget *parent, - NameValueModel *model, + EnvironmentModel *model, QTreeView *view, const QModelIndex &index, const QString &toolTipText); @@ -33,7 +33,7 @@ public: private: const QString m_toolTipText; - NameValueModel *m_model; + EnvironmentModel *m_model; QTreeView *m_view; QPersistentModelIndex m_index; mutable QTimer m_hideTipTimer; diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d7ccd1d6761..d062400ee1c 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -101,8 +101,6 @@ QtcLibrary { "environment.h", "environmentdialog.cpp", "environmentdialog.h", - "environmentmodel.cpp", - "environmentmodel.h", "execmenu.cpp", "execmenu.h", "externalterminalprocessimpl.cpp", diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 9a63d789ece..4331dbb06f1 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include From 83eaeda954bb7194f2a8673b1174552322966737 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 17:23:04 +0100 Subject: [PATCH 79/82] Utils: Merge NamesValueModel and EnvironmentModel (2/2) Rename namevaluemodel.{h,cpp} back to environmentmodel.{h,cpp} Change-Id: Idfa528b0c1c307ef4cd9dd5869f18993647b98bc Reviewed-by: Christian Kandeler --- src/libs/utils/CMakeLists.txt | 6 +----- src/libs/utils/{namevaluemodel.cpp => environmentmodel.cpp} | 2 +- src/libs/utils/{namevaluemodel.h => environmentmodel.h} | 0 src/libs/utils/namevaluevalidator.cpp | 3 ++- src/libs/utils/utils.qbs | 4 ++-- src/plugins/projectexplorer/environmentwidget.cpp | 2 +- 6 files changed, 7 insertions(+), 10 deletions(-) rename src/libs/utils/{namevaluemodel.cpp => environmentmodel.cpp} (99%) rename src/libs/utils/{namevaluemodel.h => environmentmodel.h} (100%) diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index dc3322456e5..eb2eaed9ddc 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -43,6 +43,7 @@ add_qtc_library(Utils elidinglabel.cpp elidinglabel.h environment.cpp environment.h environmentdialog.cpp environmentdialog.h + environmentmodel.cpp environmentmodel.h environmentfwd.h execmenu.cpp execmenu.h expected.h @@ -102,12 +103,7 @@ add_qtc_library(Utils namevaluedictionary.cpp namevaluedictionary.h namevaluedictionary.cpp namevaluedictionary.h namevalueitem.cpp namevalueitem.h - namevalueitem.cpp namevalueitem.h - namevaluemodel.cpp namevaluemodel.h - namevaluemodel.cpp namevaluemodel.h namevaluesdialog.cpp namevaluesdialog.h - namevaluesdialog.cpp namevaluesdialog.h - namevaluevalidator.cpp namevaluevalidator.h namevaluevalidator.cpp namevaluevalidator.h navigationtreeview.cpp navigationtreeview.h networkaccessmanager.cpp networkaccessmanager.h diff --git a/src/libs/utils/namevaluemodel.cpp b/src/libs/utils/environmentmodel.cpp similarity index 99% rename from src/libs/utils/namevaluemodel.cpp rename to src/libs/utils/environmentmodel.cpp index 400824763f8..c21470808d7 100644 --- a/src/libs/utils/namevaluemodel.cpp +++ b/src/libs/utils/environmentmodel.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "namevaluemodel.h" +#include "environmentmodel.h" #include "algorithm.h" #include "environment.h" diff --git a/src/libs/utils/namevaluemodel.h b/src/libs/utils/environmentmodel.h similarity index 100% rename from src/libs/utils/namevaluemodel.h rename to src/libs/utils/environmentmodel.h diff --git a/src/libs/utils/namevaluevalidator.cpp b/src/libs/utils/namevaluevalidator.cpp index e64c1528939..620adc137c3 100644 --- a/src/libs/utils/namevaluevalidator.cpp +++ b/src/libs/utils/namevaluevalidator.cpp @@ -2,7 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "namevaluevalidator.h" -#include "namevaluemodel.h" + +#include "environmentmodel.h" #include "tooltip/tooltip.h" #include diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d062400ee1c..7bf55d8f247 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -101,6 +101,8 @@ QtcLibrary { "environment.h", "environmentdialog.cpp", "environmentdialog.h", + "environmentmodel.cpp", + "environmentmodel.h", "execmenu.cpp", "execmenu.h", "externalterminalprocessimpl.cpp", @@ -196,8 +198,6 @@ QtcLibrary { "namevaluedictionary.h", "namevalueitem.cpp", "namevalueitem.h", - "namevaluemodel.cpp", - "namevaluemodel.h", "namevaluesdialog.cpp", "namevaluesdialog.h", "namevaluevalidator.cpp", diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 4331dbb06f1..9a63d789ece 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include From 5639c141ff153fa8d06ef0adf61d6a309790ff65 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 13 Feb 2024 18:04:27 +0100 Subject: [PATCH 80/82] Doc: Describe Qt Translation File wizard Task-number: QTCREATORBUG-30209 Change-Id: I9a5d04d59e836cb08dd3eafd9d4ea22106aea4a0 Reviewed-by: Christian Stenger Reviewed-by: --- .../images/qtcreator-new-file-ts.webp | Bin 0 -> 4784 bytes .../src/howto/creator-external-tools.qdoc | 35 +++++++++++++----- .../howto/creator-only/creator-how-tos.qdoc | 2 +- .../creator-only/creator-files-creating.qdoc | 8 ++-- .../creator-how-to-create-ts-files.qdoc | 30 +++++++++++++++ doc/qtcreator/src/qtcreator-toc.qdoc | 2 +- 6 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-new-file-ts.webp create mode 100644 doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc diff --git a/doc/qtcreator/images/qtcreator-new-file-ts.webp b/doc/qtcreator/images/qtcreator-new-file-ts.webp new file mode 100644 index 0000000000000000000000000000000000000000..3ad21a25d919e7042c399fc4f445d33bc4ade3a4 GIT binary patch literal 4784 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 S+}M@7`PQpF|0nR9F#rGz0Zb(T literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/howto/creator-external-tools.qdoc b/doc/qtcreator/src/howto/creator-external-tools.qdoc index 3f29dfc57bf..dda7eeb62ae 100644 --- a/doc/qtcreator/src/howto/creator-external-tools.qdoc +++ b/doc/qtcreator/src/howto/creator-external-tools.qdoc @@ -134,18 +134,30 @@ \title Use Qt Linguist + Most of the text to translate in an application consists of either single + words or short phrases. These typically appear as window titles, menu items, + tooltips, and labels to buttons, checkboxes, and radio buttons. + + You mark the phrases as translatable in the QML and C++ source code. Qt + localization tools provide context information for each of the phrases to + help the translator understand their meaning. You can add comments to the + phrases. + + Translation files contain all the user-visible text and keyboard shortcuts + in an application and translations of that text. + When you \l{Creating Projects}{create a new project}, you can automatically - generate a translation source file (TS) for one language. You can add other - languages later by editing the project file. + generate a translation source file (TS) for one language. To add other + languages, edit the project file or go to \uicontrol File > + \uicontrol {New File}. To open TS files in Qt Linguist, right-click a TS file in the - \uicontrol Projects or \uicontrol {File System} view and select + \uicontrol Projects or \uicontrol {File System} view and go to \uicontrol {Open With} > \uicontrol {Qt Linguist} in the context menu. - For more information about Qt Linguist, see \l{Qt Linguist Manual}. \section1 Use lupdate and lrelease - You can use the Qt Linguist release manager tools, lupdate and lrelease, + Use the Qt Linguist release manager tools, lupdate and lrelease, directly from \QC. The lupdate tool synchronizes source code and translations. The lrelease tool creates run-time translation files for use by the released application. @@ -156,22 +168,27 @@ {Qt6::LinguistTools}. By default, the project .pro file is passed to the tools as an argument. To - specify other command-line arguments for the tools, select \uicontrol Tools > + specify other command-line arguments for the tools, go to \uicontrol Tools > \uicontrol External > \uicontrol Configure. \section2 Synchronize TS files To synchronize TS files from a translator with the - application code, select \uicontrol Tools > \uicontrol External > + application code, go to \uicontrol Tools > \uicontrol External > \uicontrol Linguist > \uicontrol {Update Translations (lupdate)}. \section2 Generate QM files To generate from the TS files Qt message (QM) files that can be used by an - application, select \uicontrol Tools > \uicontrol External > + application, go to \uicontrol Tools > \uicontrol External > \uicontrol Linguist > \uicontrol {Release Translations (lrelease)}. - \sa {Use external tools} + \if defined(qtcreator) + \sa {Add translation files} + \endif + + \sa {Use external tools}, {Internationalization with Qt}, + {Qt Linguist Manual} */ /*! diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc index 6c3fc7fd84e..0643c3a1525 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -77,7 +77,7 @@ \generatelist creator-how-to-projects-create - \section2 Create Files + \section2 Add Files \generatelist creator-how-to-projects-files diff --git a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc index 6b953d4401d..d03263d4625 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc @@ -43,8 +43,8 @@ \li \uicontrol {Qt} \li Source and header files for item, table, or list models, \QD forms and a matching classes for Qt Widgets - projects, Qt resource files, as well as QML and JavaScript files - for Qt Quick projects. + projects, Qt resource and translation files, as well as QML and + JavaScript files for Qt Quick projects. \row \li \uicontrol {Compiler Explorer} \li Example setup for using Compiler Explorer to compile C++ or Python @@ -74,9 +74,7 @@ \li Empty Nim source and script files. \endtable - \sa {Create compiler explorer sessions}, {Create C++ classes}, - {Create OpenGL fragment and vertex shaders}, {Create resource files}, - {Create UML-style models}, {Create vcpkg manifest files}, + \sa {Add Files}{How To: Add Files}, {Create UML-style models}, {Use project wizards} */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc new file mode 100644 index 00000000000..cb4471aeb5d --- /dev/null +++ b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc @@ -0,0 +1,30 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page creator-how-to-add-ts-files.html + \previouspage creator-how-tos.html + + \ingroup creator-how-to-projects-files + + \title Add translation files + + When you \l{Creating Projects}{create a new project}, you can automatically + generate a translation source file (TS) for one language. To add other + languages later, use a file wizard. + + To create a translation source (TS) file for a language: + + \list 1 + \li Go to \uicontrol File > \uicontrol {New File}. + \li Select \uicontrol Qt > \uicontrol {Qt Translation File} > + \uicontrol Choose. + \li In \uicontrol Language, select a language and territory (\e locale). + \image qtcreator-new-file-ts.webp {Select language for a TS file} + \endlist + + You can see the file name in \uicontrol {Translation file}. + + \sa {Create files}, {Use project wizards}, {Use Qt Linguist}, + {Internationalization with Qt}, {Qt Linguist Manual} +*/ diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 5f2daf2737f..ec8408795fc 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -157,7 +157,7 @@ \list \li Create Projects \generatelist creator-how-to-projects-create - \li Create Files + \li Add Files \generatelist creator-how-to-projects-files \li Configure Projects \generatelist creator-how-to-projects-configure From 91c1c244a1256b2dc9979edb1a3ce83c28ef5636 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Apr 2021 14:50:51 +0200 Subject: [PATCH 81/82] ModelManagerInterface: Cancel all running threads on session switch On session switch we cancel all the running tasks. We connect to the SessionManager::aboutToLoadSession() signal, as this one is emitted just before loading new session's projects. We don't connect to SessionManager::aboutToUnloadSession(), since after this signal is emitted the unloading may be canceled due to e.g. showing the dialog asking for saving changed files in the unloaded session (the user may cancel the process of unloading). In contrast to what we do on shutdown, we don't wait for futures being finished here - it's just enough we cancel all of them. Fixes: QTCREATORBUG-25583 Change-Id: I01eeca00d150f6e98a80a050c6a19efb848b9954 Reviewed-by: hjk --- src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 10 ++++++++++ src/libs/qmljs/qmljsmodelmanagerinterface.h | 2 +- src/plugins/qmljstools/qmljsmodelmanager.cpp | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index aac0de9ab1e..a525c6c3054 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -317,6 +317,16 @@ void ModelManagerInterface::setDefaultProject(const ModelManagerInterface::Proje }); } +void ModelManagerInterface::cancelAllThreads() +{ + m_cppQmlTypesUpdater.cancel(); + // Don't execute the scheduled updates for the old session anymore + m_updateCppQmlTypesTimer->stop(); + m_asyncResetTimer->stop(); + QMutexLocker locker(&m_futuresMutex); + m_futureSynchronizer.cancelAllFutures(); +} + Snapshot ModelManagerInterface::snapshot() const { return m_syncedData.readLocked()->m_validSnapshot; diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index c57cba7e46e..ae3d8e0e6c4 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -238,7 +238,7 @@ protected: void updateImportPaths(); void loadQmlTypeDescriptionsInternal(const QString &path); void setDefaultProject(const ProjectInfo &pInfo, ProjectExplorer::Project *p); - + void cancelAllThreads(); private: void joinAllThreads(bool cancelOnWait = false); void iterateQrcFiles(ProjectExplorer::Project *project, diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index c8265d73544..36d0e657cf5 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -281,6 +282,8 @@ void ModelManager::delayedInitialization() this, &ModelManager::removeProjectInfo); connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &ModelManager::updateDefaultProjectInfo); + connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, + this, &ModelManager::cancelAllThreads); ViewerContext qbsVContext; qbsVContext.language = Dialect::QmlQbs; From 0a1783d656964df60f1ec462f81c56ea38100dc5 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 18:01:32 +0100 Subject: [PATCH 82/82] Utils: Rename NameValueItem to EnvironmentItem (1/2) Only used in Environments nowadays. Change-Id: I64a645ebebd5cb57c50d5d8f72a5e4dba40e122f Reviewed-by: Christian Kandeler --- src/libs/utils/environment.cpp | 6 +- src/libs/utils/environment.h | 6 +- src/libs/utils/environmentfwd.h | 12 +--- src/libs/utils/environmentmodel.cpp | 38 ++++++------ src/libs/utils/environmentmodel.h | 6 +- src/libs/utils/namevaluedictionary.cpp | 22 +++---- src/libs/utils/namevaluedictionary.h | 4 +- src/libs/utils/namevalueitem.cpp | 60 +++++++++---------- src/libs/utils/namevalueitem.h | 26 ++++---- src/libs/utils/namevaluesdialog.cpp | 6 +- src/libs/utils/namevaluesdialog.h | 10 ++-- src/plugins/debugger/gdb/gdbengine.cpp | 2 +- src/plugins/mcusupport/mcukitaspect.cpp | 12 ++-- src/plugins/mcusupport/mcukitaspect.h | 4 +- src/plugins/mcusupport/mcukitmanager.cpp | 2 +- .../projectexplorer/environmentwidget.cpp | 8 +-- .../projectexplorer/environmentwidget.h | 2 +- src/plugins/projectexplorer/project.cpp | 4 +- .../cmakegen/generatecmakelists.cpp | 2 +- tests/auto/environment/tst_environment.cpp | 26 ++++---- 20 files changed, 126 insertions(+), 132 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index b1143c7fab4..be43f2a2062 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -50,7 +50,7 @@ Environment::Environment(const NameValueDictionary &dict) m_changeItems.append(dict); } -NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepend) const +EnvironmentItems Environment::diff(const Environment &other, bool checkAppendPrepend) const { const NameValueDictionary &dict = resolved(); const NameValueDictionary &otherDict = other.resolved(); @@ -393,7 +393,7 @@ void Environment::unset(const QString &key) addItem(Item{std::in_place_index_t(), key}); } -void Environment::modify(const NameValueItems &items) +void Environment::modify(const EnvironmentItems &items) { addItem(Item{std::in_place_index_t(), items}); } @@ -485,7 +485,7 @@ const NameValueDictionary &Environment::resolved() const break; } case Modify: { - NameValueItems items = std::get(item); + EnvironmentItems items = std::get(item); m_dict.modify(items); break; } diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 542343aa2a9..1b6b7d2c0e0 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -37,7 +37,7 @@ public: void set(const QString &key, const QString &value, bool enabled = true); void setFallback(const QString &key, const QString &value); void unset(const QString &key); - void modify(const NameValueItems &items); + void modify(const EnvironmentItems &items); bool hasChanges() const; @@ -79,7 +79,7 @@ public: QStringList expandVariables(const QStringList &input) const; NameValueDictionary toDictionary() const; // FIXME: avoid - NameValueItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid + EnvironmentItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid struct Entry { QString key; QString value; bool enabled; }; using FindResult = std::optional; @@ -117,7 +117,7 @@ public: QString, // UnsetValue (key) std::tuple, // PrependOrSet (key, value, separator) std::tuple, // AppendOrSet (key, value, separator) - NameValueItems, // Modify + EnvironmentItems, // Modify std::monostate, // SetupEnglishOutput FilePath // SetupSudoAskPass (file path of qtc-askpass or ssh-askpass) >; diff --git a/src/libs/utils/environmentfwd.h b/src/libs/utils/environmentfwd.h index deb78279b5c..376d1ea08c5 100644 --- a/src/libs/utils/environmentfwd.h +++ b/src/libs/utils/environmentfwd.h @@ -7,16 +7,10 @@ namespace Utils { -class NameValueDictionary; -class NameValueItem; -using NameValueItems = QList; - class Environment; -using EnvironmentItem = NameValueItem; -using EnvironmentItems = NameValueItems; +class EnvironmentItem; +using EnvironmentItems = QList; -class PreprocessorMacroDictionary; -using PreprocessorMacroItem = NameValueItem; -using PreprocessorMacroItems = NameValueItems; +class NameValueDictionary; } // namespace Utils diff --git a/src/libs/utils/environmentmodel.cpp b/src/libs/utils/environmentmodel.cpp index c21470808d7..6ac9b356406 100644 --- a/src/libs/utils/environmentmodel.cpp +++ b/src/libs/utils/environmentmodel.cpp @@ -30,8 +30,8 @@ public: m_resultNameValueDictionary.modify(m_items); // Add removed variables again and mark them as "" so // that the user can actually see those removals: - for (const NameValueItem &item : std::as_const(m_items)) { - if (item.operation == NameValueItem::Unset) + for (const EnvironmentItem &item : std::as_const(m_items)) { + if (item.operation == EnvironmentItem::Unset) m_resultNameValueDictionary.set(item.name, Tr::tr("")); } } @@ -74,7 +74,7 @@ public: NameValueDictionary m_baseNameValueDictionary; NameValueDictionary m_resultNameValueDictionary; - NameValueItems m_items; + EnvironmentItems m_items; }; } // namespace Internal @@ -145,7 +145,7 @@ QVariant EnvironmentModel::data(const QModelIndex &index, int role) const // Do not return "" when editing a previously unset variable: if (role == Qt::EditRole) { int pos = d->findInChanges(indexToVariable(index)); - if (pos != -1 && d->m_items.at(pos).operation == NameValueItem::Unset) + if (pos != -1 && d->m_items.at(pos).operation == EnvironmentItem::Unset) return QString(); } QString value = d->m_resultNameValueDictionary.value(resultIterator); @@ -225,7 +225,7 @@ bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, if (d->m_resultNameValueDictionary.hasKey(newName) || newName.isEmpty()) return false; - NameValueItem newVariable(newName, oldValue); + EnvironmentItem newVariable(newName, oldValue); if (changesPos != -1) resetVariable(oldName); // restore the original base variable again @@ -249,12 +249,12 @@ bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, } else { // ... and changed it again d->m_items[changesPos].value = stringValue; - if (d->m_items[changesPos].operation == NameValueItem::Unset) - d->m_items[changesPos].operation = NameValueItem::SetEnabled; + if (d->m_items[changesPos].operation == EnvironmentItem::Unset) + d->m_items[changesPos].operation = EnvironmentItem::SetEnabled; } } else { // Add a new change item: - d->m_items.append(NameValueItem(oldName, stringValue)); + d->m_items.append(EnvironmentItem(oldName, stringValue)); } d->updateResultNameValueDictionary(); emit dataChanged(index, index); @@ -266,10 +266,10 @@ bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, QModelIndex EnvironmentModel::addVariable() { - return addVariable(NameValueItem("NEWVAR", "VALUE")); + return addVariable(EnvironmentItem("NEWVAR", "VALUE")); } -QModelIndex EnvironmentModel::addVariable(const NameValueItem &item) +QModelIndex EnvironmentModel::addVariable(const EnvironmentItem &item) { // Return existing index if the name is already in the result set: int pos = d->findInResult(item.name); @@ -283,7 +283,7 @@ QModelIndex EnvironmentModel::addVariable(const NameValueItem &item) Q_ASSERT(changePos >= 0); // Do not insert a line here as we listed the variable as before! Q_ASSERT(d->m_items.at(changePos).name == item.name); - Q_ASSERT(d->m_items.at(changePos).operation == NameValueItem::Unset); + Q_ASSERT(d->m_items.at(changePos).operation == EnvironmentItem::Unset); Q_ASSERT(d->m_items.at(changePos).value.isEmpty()); d->m_items[changePos] = item; emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex())); @@ -336,14 +336,14 @@ void EnvironmentModel::unsetVariable(const QString &name) // look in d->m_items for the variable int pos = d->findInChanges(name); if (pos != -1) { - d->m_items[pos].operation = NameValueItem::Unset; + d->m_items[pos].operation = EnvironmentItem::Unset; d->m_items[pos].value.clear(); d->updateResultNameValueDictionary(); emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); emit userChangesChanged(); return; } - d->m_items.append(NameValueItem(name, QString(), NameValueItem::Unset)); + d->m_items.append(EnvironmentItem(name, QString(), EnvironmentItem::Unset)); d->updateResultNameValueDictionary(); emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); emit userChangesChanged(); @@ -355,7 +355,7 @@ void EnvironmentModel::toggleVariable(const QModelIndex &idx) const auto newIt = d->m_resultNameValueDictionary.constFind(name); QTC_ASSERT(newIt != d->m_resultNameValueDictionary.constEnd(), return); const auto op = d->m_resultNameValueDictionary.isEnabled(newIt) - ? NameValueItem::SetDisabled : NameValueItem::SetEnabled; + ? EnvironmentItem::SetDisabled : EnvironmentItem::SetEnabled; const int changesPos = d->findInChanges(name); if (changesPos != -1) { const auto oldIt = d->m_baseNameValueDictionary.constFind(name); @@ -376,7 +376,7 @@ void EnvironmentModel::toggleVariable(const QModelIndex &idx) bool EnvironmentModel::isUnset(const QString &name) { const int pos = d->findInChanges(name); - return pos == -1 ? false : d->m_items.at(pos).operation == NameValueItem::Unset; + return pos == -1 ? false : d->m_items.at(pos).operation == EnvironmentItem::Unset; } bool EnvironmentModel::isEnabled(const QString &name) const @@ -389,14 +389,14 @@ bool EnvironmentModel::canReset(const QString &name) return d->m_baseNameValueDictionary.hasKey(name); } -NameValueItems EnvironmentModel::userChanges() const +EnvironmentItems EnvironmentModel::userChanges() const { return d->m_items; } -void EnvironmentModel::setUserChanges(const NameValueItems &items) +void EnvironmentModel::setUserChanges(const EnvironmentItems &items) { - NameValueItems filtered = Utils::filtered(items, [](const NameValueItem &i) { + EnvironmentItems filtered = Utils::filtered(items, [](const EnvironmentItem &i) { return i.name != "export " && !i.name.contains('='); }); // We assume nobody is reordering the items here. @@ -404,7 +404,7 @@ void EnvironmentModel::setUserChanges(const NameValueItems &items) return; beginResetModel(); d->m_items = filtered; - for (NameValueItem &item : d->m_items) { + for (EnvironmentItem &item : d->m_items) { QString &name = item.name; name = name.trimmed(); if (name.startsWith("export ")) diff --git a/src/libs/utils/environmentmodel.h b/src/libs/utils/environmentmodel.h index 55f53ed59e6..07670bd13fc 100644 --- a/src/libs/utils/environmentmodel.h +++ b/src/libs/utils/environmentmodel.h @@ -36,7 +36,7 @@ public: void setBaseEnvironment(const Environment &env); QModelIndex addVariable(); - QModelIndex addVariable(const NameValueItem &item); + QModelIndex addVariable(const EnvironmentItem &item); void resetVariable(const QString &name); void unsetVariable(const QString &name); void toggleVariable(const QModelIndex &index); @@ -46,8 +46,8 @@ public: QString indexToVariable(const QModelIndex &index) const; QModelIndex variableToIndex(const QString &name) const; bool changes(const QString &key) const; - NameValueItems userChanges() const; - void setUserChanges(const NameValueItems &items); + EnvironmentItems userChanges() const; + void setUserChanges(const EnvironmentItems &items); bool currentEntryIsPathList(const QModelIndex ¤t) const; signals: diff --git a/src/libs/utils/namevaluedictionary.cpp b/src/libs/utils/namevaluedictionary.cpp index 05ff4761dd1..d93298b3f15 100644 --- a/src/libs/utils/namevaluedictionary.cpp +++ b/src/libs/utils/namevaluedictionary.cpp @@ -97,34 +97,34 @@ int NameValueDictionary::size() const return m_values.size(); } -void NameValueDictionary::modify(const NameValueItems &items) +void NameValueDictionary::modify(const EnvironmentItems &items) { NameValueDictionary resultKeyValueDictionary = *this; - for (const NameValueItem &item : items) + for (const EnvironmentItem &item : items) item.apply(&resultKeyValueDictionary); *this = resultKeyValueDictionary; } -NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const +EnvironmentItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const { NameValueMap::const_iterator thisIt = constBegin(); NameValueMap::const_iterator otherIt = other.constBegin(); - NameValueItems result; + EnvironmentItems result; while (thisIt != constEnd() || otherIt != other.constEnd()) { if (thisIt == constEnd()) { result.append({other.key(otherIt), other.value(otherIt), - otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + otherIt.value().second ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); ++otherIt; } else if (otherIt == other.constEnd()) { - result.append(NameValueItem(key(thisIt), QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(key(thisIt), QString(), EnvironmentItem::Unset)); ++thisIt; } else if (thisIt.key() < otherIt.key()) { - result.append(NameValueItem(key(thisIt), QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(key(thisIt), QString(), EnvironmentItem::Unset)); ++thisIt; } else if (thisIt.key() > otherIt.key()) { result.append({other.key(otherIt), otherIt.value().first, - otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + otherIt.value().second ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); ++otherIt; } else { const QString &oldValue = thisIt.value().first; @@ -137,16 +137,16 @@ NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool QString appended = newValue.right(newValue.size() - oldValue.size()); if (appended.startsWith(OsSpecificAspects::pathListSeparator(osType()))) appended.remove(0, 1); - result.append(NameValueItem(other.key(otherIt), appended, NameValueItem::Append)); + result.append(EnvironmentItem(other.key(otherIt), appended, EnvironmentItem::Append)); } else if (checkAppendPrepend && newValue.endsWith(oldValue) && oldEnabled == newEnabled) { QString prepended = newValue.left(newValue.size() - oldValue.size()); if (prepended.endsWith(OsSpecificAspects::pathListSeparator(osType()))) prepended.chop(1); - result.append(NameValueItem(other.key(otherIt), prepended, NameValueItem::Prepend)); + result.append(EnvironmentItem(other.key(otherIt), prepended, EnvironmentItem::Prepend)); } else { result.append({other.key(otherIt), newValue, newEnabled - ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); } } ++otherIt; diff --git a/src/libs/utils/namevaluedictionary.h b/src/libs/utils/namevaluedictionary.h index 722558f8912..87d81249704 100644 --- a/src/libs/utils/namevaluedictionary.h +++ b/src/libs/utils/namevaluedictionary.h @@ -48,9 +48,9 @@ public: QString value(const QString &key) const; void set(const QString &key, const QString &value, bool enabled = true); void unset(const QString &key); - void modify(const NameValueItems &items); + void modify(const EnvironmentItems &items); /// Return the KeyValueDictionary changes necessary to modify this into the other environment. - NameValueItems diff(const NameValueDictionary &other, bool checkAppendPrepend = false) const; + EnvironmentItems diff(const NameValueDictionary &other, bool checkAppendPrepend = false) const; bool hasKey(const QString &key) const; OsType osType() const; Qt::CaseSensitivity nameCaseSensitivity() const; diff --git a/src/libs/utils/namevalueitem.cpp b/src/libs/utils/namevalueitem.cpp index adc7ff5afc9..3f4cdbd4b2c 100644 --- a/src/libs/utils/namevalueitem.cpp +++ b/src/libs/utils/namevalueitem.cpp @@ -10,34 +10,34 @@ namespace Utils { -void NameValueItem::sort(NameValueItems *list) +void EnvironmentItem::sort(EnvironmentItems *list) { - Utils::sort(*list, &NameValueItem::name); + Utils::sort(*list, &EnvironmentItem::name); } -NameValueItems NameValueItem::fromStringList(const QStringList &list) +EnvironmentItems EnvironmentItem::fromStringList(const QStringList &list) { - NameValueItems result; + EnvironmentItems result; for (const QString &string : list) { int pos = string.indexOf("+="); if (pos != -1) { - result.append({string.left(pos), string.mid(pos + 2), NameValueItem::Append}); + result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Append}); continue; } pos = string.indexOf("=+"); if (pos != -1) { - result.append({string.left(pos), string.mid(pos + 2), NameValueItem::Prepend}); + result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Prepend}); continue; } pos = string.indexOf('=', 1); if (pos == -1) { - result.append(NameValueItem(string, QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(string, QString(), EnvironmentItem::Unset)); continue; } const int hashPos = string.indexOf('#'); if (hashPos != -1 && hashPos < pos) { result.append({string.mid(hashPos + 1, pos - hashPos - 1), string.mid(pos + 1), - NameValueItem::SetDisabled}); + EnvironmentItem::SetDisabled}); } else { result.append({string.left(pos), string.mid(pos + 1)}); } @@ -45,49 +45,49 @@ NameValueItems NameValueItem::fromStringList(const QStringList &list) return result; } -QStringList NameValueItem::toStringList(const NameValueItems &list) +QStringList EnvironmentItem::toStringList(const EnvironmentItems &list) { - return Utils::transform(list, [](const NameValueItem &item) { + return Utils::transform(list, [](const EnvironmentItem &item) { switch (item.operation) { - case NameValueItem::Unset: + case EnvironmentItem::Unset: return item.name; - case NameValueItem::Append: + case EnvironmentItem::Append: return QString(item.name + "+=" + item.value); - case NameValueItem::Prepend: + case EnvironmentItem::Prepend: return QString(item.name + "=+" + item.value); - case NameValueItem::SetDisabled: + case EnvironmentItem::SetDisabled: return QString('#' + item.name + '=' + item.value); - case NameValueItem::SetEnabled: + case EnvironmentItem::SetEnabled: return QString(item.name + '=' + item.value); } return QString(); }); } -NameValueItems NameValueItem::itemsFromVariantList(const QVariantList &list) +EnvironmentItems EnvironmentItem::itemsFromVariantList(const QVariantList &list) { - return Utils::transform(list, [](const QVariant &item) { + return Utils::transform(list, [](const QVariant &item) { return itemFromVariantList(item.toList()); }); } -QVariantList NameValueItem::toVariantList(const NameValueItems &list) +QVariantList EnvironmentItem::toVariantList(const EnvironmentItems &list) { - return Utils::transform(list, [](const NameValueItem &item) { + return Utils::transform(list, [](const EnvironmentItem &item) { return QVariant(toVariantList(item)); }); } -NameValueItem NameValueItem::itemFromVariantList(const QVariantList &list) +EnvironmentItem EnvironmentItem::itemFromVariantList(const QVariantList &list) { - QTC_ASSERT(list.size() == 3, return NameValueItem("", "")); + QTC_ASSERT(list.size() == 3, return EnvironmentItem("", "")); QString key = list.value(0).toString(); Operation operation = Operation(list.value(1).toInt()); QString value = list.value(2).toString(); - return NameValueItem(key, value, operation); + return EnvironmentItem(key, value, operation); } -QVariantList NameValueItem::toVariantList(const NameValueItem &item) +QVariantList EnvironmentItem::toVariantList(const EnvironmentItem &item) { return QVariantList() << item.name << item.operation << item.value; } @@ -118,7 +118,7 @@ static QString expand(const NameValueDictionary *dictionary, QString value) return value; } -void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const +void EnvironmentItem::apply(NameValueDictionary *dictionary, Operation op) const { switch (op) { case SetEnabled: @@ -173,26 +173,26 @@ void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const } } -QDebug operator<<(QDebug debug, const NameValueItem &i) +QDebug operator<<(QDebug debug, const EnvironmentItem &i) { QDebugStateSaver saver(debug); debug.noquote(); debug.nospace(); debug << "KeyValueItem("; switch (i.operation) { - case NameValueItem::SetEnabled: + case EnvironmentItem::SetEnabled: debug << "set \"" << i.name << "\" to \"" << i.value << '"'; break; - case NameValueItem::SetDisabled: + case EnvironmentItem::SetDisabled: debug << "set \"" << i.name << "\" to \"" << i.value << '"' << "[disabled]"; break; - case NameValueItem::Unset: + case EnvironmentItem::Unset: debug << "unset \"" << i.name << '"'; break; - case NameValueItem::Prepend: + case EnvironmentItem::Prepend: debug << "prepend to \"" << i.name << "\":\"" << i.value << '"'; break; - case NameValueItem::Append: + case EnvironmentItem::Append: debug << "append to \"" << i.name << "\":\"" << i.value << '"'; break; } diff --git a/src/libs/utils/namevalueitem.h b/src/libs/utils/namevalueitem.h index 62ba9d25baf..6ad5ed03791 100644 --- a/src/libs/utils/namevalueitem.h +++ b/src/libs/utils/namevalueitem.h @@ -13,12 +13,12 @@ namespace Utils { -class QTCREATOR_UTILS_EXPORT NameValueItem +class QTCREATOR_UTILS_EXPORT EnvironmentItem { public: enum Operation : char { SetEnabled, Unset, Prepend, Append, SetDisabled }; - NameValueItem() = default; - NameValueItem(const QString &key, const QString &value, Operation operation = SetEnabled) + EnvironmentItem() = default; + EnvironmentItem(const QString &key, const QString &value, Operation operation = SetEnabled) : name(key) , value(value) , operation(operation) @@ -26,25 +26,25 @@ public: void apply(NameValueDictionary *dictionary) const { apply(dictionary, operation); } - static void sort(NameValueItems *list); - static NameValueItems fromStringList(const QStringList &list); - static QStringList toStringList(const NameValueItems &list); - static NameValueItems itemsFromVariantList(const QVariantList &list); - static QVariantList toVariantList(const NameValueItems &list); - static NameValueItem itemFromVariantList(const QVariantList &list); - static QVariantList toVariantList(const NameValueItem &item); + static void sort(EnvironmentItems *list); + static EnvironmentItems fromStringList(const QStringList &list); + static QStringList toStringList(const EnvironmentItems &list); + static EnvironmentItems itemsFromVariantList(const QVariantList &list); + static QVariantList toVariantList(const EnvironmentItems &list); + static EnvironmentItem itemFromVariantList(const QVariantList &list); + static QVariantList toVariantList(const EnvironmentItem &item); - friend bool operator==(const NameValueItem &first, const NameValueItem &second) + friend bool operator==(const EnvironmentItem &first, const EnvironmentItem &second) { return first.operation == second.operation && first.name == second.name && first.value == second.value; } - friend bool operator!=(const NameValueItem &first, const NameValueItem &second) + friend bool operator!=(const EnvironmentItem &first, const EnvironmentItem &second) { return !(first == second); } - friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const NameValueItem &i); + friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const EnvironmentItem &i); public: QString name; diff --git a/src/libs/utils/namevaluesdialog.cpp b/src/libs/utils/namevaluesdialog.cpp index 4f9537655ef..43511fe57f0 100644 --- a/src/libs/utils/namevaluesdialog.cpp +++ b/src/libs/utils/namevaluesdialog.cpp @@ -70,7 +70,7 @@ NameValueItemsWidget::NameValueItemsWidget(QWidget *parent) layout->addWidget(new QLabel(helpText, this)); const auto checkForItemChange = [this] { - const NameValueItems newItems = environmentItems(); + const EnvironmentItems newItems = environmentItems(); if (newItems != m_originalItems) { m_originalItems = newItems; emit userChangedItems(newItems); @@ -190,8 +190,8 @@ void NameValuesDialog::setPlaceholderText(const QString &text) m_editor->setPlaceholderText(text); } -std::optional NameValuesDialog::getNameValueItems(QWidget *parent, - const NameValueItems &initial, +std::optional NameValuesDialog::getNameValueItems(QWidget *parent, + const EnvironmentItems &initial, const QString &placeholderText, Polisher polisher, const QString &windowTitle) diff --git a/src/libs/utils/namevaluesdialog.h b/src/libs/utils/namevaluesdialog.h index af847bb5a1d..a1e884fe5b5 100644 --- a/src/libs/utils/namevaluesdialog.h +++ b/src/libs/utils/namevaluesdialog.h @@ -34,20 +34,20 @@ signals: private: Internal::TextEditHelper *m_editor; - NameValueItems m_originalItems; + EnvironmentItems m_originalItems; }; class QTCREATOR_UTILS_EXPORT NameValuesDialog : public QDialog { public: - void setNameValueItems(const NameValueItems &items); - NameValueItems nameValueItems() const; + void setNameValueItems(const EnvironmentItems &items); + EnvironmentItems nameValueItems() const; void setPlaceholderText(const QString &text); using Polisher = std::function; - static std::optional getNameValueItems(QWidget *parent = nullptr, - const NameValueItems &initial = {}, + static std::optional getNameValueItems(QWidget *parent = nullptr, + const EnvironmentItems &initial = {}, const QString &placeholderText = {}, Polisher polish = {}, const QString &windowTitle = {}); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 406b5524473..9efc98f24c3 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4093,7 +4093,7 @@ void GdbEngine::setEnvironmentVariables() Environment baseEnv = runParameters().debugger.environment; Environment runEnv = runParameters().inferior.environment; - const NameValueItems items = baseEnv.diff(runEnv); + const EnvironmentItems items = baseEnv.diff(runEnv); for (const EnvironmentItem &item : items) { // imitate the weird windows gdb behavior of setting the case of the path environment // variable name to an all uppercase PATH diff --git a/src/plugins/mcusupport/mcukitaspect.cpp b/src/plugins/mcusupport/mcukitaspect.cpp index f53dcacfd04..8d497f209dd 100644 --- a/src/plugins/mcusupport/mcukitaspect.cpp +++ b/src/plugins/mcusupport/mcukitaspect.cpp @@ -32,19 +32,19 @@ Utils::Id McuDependenciesKitAspect::id() return "PE.Profile.McuCMakeDependencies"; } -Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *kit) +Utils::EnvironmentItems McuDependenciesKitAspect::dependencies(const Kit *kit) { if (kit) - return Utils::NameValueItem::fromStringList( + return Utils::EnvironmentItem::fromStringList( kit->value(McuDependenciesKitAspect::id()).toStringList()); - return Utils::NameValueItems(); + return Utils::EnvironmentItems(); } -void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies) +void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::EnvironmentItems &dependencies) { if (k) k->setValue(McuDependenciesKitAspect::id(), - Utils::NameValueItem::toStringList(dependencies)); + Utils::EnvironmentItem::toStringList(dependencies)); } Utils::NameValuePairs McuDependenciesKitAspect::configuration(const Kit *kit) @@ -108,7 +108,7 @@ public: if (!variant.isNull() && !variant.canConvert(QVariant::List)) { qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(kit->displayName())); - McuDependenciesKitAspect::setDependencies(kit, Utils::NameValueItems()); + McuDependenciesKitAspect::setDependencies(kit, Utils::EnvironmentItems()); } } diff --git a/src/plugins/mcusupport/mcukitaspect.h b/src/plugins/mcusupport/mcukitaspect.h index a86841a72aa..46256213488 100644 --- a/src/plugins/mcusupport/mcukitaspect.h +++ b/src/plugins/mcusupport/mcukitaspect.h @@ -11,8 +11,8 @@ class McuDependenciesKitAspect final { public: static Utils::Id id(); - static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *kit); - static void setDependencies(ProjectExplorer::Kit *kit, const Utils::NameValueItems &dependencies); + static Utils::EnvironmentItems dependencies(const ProjectExplorer::Kit *kit); + static void setDependencies(ProjectExplorer::Kit *kit, const Utils::EnvironmentItems &dependencies); static Utils::NameValuePairs configuration(const ProjectExplorer::Kit *kit); }; diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index 456bdbdcdfc..08c9c8abb09 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -180,7 +180,7 @@ public: const McuTarget *mcuTarget, const McuPackagePtr &qtForMCUsSdkPackage) { - NameValueItems dependencies; + EnvironmentItems dependencies; auto processPackage = [&dependencies](const McuPackagePtr &package) { const auto cmakeVariableName = package->cmakeVariableName(); diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 9a63d789ece..a34f8bc256e 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -481,25 +481,25 @@ void EnvironmentWidget::unsetEnvironmentButtonClicked() d->m_editor.setEnvironmentItems(d->m_model->userChanges()); } -void EnvironmentWidget::amendPathList(Utils::NameValueItem::Operation op) +void EnvironmentWidget::amendPathList(Utils::EnvironmentItem::Operation op) { const QString varName = d->m_model->indexToVariable(d->m_environmentView->currentIndex()); const FilePath dir = FileUtils::getExistingDirectory(this, Tr::tr("Choose Directory")); if (dir.isEmpty()) return; - Utils::NameValueItems changes = d->m_model->userChanges(); + Utils::EnvironmentItems changes = d->m_model->userChanges(); changes.append({varName, dir.toUserOutput(), op}); setUserChanges(changes); } void EnvironmentWidget::appendPathButtonClicked() { - amendPathList(Utils::NameValueItem::Append); + amendPathList(Utils::EnvironmentItem::Append); } void EnvironmentWidget::prependPathButtonClicked() { - amendPathList(Utils::NameValueItem::Prepend); + amendPathList(Utils::EnvironmentItem::Prepend); } void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex ¤t) diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h index a00e45bcda7..b1a26b036b3 100644 --- a/src/plugins/projectexplorer/environmentwidget.h +++ b/src/plugins/projectexplorer/environmentwidget.h @@ -57,7 +57,7 @@ private: void linkActivated(const QString &link); using PathListModifier = std::function; - void amendPathList(Utils::NameValueItem::Operation op); + void amendPathList(Utils::EnvironmentItem::Operation op); class Private; const std::unique_ptr d; diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index cd46c2a521c..7f2eee43db7 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -1063,13 +1063,13 @@ void Project::setNamedSettings(const Key &name, const QVariant &value) void Project::setAdditionalEnvironment(const EnvironmentItems &envItems) { - setNamedSettings(PROJECT_ENV_KEY, NameValueItem::toStringList(envItems)); + setNamedSettings(PROJECT_ENV_KEY, EnvironmentItem::toStringList(envItems)); emit environmentChanged(); } EnvironmentItems Project::additionalEnvironment() const { - return NameValueItem::fromStringList(namedSettings(PROJECT_ENV_KEY).toStringList()); + return EnvironmentItem::fromStringList(namedSettings(PROJECT_ENV_KEY).toStringList()); } bool Project::needsConfiguration() const diff --git a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp index 524150db41b..50d8596ae36 100644 --- a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp +++ b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp @@ -286,7 +286,7 @@ const QString projectEnvironmentVariable(const QString &key) if (auto buildSystem = getBuildSystem()) { auto envItems = buildSystem->environment(); - auto confEnv = std::find_if(envItems.begin(), envItems.end(), [key](NameValueItem &item) { + auto confEnv = std::find_if(envItems.begin(), envItems.end(), [key](EnvironmentItem &item) { return item.name == key; }); if (confEnv != envItems.end()) diff --git a/tests/auto/environment/tst_environment.cpp b/tests/auto/environment/tst_environment.cpp index 64dfe426487..3cf9c127a22 100644 --- a/tests/auto/environment/tst_environment.cpp +++ b/tests/auto/environment/tst_environment.cpp @@ -262,11 +262,11 @@ void tst_Environment::expansion() void tst_Environment::incrementalChanges() { const Environment origEnv({{"VAR1", "VALUE1"}, {"VAR2", "VALUE2"}, {"PATH", "/usr/bin"}}); - const NameValueItems changes({ - {"VAR1", QString(), NameValueItem::Unset}, - {"VAR2", "VALUE2", NameValueItem::SetDisabled}, - {"PATH", "/usr/local/bin", NameValueItem::Append}, - {"PATH", "/tmp", NameValueItem::Prepend}}); + const EnvironmentItems changes({ + {"VAR1", QString(), EnvironmentItem::Unset}, + {"VAR2", "VALUE2", EnvironmentItem::SetDisabled}, + {"PATH", "/usr/local/bin", EnvironmentItem::Append}, + {"PATH", "/tmp", EnvironmentItem::Prepend}}); // Check values after change application. Environment newEnv = origEnv; @@ -281,8 +281,8 @@ void tst_Environment::incrementalChanges() QString("/tmp").append(sep).append("/usr/bin").append(sep).append("/usr/local/bin")); // Check apply/diff round-trips. - const NameValueItems diff = origEnv.diff(newEnv); - const NameValueItems reverseDiff = newEnv.diff(origEnv); + const EnvironmentItems diff = origEnv.diff(newEnv); + const EnvironmentItems reverseDiff = newEnv.diff(origEnv); Environment newEnv2 = origEnv; newEnv2.modify(diff); QCOMPARE(newEnv, newEnv2); @@ -290,12 +290,12 @@ void tst_Environment::incrementalChanges() QCOMPARE(newEnv2, origEnv); // Check conversion round-trips. - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(changes)), changes); - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(diff)), diff); - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(reverseDiff)), reverseDiff); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(changes)), changes); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(diff)), diff); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(reverseDiff)), + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(changes)), changes); + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(diff)), diff); + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(reverseDiff)), reverseDiff); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(changes)), changes); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(diff)), diff); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(reverseDiff)), reverseDiff); }