diff options
50 files changed, 925 insertions, 324 deletions
diff --git a/doc/qtcreator/images/qtcreator-mode-selector.webp b/doc/qtcreator/images/qtcreator-mode-selector.webp Binary files differindex 54075491e3a..eb88f1deff2 100644 --- a/doc/qtcreator/images/qtcreator-mode-selector.webp +++ b/doc/qtcreator/images/qtcreator-mode-selector.webp diff --git a/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc b/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc index 9094156eb6d..7d1c4f72e16 100644 --- a/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc +++ b/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc @@ -153,7 +153,7 @@ \uicontrol {Clang Tools}. \image {qtcreator-clang-tools-settings.webp} {Clang Tools customized settings} \li Clear \uicontrol {Use global settings}. - \li Specify \uicontrol preferences for the project. + \li Set preferences for the project. \li In \uicontrol {Suppressed diagnostics}, you can view the suppression list for a project and to remove diagnostics from it. \endlist diff --git a/doc/qtcreator/src/howto/creator-how-to-find-preferences.qdoc b/doc/qtcreator/src/howto/creator-how-to-find-preferences.qdoc index 94559e76fea..7eb73a40801 100644 --- a/doc/qtcreator/src/howto/creator-how-to-find-preferences.qdoc +++ b/doc/qtcreator/src/howto/creator-how-to-find-preferences.qdoc @@ -26,13 +26,13 @@ \section1 Filter preferences To find a particular preference, use the filter located at the top left of - the \uicontrol Preferences dialog. + the \uicontrol Preferences mode. \image {qtcreator-preferences.webp} {Filtering preferences} \section1 Go to tabs in Preferences - To go to a tab in the \uicontrol Preferences dialog from anywhere in \QC, + To go to a tab in the \uicontrol Preferences mode from anywhere in \QC, use the \c t \l{Navigate with locator}{locator} filter. For example, to open the \uicontrol Interface tab, enter \c {t preferences interface} in the locator. diff --git a/doc/qtcreator/src/user-interface/creator-only/creator-how-to-switch-between-modes.qdoc b/doc/qtcreator/src/user-interface/creator-only/creator-how-to-switch-between-modes.qdoc index 260eaa072a7..ca4ec1dc976 100644 --- a/doc/qtcreator/src/user-interface/creator-only/creator-how-to-switch-between-modes.qdoc +++ b/doc/qtcreator/src/user-interface/creator-only/creator-how-to-switch-between-modes.qdoc @@ -27,7 +27,7 @@ \li Purpose \li Read More \row - \li {1,8} \inlineimage {qtcreator-mode-selector.webp} {Mode selector} + \li {1,9} \inlineimage {qtcreator-mode-selector.webp} {Mode selector} \row \li \uicontrol Welcome \li \key Ctrl+1 @@ -66,6 +66,11 @@ \li \key Ctrl+7 \li Read documentation. \li \l{Getting help} + \row + \li \uicontrol Preferences + \li \key Ctrl+8 + \li Set global preferences. + \li \l{Find preferences} \endtable Some actions in \QC trigger a mode change. For example, diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index a7e6ed78eac..9fcb8a4edfe 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -147,6 +147,7 @@ add_qtc_library(Utils qtcprocess.cpp qtcprocess.h qtcsettings.cpp qtcsettings.h qtcsettings_p.h qtcwidgets.cpp qtcwidgets.h + qtdesignsystemstyle.cpp qtdesignsystemstyle.h ranges.h reloadpromptutils.cpp reloadpromptutils.h removefiledialog.cpp removefiledialog.h diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index cd8ed27089b..c9c519622c1 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -449,7 +449,7 @@ bool BaseAspect::isAutoApply() const } /*! - Sets auto-apply mode. When auto-apply mode is \a on, user interaction to this + Sets auto-apply mode. When auto-apply mode is \a off, user interaction to this aspect's widget will not modify the \c value of the aspect until \c apply() is called programmatically. diff --git a/src/libs/utils/datafromprocess.h b/src/libs/utils/datafromprocess.h index e8b996b29aa..b87b7f7d133 100644 --- a/src/libs/utils/datafromprocess.h +++ b/src/libs/utils/datafromprocess.h @@ -8,9 +8,12 @@ #include "environment.h" #include "filepath.h" #include "qtcprocess.h" +#include "settingsdatabase.h" #include <QDateTime> #include <QHash> +#include <QJsonDocument> +#include <QJsonObject> #include <QMutex> #include <QMutexLocker> @@ -47,6 +50,8 @@ public: OutputParser parser; ErrorHandler errorHandler; Callback callback; + Callback cachedValueChangedCallback; + bool persistValue = true; QList<ProcessResult> allowedResults{ProcessResult::FinishedWithSuccess}; }; @@ -104,6 +109,33 @@ inline std::optional<Data> DataFromProcess<Data>::getOrProvideData(const Paramet const auto outputRetriever = std::make_shared<Process>(); outputRetriever->setCommand(params.commandLine); + + if (params.persistValue && !params.callback) { + const QChar separator = params.commandLine.executable().pathListSeparator(); + const QString stringKey = params.commandLine.executable().toUrlishString() + separator + + params.commandLine.arguments() + separator + + params.environment.toStringList().join(separator); + if (const QByteArray json = SettingsDatabase::value(stringKey).toByteArray(); + !json.isEmpty()) { + if (const auto doc = QJsonDocument::fromJson(json); doc.isObject()) { + const QJsonObject settingsObject = doc.object(); + const QString out = settingsObject["stdout"].toString(); + const QString err = settingsObject["stderr"].toString(); + std::optional<Data> data = params.parser(out, err); + QMutexLocker<QMutex> cacheLocker(&m_cacheMutex); + m_cache.insert(key, std::make_pair(data, exeTimestamp)); + QObject::connect( + outputRetriever.get(), + &Process::done, + [params, exeTimestamp, key, outputRetriever] { + handleProcessFinished(params, exeTimestamp, key, outputRetriever); + }); + outputRetriever->start(); + return data; + } + } + } + if (params.callback) { QObject::connect(outputRetriever.get(), &Process::done, @@ -133,11 +165,34 @@ inline std::optional<Data> DataFromProcess<Data>::handleProcessFinished( } std::optional<Data> data; - if (params.allowedResults.contains(process->result())) + if (params.allowedResults.contains(process->result())) { + if (params.persistValue) { + const QChar separator = params.commandLine.executable().pathListSeparator(); + const QString stringKey = params.commandLine.executable().toUrlishString() + separator + + params.commandLine.arguments() + separator + + params.environment.toStringList().join(separator); + QJsonObject settingsObject; + const QString out = process->cleanedStdOut(); + const QString err = process->cleanedStdErr(); + settingsObject["stdout"] = out; + settingsObject["stderr"] = err; + SettingsDatabase::setValue( + stringKey, + QString::fromUtf8(QJsonDocument(settingsObject).toJson(QJsonDocument::Compact))); + } data = params.parser(process->cleanedStdOut(), process->cleanedStdErr()); - else if (params.errorHandler) + } else if (params.errorHandler) { params.errorHandler(*process); + } QMutexLocker<QMutex> cacheLocker(&m_cacheMutex); + if (params.cachedValueChangedCallback) { + const auto it = m_cache.constFind(cacheKey); + if (it != m_cache.constEnd() && it.value().second == exeTimestamp) { + if (it.value().first != data) + params.cachedValueChangedCallback(data); + } + } + m_cache.insert(cacheKey, std::make_pair(data, exeTimestamp)); if (params.callback) { params.callback(data); diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 992e3409355..95f965d392d 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -522,6 +522,11 @@ void addToLayout(Layout *layout, QWidget *inner) layout->addLayoutItem(inner); } +void addToLayout(Layout *layout, QWidget &inner) +{ + layout->addLayoutItem(&inner); +} + void addToLayout(Layout *layout, QLayout *inner) { layout->addLayoutItem(inner); diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 3c6b9925a3b..fb5e8813151 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -703,6 +703,7 @@ QTC_DEFINE_BUILDER_SETTER(minimumHeight, setMinimumHeight) QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const Layout &inner); QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const Widget &inner); QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, QWidget *inner); +QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, QWidget &inner); QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, QLayout *inner); QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const LayoutModifier &inner); QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const QString &inner); diff --git a/src/libs/utils/qtcwidgets.cpp b/src/libs/utils/qtcwidgets.cpp index 84e8c9c41c5..9f7cf62dcc1 100644 --- a/src/libs/utils/qtcwidgets.cpp +++ b/src/libs/utils/qtcwidgets.cpp @@ -6,6 +6,7 @@ #include "hostosinfo.h" #include "icon.h" #include "networkaccessmanager.h" +#include "qtdesignsystemstyle.h" #include <QtTaskTree/QNetworkReplyWrapper> #include <QtTaskTree/QSingleTaskTreeRunner> @@ -896,49 +897,13 @@ void QtcImage::setPixmap(const QPixmap &px) update(); } -constexpr TextFormat TabBarTf - {Theme::Token_Text_Muted, StyleHelper::UiElementH5}; -constexpr TextFormat TabBarTfActive - {Theme::Token_Text_Default, TabBarTf.uiElement}; - QtcTabBar::QtcTabBar(QWidget *parent) : QTabBar(parent) { - setExpanding(false); - setFont(TabBarTf.font()); + setStyle(QtDesignSystemStyle::instance()); setMouseTracking(true); } -void QtcTabBar::paintEvent([[maybe_unused]] QPaintEvent *event) -{ - QPainter p(this); - const int padding = PaddingHXxs; - const QRectF borderR = rect().toRectF().adjusted(padding + 0.5, 0.5, -(padding + 0.5), -0.5); - p.setPen(creatorColor(isEnabled() ? Theme::Token_Stroke_Subtle - : Theme::Token_Foreground_Subtle)); - p.drawLine(borderR.bottomLeft(), borderR.bottomRight()); - p.setFont(TabBarTf.font()); - for (int tabIndex = 0; tabIndex < count(); tabIndex++) { - QStyleOptionTab opt; - initStyleOption(&opt, tabIndex); - const bool selected = opt.state & QStyle::State_Selected; - const bool enabled = isEnabled(); - const bool hovered = !selected && opt.rect.contains(mapFromGlobal(QCursor::pos())); - if (selected || (hovered && enabled)) { - QRect highLightRect = opt.rect.adjusted(padding, 0, -padding, 0); - highLightRect.moveTop(highLightRect.height() - StyleHelper::HighlightThickness); - const QColor color = creatorColor(enabled ? hovered ? Theme::Token_Text_Subtle - : Theme::Token_Accent_Default - : Theme::Token_Foreground_Subtle); - p.fillRect(highLightRect, color); - } - const QColor textColor = enabled ? (selected ? TabBarTfActive : TabBarTf).color() - : creatorColor(Theme::Token_Text_Subtle); - p.setPen(textColor); - p.drawText(opt.rect, Qt::AlignCenter, opt.text); - } -} - bool QtcTabBar::event(QEvent *event) { if (event->type() == QEvent::MouseMove || event->type() == QEvent::Leave) diff --git a/src/libs/utils/qtcwidgets.h b/src/libs/utils/qtcwidgets.h index 52c3bb25ae4..7e07b93e7a4 100644 --- a/src/libs/utils/qtcwidgets.h +++ b/src/libs/utils/qtcwidgets.h @@ -177,7 +177,6 @@ public: QtcTabBar(QWidget *parent = nullptr); protected: - void paintEvent(QPaintEvent *event) override; bool event(QEvent *event) override; }; diff --git a/src/libs/utils/qtdesignsystemstyle.cpp b/src/libs/utils/qtdesignsystemstyle.cpp new file mode 100644 index 00000000000..1eebe93a297 --- /dev/null +++ b/src/libs/utils/qtdesignsystemstyle.cpp @@ -0,0 +1,157 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "qtdesignsystemstyle.h" + +#include "stylehelper.h" +#include "utilsicons.h" + +#include <QGuiApplication> +#include <QPaintEvent> +#include <QPainter> +#include <QPainterPath> +#include <QPixmapCache> +#include <QWidget> +#include <QStyleOption> +#include <QTabBar> + +namespace Utils { + +using namespace StyleHelper; +using namespace StyleHelper::SpacingTokens; + +constexpr TextFormat TabBarTf + {Theme::Token_Text_Muted, StyleHelper::UiElementH5}; +constexpr TextFormat TabBarTfActive + {Theme::Token_Text_Default, TabBarTf.uiElement}; +constexpr TextFormat TabBarTfDisabled + {Theme::Token_Text_Subtle, TabBarTf.uiElement}; + +QtDesignSystemStyle::QtDesignSystemStyle() +{ +} + +QtDesignSystemStyle::~QtDesignSystemStyle() = default; + +void QtDesignSystemStyle::drawControl(ControlElement element, const QStyleOption *opt, + QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case CE_TabBarTabLabel: { + auto tabOpt = qstyleoption_cast<const QStyleOptionTab*>(opt); + QStyleOptionTab myTabOpt = *tabOpt; + const QColor c = ((myTabOpt.state & QStyle::State_Enabled) ? + (myTabOpt.state & QStyle::State_Selected) ? TabBarTfActive + : TabBarTf + : TabBarTfDisabled).color(); + myTabOpt.palette.setColor(widget->foregroundRole(), c); + myTabOpt.state = myTabOpt.state & ~QStyle::State_HasFocus; // Avoid extra focus rect + QCommonStyle::drawControl(element, &myTabOpt, painter, widget); + break; + } + case CE_TabBarTabShape: { + const bool selected = opt->state & QStyle::State_Selected; + const bool enabled = opt->state & QStyle::State_Enabled; + const bool hovered = !selected && opt->rect.contains(widget->mapFromGlobal(QCursor::pos())); + auto tabOpt = qstyleoption_cast<const QStyleOptionTab*>(opt); + const int paddingL = tabOpt->position == QStyleOptionTab::Beginning ? 0 : PaddingHXxs; + const int paddingR = tabOpt->position == QStyleOptionTab::End ? 0 : PaddingHXxs; + const QRect shapeR = opt->rect.adjusted(paddingL, 0, -paddingR, 0); + if (selected || (hovered && enabled)) { + if (hovered || tabOpt->position == QStyleOptionTab::Moving) { + StyleHelper::drawCardBg(painter, shapeR.adjusted(0, 0, 0, +SpacingTokens::RadiusS), + creatorColor(Theme::Token_Foreground_Subtle)); + } + QRect highLightRect = shapeR; + highLightRect.moveTop(highLightRect.height() - StyleHelper::HighlightThickness); + const QColor color = creatorColor(enabled ? hovered ? Theme::Token_Text_Subtle + : Theme::Token_Accent_Default + : Theme::Token_Foreground_Subtle); + painter->fillRect(highLightRect, color); + } + break; + } + default: + QCommonStyle::drawControl(element, opt, painter, widget); + break; + } +} + +void QtDesignSystemStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *opt, + QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case PE_FrameTabBarBase: { + QRectF borderR = opt->rect.toRectF(); + const int lineWidth = 1; + borderR.setTop(borderR.bottom() - lineWidth); + const bool enabled = opt->state & QStyle::State_Enabled; + const QColor color = creatorColor(enabled ? Theme::Token_Stroke_Subtle + : Theme::Token_Foreground_Subtle); + painter->fillRect(borderR, color); + break; + } + default: + QCommonStyle::drawPrimitive(element, opt, painter, widget); + break; + } +} + +int QtDesignSystemStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, + const QWidget *widget) const +{ + switch (m) { + case PM_TabBarTabShiftVertical: + case PM_TabBarTabShiftHorizontal: + return 0; + case PM_TabBarTabHSpace: + return PaddingHL + PaddingHL; + case PM_TabBarTabVSpace: { + const int textHeight = opt->fontMetrics.height(); + return PaddingVM + TabBarTf.lineHeight() + PaddingVM - textHeight; + } + default: + return QCommonStyle::pixelMetric(m, opt, widget); + } +} + +QIcon QtDesignSystemStyle::standardIcon(StandardPixmap sp, const QStyleOption *opt, + const QWidget *widget) const +{ + QIcon icon; + + switch (sp) { + case SP_TabCloseButton: { + static const QIcon tabClose = Icons::CLOSE_FOREGROUND.icon(); + icon = tabClose; + break; + } + default: + icon = QCommonStyle::standardIcon(sp, opt, widget); + break; + } + + return icon; +} +void QtDesignSystemStyle::polish(QWidget *widget) +{ + QCommonStyle::polish(widget); + + if (auto tabBar = qobject_cast<QTabBar*>(widget)) { + tabBar->setFont(TabBarTf.font()); + for (int count = tabBar->count(), i = 0; i < count; ++i ) { + for (const QTabBar::ButtonPosition pos : {QTabBar::LeftSide, QTabBar::RightSide}) { + if (QWidget *tabButton = tabBar->tabButton(i, pos)) + tabButton->setStyle(this); + } + } + } +} + +QStyle *QtDesignSystemStyle::instance() +{ + static QtDesignSystemStyle style; + return &style; +} + +} // namespace Utils diff --git a/src/libs/utils/qtdesignsystemstyle.h b/src/libs/utils/qtdesignsystemstyle.h new file mode 100644 index 00000000000..ed69ca53fe9 --- /dev/null +++ b/src/libs/utils/qtdesignsystemstyle.h @@ -0,0 +1,31 @@ +// Copyright (C) 2025 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 <QCommonStyle> + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT QtDesignSystemStyle : public QCommonStyle +{ +public: + QtDesignSystemStyle(); + ~QtDesignSystemStyle(); + + void drawControl(ControlElement element, const QStyleOption *opt, QPainter *painter, + const QWidget *widget = nullptr) const override; + void drawPrimitive(PrimitiveElement element, const QStyleOption *opt, QPainter *painter, + const QWidget *widget = nullptr) const override; + int pixelMetric(PixelMetric metric, const QStyleOption *opt = nullptr, + const QWidget *widget = nullptr) const override; + QIcon standardIcon(StandardPixmap sp, const QStyleOption *opt, + const QWidget *widget) const override; + void polish(QWidget *widget) override; + + static QStyle *instance(); +}; + +} // namespace Utils diff --git a/src/libs/utils/settingsdatabase.cpp b/src/libs/utils/settingsdatabase.cpp index c4e862978d8..f53c81b2b8a 100644 --- a/src/libs/utils/settingsdatabase.cpp +++ b/src/libs/utils/settingsdatabase.cpp @@ -16,6 +16,8 @@ #include <QStringList> #include <QVariant> +#include <chrono> + /*! \namespace Utils::SettingsDatabase \inheaderfile utils/settingsdatabase.h @@ -39,6 +41,7 @@ namespace Utils::SettingsDatabase { enum { debug_settings = 0 }; using SettingsMap = QMap<QString, QVariant>; +using LastUsageMap = QMap<QString, std::chrono::system_clock::time_point>; class SettingsDatabaseImpl { @@ -58,6 +61,7 @@ public: } SettingsMap m_settings; + LastUsageMap m_lastUsage; QStringList m_groups; @@ -110,6 +114,17 @@ void ensureImpl() } } + QVariantMap lastUsages = value("SettingsDataBaseLastUsages").toMap(); + for (auto it = d->m_settings.begin(); it != d->m_settings.constEnd(); ++it) { + auto lastUsageIt = lastUsages.find(it.key()); + std::chrono::system_clock::time_point lastUsage; + if (lastUsageIt != lastUsages.end()) + lastUsage = std::chrono::system_clock::from_time_t(lastUsageIt.value().toLongLong()); + else + lastUsage = std::chrono::system_clock::now(); + d->m_lastUsage.insert(it.key(), lastUsage); + } + // syncing can be slow, especially on Linux and Windows d->m_db.exec(QLatin1String("PRAGMA synchronous = OFF;")); } @@ -122,6 +137,16 @@ void destroy() // TODO: Delay writing of dirty keys and save them here + QVariantMap lastUsages; + const std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + for (auto it = d->m_lastUsage.begin(); it != d->m_lastUsage.end(); ++it) { + if (now - it.value() > std::chrono::months(1)) + remove(it.key()); + else + lastUsages.insert(it.key(), static_cast<qint64>(std::chrono::system_clock::to_time_t(it.value()))); + } + setValue("SettingsDataBaseLastUsages", lastUsages); + delete d; d = nullptr; QSqlDatabase::removeDatabase(QLatin1String("settings")); @@ -134,6 +159,7 @@ void setValue(const QString &key, const QVariant &value) // Add to cache d->m_settings.insert(effectiveKey, value); + d->m_lastUsage.insert(effectiveKey, std::chrono::system_clock::now()); if (!d->m_db.isOpen()) return; @@ -175,6 +201,7 @@ QVariant value(const QString &key, const QVariant &defaultValue) d->m_settings.insert(effectiveKey, value); } + d->m_lastUsage.insert(effectiveKey, std::chrono::system_clock::now()); return value; } diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index b7a5457c01a..1a9c9d24db1 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -278,6 +278,8 @@ QtcLibrary { "qtcsettings_p.h", "qtcwidgets.cpp", "qtcwidgets.h", + "qtdesignsystemstyle.cpp", + "qtdesignsystemstyle.h", "ranges.h", "reloadpromptutils.cpp", "reloadpromptutils.h", diff --git a/src/plugins/clangtools/executableinfo.cpp b/src/plugins/clangtools/executableinfo.cpp index 9a93d4dd79c..73f9e9f6ed8 100644 --- a/src/plugins/clangtools/executableinfo.cpp +++ b/src/plugins/clangtools/executableinfo.cpp @@ -175,6 +175,7 @@ static FilePath queryResourceDir(const FilePath &clangToolPath) parser); params.environment.setupEnglishOutput(); params.allowedResults << ProcessResult::FinishedWithError; + params.persistValue = false; if (const auto filePath = DataFromProcess<FilePath>::getData(params)) return *filePath; return {}; @@ -197,6 +198,7 @@ QString queryVersion(const FilePath &clangToolPath, QueryFailMode failMode) return {}; }; DataFromProcess<QString>::Parameters params({clangToolPath, {"--version"}}, parser); + params.persistValue = true; params.environment.setupEnglishOutput(); if (failMode == QueryFailMode::Noisy) params.errorHandler = handleProcessError; @@ -225,5 +227,29 @@ QPair<FilePath, QString> getClangIncludeDirAndVersion(const FilePath &clangToolP return it.value(); } +bool operator==(const ClazyStandaloneInfo &c1, const ClazyStandaloneInfo &c2) +{ + return c1.version == c2.version + && c1.defaultChecks == c2.defaultChecks + && c1.supportedChecks == c2.supportedChecks; +} + +bool operator!=(const ClazyStandaloneInfo &c1, const ClazyStandaloneInfo &c2) +{ + return !(c1 == c2); +} + +bool operator==(const ClazyCheck &c1, const ClazyCheck &c2) +{ + return c1.name == c2.name + && c1.level == c2.level + && c1.topics == c2.topics; +} + +bool operator!=(const ClazyCheck &c1, const ClazyCheck &c2) +{ + return !(c1 == c2); +} + } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/clangtools/executableinfo.h b/src/plugins/clangtools/executableinfo.h index 5db586b5356..f828afb70ac 100644 --- a/src/plugins/clangtools/executableinfo.h +++ b/src/plugins/clangtools/executableinfo.h @@ -32,6 +32,9 @@ public: QString name; int level; QStringList topics; + + friend bool operator==(const ClazyCheck &c1, const ClazyCheck &c2); + friend bool operator!=(const ClazyCheck &c1, const ClazyCheck &c2); }; using ClazyChecks = QVector<ClazyCheck>; @@ -43,6 +46,9 @@ public: QVersionNumber version; QStringList defaultChecks; ClazyChecks supportedChecks; + + friend bool operator==(const ClazyStandaloneInfo &c1, const ClazyStandaloneInfo &c2); + friend bool operator!=(const ClazyStandaloneInfo &c1, const ClazyStandaloneInfo &c2); }; } // namespace Internal diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp index 11e109e3c80..c15247efc12 100644 --- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp @@ -697,9 +697,7 @@ void CMakeToolConfigWidget::redetect() // Step 1: Detect const IDeviceConstPtr dev = currentDevice(); QTC_ASSERT(dev, return); - const FilePath root = dev->rootPath(); - auto toAdd - = CMakeToolManager::autoDetectCMakeTools(dev->systemEnvironment().mappedPath(root), root); + auto toAdd = CMakeToolManager::autoDetectCMakeTools(dev->toolSearchPaths(), dev->rootPath()); // Step 2: Match existing against newly detected. QList<Id> toRemove; diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index e8ef35f2419..0e530b47960 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -47,8 +47,46 @@ static Locator *m_instance = nullptr; const char kDirectoryFilterPrefix[] = "directory"; const char kUrlFilterPrefix[] = "url"; -const char kUseCenteredPopup[] = "UseCenteredPopupForShortcut"; -const char kUseTabCompletion[] = "UseTabCompletion"; + +LocatorSettings::LocatorSettings() +{ + setAutoApply(false); + setSettingsGroup("Locator"); + + useCenteredPopup.setSettingsKey("UseCenteredPopupForShortcut"); + useCenteredPopup.setDefaultValue(false); + useCenteredPopup.setLabelText(Tr::tr("Open as Centered Popup")); + + useTabCompletion.setSettingsKey("UseTabCompletion"); + useTabCompletion.setDefaultValue(true); + useTabCompletion.setLabelText(Tr::tr("Use Tab Completion")); + + relativePaths.setSettingsKey("RelativePaths"); + relativePaths.setDefaultValue(false); + relativePaths.setLabelText(Tr::tr("Show Paths in Relation to Active Project")); + relativePaths.setToolTip( + Tr::tr("Locator filters show relative paths to the active project when possible.")); + + refreshInterval.setSettingsKey("RefreshInterval"); + refreshInterval.setRange(0, 320); + refreshInterval.setSingleStep(5); + refreshInterval.setDefaultValue(60); + //: short for "minutes" + refreshInterval.setSuffix(Tr::tr(" min")); + refreshInterval.setLabelText(Tr::tr("Refresh interval:")); + refreshInterval.setToolTip( + Tr::tr( + "Locator filters that do not update their cached data immediately, such as the " + "custom directory filters, update it after this time interval.")); + + readSettings(); +} + +LocatorSettings &locatorSettings() +{ + static LocatorSettings theSettings; + return theSettings; +} class LocatorData { @@ -160,30 +198,7 @@ void Locator::aboutToShutdown() void Locator::loadSettings() { namespace DB = SettingsDatabase; - // check if we have to read old settings - // TOOD remove a few versions after 4.15 - const QString settingsGroup = DB::contains("Locator") ? QString("Locator") - : QString("QuickOpen"); - const Settings def; - DB::beginGroup(settingsGroup); - // TODO SettingsDatabase just for old settings from QtC < 16.0 - // when removed, the defaults need to move to the ICore::settings() code path below - { - m_refreshTimer.setInterval( - minutes(DB::value("RefreshInterval", int(def.refreshInterval / 1min)).toInt())); - m_settings.relativePaths = DB::value("RelativePaths", def.relativePaths).toBool(); - m_settings.useCenteredPopup = DB::value(kUseCenteredPopup, def.useCenteredPopup).toBool(); - } - ICore::settings()->withGroup("Locator", [this](QtcSettings *settings) { - m_refreshTimer.setInterval( - minutes(settings->value("RefreshInterval", refreshInterval()).toInt())); - m_settings.relativePaths - = settings->value("RelativePaths", m_settings.relativePaths).toBool(); - m_settings.useCenteredPopup - = settings->value(kUseCenteredPopup, m_settings.useCenteredPopup).toBool(); - m_settings.useTabCompletion - = settings->value(kUseTabCompletion, m_settings.useTabCompletion).toBool(); - }); + DB::beginGroup("Locator"); for (ILocatorFilter *filter : std::as_const(m_filters)) { if (DB::contains(filter->id().toString())) { @@ -215,8 +230,19 @@ void Locator::loadSettings() DB::endGroup(); DB::endGroup(); - if (m_refreshTimer.interval() > 0) + const auto updateTimer = [this] { + const int interval = locatorSettings().refreshInterval(); + if (interval < 1) { + m_refreshTimer.stop(); + m_refreshTimer.setInterval(0); + return; + } + m_refreshTimer.setInterval(minutes(interval)); m_refreshTimer.start(); + }; + locatorSettings().refreshInterval.addOnChanged(this, updateTimer); + updateTimer(); + m_settingsInitialized = true; setFilters(m_filters + customFilters); } @@ -305,17 +331,10 @@ void Locator::saveSettings() const if (!m_settingsInitialized) return; - const Settings def; namespace DB = SettingsDatabase; DB::beginTransaction(); DB::beginGroup("Locator"); DB::remove(QString()); - // TODO SettingsDatabase only for backward compatibility < 16.0 - { - DB::setValue("RefreshInterval", refreshInterval()); - DB::setValue("RelativePaths", relativePaths()); - DB::setValueWithDefault(kUseCenteredPopup, m_settings.useCenteredPopup, def.useCenteredPopup); - } for (ILocatorFilter *filter : m_filters) { if (!m_customFilters.contains(filter) && filter->id().isValid()) { const QByteArray state = filter->saveState(); @@ -337,15 +356,7 @@ void Locator::saveSettings() const DB::endGroup(); DB::endTransaction(); - ICore::settings()->withGroup("Locator", [this, &def](QtcSettings *settings) { - settings->setValueWithDefault( - "RefreshInterval", refreshInterval(), int(def.refreshInterval / 1min)); - settings->setValueWithDefault("RelativePaths", m_settings.relativePaths, def.relativePaths); - settings->setValueWithDefault( - kUseCenteredPopup, m_settings.useCenteredPopup, def.useCenteredPopup); - settings->setValueWithDefault( - kUseTabCompletion, m_settings.useTabCompletion, def.useTabCompletion); - }); + locatorSettings().writeSettings(); } /*! @@ -378,52 +389,6 @@ void Locator::setCustomFilters(QList<ILocatorFilter *> filters) m_customFilters = filters; } -int Locator::refreshInterval() const -{ - return m_refreshTimer.interval() / 60000; -} - -void Locator::setRefreshInterval(int interval) -{ - if (interval < 1) { - m_refreshTimer.stop(); - m_refreshTimer.setInterval(0); - return; - } - m_refreshTimer.setInterval(minutes(interval)); - m_refreshTimer.start(); -} - -bool Locator::relativePaths() const -{ - return m_settings.relativePaths; -} - -void Locator::setRelativePaths(bool use) -{ - m_settings.relativePaths = use; -} - -bool Locator::useCenteredPopupForShortcut() -{ - return m_instance->m_settings.useCenteredPopup; -} - -void Locator::setUseCenteredPopupForShortcut(bool center) -{ - m_instance->m_settings.useCenteredPopup = center; -} - -bool Locator::useTabCompletion() -{ - return m_instance->m_settings.useTabCompletion; -} - -void Locator::setUseTabCompletion(bool useTabCompletion) -{ - m_instance->m_settings.useTabCompletion = useTabCompletion; -} - void Locator::refresh(const QList<ILocatorFilter *> &filters) { if (ExtensionSystem::PluginManager::isShuttingDown()) diff --git a/src/plugins/coreplugin/locator/locator.h b/src/plugins/coreplugin/locator/locator.h index 670be56a48a..1bc36eab95c 100644 --- a/src/plugins/coreplugin/locator/locator.h +++ b/src/plugins/coreplugin/locator/locator.h @@ -7,6 +7,7 @@ #include "../actionmanager/command.h" #include <extensionsystem/iplugin.h> +#include <utils/aspects.h> #include <QtTaskTree/QSingleTaskTreeRunner> @@ -19,6 +20,18 @@ namespace Internal { class LocatorData; class LocatorWidget; +struct LocatorSettings : public Utils::AspectContainer +{ + LocatorSettings(); + + Utils::BoolAspect useCenteredPopup{this}; + Utils::BoolAspect useTabCompletion{this}; + Utils::BoolAspect relativePaths{this}; + Utils::IntegerAspect refreshInterval{this}; // minutes +}; + +LocatorSettings &locatorSettings(); + class Locator : public QObject { Q_OBJECT @@ -38,15 +51,6 @@ public: QList<ILocatorFilter *> customFilters(); void setFilters(QList<ILocatorFilter *> f); void setCustomFilters(QList<ILocatorFilter *> f); - int refreshInterval() const; - void setRefreshInterval(int interval); - bool relativePaths() const; - void setRelativePaths(bool use); - - static bool useCenteredPopupForShortcut(); - static void setUseCenteredPopupForShortcut(bool center); - static bool useTabCompletion(); - static void setUseTabCompletion(bool useTabCompletion); static void showFilter(ILocatorFilter *filter, LocatorWidget *widget); @@ -64,17 +68,8 @@ private: LocatorData *m_locatorData = nullptr; - struct Settings - { - bool useCenteredPopup = false; - bool useTabCompletion = true; - bool relativePaths = false; - // only for the default: - const std::chrono::minutes refreshInterval = std::chrono::minutes(60); - }; - bool m_settingsInitialized = false; - Settings m_settings; + LocatorSettings m_settings; QList<ILocatorFilter *> m_filters; QList<ILocatorFilter *> m_customFilters; QMap<Utils::Id, QAction *> m_filterActionMap; diff --git a/src/plugins/coreplugin/locator/locatormanager.cpp b/src/plugins/coreplugin/locator/locatormanager.cpp index 9b844065c65..26fd32f5775 100644 --- a/src/plugins/coreplugin/locator/locatormanager.cpp +++ b/src/plugins/coreplugin/locator/locatormanager.cpp @@ -35,7 +35,7 @@ static LocatorWidget *locatorWidget() // if that is a popup, try to find a better one if (window->windowFlags() & Qt::Popup && window->parentWidget()) window = window->parentWidget()->window(); - if (!Locator::useCenteredPopupForShortcut()) { + if (!locatorSettings().useCenteredPopup()) { if (auto *widget = Aggregation::query<LocatorWidget>(window)) { if (popup) popup->close(); diff --git a/src/plugins/coreplugin/locator/locatorsettingspage.cpp b/src/plugins/coreplugin/locator/locatorsettingspage.cpp index 8419b78f342..74ebd92c73a 100644 --- a/src/plugins/coreplugin/locator/locatorsettingspage.cpp +++ b/src/plugins/coreplugin/locator/locatorsettingspage.cpp @@ -259,24 +259,6 @@ public: auto addButton = new QPushButton(Tr::tr("Add...")); - auto refreshIntervalLabel = new QLabel(Tr::tr("Refresh interval:")); - refreshIntervalLabel->setToolTip( - Tr::tr("Locator filters that do not update their cached data immediately, such as the " - "custom directory filters, update it after this time interval.")); - - m_refreshInterval = new QSpinBox; - m_refreshInterval->setToolTip(refreshIntervalLabel->toolTip()); - m_refreshInterval->setSuffix(Tr::tr(" min")); - m_refreshInterval->setFrame(true); - m_refreshInterval->setButtonSymbols(QAbstractSpinBox::PlusMinus); - m_refreshInterval->setMaximum(320); - m_refreshInterval->setSingleStep(5); - m_refreshInterval->setValue(60); - - m_relativePaths = new QCheckBox(Tr::tr("Show Paths in Relation to Active Project")); - m_relativePaths->setToolTip( - Tr::tr("Locator filters show relative paths to the active project when possible.")); - auto filterEdit = new FancyLineEdit; filterEdit->setFiltering(true); @@ -316,6 +298,8 @@ public: m_editButton = new QPushButton(Tr::tr("Edit...")); m_editButton->setEnabled(false); + const LocatorSettings &settings = locatorSettings(); + using namespace Layouting; Column buttons{addButton, m_removeButton, m_editButton, st}; @@ -324,8 +308,10 @@ public: Grid { filterEdit, br, m_filterList, buttons, br, - Span(2, Row{refreshIntervalLabel, m_refreshInterval, st}), br, - Span(2, Row{m_relativePaths, st}) + Column { + Row {settings.refreshInterval, st}, + settings.relativePaths + } }.attachTo(this); // clang-format on @@ -360,8 +346,6 @@ public: }); addButton->setMenu(addMenu); - m_refreshInterval->setValue(m_plugin->refreshInterval()); - m_relativePaths->setChecked(m_plugin->relativePaths()); saveFilterStates(); } @@ -382,8 +366,6 @@ private: Utils::TreeView *m_filterList; QPushButton *m_removeButton; QPushButton *m_editButton; - QSpinBox *m_refreshInterval; - QCheckBox *m_relativePaths; Locator *m_plugin = nullptr; Utils::TreeModel<> *m_model = nullptr; QSortFilterProxyModel *m_proxyModel = nullptr; @@ -406,8 +388,7 @@ void LocatorSettingsWidget::apply() // Pass the new configuration on to the plugin m_plugin->setFilters(m_filters); m_plugin->setCustomFilters(m_customFilters); - m_plugin->setRefreshInterval(m_refreshInterval->value()); - m_plugin->setRelativePaths(m_relativePaths->isChecked()); + locatorSettings().apply(); requestRefresh(); m_plugin->saveSettings(); saveFilterStates(); diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 4eca0ab741f..cb238bb60c2 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -168,7 +168,7 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const if (index.column() == DisplayNameColumn) return m_entries.at(index.row()).displayName; if (index.column() == ExtraInfoColumn) { - if (Locator::instance()->relativePaths()) { + if (locatorSettings().relativePaths()) { return ICore::pathRelativeToActiveProject(FilePath::fromUserInput(m_entries.at(index.row()).extraInfo)).toUserOutput(); } else { return m_entries.at(index.row()).extraInfo; @@ -512,7 +512,7 @@ void CompletionList::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Tab: - if (Locator::useTabCompletion()) { + if (locatorSettings().useTabCompletion()) { emit completionRequested(currentIndex()); return; } @@ -576,8 +576,8 @@ bool CompletionList::eventFilter(QObject *watched, QEvent *event) LocatorWidget::LocatorWidget(Locator *locator) : m_locatorModel(new LocatorModel(this)) , m_filterMenu(new QMenu(this)) - , m_centeredPopupAction(new QAction(Tr::tr("Open as Centered Popup"), this)) - , m_useTabCompletion(new QAction(Tr::tr("Use Tab Completion"), this)) + , m_centeredPopupAction(new QAction(locatorSettings().useCenteredPopup.labelText(), this)) + , m_useTabCompletion(new QAction(locatorSettings().useTabCompletion.labelText(), this)) , m_refreshAction(new QAction(Tr::tr("Refresh"), this)) , m_configureAction(new QAction(ICore::msgShowOptionsDialog(), this)) , m_fileLineEdit(new FancyLineEdit) @@ -610,24 +610,26 @@ LocatorWidget::LocatorWidget(Locator *locator) this->installEventFilter(this); m_centeredPopupAction->setCheckable(true); - m_centeredPopupAction->setChecked(Locator::useCenteredPopupForShortcut()); + m_centeredPopupAction->setChecked(locatorSettings().useCenteredPopup()); m_useTabCompletion->setCheckable(true); - m_useTabCompletion->setChecked(Locator::useTabCompletion()); + m_useTabCompletion->setChecked(locatorSettings().useTabCompletion()); connect(m_filterMenu, &QMenu::aboutToShow, this, [this] { - m_centeredPopupAction->setChecked(Locator::useCenteredPopupForShortcut()); - m_useTabCompletion->setChecked(Locator::useTabCompletion()); + m_centeredPopupAction->setChecked(locatorSettings().useCenteredPopup()); + m_useTabCompletion->setChecked(locatorSettings().useTabCompletion()); }); Utils::addToolTipsToMenu(m_filterMenu); connect(m_centeredPopupAction, &QAction::toggled, locator, [locator](bool toggled) { - if (toggled != Locator::useCenteredPopupForShortcut()) { - Locator::setUseCenteredPopupForShortcut(toggled); + if (toggled != locatorSettings().useCenteredPopup()) { + locatorSettings().useCenteredPopup.setValue(toggled); QMetaObject::invokeMethod(locator, [] { LocatorManager::show({}); }); } }); - connect(m_useTabCompletion, &QAction::toggled, locator, &Locator::setUseTabCompletion); + connect(m_useTabCompletion, &QAction::toggled, locator, [](bool checked) { + locatorSettings().useTabCompletion.setValue(checked); + }); m_filterMenu->addAction(m_centeredPopupAction); m_filterMenu->addAction(m_useTabCompletion); diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 2a7de0a0095..67009dd517f 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -203,7 +203,7 @@ public: void cancel(); DebuggerTreeItem *currentTreeItem(); - void detectDebuggers(const IDeviceConstPtr &device); + void detectDebuggers(const IDeviceConstPtr &device, const FilePaths &searchPaths); void restoreDebuggers(); void saveDebuggers(); @@ -922,15 +922,15 @@ void DebuggerItemModel::restoreDebuggers() readDebuggers(userSettingsFileName(), false); // Auto detect current. - detectDebuggers(DeviceManager::defaultDesktopDevice()); + const IDeviceConstPtr desktopDevice = DeviceManager::defaultDesktopDevice(); + if (QTC_GUARD(desktopDevice)) + detectDebuggers(desktopDevice, desktopDevice->systemEnvironment().path()); } -void DebuggerItemModel::detectDebuggers(const IDeviceConstPtr &device) +void DebuggerItemModel::detectDebuggers(const IDeviceConstPtr &device, const FilePaths &searchPaths) { QTC_ASSERT(device, return); - const FilePaths searchPaths = Utils::transform( - device->systemEnvironment().path(), - [root = device->rootPath()](const FilePath &raw) { return root.withNewMappedPath(raw); }); + autoDetectGdbOrLldbDebuggers(searchPaths, {}); if (device->id() == ProjectExplorer::Constants::DESKTOP_DEVICE_ID) { autoDetectCdbDebuggers(); @@ -1222,7 +1222,11 @@ public: connect(m_delButton, &QAbstractButton::clicked, this, &DebuggerSettingsPageWidget::removeDebugger, Qt::QueuedConnection); connect(m_detectButton , &QAbstractButton::clicked, - this, [this] { itemModel().detectDebuggers(currentDevice()); }); + this, [this] { + const IDeviceConstPtr dev = currentDevice(); + QTC_ASSERT(dev, return); + itemModel().detectDebuggers(dev, dev->toolSearchPaths()); + }); m_deviceComboBox->setCurrentIndex( m_deviceModel->indexOf(DeviceManager::defaultDesktopDevice())); @@ -1235,6 +1239,11 @@ public: m_itemConfigWidget = new DebuggerItemConfigWidget; m_container->setWidget(m_itemConfigWidget); updateButtons(); + + connect(DeviceManager::instance(), &DeviceManager::toolDetectionRequested, this, + [](Id devId, const FilePaths &searchPaths) { + itemModel().detectDebuggers(DeviceManager::find(devId), searchPaths); + }); } void apply() final diff --git a/src/plugins/projectexplorer/buildsteplist.cpp b/src/plugins/projectexplorer/buildsteplist.cpp index d0badc4b5c4..b01cc1f3bf9 100644 --- a/src/plugins/projectexplorer/buildsteplist.cpp +++ b/src/plugins/projectexplorer/buildsteplist.cpp @@ -145,6 +145,13 @@ QList<BuildStep *> BuildStepList::steps() const return m_steps; } +QList<BuildStep *> BuildStepList::takeSteps() +{ + QList<BuildStep *> steps = m_steps; + m_steps.clear(); + return steps; +} + BuildStep *BuildStepList::firstStepWithId(Utils::Id id) const { return Utils::findOrDefault(m_steps, Utils::equal(&BuildStep::id, id)); diff --git a/src/plugins/projectexplorer/buildsteplist.h b/src/plugins/projectexplorer/buildsteplist.h index 6b49ee3095e..fe9f2905d68 100644 --- a/src/plugins/projectexplorer/buildsteplist.h +++ b/src/plugins/projectexplorer/buildsteplist.h @@ -28,6 +28,7 @@ public: void clear(); QList<BuildStep *> steps() const; + QList<BuildStep *> takeSteps(); template <class BS> BS *firstOfType() const { BS *bs = nullptr; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 4197a3b709c..8556a3d829c 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -296,6 +296,11 @@ bool IDevice::supportsFileTransferMethod(FileTransferMethod method) const return false; } +FilePaths IDevice::toolSearchPaths() const +{ + return d->autoDetectionPaths(); +} + IDevice::RecipeAndSearchPath IDevice::autoDetectDeviceToolsRecipe() { struct Data diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 2dacfa7e1a0..019c794d140 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -295,6 +295,7 @@ public: virtual bool supportsQtTargetDeviceType(const QSet<Utils::Id> &targetDeviceTypes) const; + Utils::FilePaths toolSearchPaths() const; class RecipeAndSearchPath { public: QtTaskTree::Group recipe; diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 5d023c93062..266dffff271 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1473,31 +1473,27 @@ Toolchains GccToolchainFactory::autoDetect(const ToolchainDetector &detector) co if (!m_autoDetecting) return {}; - const bool isLocal = detector.device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; + const FilePath rootPath = detector.device->rootPath(); + const OsType os = detector.device->osType(); FilePaths searchPaths = detector.searchPaths; - if (!isLocal) { - if (searchPaths.isEmpty()) - searchPaths = detector.device->systemEnvironment().path(); - searchPaths = Utils::transform(searchPaths, [&](const FilePath &onDevice) { - return detector.device->filePath(onDevice.path()); - }); - } else if (searchPaths.isEmpty()) { - searchPaths = Environment::systemEnvironment().path(); + if (searchPaths.isEmpty()) + searchPaths = detector.device->systemEnvironment().mappedPath(rootPath); + + if (os == OsTypeWindows) { searchPaths << gnuSearchPathsFromRegistry(); searchPaths << atmelSearchPathsFromRegistry(); searchPaths << renesasRl78SearchPathsFromRegistry(); - if (HostOsInfo::isMacHost()) { - searchPaths << "/opt/homebrew/opt/ccache/libexec" // homebrew arm - << "/usr/local/opt/ccache/libexec" // homebrew intel - << "/opt/local/libexec/ccache"; // macports, no links are created automatically though - } - if (HostOsInfo::isAnyUnixHost()) { - FilePath ccachePath = "/usr/lib/ccache/bin"; - if (!ccachePath.exists()) - ccachePath = "/usr/lib/ccache"; - if (ccachePath.exists() && !searchPaths.contains(ccachePath)) - searchPaths << ccachePath; - } + } else if (os == OsTypeMac) { + searchPaths << rootPath.withNewPath("/opt/homebrew/opt/ccache/libexec") // homebrew arm + << rootPath.withNewPath("/usr/local/opt/ccache/libexec") // homebrew intel + << rootPath.withNewPath("/opt/local/libexec/ccache"); // macports, no links are created automatically though + } + if (os == OsTypeMac || os == OsTypeLinux || os == OsTypeOtherUnix) { + FilePath ccachePath = rootPath.withNewPath("/usr/lib/ccache/bin"); + if (!ccachePath.exists()) + ccachePath = rootPath.withNewPath("/usr/lib/ccache"); + if (ccachePath.exists() && !searchPaths.contains(ccachePath)) + searchPaths << ccachePath; } FilePaths executables; @@ -1510,17 +1506,15 @@ Toolchains GccToolchainFactory::autoDetect(const ToolchainDetector &detector) co }, {nameFilters, QDir::Files | QDir::Executable }); // Gcc is almost never what you want on macOS, but it is by default found in /usr/bin - if (HostOsInfo::isMacHost() && detector.device->type() == Constants::DESKTOP_DEVICE_TYPE) { - executables.removeOne(FilePath::fromPathPart(u"/usr/bin/gcc")); - executables.removeOne(FilePath::fromPathPart(u"/usr/bin/g++")); - executables.removeOne(FilePath::fromPathPart(u"/usr/bin/llvm-gcc")); - executables.removeOne(FilePath::fromPathPart(u"/usr/bin/llvm-g++")); + if (detector.device->osType() == OsTypeMac) { + executables.removeOne(rootPath.withNewPath("/usr/bin/gcc")); + executables.removeOne(rootPath.withNewPath("/usr/bin/g++")); + executables.removeOne(rootPath.withNewPath("/usr/bin/llvm-gcc")); + executables.removeOne(rootPath.withNewPath("/usr/bin/llvm-g++")); } Utils::sort(executables); - const OsType os = detector.device->osType(); - Toolchains result; // Linux ICC @@ -1555,7 +1549,7 @@ Toolchains GccToolchainFactory::autoDetect(const ToolchainDetector &detector) co GccToolchain::Clang)); known.append(tcs); - if (isLocal) + if (detector.device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) tcs.append(autoDetectSdkClangToolchain(known)); result += tcs; diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 398faf010d6..fd56cfe3c6d 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1612,6 +1612,9 @@ public: static ClangClInfo getInfo(const FilePath &filePath); + friend bool operator==(const ClangClInfo &lhs, const ClangClInfo &rhs); + friend bool operator!=(const ClangClInfo &lhs, const ClangClInfo &rhs); + private: FilePath m_filePath; QVersionNumber m_version; @@ -2375,6 +2378,17 @@ ClangClInfo ClangClInfo::getInfo(const FilePath &filePath) return info ? *info : ClangClInfo(); } +bool operator==(const ClangClInfo &lhs, const ClangClInfo &rhs) +{ + return lhs.m_filePath == rhs.m_filePath && lhs.m_version == rhs.m_version + && lhs.m_defaultAbi == rhs.m_defaultAbi; +} + +bool operator!=(const ClangClInfo &lhs, const ClangClInfo &rhs) +{ + return !(lhs == rhs); +} + } // namespace ProjectExplorer::Internal Q_DECLARE_METATYPE(ProjectExplorer::Internal::MsvcToolchain::Platform) diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index a3803d086f7..43ee1286897 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -352,7 +352,7 @@ public: const Toolchains alreadyKnown; const IDeviceConstPtr device; - const Utils::FilePaths searchPaths; // If empty use device path and/or magic. + const Utils::FilePaths searchPaths; // If empty use PATH. }; class PROJECTEXPLORER_EXPORT ToolchainFactory diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp index a655f5c1bc3..f91599d4135 100644 --- a/src/plugins/projectexplorer/toolchainmanager.cpp +++ b/src/plugins/projectexplorer/toolchainmanager.cpp @@ -120,11 +120,7 @@ void ToolchainManager::restoreToolchains() if (!device) return; - // FIXME: ToolchainDetector needs extension to instruct downstream code to - // look at all possible combinations of PATH and explicit search paths, - // so that the settings from the device widget can be honored. - ToolchainDetector detector(m_instance->toolchains(), device, {}); - + ToolchainDetector detector(m_instance->toolchains(), device, device->toolSearchPaths()); Toolchains toRegister; for (ToolchainFactory *f : ToolchainFactory::allToolchainFactories()) { for (Toolchain * const tc : f->autoDetect(detector)) { diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index d56fbd0b06c..744f62681c1 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -531,8 +531,10 @@ void ToolChainOptionsWidget::redetectToolchains() ToolchainManager::resetBadToolchains(); // Step 2: Re-detect toolchains. + const IDeviceConstPtr device = currentDevice(); + QTC_ASSERT(device, return); for (ToolchainFactory *f : ToolchainFactory::allToolchainFactories()) { - const ToolchainDetector detector(knownTcs, currentDevice(), {}); // FIXME: Pass search paths + const ToolchainDetector detector(knownTcs, device, device->toolSearchPaths()); for (Toolchain * const tc : f->autoDetect(detector)) { if (knownTcs.contains(tc)) continue; diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index e00d16e7179..6c257aa2c90 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -151,22 +151,19 @@ class InterpreterDetailsWidget : public QWidget { Q_OBJECT public: - InterpreterDetailsWidget(QWidget *parent) - : QWidget(parent) - , m_name(new QLineEdit) - , m_executable(new PathChooser()) + InterpreterDetailsWidget() { - m_executable->setExpectedKind(PathChooser::ExistingCommand); - m_executable->setAllowPathFromDevice(true); + m_executable.setExpectedKind(PathChooser::ExistingCommand); + m_executable.setAllowPathFromDevice(true); - connect(m_name, &QLineEdit::textChanged, this, &InterpreterDetailsWidget::changed); - connect(m_executable, &PathChooser::textChanged, this, &InterpreterDetailsWidget::changed); + connect(&m_name, &QLineEdit::textChanged, this, &InterpreterDetailsWidget::changed); + connect(&m_executable, &PathChooser::textChanged, this, &InterpreterDetailsWidget::changed); using namespace Layouting; Form { - Tr::tr("Name:"), m_name, br, - Tr::tr("Executable"), m_executable, + Tr::tr("Name:"), &m_name, br, + Tr::tr("Executable"), &m_executable, noMargin }.attachTo(this); } @@ -175,18 +172,18 @@ public: { QSignalBlocker blocker(this); // do not emit changed when we change the controls here m_currentInterpreter = interpreter; - m_name->setText(interpreter.name); - m_executable->setFilePath(interpreter.command); + m_name.setText(interpreter.name); + m_executable.setFilePath(interpreter.command); } Interpreter toInterpreter() { - m_currentInterpreter.command = m_executable->filePath(); - m_currentInterpreter.name = m_name->text(); + m_currentInterpreter.command = m_executable.filePath(); + m_currentInterpreter.name = m_name.text(); return m_currentInterpreter; } - QLineEdit *m_name = nullptr; - PathChooser *m_executable = nullptr; + QLineEdit m_name; + PathChooser m_executable; Interpreter m_currentInterpreter; signals: @@ -210,13 +207,6 @@ public: } private: - QTreeView *m_view = nullptr; - InterpreterDetailsWidget *m_detailsWidget = nullptr; - QPushButton *m_deleteButton = nullptr; - QPushButton *m_makeDefaultButton = nullptr; - QPushButton *m_generateKitButton = nullptr; - QPushButton *m_cleanButton = nullptr; - void currentChanged(const QModelIndex &index, const QModelIndex &previous); void detailsChanged(); void updateCleanButton(); @@ -226,59 +216,64 @@ private: void makeDefault(); void generateKit(); void cleanUp(); + + QTreeView m_view; + InterpreterDetailsWidget m_detailsWidget; + QPushButton m_addButton; + QPushButton m_deleteButton; + QPushButton m_makeDefaultButton; + QPushButton m_generateKitButton; + QPushButton m_cleanButton; }; InterpreterOptionsWidget::InterpreterOptionsWidget() - : m_detailsWidget(new InterpreterDetailsWidget(this)) { - auto addButton = new QPushButton(Tr::tr("&Add"), this); + m_addButton.setText(Tr::tr("&Add")); - m_deleteButton = new QPushButton(Tr::tr("&Delete"), this); - m_deleteButton->setEnabled(false); - m_makeDefaultButton = new QPushButton(Tr::tr("&Make Default")); - m_makeDefaultButton->setEnabled(false); - m_generateKitButton = new QPushButton(Tr::tr("&Generate Kit")); - m_generateKitButton->setEnabled(false); + m_deleteButton.setText(Tr::tr("&Delete")); + m_deleteButton.setEnabled(false); + m_makeDefaultButton.setText(Tr::tr("&Make Default")); + m_makeDefaultButton.setEnabled(false); + m_generateKitButton.setText(Tr::tr("&Generate Kit")); + m_generateKitButton.setEnabled(false); - m_cleanButton = new QPushButton(Tr::tr("&Clean Up"), this); - m_cleanButton->setToolTip(Tr::tr("Remove all Python interpreters without a valid executable.")); - - m_view = new QTreeView(this); + m_cleanButton.setText(Tr::tr("&Clean Up")); + m_cleanButton.setToolTip(Tr::tr("Remove all Python interpreters without a valid executable.")); using namespace Layouting; - - Column buttons { - addButton, - m_deleteButton, - m_makeDefaultButton, - m_generateKitButton, - m_cleanButton, - st - }; - - Column { - Row { m_view, buttons }, - m_detailsWidget + Row { + Column { + m_view, + m_detailsWidget + }, + Column { + m_addButton, + m_deleteButton, + m_makeDefaultButton, + m_generateKitButton, + m_cleanButton, + st + } }.attachTo(this); updateCleanButton(); - m_detailsWidget->hide(); + m_detailsWidget.hide(); - m_view->setModel(&interpreterModel()); - m_view->setHeaderHidden(true); - m_view->setSelectionMode(QAbstractItemView::SingleSelection); - m_view->setSelectionBehavior(QAbstractItemView::SelectItems); + m_view.setModel(&interpreterModel()); + m_view.setHeaderHidden(true); + m_view.setSelectionMode(QAbstractItemView::SingleSelection); + m_view.setSelectionBehavior(QAbstractItemView::SelectItems); - connect(addButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::addItem); - connect(m_deleteButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::deleteItem); - connect(m_makeDefaultButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::makeDefault); - connect(m_generateKitButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::generateKit); - connect(m_cleanButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::cleanUp); + connect(&m_addButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::addItem); + connect(&m_deleteButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::deleteItem); + connect(&m_makeDefaultButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::makeDefault); + connect(&m_generateKitButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::generateKit); + connect(&m_cleanButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::cleanUp); - connect(m_detailsWidget, &InterpreterDetailsWidget::changed, + connect(&m_detailsWidget, &InterpreterDetailsWidget::changed, this, &InterpreterOptionsWidget::detailsChanged); - connect(m_view->selectionModel(), &QItemSelectionModel::currentChanged, + connect(m_view.selectionModel(), &QItemSelectionModel::currentChanged, this, &InterpreterOptionsWidget::currentChanged); } @@ -312,27 +307,27 @@ QList<Interpreter> InterpreterModel::interpreterFrom(const QString &detectionSou void InterpreterOptionsWidget::currentChanged(const QModelIndex &index, const QModelIndex &previous) { if (previous.isValid()) { - interpreterModel().itemAt(previous.row())->itemData = m_detailsWidget->toInterpreter(); + interpreterModel().itemAt(previous.row())->itemData = m_detailsWidget.toInterpreter(); emit interpreterModel().dataChanged(previous, previous); } if (index.isValid()) { const Interpreter interpreter = interpreterModel().itemAt(index.row())->itemData; - m_detailsWidget->updateInterpreter(interpreter); - m_detailsWidget->show(); + m_detailsWidget.updateInterpreter(interpreter); + m_detailsWidget.show(); updateGenerateKitButton(interpreter); } else { - m_detailsWidget->hide(); - m_generateKitButton->setEnabled(false); + m_detailsWidget.hide(); + m_generateKitButton.setEnabled(false); } - m_deleteButton->setEnabled(index.isValid()); - m_makeDefaultButton->setEnabled(index.isValid()); + m_deleteButton.setEnabled(index.isValid()); + m_makeDefaultButton.setEnabled(index.isValid()); } void InterpreterOptionsWidget::detailsChanged() { - const QModelIndex &index = m_view->currentIndex(); + const QModelIndex &index = m_view.currentIndex(); if (index.isValid()) { - const Interpreter interpreter = m_detailsWidget->toInterpreter(); + const Interpreter interpreter = m_detailsWidget.toInterpreter(); interpreterModel().itemAt(index.row())->itemData = interpreter; emit interpreterModel().dataChanged(index, index); updateGenerateKitButton(interpreter); @@ -342,7 +337,7 @@ void InterpreterOptionsWidget::detailsChanged() void InterpreterOptionsWidget::updateCleanButton() { - m_cleanButton->setEnabled(Utils::anyOf(interpreterModel().allData(), [](const Interpreter &interpreter) { + m_cleanButton.setEnabled(Utils::anyOf(interpreterModel().allData(), [](const Interpreter &interpreter) { return !interpreter.command.isExecutableFile(); })); } @@ -351,7 +346,7 @@ void InterpreterOptionsWidget::updateGenerateKitButton(const Interpreter &interp { bool enabled = !KitManager::kit(Id::fromString(interpreter.id)) && (!interpreter.command.isLocal() || interpreter.command.isExecutableFile()); - m_generateKitButton->setEnabled(enabled); + m_generateKitButton.setEnabled(enabled); } void InterpreterOptionsWidget::addItem() @@ -359,13 +354,13 @@ void InterpreterOptionsWidget::addItem() const QModelIndex &index = interpreterModel().indexForItem(interpreterModel().appendItem( {QUuid::createUuid().toString(), QString("Python"), FilePath(), DetectionSource::Manual})); QTC_ASSERT(index.isValid(), return); - m_view->setCurrentIndex(index); + m_view.setCurrentIndex(index); updateCleanButton(); } void InterpreterOptionsWidget::deleteItem() { - const QModelIndex &index = m_view->currentIndex(); + const QModelIndex &index = m_view.currentIndex(); if (index.isValid()) interpreterModel().destroyItem(interpreterModel().itemAt(index.row())); updateCleanButton(); @@ -533,7 +528,7 @@ static PyLSOptionsPage &pylspOptionsPage() void InterpreterOptionsWidget::makeDefault() { - const QModelIndex &index = m_view->currentIndex(); + const QModelIndex &index = m_view.currentIndex(); if (index.isValid()) { QModelIndex defaultIndex = interpreterModel().findIndex([](const Interpreter &interpreter) { return interpreter.id == s_defaultId; @@ -547,10 +542,10 @@ void InterpreterOptionsWidget::makeDefault() void InterpreterOptionsWidget::generateKit() { - const QModelIndex &index = m_view->currentIndex(); + const QModelIndex &index = m_view.currentIndex(); if (index.isValid()) PythonSettings::addKitsForInterpreter(interpreterModel().itemAt(index.row())->itemData, true); - m_generateKitButton->setEnabled(false); + m_generateKitButton.setEnabled(false); } void InterpreterOptionsWidget::cleanUp() diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index d33b5a69e41..7b34fce355c 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -175,6 +175,8 @@ QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target, Id id) QmakeBuildConfiguration::~QmakeBuildConfiguration() { + m_makeStepOnlyList.takeSteps(); + // BuildSystem might send signals during destruction before this QObject // had a chance to disconnect from it. disconnect(m_bsParsingFinishedConnection); @@ -338,6 +340,14 @@ void QmakeBuildConfiguration::setFileNodeBuild(FileNode *node) m_fileNodeBuild = node; } +BuildStepList *QmakeBuildConfiguration::makeStepOnlyList() +{ + m_makeStepOnlyList.takeSteps(); + if (const auto makeStep = buildSteps()->firstStepWithId(Constants::MAKESTEP_BS_ID)) + m_makeStepOnlyList.appendStep(makeStep); + return &m_makeStepOnlyList; +} + FilePath QmakeBuildConfiguration::makefile() const { return FilePath::fromString(qmakeBuildSystem()->rootProFile()->singleVariableValue(Variable::Makefile)); diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h index c969d8e0bed..69d3855dcd5 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h @@ -7,6 +7,8 @@ #include <projectexplorer/buildaspects.h> #include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/projectexplorerconstants.h> #include <qtsupport/baseqtversion.h> #include <qtsupport/qtbuildaspects.h> @@ -37,6 +39,8 @@ public: ProjectExplorer::FileNode *fileNodeBuild() const; void setFileNodeBuild(ProjectExplorer::FileNode *node); + ProjectExplorer::BuildStepList *makeStepOnlyList(); + QtSupport::QtVersion::QmakeBuildConfigs qmakeBuildConfiguration() const; void setQMakeBuildConfiguration(QtSupport::QtVersion::QmakeBuildConfigs config); @@ -133,6 +137,8 @@ private: QtSupport::QtVersion::QmakeBuildConfigs m_qmakeBuildConfiguration; QmakeProFileNode *m_subNodeBuild = nullptr; ProjectExplorer::FileNode *m_fileNodeBuild = nullptr; + ProjectExplorer::BuildStepList + m_makeStepOnlyList{this, ProjectExplorer::Constants::BUILDSTEPS_BUILD}; QMetaObject::Connection m_bsParsingFinishedConnection; }; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 2445a823c8d..7edd8609a9b 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1582,15 +1582,19 @@ void QmakeBuildSystem::buildHelper(Action action, bool isFileBuild, QmakeProFile bc->setSubNodeBuild(profile->proFileNode()); } - if (isFileBuild) + BuildStepList *buildSteps = bc->buildSteps(); + if (isFileBuild) { bc->setFileNodeBuild(buildableFile); + if (BuildStepList * const bsl = bc->makeStepOnlyList(); !bsl->isEmpty()) + buildSteps = bsl; + } if (ProjectExplorerPlugin::saveModifiedFiles()) { if (action == BUILD) - BuildManager::buildList(bc->buildSteps()); + BuildManager::buildList(buildSteps); else if (action == CLEAN) BuildManager::buildList(bc->cleanSteps()); else if (action == REBUILD) - BuildManager::buildLists({bc->cleanSteps(), bc->buildSteps()}); + BuildManager::buildLists({bc->cleanSteps(), buildSteps}); } bc->setSubNodeBuild(nullptr); diff --git a/src/plugins/qmldesigner/libs/designercore/model/model.cpp b/src/plugins/qmldesigner/libs/designercore/model/model.cpp index 3f43060c481..f40843b548e 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/model.cpp @@ -271,7 +271,7 @@ void ModelPrivate::setImports(Imports imports) projectStorage->synchronizeDocumentImports(std::move(imports), m_sourceId); } notifyImportsChanged(addedImports, removedImports); - updateModelNodeTypeIds(removedImports); + // updateModelNodeTypeIds(removedImports); // Crashes without USE_PROJECTSTORAGE } } diff --git a/src/plugins/saferenderer/saferenderer.qrc b/src/plugins/saferenderer/saferenderer.qrc index 84999a48aac..38bad272e12 100644 --- a/src/plugins/saferenderer/saferenderer.qrc +++ b/src/plugins/saferenderer/saferenderer.qrc @@ -15,5 +15,12 @@ <file>wizards/qsrapp2_1/qml.qrc.tpl</file> <file>wizards/qsrapp2_1/safeasset.qrc.tpl</file> <file>wizards/qsrapp2_1/wizard.json</file> + <file>wizards/qsrapp2_2/file.pro</file> + <file>wizards/qsrapp2_2/CMakeLists.txt</file> + <file>wizards/qsrapp2_2/main.cpp.tpl</file> + <file>wizards/qsrapp2_2/main.qml.tpl</file> + <file>wizards/qsrapp2_2/qml.qrc.tpl</file> + <file>wizards/qsrapp2_2/safeasset.qrc.tpl</file> + <file>wizards/qsrapp2_2/wizard.json</file> </qresource> </RCC> diff --git a/src/plugins/saferenderer/wizards/qsrapp2_1/CMakeLists.txt b/src/plugins/saferenderer/wizards/qsrapp2_1/CMakeLists.txt index e17daccd9c1..336e251c5a2 100644 --- a/src/plugins/saferenderer/wizards/qsrapp2_1/CMakeLists.txt +++ b/src/plugins/saferenderer/wizards/qsrapp2_1/CMakeLists.txt @@ -61,6 +61,11 @@ else() message(STATUS "Project is not linked with Qt when building for embedded systems.") endif() +install(TARGETS %{CMakeProjectName} + BUNDLE DESTINATION . + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + target_link_libraries(%{CMakeProjectName} PUBLIC Qt::SafeRenderer Qt::SafePlatformAdaptation diff --git a/src/plugins/saferenderer/wizards/qsrapp2_1/main.cpp.tpl b/src/plugins/saferenderer/wizards/qsrapp2_1/main.cpp.tpl index 80b45e04bb9..ac629c4ce6b 100644 --- a/src/plugins/saferenderer/wizards/qsrapp2_1/main.cpp.tpl +++ b/src/plugins/saferenderer/wizards/qsrapp2_1/main.cpp.tpl @@ -1,7 +1,4 @@ %{Cpp:LicenseTemplate}\ -%{JS: QtSupport.qtIncludes([ 'QtCore/QCoreApplication' ], - [ 'QtCore/QCoreApplication' ]) }\ - #include <QtSafeRenderer/qsafelayout.h> #include <QtSafeRenderer/qsafelayoutresourcereader.h> #include <QtSafeRenderer/statemanager.h> @@ -22,8 +19,8 @@ int main(int argc, char *argv[]) { - Q_UNUSED(argc); - Q_UNUSED(argv); + (void)argc; + (void)argv; static SafeRenderer::QSafeLayoutResourceReader layout("/layoutData/main/main.srl"); diff --git a/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json b/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json index ff0c0ab2240..0ce260b2f91 100644 --- a/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json +++ b/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project", "CMakeProjectManager.CMakeProject" ], "id": "E.QSRApp2_1", "category": "D.QtSafeRendererApplication", - "trDescription": "Creates a Qt Safe Renderer 2.1 (and newer) project with a simple UI and project setup.\n\nSupports both qmake and CMake.", + "trDescription": "Creates a Qt Safe Renderer 2.1 project with a simple UI and project setup.\n\nSupports both qmake and CMake.", "trDisplayName": "Qt Safe Renderer Application 2.1", "trDisplayCategory": "Application (Qt Safe Renderer)", "icon": "../icon.png", diff --git a/src/plugins/saferenderer/wizards/qsrapp2_2/CMakeLists.txt b/src/plugins/saferenderer/wizards/qsrapp2_2/CMakeLists.txt new file mode 100644 index 00000000000..336e251c5a2 --- /dev/null +++ b/src/plugins/saferenderer/wizards/qsrapp2_2/CMakeLists.txt @@ -0,0 +1,72 @@ +cmake_minimum_required(VERSION 3.16) +project(%{CMakeProjectName} LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) + +# Define the condition for HOST_BUILD +set(HOST_BUILD OFF) # Default to OFF + +if (NOT CMAKE_CROSSCOMPILING AND (NOT UNIX OR NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm|aarch64") OR APPLE)) + set(HOST_BUILD ON) +endif() + +find_package(Qt6 REQUIRED COMPONENTS Core Qml Quick SafeRenderer SafeRendererTools SafePlatformAdaptation) + +set(sources main.cpp +) + +set (safeqmls +"main.qml" +) + +# Resource files are passed to qtsafelayouttool +set(resource_files + "qml.qrc" +) + +#resource.bin is loaded by qtsafelayouttool to find the resource data asset. +qt6_add_binary_resources(resources_%{CMakeProjectName} ${resource_files} DESTINATION resource.bin) +qsr_add_safelayout(generatelayout_%{CMakeProjectName} SAFE_QMLS ${safeqmls} + OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/layoutData + SAFE_RESOURCE "${CMAKE_CURRENT_LIST_DIR}/safeasset.qrc" + INPUT_RESOURCES resource.bin) +qsr_add_resource(buildresource_%{CMakeProjectName} sources "${CMAKE_CURRENT_LIST_DIR}/safeasset.qrc") + +if (HOST_BUILD) + qt6_add_resources(sources ${resource_files}) +endif() + +add_executable(%{CMakeProjectName} WIN32 MACOSX_BUNDLE + ${sources} +) + +#Enable when using monitor feature: +#target_compile_definitions(%{CMakeProjectName} PRIVATE USE_OUTPUTVERIFIER) + +add_dependencies(%{CMakeProjectName} generatelayout_%{CMakeProjectName}) + +if (HOST_BUILD) + target_compile_definitions(%{CMakeProjectName} PUBLIC + HOST_BUILD + ) + + target_link_libraries(%{CMakeProjectName} PUBLIC + Qt::Quick + Qt::Widgets + Qt::Qml + ) +else() + message(STATUS "Project is not linked with Qt when building for embedded systems.") +endif() + +install(TARGETS %{CMakeProjectName} + BUNDLE DESTINATION . + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +target_link_libraries(%{CMakeProjectName} PUBLIC + Qt::SafeRenderer + Qt::SafePlatformAdaptation +) diff --git a/src/plugins/saferenderer/wizards/qsrapp2_2/file.pro b/src/plugins/saferenderer/wizards/qsrapp2_2/file.pro new file mode 100644 index 00000000000..6233d49b9cc --- /dev/null +++ b/src/plugins/saferenderer/wizards/qsrapp2_2/file.pro @@ -0,0 +1,46 @@ +QT = qtsaferenderer qsrplatformadaptation + +CONFIG += c++17 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \\ + %{CppFileName} + + +# List of language codes that your application supports. For example, SAFE_LANGUAGES = en fi. +#SAFE_LANGUAGES = en + +# List of translation file names excluding the language code. For example, SAFE_TRANSLATION = $$PWD/safeui. +#SAFE_TRANSLATION = $$PWD/safeui + +# List of translation file names including the language code. There must be one file +# for each language listed in SAFE_LANGUAGES. For example, TRANSLATIONS += safeui_en.ts safeui_fi.ts. +#TRANSLATIONS += safeui_en.ts + +# You can use an lupdate_only{...} conditional statement to specify the QML files that contain texts. +#lupdate_only { +# SOURCES += main.qml +#} + + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = $$PWD/imports + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + + +CONFIG += qtsaferenderer exceptions +SAFE_QML = $$PWD/main.qml +SAFE_LAYOUT_PATH = $$PWD/layoutData +SAFE_RESOURCES += safeasset.qrc + +!cross_compile: DEFINES += HOST_BUILD +!cross_compile: QT += widgets quick svg + +DISTFILES += main.qml diff --git a/src/plugins/saferenderer/wizards/qsrapp2_2/main.cpp.tpl b/src/plugins/saferenderer/wizards/qsrapp2_2/main.cpp.tpl new file mode 100644 index 00000000000..ae85076086d --- /dev/null +++ b/src/plugins/saferenderer/wizards/qsrapp2_2/main.cpp.tpl @@ -0,0 +1,59 @@ +%{Cpp:LicenseTemplate}\ +#include <QtSafeRenderer/qsafelayout.h> +#include <QtSafeRenderer/qsafelayoutresourcereader.h> +#include <QtSafeRenderer/statemanager.h> + +#if defined(HOST_BUILD) +#include <QGuiApplication> +#include <QQmlApplicationEngine> +#include <QQmlContext> +#endif + +#if defined(USE_OUTPUTVERIFIER) +#include <outputverifier.h> +#include <outputverifier_capi.h> +#endif + +#include "safewindow.h" +#include "eventhandler.h" + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + static SafeRenderer::QSafeLayoutResourceReader layout("/layoutData/main/main.srl"); + + SafeRenderer::SafeWindow telltaleWindow(layout.size(), SafeRenderer::QSafePoint(0U, 0U)); + +#if defined(USE_OUTPUTVERIFIER) + SafeRenderer::OutputVerifier &outputVerifier = SafeRenderer::OutputVerifier::getOutputVerifierInstance(); + OutputVerifier_initVerifierDevice(0, 0, layout.size().width(), layout.size().height()); +#endif + + static SafeRenderer::StateManager stateManager(telltaleWindow, layout); + telltaleWindow.requestUpdate(); //Request is required because eventHandler is not running yet. + +#if defined(USE_OUTPUTVERIFIER) + SafeRenderer::EventHandler msgHandler(stateManager, telltaleWindow, outputVerifier); +#else + SafeRenderer::EventHandler msgHandler(stateManager, telltaleWindow); +#endif + +#if defined(HOST_BUILD) + //Mixing the Qt and Qt Safe Renderer renderers is done here only for demonstration purposes on host, not for production purposes of any kind. + QQmlApplicationEngine engine; + const QUrl url(QStringLiteral("qrc:/main.qml")); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, qApp, + [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + qDebug() << "Failed to start the main.qml"; + }, Qt::QueuedConnection); + engine.addImportPath(":/imports"); + engine.load(url); +#endif + + msgHandler.handleEvents(); + + return 0; +} diff --git a/src/plugins/saferenderer/wizards/qsrapp2_2/main.qml.tpl b/src/plugins/saferenderer/wizards/qsrapp2_2/main.qml.tpl new file mode 100644 index 00000000000..115a6dcd4b5 --- /dev/null +++ b/src/plugins/saferenderer/wizards/qsrapp2_2/main.qml.tpl @@ -0,0 +1,25 @@ +import Qt.SafeRenderer +import QtQuick.Window + +Window { + id: window + width: 640 + height: 480 + visible: true + title: qsTr("Hello QSR") + + SafeText { + id: safeText + objectName: "safetextitem" + x: 206 + y: 208 + width: 380 + height: 50 + color: "#8ae234" + fillColor: "black" + text: "Hello Qt Safe Renderer!" + font.family: "Arial" + horizontalAlignment: Text.AlignLeft + font.pixelSize: 32 + } +} diff --git a/src/plugins/saferenderer/wizards/qsrapp2_2/qml.qrc.tpl b/src/plugins/saferenderer/wizards/qsrapp2_2/qml.qrc.tpl new file mode 100644 index 00000000000..5f6483ac33f --- /dev/null +++ b/src/plugins/saferenderer/wizards/qsrapp2_2/qml.qrc.tpl @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + </qresource> +</RCC> diff --git a/src/plugins/saferenderer/wizards/qsrapp2_2/safeasset.qrc.tpl b/src/plugins/saferenderer/wizards/qsrapp2_2/safeasset.qrc.tpl new file mode 100644 index 00000000000..601b61fc4c2 --- /dev/null +++ b/src/plugins/saferenderer/wizards/qsrapp2_2/safeasset.qrc.tpl @@ -0,0 +1,2 @@ +<!DOCTYPE RCC> +<RCC/> diff --git a/src/plugins/saferenderer/wizards/qsrapp2_2/wizard.json b/src/plugins/saferenderer/wizards/qsrapp2_2/wizard.json new file mode 100644 index 00000000000..3be081525de --- /dev/null +++ b/src/plugins/saferenderer/wizards/qsrapp2_2/wizard.json @@ -0,0 +1,115 @@ +{ + "version": 1, + "supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project", "CMakeProjectManager.CMakeProject" ], + "id": "E.QSRApp2_2", + "category": "D.QtSafeRendererApplication", + "trDescription": "Creates a Qt Safe Renderer 2.2 (and newer) project with a simple UI and project setup.\n\nSupports both qmake and CMake.", + "trDisplayName": "Qt Safe Renderer Application 2.2", + "trDisplayCategory": "Application (Qt Safe Renderer)", + "icon": "../icon.png", + "iconKind": "Themed", + "featuresRequired": [ "QtSupport.Wizards.FeatureQt" ], + "enabled": "%{JS: isAnyPluginRunning(['qmakeprojectmanager', 'cmakeprojectmanager'])}", + + "options": + [ + { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') == 'qmake' ? value('ProFile') : value('CMakeFile')}" }, + { "key": "CMakeProjectName", "value": "%{JS: value('ProjectName').replace(/-/g, '_')}" }, + { "key": "ProFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'pro')}" }, + { "key": "CMakeFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/CMakeLists.txt')}" }, + { "key": "HasTranslation", "value": "%{JS: value('TsFileName') !== ''}" }, + { "key": "CppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src')}" } + ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project", + "data": { "trDescription": "This wizard creates a simple Qt Safe Renderer application." } + }, + { + "trDisplayName": "Define Build System", + "trShortTitle": "Build System", + "typeId": "Fields", + "skipForSubprojects": true, + "data": + [ + { + "name": "BuildSystem", + "trDisplayName": "Build system:", + "type": "ComboBox", + "persistenceKey": "BuildSystemType", + "data": + { + "index": 1, + "items": + [ + { + "trKey": "qmake", + "value": "qmake", + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" + }, + { + "trKey": "cmake", + "value": "cmake", + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" + } + ] + } + } + ] + }, + { + "trDisplayName": "Kit Selection", + "trShortTitle": "Kits", + "typeId": "Kits", + "data": { "projectFilePath": "%{ProjectFile}" } + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "file.pro", + "target": "%{ProFile}", + "openAsProject": true, + "condition": "%{JS: value('BuildSystem') === 'qmake'}" + }, + { + "source": "CMakeLists.txt", + "target": "%{CMakeFile}", + "openAsProject": true, + "condition": "%{JS: value('BuildSystem') === 'cmake'}" + }, + { + "source": "main.cpp.tpl", + "target": "%{CppFileName}", + "openInEditor": false + }, + { + "source": "safeasset.qrc.tpl", + "target": "safeasset.qrc" + }, + { + "source": "qml.qrc.tpl", + "target": "qml.qrc" + }, + { + "source": "main.qml.tpl", + "target": "main.qml", + "openInEditor": true + } + ] + } + ] +} diff --git a/tests/manual/widgets/components/tst_manual_widgets_components.cpp b/tests/manual/widgets/components/tst_manual_widgets_components.cpp index ab322d8eded..0fe69665b35 100644 --- a/tests/manual/widgets/components/tst_manual_widgets_components.cpp +++ b/tests/manual/widgets/components/tst_manual_widgets_components.cpp @@ -41,7 +41,10 @@ QWidget *widgets() switchOff->setLayoutDirection(Qt::LeftToRight); auto tabBar = new QtcTabBar; - tabBar->addTab("Tab number 1"); + tabBar->setExpanding(false); + tabBar->setMovable(true); + tabBar->setTabsClosable(true); + tabBar->addTab("Tab 1"); tabBar->addTab("2"); tabBar->addTab("3"); |
