Merge remote-tracking branch 'origin/7.0'

Conflicts:
	cmake/QtCreatorIDEBranding.cmake
	qbs/modules/qtc/qtc.qbs
	qtcreator_ide_branding.pri
	src/plugins/studiowelcome/recentpresets.h
	src/plugins/studiowelcome/userpresets.h

Change-Id: Ie573b945eb28347a36ee1b3582fbd6ab0c0f866c
This commit is contained in:
Eike Ziller
2022-03-28 15:10:11 +02:00
62 changed files with 974 additions and 880 deletions

View File

@@ -190,6 +190,8 @@ Platforms
### Android ### Android
* Improved monitoring for connected devices by using `track-devices` command and
file watching instead of polling (QTCREATORBUG-23991)
* Added option for default NDK (QTCREATORBUG-21755, QTCREATORBUG-22389, * Added option for default NDK (QTCREATORBUG-21755, QTCREATORBUG-22389,
QTCREATORBUG-24248, QTCREATORBUG-26281) QTCREATORBUG-24248, QTCREATORBUG-26281)
* Fixed that `Include prebuilt OpenSSL libraries` could add it to the wrong * Fixed that `Include prebuilt OpenSSL libraries` could add it to the wrong

View File

@@ -185,13 +185,13 @@ void registerNodeInstanceMetaObject(QObject *object, QQmlEngine *engine)
QQuickDesignerSupportProperties::registerNodeInstanceMetaObject(object, engine); QQuickDesignerSupportProperties::registerNodeInstanceMetaObject(object, engine);
} }
static bool isQuickStyleItemMetaObject(const QMetaObject *metaObject) static bool isMetaObjectofType(const QMetaObject *metaObject, const QByteArray &type)
{ {
if (metaObject) { if (metaObject) {
if (metaObject->className() == QByteArrayLiteral("QQuickStyleItem")) if (metaObject->className() == type)
return true; return true;
return isQuickStyleItemMetaObject(metaObject->superClass()); return isMetaObjectofType(metaObject->superClass(), type);
} }
return false; return false;
@@ -200,7 +200,15 @@ static bool isQuickStyleItemMetaObject(const QMetaObject *metaObject)
static bool isQuickStyleItem(QObject *object) static bool isQuickStyleItem(QObject *object)
{ {
if (object) if (object)
return isQuickStyleItemMetaObject(object->metaObject()); return isMetaObjectofType(object->metaObject(), "QQuickStyleItem");
return false;
}
static bool isDelegateModel(QObject *object)
{
if (object)
return isMetaObjectofType(object->metaObject(), "QQmlDelegateModel");
return false; return false;
} }
@@ -400,7 +408,7 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta
doComponentCompleteRecursive(child, nodeInstanceServer); doComponentCompleteRecursive(child, nodeInstanceServer);
} }
if (!isQuickStyleItem(item)) { if (!isQuickStyleItem(object) && !isDelegateModel(object)) {
if (item) { if (item) {
static_cast<QQmlParserStatus *>(item)->componentComplete(); static_cast<QQmlParserStatus *>(item)->componentComplete();
} else { } else {

View File

@@ -665,15 +665,23 @@ Item {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
property bool allowTooltip: true
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onExited: tooltipBackend.hideTooltip() onExited: tooltipBackend.hideTooltip()
onCanceled: tooltipBackend.hideTooltip() onEntered: allowTooltip = true
onCanceled: {
tooltipBackend.hideTooltip()
allowTooltip = true
}
onPositionChanged: tooltipBackend.reposition() onPositionChanged: tooltipBackend.reposition()
onPressed: (mouse)=> { onPressed: (mouse)=> {
forceActiveFocus() forceActiveFocus()
allowTooltip = false
tooltipBackend.hideTooltip()
var ctrlDown = mouse.modifiers & Qt.ControlModifier var ctrlDown = mouse.modifiers & Qt.ControlModifier
if (mouse.button === Qt.LeftButton) { if (mouse.button === Qt.LeftButton) {
if (!root.selectedAssets[filePath] && !ctrlDown) if (!root.selectedAssets[filePath] && !ctrlDown)
@@ -698,12 +706,12 @@ Item {
root.contextDir = model.fileDir root.contextDir = model.fileDir
root.isDirContextMenu = false root.isDirContextMenu = false
tooltipBackend.hideTooltip()
contextMenu.popup() contextMenu.popup()
} }
} }
onReleased: (mouse)=> { onReleased: (mouse)=> {
allowTooltip = true
if (mouse.button === Qt.LeftButton) { if (mouse.button === Qt.LeftButton) {
if (!(mouse.modifiers & Qt.ControlModifier)) if (!(mouse.modifiers & Qt.ControlModifier))
root.selectedAssets = {} root.selectedAssets = {}
@@ -720,7 +728,7 @@ Item {
Timer { Timer {
interval: 1000 interval: 1000
running: mouseArea.containsMouse running: mouseArea.containsMouse && mouseArea.allowTooltip
onTriggered: { onTriggered: {
if (suffix === ".ttf" || suffix === ".otf") { if (suffix === ".ttf" || suffix === ".otf") {
tooltipBackend.name = fileName tooltipBackend.name = fileName

View File

@@ -88,6 +88,8 @@ Item {
onShowContextMenu: delegateRoot.showContextMenu() onShowContextMenu: delegateRoot.showContextMenu()
onPressed: (mouse)=> { onPressed: (mouse)=> {
allowTooltip = false
hide()
if (mouse.button === Qt.LeftButton) if (mouse.button === Qt.LeftButton)
rootView.startDragAndDrop(itemLibraryEntry, mapToGlobal(mouse.x, mouse.y)) rootView.startDragAndDrop(itemLibraryEntry, mapToGlobal(mouse.x, mouse.y))
} }

View File

@@ -222,6 +222,8 @@ ScrollView {
: Qt.ArrowCursor : Qt.ArrowCursor
onClicked: { onClicked: {
delegate.GridView.view.currentIndex = index
removePresetDialog.presetName = presetName.text removePresetDialog.presetName = presetName.text
removePresetDialog.open() removePresetDialog.open()
} }

View File

@@ -30,6 +30,8 @@ import HelperWidgets 2.0
MouseArea { MouseArea {
id: mouseArea id: mouseArea
property bool allowTooltip: true
signal showContextMenu() signal showContextMenu()
function hide() function hide()
@@ -38,7 +40,12 @@ MouseArea {
} }
onExited: tooltipBackend.hideTooltip() onExited: tooltipBackend.hideTooltip()
onCanceled: tooltipBackend.hideTooltip() onEntered: allowTooltip = true
onCanceled: {
tooltipBackend.hideTooltip()
allowTooltip = true
}
onReleased: allowTooltip = true
onPositionChanged: tooltipBackend.reposition() onPositionChanged: tooltipBackend.reposition()
onClicked: function(mouse) { onClicked: function(mouse) {
forceActiveFocus() forceActiveFocus()
@@ -51,7 +58,7 @@ MouseArea {
Timer { Timer {
interval: 1000 interval: 1000
running: mouseArea.containsMouse running: mouseArea.containsMouse && mouseArea.allowTooltip
onTriggered: { onTriggered: {
tooltipBackend.name = itemName tooltipBackend.name = itemName
tooltipBackend.path = componentPath tooltipBackend.path = componentPath

View File

@@ -27,7 +27,7 @@
Metadata { Metadata {
id: metadataFile id: metadataFile
defaultVersion: v20 defaultVersion: v21
VersionData { VersionData {
id: v14 id: v14
@@ -58,4 +58,10 @@ Metadata {
name: "Qt for MCUs 2.0" name: "Qt for MCUs 2.0"
path: "qul-20.qml" path: "qul-20.qml"
} }
VersionData {
id: v21
name: "Qt for MCUs 2.1"
path: "qul-21.qml"
}
} }

View File

@@ -0,0 +1,224 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
//differences from 2.0:
//text.elide is introduced in QUL
VersionData {
name: "Qt for MCUs 2.1"
bannedItems: ["QtQuick.AnimatedImage",
"QtQuick.FocusScope",
"QtQuick.TextInput",
"QtQuick.TextEdit",
"QtQuick.Flow",
"QtQuick.Grid",
"QtQuick.GridView",
"QtQuick.PathView",
"QtQuick.Loader",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
"QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
"QtQuick.Controls.ItemDelegate",
"QtQuick.Controls.Label",
"QtQuick.Controls.Page",
"QtQuick.Controls.PageIndicator",
"QtQuick.Controls.Pane",
"QtQuick.Controls.RadioDelegate",
"QtQuick.Controls.RangeSlider",
"QtQuick.Controls.RoundButton",
"QtQuick.Controls.ScrollView",
"QtQuick.Controls.SpinBox",
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
"QtQuick.Controls.ToolBar",
"QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
"QtQuick.Controls.ToolSeparator",
"QtQuick.Controls.Tumbler",
"QtQuick.Shapes.ConicalGradient",
"QtQuick.Shapes.LinearGradient",
"QtQuick.Shapes.RadialGradient",
"QtQuick.Shapes.ShapeGradient"]
allowedImports: ["QtQuick",
"QtQuick.Shapes",
"QtQuick.Controls",
"QtQuick.Timeline",
"QtQuickUltralite.Extras",
"QtQuickUltralite.Layers"]
bannedImports: ["FlowView"]
//ComplexProperty is not a type, it's just a way to handle bigger props
ComplexProperty {
prefix: "font"
bannedProperties: ["wordSpacing", "letterSpacing", "hintingPreference",
"kerning", "preferShaping", "capitalization",
"strikeout", "underline", "styleName"]
}
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
"rotation", "scale", "transformOrigin"]
}
QtQuick.Rectangle {
bannedProperties: ["gradient", "border"]
}
QtQuick.Flickable {
bannedProperties: ["boundsBehavior", "boundsMovement", "flickDeceleration",
"flickableDirection", "leftMargin", "rightMargin", "bottomMargin", "topMargin",
"originX", "originY", "pixelAligned", "pressDelay", "synchronousDrag"]
}
QtQuick.MouseArea {
bannedProperties: ["propagateComposedEvents", "preventStealing", "cursorShape",
"scrollGestureEnabled", "drag", "acceptedButtons", "hoverEnabled"]
}
QtQuick.Image {
allowChildren: false
allowedProperties: ["rotation", "scale", "transformOrigin"]
bannedProperties: ["mirror", "mipmap", "cache", "autoTransform", "asynchronous",
"sourceSize", "smooth"]
}
QtQuick.BorderImage {
bannedProperties: ["asynchronous", "cache", "currentFrame", "frameCount",
"horizontalTileMode", "mirror", "progress", "smooth", "sourceSize",
"status", "verticalTileMode"]
}
QtQuick.Text {
allowChildren: false
allowedProperties: ["rotation", "scale", "transformOrigin"]
bannedProperties: ["lineHeight", "lineHeightMode", "wrapMode", "style",
"styleColor", "minimumPointSize", "minimumPixelSize",
"fontSizeMode", "renderType", "renderTypeQuality", "textFormat", "maximumLineCount"]
}
//Padding is not an actual item, but rather set of properties in Text
Padding {
bannedProperties: ["bottomPadding", "topPadding", "leftPadding", "rightPadding"]
}
QtQuick.Column {
bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding"]
}
QtQuick.Row {
bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding",
"effectiveLayoutDirection", "layoutDirection"]
}
QtQuick.ListView {
bannedProperties: ["cacheBuffer", "highlightRangeMode", "highlightMoveDuration",
"highlightResizeDuration", "preferredHighlightBegin", "layoutDirection",
"preferredHighlightEnd", "highlightFollowsCurrentItem", "keyNavigationWraps",
"snapMode", "highlightMoveVelocity", "highlightResizeVelocity"]
}
QtQuick.Animation {
bannedProperties: ["paused"]
}
//Quick Controls2 Items and properties:
QtQuick.Controls.Control {
bannedProperties: ["focusPolicy", "hoverEnabled", "wheelEnabled"]
}
QtQuick.Controls.AbstractButton {
bannedProperties: ["display", "autoExclusive"]
}
QtQuick.Controls.ProgressBar {
bannedProperties: ["indeterminate"]
}
QtQuick.Controls.Slider {
bannedProperties: ["live", "snapMode", "touchDragThreshold"]
}
//Path and Shapes related:
QtQuick.Path {
bannedProperties: ["scale", "pathElements"]
}
QtQuick.PathArc {
bannedProperties: ["relativeX", "relativeY"]
}
QtQuick.PathLine {
bannedProperties: ["relativeX", "relativeY"]
}
QtQuick.PathMove {
bannedProperties: ["relativeX", "relativeY"]
}
QtQuick.PathQuad {
bannedProperties: ["relativeX", "relativeY",
"relativeControlX", "relativeControlY"]
}
QtQuick.PathCubic {
bannedProperties: ["relativeX", "relativeY",
"relativeControl1X", "relativeControl1Y",
"relativeControl2X", "relativeControl2Y"]
}
QtQuick.PathElement {
//nothing
}
QtQuick.PathSvg {
//nothing
}
QtQuick.Shapes.Shape {
bannedProperties: ["asynchronous", "containsMode", "data",
"renderType", "status", "vendorExtensionsEnabled"]
}
QtQuick.Shapes.ShapePath {
bannedProperties: ["dashOffset", "dashPattern",
"fillGradient", "strokeStyle"]
}
}

View File

@@ -161,7 +161,7 @@ FocusScope {
Text { Text {
text: "+" text: "+"
anchors.centerIn: parent anchors.centerIn: parent
anchors.verticalCenterOffset: -16 anchors.verticalCenterOffset: -(5 + (font.pixelSize - 35) / 9)
font.pixelSize: parent.height * .5 font.pixelSize: parent.height * .5
color: Qt.lighter(StudioTheme.Values.themeControlBackgroundInteraction, addState.containsMouse ? 1.5 : 1) color: Qt.lighter(StudioTheme.Values.themeControlBackgroundInteraction, addState.containsMouse ? 1.5 : 1)
} }

View File

@@ -570,7 +570,8 @@ public:
"x", "y", "opacity", "parent", "item", "flow", "x", "y", "opacity", "parent", "item", "flow",
"color", "margin", "padding", "print", "border", "font", "color", "margin", "padding", "print", "border", "font",
"text", "source", "state", "visible", "focus", "data", "text", "source", "state", "visible", "focus", "data",
"clip", "layer", "scale", "enabled", "anchors"}) "clip", "layer", "scale", "enabled", "anchors",
"texture", "shaderInfo", "sprite", "spriteSequence", "baseState"})
{} {}
}; };

View File

@@ -53,7 +53,10 @@ clang::format::FormatStyle qtcStyle()
style.Language = FormatStyle::LK_Cpp; style.Language = FormatStyle::LK_Cpp;
style.AccessModifierOffset = -4; style.AccessModifierOffset = -4;
style.AlignAfterOpenBracket = FormatStyle::BAS_Align; style.AlignAfterOpenBracket = FormatStyle::BAS_Align;
#if LLVM_VERSION_MAJOR >= 12 #if LLVM_VERSION_MAJOR >= 15
style.AlignConsecutiveAssignments = {false};
style.AlignConsecutiveDeclarations = {false};
#elif LLVM_VERSION_MAJOR >= 12
style.AlignConsecutiveAssignments = FormatStyle::ACS_None; style.AlignConsecutiveAssignments = FormatStyle::ACS_None;
style.AlignConsecutiveDeclarations = FormatStyle::ACS_None; style.AlignConsecutiveDeclarations = FormatStyle::ACS_None;
#else #else

View File

@@ -253,7 +253,7 @@ public:
{ {
const QByteArray ba = QByteArray::fromHex(rawData.toUtf8()); const QByteArray ba = QByteArray::fromHex(rawData.toUtf8());
const auto p = (const T*)ba.data(); const auto p = (const T*)ba.data();
for (int i = 0, n = ba.size() / sizeof(T); i < n; ++i) { for (int i = 0, n = int(ba.size() / sizeof(T)); i < n; ++i) {
auto child = new WatchItem; auto child = new WatchItem;
child->arrayIndex = i; child->arrayIndex = i;
child->value = decodeItemHelper(p[i]); child->value = decodeItemHelper(p[i]);

View File

@@ -276,6 +276,7 @@ extend_qtc_plugin(QmlDesigner
nameitemdelegate.cpp nameitemdelegate.h nameitemdelegate.cpp nameitemdelegate.h
navigator.qrc navigator.qrc
navigatormodelinterface.h navigatormodelinterface.h
navigatorsearchwidget.cpp navigatorsearchwidget.h
navigatortreemodel.cpp navigatortreemodel.h navigatortreemodel.cpp navigatortreemodel.h
navigatortreeview.cpp navigatortreeview.h navigatortreeview.cpp navigatortreeview.h
navigatorview.cpp navigatorview.h navigatorview.cpp navigatorview.h

View File

@@ -253,11 +253,8 @@ const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes()
return retList; return retList;
} }
AssetsLibraryModel::AssetsLibraryModel(SynchronousImageCache &fontImageCache, AssetsLibraryModel::AssetsLibraryModel(Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent)
Utils::FileSystemWatcher *fileSystemWatcher,
QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_fontImageCache(fontImageCache)
, m_fileSystemWatcher(fileSystemWatcher) , m_fileSystemWatcher(fileSystemWatcher)
{ {
// add role names // add role names

View File

@@ -47,9 +47,7 @@ class AssetsLibraryModel : public QAbstractListModel
Q_PROPERTY(bool isEmpty READ isEmpty WRITE setIsEmpty NOTIFY isEmptyChanged) Q_PROPERTY(bool isEmpty READ isEmpty WRITE setIsEmpty NOTIFY isEmptyChanged)
public: public:
AssetsLibraryModel(QmlDesigner::SynchronousImageCache &fontImageCache, AssetsLibraryModel(Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent = nullptr);
Utils::FileSystemWatcher *fileSystemWatcher,
QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -97,7 +95,6 @@ private:
void setIsEmpty(bool empty); void setIsEmpty(bool empty);
SynchronousImageCache &m_fontImageCache;
QHash<QString, QPair<QDateTime, QIcon>> m_iconCache; QHash<QString, QPair<QDateTime, QIcon>> m_iconCache;
QString m_searchText; QString m_searchText;

View File

@@ -117,7 +117,7 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache,
, m_fontImageCache(synchronousFontImageCache) , m_fontImageCache(synchronousFontImageCache)
, m_assetsIconProvider(new AssetsLibraryIconProvider(synchronousFontImageCache)) , m_assetsIconProvider(new AssetsLibraryIconProvider(synchronousFontImageCache))
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) , m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
, m_assetsModel(new AssetsLibraryModel(synchronousFontImageCache, m_fileSystemWatcher, this)) , m_assetsModel(new AssetsLibraryModel(m_fileSystemWatcher, this))
, m_assetsWidget(new QQuickWidget(this)) , m_assetsWidget(new QQuickWidget(this))
, m_imageCache{imageCache} , m_imageCache{imageCache}
{ {
@@ -130,11 +130,13 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache,
m_assetsWidget->installEventFilter(this); m_assetsWidget->installEventFilter(this);
m_fontPreviewTooltipBackend = std::make_unique<PreviewTooltipBackend>(asynchronousFontImageCache); m_fontPreviewTooltipBackend = std::make_unique<PreviewTooltipBackend>(asynchronousFontImageCache);
// We want font images to have custom size, so don't scale them in the tooltip
m_fontPreviewTooltipBackend->setScaleImage(false);
// Note: Though the text specified here appears in UI, it shouldn't be translated, as it's // Note: Though the text specified here appears in UI, it shouldn't be translated, as it's
// a commonly used sentence to preview the font glyphs in latin fonts. // a commonly used sentence to preview the font glyphs in latin fonts.
// For fonts that do not have latin glyphs, the font family name will have to suffice for preview. // For fonts that do not have latin glyphs, the font family name will have to suffice for preview.
m_fontPreviewTooltipBackend->setAuxiliaryData( m_fontPreviewTooltipBackend->setAuxiliaryData(
ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300}, ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 150},
Theme::getColor(Theme::DStextColor).name(), Theme::getColor(Theme::DStextColor).name(),
QStringLiteral("The quick brown fox jumps\n" QStringLiteral("The quick brown fox jumps\n"
"over the lazy dog\n" "over the lazy dog\n"

View File

@@ -126,7 +126,6 @@ QString AddImagesDialog::getDirectory(const QStringList &fileNames, const QStrin
setDirectoryForComboBox(newDir); setDirectoryForComboBox(newDir);
}); });
mainLayout->addWidget(new QLabel(QCoreApplication::translate("AddImageToResources", "In directory:")), 1, 0);
mainLayout->addWidget(directoryComboBox, 1, 0, 1, 3); mainLayout->addWidget(directoryComboBox, 1, 0, 1, 3);
mainLayout->addWidget(browseButton, 1, 3, 1 , 1); mainLayout->addWidget(browseButton, 1, 3, 1 , 1);

View File

@@ -45,6 +45,7 @@ public:
virtual void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) = 0; virtual void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) = 0;
virtual void notifyIconsChanged() = 0; virtual void notifyIconsChanged() = 0;
virtual void setFilter(bool showObjects) = 0; virtual void setFilter(bool showObjects) = 0;
virtual void setNameFilter(const QString &filter) = 0;
virtual void setOrder(bool reverse) = 0; virtual void setOrder(bool reverse) = 0;
virtual void resetModel() = 0; virtual void resetModel() = 0;
}; };

View File

@@ -0,0 +1,66 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "navigatorsearchwidget.h"
#include <utils/stylehelper.h>
#include <theme.h>
#include <QBoxLayout>
#include <QLabel>
#include <QPushButton>
namespace QmlDesigner {
NavigatorSearchWidget::NavigatorSearchWidget(QWidget *parent)
: QWidget(parent)
{
auto layout = new QBoxLayout(QBoxLayout::LeftToRight);
setLayout(layout);
const QString fontName = "qtds_propertyIconFont.ttf";
const int iconSize = 15;
const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::IconsBaseColor));
const QIcon searchIcon = Utils::StyleHelper::getIconFromIconFont(
fontName, QmlDesigner::Theme::getIconUnicode(QmlDesigner::Theme::Icon::search),
iconSize, iconSize, iconColor);
m_textField = new QLineEdit;
m_textField->setPlaceholderText(tr("Filter"));
m_textField->setFrame(false);
m_textField->setClearButtonEnabled(true);
m_textField->addAction(searchIcon, QLineEdit::LeadingPosition);
connect(m_textField, &QLineEdit::textChanged, this, &NavigatorSearchWidget::textChanged);
layout->addWidget(m_textField);
}
void NavigatorSearchWidget::clear()
{
m_textField->clear();
}
} // QmlDesigner

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QLineEdit>
namespace QmlDesigner {
class NavigatorSearchWidget : public QWidget
{
Q_OBJECT
public:
NavigatorSearchWidget(QWidget *parent = nullptr);
void clear();
signals:
void textChanged(const QString &text);
private:
QLineEdit *m_textField;
};
} //QmlDesigner

View File

@@ -324,14 +324,25 @@ QList<ModelNode> NavigatorTreeModel::filteredList(const NodeListProperty &proper
return it.value(); return it.value();
QList<ModelNode> list; QList<ModelNode> list;
QList<ModelNode> propertyNodes = property.toModelNodeList();
QList<ModelNode> nameFilteredList;
if (m_nameFilter.isEmpty()) {
nameFilteredList = propertyNodes;
} else {
nameFilteredList.append(Utils::filtered(propertyNodes, [&] (const ModelNode &arg){
const bool value = m_nameFilteredList.contains(arg);
return value;
}));
}
if (filter) { if (filter) {
list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { list.append(Utils::filtered(nameFilteredList, [] (const ModelNode &arg) {
const bool value = QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); const bool value = QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator();
return value; return value;
})); }));
} else { } else {
list = property.toModelNodeList(); list = nameFilteredList;
} }
appendForcedNodes(property, list); appendForcedNodes(property, list);
@@ -1222,6 +1233,35 @@ void NavigatorTreeModel::setFilter(bool showOnlyVisibleItems)
resetModel(); resetModel();
} }
void NavigatorTreeModel::setNameFilter(const QString &filter)
{
m_nameFilter = filter;
m_rowCache.clear();
ModelNode rootNode = m_view->rootModelNode();
QList<ModelNode> allNodes = rootNode.allSubModelNodes();
m_nameFilteredList.clear();
if (filter.isEmpty()) {
m_nameFilteredList = allNodes;
} else {
for (ModelNode &node : rootNode.allSubModelNodes()) {
if (node.displayName().contains(filter, Qt::CaseSensitivity::CaseInsensitive)) {
m_nameFilteredList.append(node);
ModelNode n = node;
while (n.hasParentProperty()) {
n = n.parentProperty().parentModelNode();
if (n.isRootNode() || m_nameFilteredList.contains(n))
break;
m_nameFilteredList.append(n);
}
}
}
}
resetModel();
}
void NavigatorTreeModel::setOrder(bool reverseItemOrder) void NavigatorTreeModel::setOrder(bool reverseItemOrder)
{ {
m_reverseItemOrder = reverseItemOrder; m_reverseItemOrder = reverseItemOrder;

View File

@@ -101,6 +101,7 @@ public:
void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) override; void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) override;
void notifyIconsChanged() override; void notifyIconsChanged() override;
void setFilter(bool showOnlyVisibleItems) override; void setFilter(bool showOnlyVisibleItems) override;
void setNameFilter(const QString &filter) override;
void setOrder(bool reverseItemOrder) override; void setOrder(bool reverseItemOrder) override;
void resetModel() override; void resetModel() override;
@@ -140,6 +141,8 @@ private:
bool m_showOnlyVisibleItems = true; bool m_showOnlyVisibleItems = true;
bool m_reverseItemOrder = false; bool m_reverseItemOrder = false;
DesignerActionManager *m_actionManager = nullptr; DesignerActionManager *m_actionManager = nullptr;
QString m_nameFilter;
QList<ModelNode> m_nameFilteredList;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -293,8 +293,15 @@ void NavigatorTreeView::mousePressEvent(QMouseEvent *event)
void NavigatorTreeView::startDrag(Qt::DropActions supportedActions) void NavigatorTreeView::startDrag(Qt::DropActions supportedActions)
{ {
if (m_dragAllowed) if (m_dragAllowed) {
if (m_previewToolTip) {
// Workaround to ensure tooltip doesn't linger during drag, as drag grabs all mouse
// events on some platforms (e.g. mac)
m_previewToolTip->hide();
m_previewToolTipNodeId = -1;
}
QTreeView::startDrag(supportedActions); QTreeView::startDrag(supportedActions);
}
} }
} }

View File

@@ -151,6 +151,8 @@ void NavigatorView::modelAttached(Model *model)
treeView->setIndentation(20); treeView->setIndentation(20);
m_currentModelInterface->setFilter(false); m_currentModelInterface->setFilter(false);
m_currentModelInterface->setNameFilter("");
m_widget->clearSearch();
QTimer::singleShot(0, this, [this, treeView]() { QTimer::singleShot(0, this, [this, treeView]() {
m_currentModelInterface->setFilter( m_currentModelInterface->setFilter(
@@ -575,6 +577,12 @@ void NavigatorView::reverseOrderToggled(bool flag)
DesignerSettings::setValue(DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, flag); DesignerSettings::setValue(DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, flag);
} }
void NavigatorView::textFilterChanged(const QString &text)
{
m_treeModel->setNameFilter(text);
treeWidget()->expandAll();
}
void NavigatorView::changeSelection(const QItemSelection & /*newSelection*/, const QItemSelection &/*deselected*/) void NavigatorView::changeSelection(const QItemSelection & /*newSelection*/, const QItemSelection &/*deselected*/)
{ {
if (m_blockSelectionChangedSignal) if (m_blockSelectionChangedSignal)
@@ -703,6 +711,8 @@ void NavigatorView::setupWidget()
connect(m_widget.data(), &NavigatorWidget::filterToggled, this, &NavigatorView::filterToggled); connect(m_widget.data(), &NavigatorWidget::filterToggled, this, &NavigatorView::filterToggled);
connect(m_widget.data(), &NavigatorWidget::reverseOrderToggled, this, &NavigatorView::reverseOrderToggled); connect(m_widget.data(), &NavigatorWidget::reverseOrderToggled, this, &NavigatorView::reverseOrderToggled);
connect(m_widget.data(), &NavigatorWidget::textFilterChanged, this, &NavigatorView::textFilterChanged);
#ifndef QMLDESIGNER_TEST #ifndef QMLDESIGNER_TEST
const QString fontName = "qtds_propertyIconFont.ttf"; const QString fontName = "qtds_propertyIconFont.ttf";
const QSize size = QSize(28, 28); const QSize size = QSize(28, 28);

View File

@@ -118,6 +118,8 @@ private:
void filterToggled(bool); void filterToggled(bool);
void reverseOrderToggled(bool); void reverseOrderToggled(bool);
void textFilterChanged(const QString &text);
protected: //functions protected: //functions
QTreeView *treeWidget() const; QTreeView *treeWidget() const;
NavigatorTreeModel *treeModel(); NavigatorTreeModel *treeModel();

View File

@@ -23,6 +23,7 @@
** **
****************************************************************************/ ****************************************************************************/
#include "navigatorsearchwidget.h"
#include "navigatorwidget.h" #include "navigatorwidget.h"
#include "navigatorview.h" #include "navigatorview.h"
@@ -160,6 +161,10 @@ QToolBar *NavigatorWidget::createToolBar()
for (auto toolButton : buttons) for (auto toolButton : buttons)
toolBar->addWidget(toolButton); toolBar->addWidget(toolButton);
m_searchWidget = new NavigatorSearchWidget();
connect(m_searchWidget, &NavigatorSearchWidget::textChanged, this, &NavigatorWidget::textFilterChanged);
toolBar->addWidget(m_searchWidget);
return toolBar; return toolBar;
} }
@@ -211,4 +216,9 @@ QByteArray NavigatorWidget::dragType() const
return m_dragType; return m_dragType;
} }
void NavigatorWidget::clearSearch()
{
m_searchWidget->clear();
}
} }

View File

@@ -39,6 +39,7 @@ QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
namespace QmlDesigner { namespace QmlDesigner {
class NavigatorView; class NavigatorView;
class NavigatorSearchWidget;
class NavigatorWidget: public QFrame class NavigatorWidget: public QFrame
{ {
@@ -59,6 +60,8 @@ public:
void setDragType(const QByteArray &type); void setDragType(const QByteArray &type);
QByteArray dragType() const; QByteArray dragType() const;
void clearSearch();
signals: signals:
void leftButtonClicked(); void leftButtonClicked();
void rightButtonClicked(); void rightButtonClicked();
@@ -66,6 +69,7 @@ signals:
void downButtonClicked(); void downButtonClicked();
void filterToggled(bool); void filterToggled(bool);
void reverseOrderToggled(bool); void reverseOrderToggled(bool);
void textFilterChanged(const QString &name);
protected: protected:
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
@@ -77,6 +81,7 @@ private:
NavigatorTreeView *m_treeView; NavigatorTreeView *m_treeView;
QPointer<NavigatorView> m_navigatorView; QPointer<NavigatorView> m_navigatorView;
QByteArray m_dragType; QByteArray m_dragType;
NavigatorSearchWidget *m_searchWidget;
}; };
} }

View File

@@ -62,10 +62,16 @@ void PreviewImageTooltip::setInfo(const QString &info)
m_ui->infoLabel->setText(info); m_ui->infoLabel->setText(info);
} }
void PreviewImageTooltip::setImage(const QImage &image) void PreviewImageTooltip::setImage(const QImage &image, bool scale)
{ {
m_ui->imageLabel->setPixmap(QPixmap::fromImage({image}).scaled(m_ui->imageLabel->width(), QPixmap pm = QPixmap::fromImage({image});
m_ui->imageLabel->height(), if (scale) {
Qt::KeepAspectRatio)); m_ui->imageLabel->setPixmap(pm.scaled(m_ui->imageLabel->width(),
m_ui->imageLabel->height(),
Qt::KeepAspectRatio));
} else {
m_ui->imageLabel->setPixmap(pm);
}
} }
} }

View File

@@ -46,7 +46,7 @@ public:
void setName(const QString &name); void setName(const QString &name);
void setPath(const QString &path); void setPath(const QString &path);
void setInfo(const QString &info); void setInfo(const QString &info);
void setImage(const QImage &pixmap); void setImage(const QImage &image, bool scale = true);
private: private:
std::unique_ptr<Ui::PreviewImageTooltip> m_ui; std::unique_ptr<Ui::PreviewImageTooltip> m_ui;

View File

@@ -55,10 +55,10 @@ void PreviewTooltipBackend::showTooltip()
m_cache.requestImage( m_cache.requestImage(
m_path, m_path,
[tooltip = QPointer<PreviewImageTooltip>(m_tooltip.get())](const QImage &image) { [tooltip = QPointer<PreviewImageTooltip>(m_tooltip.get()), scaleImage = m_scaleImage](const QImage &image) {
QMetaObject::invokeMethod(tooltip, [tooltip, image] { QMetaObject::invokeMethod(tooltip, [tooltip, image, scaleImage] {
if (tooltip) { if (tooltip) {
tooltip->setImage(image); tooltip->setImage(image, scaleImage);
tooltip->show(); tooltip->show();
} }
}); });
@@ -126,9 +126,10 @@ QString PreviewTooltipBackend::name() const
void PreviewTooltipBackend::setName(const QString &name) void PreviewTooltipBackend::setName(const QString &name)
{ {
m_name = name; if (m_name != name) {
if (m_name != name) m_name = name;
emit nameChanged(); emit nameChanged();
}
} }
QString PreviewTooltipBackend::path() const QString PreviewTooltipBackend::path() const
@@ -138,9 +139,10 @@ QString PreviewTooltipBackend::path() const
void PreviewTooltipBackend::setPath(const QString &path) void PreviewTooltipBackend::setPath(const QString &path)
{ {
m_path = path; if (m_path != path) {
if (m_path != path) m_path = path;
emit pathChanged(); emit pathChanged();
}
} }
QString PreviewTooltipBackend::info() const QString PreviewTooltipBackend::info() const
@@ -150,9 +152,10 @@ QString PreviewTooltipBackend::info() const
void PreviewTooltipBackend::setInfo(const QString &info) void PreviewTooltipBackend::setInfo(const QString &info)
{ {
m_info = info; if (m_info != info) {
if (m_info != info) m_info = info;
emit infoChanged(); emit infoChanged();
}
} }
QString PreviewTooltipBackend::extraId() const QString PreviewTooltipBackend::extraId() const
@@ -163,9 +166,23 @@ QString PreviewTooltipBackend::extraId() const
// Sets the imageCache extraId hint. Valid content depends on image cache collector used. // Sets the imageCache extraId hint. Valid content depends on image cache collector used.
void PreviewTooltipBackend::setExtraId(const QString &extraId) void PreviewTooltipBackend::setExtraId(const QString &extraId)
{ {
m_extraId = extraId; if (m_extraId != extraId) {
if (m_extraId != extraId) m_extraId = extraId;
emit extraIdChanged(); emit extraIdChanged();
}
}
bool PreviewTooltipBackend::scaleImage() const
{
return m_scaleImage;
}
void PreviewTooltipBackend::setScaleImage(bool scale)
{
if (m_scaleImage != scale) {
m_scaleImage = scale;
emit scaleImageChanged();
}
} }
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -45,6 +45,7 @@ class PreviewTooltipBackend : public QObject
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(QString info READ info WRITE setInfo NOTIFY infoChanged) Q_PROPERTY(QString info READ info WRITE setInfo NOTIFY infoChanged)
Q_PROPERTY(QString extraId READ extraId WRITE setExtraId NOTIFY extraIdChanged) Q_PROPERTY(QString extraId READ extraId WRITE setExtraId NOTIFY extraIdChanged)
Q_PROPERTY(bool scaleImage READ scaleImage WRITE setScaleImage NOTIFY scaleImageChanged)
public: public:
PreviewTooltipBackend(AsynchronousImageCache &cache); PreviewTooltipBackend(AsynchronousImageCache &cache);
@@ -62,6 +63,8 @@ public:
void setInfo(const QString &info); void setInfo(const QString &info);
QString extraId() const; QString extraId() const;
void setExtraId(const QString &extraId); void setExtraId(const QString &extraId);
bool scaleImage() const;
void setScaleImage(bool scale);
bool isVisible() const; bool isVisible() const;
@@ -75,12 +78,14 @@ signals:
void pathChanged(); void pathChanged();
void infoChanged(); void infoChanged();
void extraIdChanged(); void extraIdChanged();
void scaleImageChanged();
private: private:
QString m_name; QString m_name;
QString m_path; QString m_path;
QString m_info; QString m_info;
QString m_extraId; QString m_extraId;
bool m_scaleImage = true;
std::unique_ptr<PreviewImageTooltip> m_tooltip; std::unique_ptr<PreviewImageTooltip> m_tooltip;
ImageCache::AuxiliaryData m_auxiliaryData; ImageCache::AuxiliaryData m_auxiliaryData;
AsynchronousImageCache &m_cache; AsynchronousImageCache &m_cache;

View File

@@ -227,6 +227,8 @@ ModelNode TransitionEditorView::addNewTransition()
const QString targetId = target.id(); const QString targetId = target.id();
for (const VariantProperty &property : change.modelNode().variantProperties()) { for (const VariantProperty &property : change.modelNode().variantProperties()) {
TypeName typeName = target.metaInfo().propertyTypeName(property.name()); TypeName typeName = target.metaInfo().propertyTypeName(property.name());
if (typeName.startsWith("<cpp>."))
typeName.remove(0, 6);
if (validProperties.contains(typeName)) if (validProperties.contains(typeName))
locList.append(QString::fromUtf8(property.name())); locList.append(QString::fromUtf8(property.name()));

View File

@@ -131,7 +131,7 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
auto &&auxiliaryData = Utils::get<ImageCache::FontCollectorSizeAuxiliaryData>(auxiliaryDataValue); auto &&auxiliaryData = Utils::get<ImageCache::FontCollectorSizeAuxiliaryData>(auxiliaryDataValue);
QColor textColor = auxiliaryData.colorName; QColor textColor = auxiliaryData.colorName;
QSize size = auxiliaryData.size; QSize size = auxiliaryData.size;
QString text = font.family() + "\n\n" + auxiliaryData.text; QString text = font.family() + "\n" + auxiliaryData.text;
QImage image = createFontImage(text, textColor, font, size); QImage image = createFontImage(text, textColor, font, size);

View File

@@ -565,9 +565,11 @@ void NodeInstanceView::nodeReparented(const ModelNode &node, const NodeAbstractP
// Reset puppet when particle emitter/affector is reparented to work around issue in // Reset puppet when particle emitter/affector is reparented to work around issue in
// autodetecting the particle system it belongs to. QTBUG-101157 // autodetecting the particle system it belongs to. QTBUG-101157
if ((node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D") // Reset is also needed when particle shapes are reparented. QTBUG-101882
|| node.isSubclassOf("QtQuick.Particles3D.Affector3D")) if (((node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D")
&& node.property("system").toBindingProperty().expression().isEmpty()) { || node.isSubclassOf("QtQuick.Particles3D.Affector3D"))
&& node.property("system").toBindingProperty().expression().isEmpty())
|| node.isSubclassOf("QQuick3DParticleAbstractShape")) {
resetPuppet(); resetPuppet();
} }
} }

View File

@@ -97,6 +97,9 @@ static TypeName resolveTypeName(const ASTPropertyReference *ref, const ContextPt
if (const CppComponentValue * componentObjectValue = value->asCppComponentValue()) { if (const CppComponentValue * componentObjectValue = value->asCppComponentValue()) {
type = componentObjectValue->className().toUtf8(); type = componentObjectValue->className().toUtf8();
dotProperties = getObjectTypes(componentObjectValue, context); dotProperties = getObjectTypes(componentObjectValue, context);
} else if (const ObjectValue * objectValue = value->asObjectValue()) {
type = objectValue->className().toUtf8();
dotProperties = getObjectTypes(objectValue, context);
} }
if (type == "alias") { if (type == "alias") {

View File

@@ -42,7 +42,7 @@ DocumentMessage::DocumentMessage(Exception *exception):
m_line(exception->line()), m_line(exception->line()),
m_column(-1), m_column(-1),
m_description(exception->description()), m_description(exception->description()),
m_url(exception->file()) m_url(QUrl::fromLocalFile(exception->file()))
{ {
} }
@@ -84,14 +84,14 @@ QString DocumentMessage::toString() const
if (line() != -1) { if (line() != -1) {
if (!str.isEmpty()) if (!str.isEmpty())
str += QLatin1Char(' '); str += QLatin1Char(' ');
str += ::QmlDesigner::DocumentMessage::tr("line %1").arg(line()); str += ::QmlDesigner::DocumentMessage::tr("line %1\n").arg(line());
} }
if (column() != -1) { if (column() != -1) {
if (!str.isEmpty()) if (!str.isEmpty())
str += QLatin1Char(' '); str += QLatin1Char(' ');
str += ::QmlDesigner::DocumentMessage::tr("column %1").arg(column()); str += ::QmlDesigner::DocumentMessage::tr("column %1\n").arg(column());
} }
if (!str.isEmpty()) if (!str.isEmpty())

View File

@@ -335,7 +335,8 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
if (!newQmlObjectNode.isValid()) if (!newQmlObjectNode.isValid())
return; return;
newQmlObjectNode.modelNode().setIdWithoutRefactoring(view->model()->generateNewId(itemLibraryEntry.name())); if (newQmlObjectNode.id().isEmpty())
newQmlObjectNode.modelNode().setIdWithoutRefactoring(view->model()->generateNewId(itemLibraryEntry.name()));
for (const auto &propertyBindingEntry : propertyBindingList) for (const auto &propertyBindingEntry : propertyBindingList)
newQmlObjectNode.modelNode().bindingProperty(propertyBindingEntry.first).setExpression(propertyBindingEntry.second); newQmlObjectNode.modelNode().bindingProperty(propertyBindingEntry.first).setExpression(propertyBindingEntry.second);

View File

@@ -680,6 +680,8 @@ Project {
"navigator/nameitemdelegate.cpp", "navigator/nameitemdelegate.cpp",
"navigator/nameitemdelegate.h", "navigator/nameitemdelegate.h",
"navigator/navigator.qrc", "navigator/navigator.qrc",
"navigator/navigatorsearchwidget.cpp",
"navigator/navigatorsearchwidget.h",
"navigator/navigatortreemodel.cpp", "navigator/navigatortreemodel.cpp",
"navigator/navigatortreemodel.h", "navigator/navigatortreemodel.h",
"navigator/navigatortreeview.cpp", "navigator/navigatortreeview.cpp",

View File

@@ -235,8 +235,6 @@ QString QmlProjectRunConfiguration::commandLineArguments() const
if (!main.isEmpty()) if (!main.isEmpty())
ProcessArgs::addArg(&args, main, osType); ProcessArgs::addArg(&args, main, osType);
if (m_multiLanguageAspect && m_multiLanguageAspect->value())
ProcessArgs::addArg(&args, "-qmljsdebugger=file:unused_if_debugger_arguments_added,services:DebugTranslation", osType);
return args; return args;
} }

View File

@@ -13,7 +13,6 @@ add_qtc_plugin(StudioWelcome
wizardfactories.cpp wizardfactories.h wizardfactories.cpp wizardfactories.h
createproject.cpp createproject.h createproject.cpp createproject.h
wizardhandler.cpp wizardhandler.h wizardhandler.cpp wizardhandler.h
recentpresets.cpp recentpresets.h
userpresets.cpp userpresets.h userpresets.cpp userpresets.h
screensizemodel.h screensizemodel.h
algorithm.h algorithm.h

View File

@@ -42,6 +42,16 @@ template<typename C, typename F>
return it == end ? nullopt : make_optional(*it); return it == end ? nullopt : make_optional(*it);
} }
template<typename C>
[[nodiscard]] bool containsItem(const C &container, const typename C::value_type &item)
{
auto begin = std::cbegin(container);
auto end = std::cend(container);
auto it = std::find(begin, end, item);
return it == end ? false : true;
}
///////// FILTER ///////// FILTER
template<typename C, typename T = typename C::value_type> template<typename C, typename T = typename C::value_type>
[[nodiscard]] C filterOut(const C &container, const T &value = T()) [[nodiscard]] C filterOut(const C &container, const T &value = T())
@@ -67,13 +77,14 @@ void concat(C &out, const SC &container)
} }
template<typename C, typename T> template<typename C, typename T>
void erase_one(C &container, const T &value) bool erase_one(C &container, const T &value)
{ {
typename C::const_iterator i = std::find(std::cbegin(container), std::cend(container), value); typename C::const_iterator i = std::find(std::cbegin(container), std::cend(container), value);
if (i == std::cend(container)) if (i == std::cend(container))
return; return false;
container.erase(i); container.erase(i);
return true;
} }
template<typename C, typename T> template<typename C, typename T>

View File

@@ -47,7 +47,7 @@ QString PresetData::recentsTabName()
void PresetData::setData(const PresetsByCategory &presetsByCategory, void PresetData::setData(const PresetsByCategory &presetsByCategory,
const std::vector<UserPresetData> &userPresetsData, const std::vector<UserPresetData> &userPresetsData,
const std::vector<RecentPresetData> &loadedRecentsData) const std::vector<UserPresetData> &loadedRecentsData)
{ {
QTC_ASSERT(!presetsByCategory.empty(), return ); QTC_ASSERT(!presetsByCategory.empty(), return );
m_recents = loadedRecentsData; m_recents = loadedRecentsData;
@@ -60,16 +60,13 @@ void PresetData::setData(const PresetsByCategory &presetsByCategory,
PresetItems wizardPresets = Utils::flatten(m_presets); PresetItems wizardPresets = Utils::flatten(m_presets);
PresetItems userPresetItems = makeUserPresets(wizardPresets); PresetItems userPresetItems = makeUserPresets(wizardPresets, m_userPresets);
if (!userPresetItems.empty()) { if (!userPresetItems.empty()) {
m_categories.push_back(CustomTabName); m_categories.push_back(CustomTabName);
m_presets.push_back(userPresetItems); m_presets.push_back(userPresetItems);
} }
PresetItems allWizardPresets = std::move(wizardPresets); PresetItems recentPresets = makeUserPresets(wizardPresets, m_recents);
Utils::concat(allWizardPresets, userPresetItems);
PresetItems recentPresets = makeRecentPresets(allWizardPresets);
if (!recentPresets.empty()) { if (!recentPresets.empty()) {
Utils::prepend(m_categories, RecentsTabName); Utils::prepend(m_categories, RecentsTabName);
Utils::prepend(m_presets, recentPresets); Utils::prepend(m_presets, recentPresets);
@@ -79,7 +76,7 @@ void PresetData::setData(const PresetsByCategory &presetsByCategory,
} }
void PresetData::reload(const std::vector<UserPresetData> &userPresetsData, void PresetData::reload(const std::vector<UserPresetData> &userPresetsData,
const std::vector<RecentPresetData> &loadedRecentsData) const std::vector<UserPresetData> &loadedRecentsData)
{ {
m_categories.clear(); m_categories.clear();
m_presets.clear(); m_presets.clear();
@@ -96,11 +93,12 @@ std::shared_ptr<PresetItem> PresetData::findPresetItemForUserPreset(const UserPr
}); });
} }
PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets) PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets,
const std::vector<UserPresetData> &data)
{ {
PresetItems result; PresetItems result;
for (const UserPresetData &userPresetData : m_userPresets) { for (const UserPresetData &userPresetData : data) {
std::shared_ptr<PresetItem> foundPreset = findPresetItemForUserPreset(userPresetData, std::shared_ptr<PresetItem> foundPreset = findPresetItemForUserPreset(userPresetData,
wizardPresets); wizardPresets);
if (!foundPreset) if (!foundPreset)
@@ -128,35 +126,6 @@ PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets)
return result; return result;
} }
std::shared_ptr<PresetItem> PresetData::findPresetItemForRecent(const RecentPresetData &recent, const PresetItems &wizardPresets)
{
return Utils::findOrDefault(wizardPresets, [&recent](const std::shared_ptr<PresetItem> &item) {
bool sameName = item->categoryId == recent.category
&& item->displayName() == recent.presetName;
bool sameType = (recent.isUserPreset ? item->isUserPreset() : !item->isUserPreset());
return sameName && sameType;
});
}
PresetItems PresetData::makeRecentPresets(const PresetItems &wizardPresets)
{
PresetItems result;
for (const RecentPresetData &recent : m_recents) {
std::shared_ptr<PresetItem> preset = findPresetItemForRecent(recent, wizardPresets);
if (preset) {
auto clone = std::shared_ptr<PresetItem>{preset->clone()};
clone->screenSizeName = recent.sizeName;
result.push_back(clone);
}
}
return result;
}
/****************** BasePresetModel ******************/ /****************** BasePresetModel ******************/
BasePresetModel::BasePresetModel(const PresetData *data, QObject *parent) BasePresetModel::BasePresetModel(const PresetData *data, QObject *parent)

View File

@@ -33,7 +33,6 @@
#include <utils/optional.h> #include <utils/optional.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include "recentpresets.h"
#include "userpresets.h" #include "userpresets.h"
namespace Utils { namespace Utils {
@@ -169,10 +168,10 @@ class PresetData
{ {
public: public:
void reload(const std::vector<UserPresetData> &userPresets, void reload(const std::vector<UserPresetData> &userPresets,
const std::vector<RecentPresetData> &loadedRecents); const std::vector<UserPresetData> &loadedRecents);
void setData(const PresetsByCategory &presets, void setData(const PresetsByCategory &presets,
const std::vector<UserPresetData> &userPresets, const std::vector<UserPresetData> &userPresets,
const std::vector<RecentPresetData> &recents); const std::vector<UserPresetData> &recents);
const std::vector<PresetItems> &presets() const { return m_presets; } const std::vector<PresetItems> &presets() const { return m_presets; }
const Categories &categories() const { return m_categories; } const Categories &categories() const { return m_categories; }
@@ -180,16 +179,13 @@ public:
static QString recentsTabName(); static QString recentsTabName();
private: private:
PresetItems makeRecentPresets(const PresetItems &wizardPresets); PresetItems makeUserPresets(const PresetItems &wizardPresets, const std::vector<UserPresetData> &data);
PresetItems makeUserPresets(const PresetItems &wizardPresets);
std::shared_ptr<PresetItem> findPresetItemForUserPreset(const UserPresetData &preset, const PresetItems &wizardPresets); std::shared_ptr<PresetItem> findPresetItemForUserPreset(const UserPresetData &preset, const PresetItems &wizardPresets);
std::shared_ptr<PresetItem> findPresetItemForRecent(const RecentPresetData &recent, const PresetItems &wizardPresets);
private: private:
std::vector<PresetItems> m_presets; std::vector<PresetItems> m_presets;
Categories m_categories; Categories m_categories;
std::vector<RecentPresetData> m_recents; std::vector<UserPresetData> m_recents;
std::vector<UserPresetData> m_userPresets; std::vector<UserPresetData> m_userPresets;
PresetsByCategory m_presetsByCategory; PresetsByCategory m_presetsByCategory;
}; };

View File

@@ -72,10 +72,14 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
, m_presetModel{new PresetModel(&m_presetData, this)} , m_presetModel{new PresetModel(&m_presetData, this)}
, m_screenSizeModel{new ScreenSizeModel(this)} , m_screenSizeModel{new ScreenSizeModel(this)}
, m_styleModel{new StyleModel(this)} , m_styleModel{new StyleModel(this)}
, m_recentsStore{Core::ICore::settings()} , m_recentsStore{"RecentPresets.json", StorePolicy::UniqueValues}
, m_userPresetsStore{"UserPresets.json", StorePolicy::UniqueNames}
{ {
setParent(m_dialog); setParent(m_dialog);
m_recentsStore.setReverseOrder();
m_recentsStore.setMaximum(10);
m_dialog->setResizeMode(QQuickWidget::SizeRootObjectToView); // SizeViewToRootObject m_dialog->setResizeMode(QQuickWidget::SizeRootObjectToView); // SizeViewToRootObject
m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"), m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"),
new Internal::NewProjectDialogImageProvider()); new Internal::NewProjectDialogImageProvider());
@@ -190,8 +194,11 @@ void QdsNewDialog::updateScreenSizes()
void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandardItemModel *styleModel) void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandardItemModel *styleModel)
{ {
m_screenSizeModel->setBackendModel(screenSizeModel); if (screenSizeModel)
m_styleModel->setBackendModel(styleModel); m_screenSizeModel->setBackendModel(screenSizeModel);
if (styleModel)
m_styleModel->setBackendModel(styleModel);
auto userPreset = m_currentPreset->asUserPreset(); auto userPreset = m_currentPreset->asUserPreset();
@@ -326,7 +333,7 @@ void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
WizardFactories factories{factories_, m_dialog, platform}; WizardFactories factories{factories_, m_dialog, platform};
std::vector<RecentPresetData> recents = m_recentsStore.fetchAll(); std::vector<UserPresetData> recents = m_recentsStore.fetchAll();
std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll(); std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
m_presetData.setData(factories.presetsGroupedByCategory(), userPresets, recents); m_presetData.setData(factories.presetsGroupedByCategory(), userPresets, recents);
@@ -360,33 +367,13 @@ void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
* sure that all events have occurred before we go ahead and configure the wizard. * sure that all events have occurred before we go ahead and configure the wizard.
*/ */
auto userPreset = m_currentPreset->asUserPreset(); /* onWizardCreated will have been called by this time, as a result of m_presetModel->reset(),
* but at that time the Details and Styles panes haven't been loaded yet - only the backend
* models loaded. We call it again, cause at this point those panes are now loaded, and we can
* set them up.
*/
if (m_qmlDetailsLoaded) { onWizardCreated(nullptr, nullptr);
updateScreenSizes();
if (m_wizard.haveTargetQtVersion()) {
int index = (userPreset ? m_wizard.targetQtVersionIndex(userPreset->qtVersion)
: m_wizard.targetQtVersionIndex());
if (index != -1)
setTargetQtVersionIndex(index);
}
if (m_wizard.haveVirtualKeyboard() && userPreset)
setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard);
emit haveVirtualKeyboardChanged();
emit haveTargetQtVersionChanged();
}
if (m_qmlStylesLoaded && m_wizard.haveStyleModel()) {
if (userPreset) {
int index = m_wizard.styleIndex(userPreset->styleName);
if (index != -1)
setStyleIndex(index);
}
m_styleModel->reset();
}
} }
QString QdsNewDialog::recentsTabName() const QString QdsNewDialog::recentsTabName() const
@@ -431,7 +418,8 @@ void QdsNewDialog::accept()
std::shared_ptr<PresetItem> item = m_wizard.preset(); std::shared_ptr<PresetItem> item = m_wizard.preset();
QString customSizeName = m_qmlCustomWidth + " x " + m_qmlCustomHeight; QString customSizeName = m_qmlCustomWidth + " x " + m_qmlCustomHeight;
m_recentsStore.add(item->categoryId, item->displayName(), customSizeName, item->isUserPreset()); UserPresetData preset = currentUserPresetData(m_currentPreset->displayName());
m_recentsStore.save(preset);
m_dialog->close(); m_dialog->close();
m_dialog->deleteLater(); m_dialog->deleteLater();
@@ -471,7 +459,7 @@ void QdsNewDialog::setSelectedPreset(int selection)
} }
} }
void QdsNewDialog::savePresetDialogAccept() UserPresetData QdsNewDialog::currentUserPresetData(const QString &displayName) const
{ {
QString screenSize = m_qmlCustomWidth + " x " + m_qmlCustomHeight; QString screenSize = m_qmlCustomWidth + " x " + m_qmlCustomHeight;
QString targetQtVersion = ""; QString targetQtVersion = "";
@@ -489,12 +477,19 @@ void QdsNewDialog::savePresetDialogAccept()
UserPresetData preset = {m_currentPreset->categoryId, UserPresetData preset = {m_currentPreset->categoryId,
m_currentPreset->wizardName, m_currentPreset->wizardName,
m_qmlPresetName, displayName,
screenSize, screenSize,
useVirtualKeyboard, useVirtualKeyboard,
targetQtVersion, targetQtVersion,
styleName}; styleName};
return preset;
}
void QdsNewDialog::savePresetDialogAccept()
{
UserPresetData preset = currentUserPresetData(m_qmlPresetName);
if (!m_userPresetsStore.save(preset)) { if (!m_userPresetsStore.save(preset)) {
QMessageBox::warning(m_dialog, QMessageBox::warning(m_dialog,
tr("Save Preset"), tr("Save Preset"),
@@ -503,7 +498,7 @@ void QdsNewDialog::savePresetDialogAccept()
} }
// reload model // reload model
std::vector<RecentPresetData> recents = m_recentsStore.fetchAll(); std::vector<UserPresetData> recents = m_recentsStore.fetchAll();
std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll(); std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
m_presetData.reload(userPresets, recents); m_presetData.reload(userPresets, recents);
@@ -520,8 +515,8 @@ void QdsNewDialog::removeCurrentPreset()
} }
// remove preset & reload model // remove preset & reload model
std::vector<RecentPresetData> recents = m_recentsStore.remove(m_currentPreset->categoryId, UserPresetData currentPreset = currentUserPresetData(m_qmlPresetName);
m_currentPreset->displayName()); std::vector<UserPresetData> recents = m_recentsStore.remove(currentPreset);
auto userPreset = m_currentPreset->asUserPreset(); auto userPreset = m_currentPreset->asUserPreset();
m_userPresetsStore.remove(userPreset->categoryId, userPreset->displayName()); m_userPresetsStore.remove(userPreset->categoryId, userPreset->displayName());

View File

@@ -34,7 +34,6 @@
#include "presetmodel.h" #include "presetmodel.h"
#include "screensizemodel.h" #include "screensizemodel.h"
#include "stylemodel.h" #include "stylemodel.h"
#include "recentpresets.h"
#include "userpresets.h" #include "userpresets.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -153,6 +152,7 @@ private:
void updateScreenSizes(); void updateScreenSizes();
bool eventFilter(QObject *obj, QEvent *ev) override; bool eventFilter(QObject *obj, QEvent *ev) override;
UserPresetData currentUserPresetData(const QString &displayName) const;
private slots: private slots:
void onDeletingWizard(); void onDeletingWizard();
@@ -194,7 +194,7 @@ private:
std::shared_ptr<PresetItem> m_currentPreset; std::shared_ptr<PresetItem> m_currentPreset;
WizardHandler m_wizard; WizardHandler m_wizard;
RecentPresetsStore m_recentsStore; UserPresetsStore m_recentsStore;
UserPresetsStore m_userPresetsStore; UserPresetsStore m_userPresetsStore;
}; };

View File

@@ -1,152 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "recentpresets.h"
#include "algorithm.h"
#include <QRegularExpression>
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <utils/qtcsettings.h>
using namespace StudioWelcome;
constexpr char GROUP_NAME[] = "RecentPresets";
constexpr char WIZARDS[] = "Wizards";
void RecentPresetsStore::add(const QString &categoryId,
const QString &name,
const QString &sizeName,
bool isUserPreset)
{
std::vector<RecentPresetData> existing = fetchAll();
std::vector<RecentPresetData> recents
= addRecentToExisting(RecentPresetData{categoryId, name, sizeName, isUserPreset}, existing);
save(recents);
}
void RecentPresetsStore::save(const std::vector<RecentPresetData> &recents)
{
QStringList encodedRecents = encodeRecentPresets(recents);
m_settings->beginGroup(GROUP_NAME);
m_settings->setValue(WIZARDS, encodedRecents);
m_settings->endGroup();
m_settings->sync();
}
std::vector<RecentPresetData> RecentPresetsStore::remove(const QString &categoryId, const QString &presetName)
{
std::vector<RecentPresetData> recents = fetchAll();
size_t countBefore = recents.size();
/* NOTE: when removing one preset, it may happen that there are more than one recent for that
* preset. In that case, we need to remove all associated recents, for the preset.*/
Utils::erase(recents, [&](const RecentPresetData &p) {
return p.category == categoryId && p.presetName == presetName;
});
if (recents.size() < countBefore)
save(recents);
return recents;
}
std::vector<RecentPresetData> RecentPresetsStore::addRecentToExisting(
const RecentPresetData &preset, std::vector<RecentPresetData> &recents)
{
Utils::erase_one(recents, preset);
Utils::prepend(recents, preset);
if (int(recents.size()) > m_max)
recents.pop_back();
return recents;
}
std::vector<RecentPresetData> RecentPresetsStore::fetchAll() const
{
m_settings->beginGroup(GROUP_NAME);
QVariant value = m_settings->value(WIZARDS);
m_settings->endGroup();
std::vector<RecentPresetData> result;
if (value.type() == QVariant::String)
result.push_back(decodeOneRecentPreset(value.toString()));
else if (value.type() == QVariant::StringList)
Utils::concat(result, decodeRecentPresets(value.toList()));
const RecentPresetData empty;
return Utils::filtered(result, [&empty](const RecentPresetData &recent) { return recent != empty; });
}
QStringList RecentPresetsStore::encodeRecentPresets(const std::vector<RecentPresetData> &recents)
{
return Utils::transform<QList>(recents, [](const RecentPresetData &p) -> QString {
QString name = p.presetName;
if (p.isUserPreset)
name.prepend("[U]");
return p.category + "/" + name + ":" + p.sizeName;
});
}
RecentPresetData RecentPresetsStore::decodeOneRecentPreset(const QString &encoded)
{
QRegularExpression pattern{R"(^(\S+)/(.+):(\d+ x \d+)$)"};
auto m = pattern.match(encoded);
if (!m.hasMatch())
return RecentPresetData{};
QString category = m.captured(1);
QString name = m.captured(2);
QString size = m.captured(3);
bool isUserPreset = name.startsWith("[U]");
if (isUserPreset)
name = name.split("[U]")[1];
if (!QRegularExpression{R"(^\w[\w ]*$)"}.match(name).hasMatch())
return RecentPresetData{};
RecentPresetData result;
result.category = category;
result.presetName = name;
result.sizeName = size;
result.isUserPreset = isUserPreset;
return result;
}
std::vector<RecentPresetData> RecentPresetsStore::decodeRecentPresets(const QVariantList &values)
{
return Utils::transform<std::vector>(values, [](const QVariant &value) {
return decodeOneRecentPreset(value.toString());
});
}

View File

@@ -1,103 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QDebug>
#include <QPair>
#include <QSettings>
#include <vector>
namespace StudioWelcome {
struct RecentPresetData
{
RecentPresetData() = default;
RecentPresetData(const QString &category,
const QString &name,
const QString &size,
bool isUserPreset = false)
: category{category}
, presetName{name}
, sizeName{size}
, isUserPreset{isUserPreset}
{}
QString category;
QString presetName;
QString sizeName;
bool isUserPreset = false;
};
inline bool operator==(const RecentPresetData &lhs, const RecentPresetData &rhs)
{
return lhs.category == rhs.category && lhs.presetName == rhs.presetName
&& lhs.sizeName == rhs.sizeName && lhs.isUserPreset == rhs.isUserPreset;
}
inline bool operator!=(const RecentPresetData &lhs, const RecentPresetData &rhs)
{
return !(lhs == rhs);
}
inline QDebug &operator<<(QDebug &d, const RecentPresetData &preset)
{
d << "RecentPreset{category=" << preset.category << "; name=" << preset.presetName
<< "; size=" << preset.sizeName << "; isUserPreset=" << preset.isUserPreset << "}";
return d;
}
class RecentPresetsStore
{
public:
explicit RecentPresetsStore(QSettings *settings)
: m_settings{settings}
{}
void setMaximum(int n) { m_max = n; }
void add(const QString &categoryId,
const QString &name,
const QString &sizeName,
bool isUserPreset = false);
std::vector<RecentPresetData> remove(const QString &categoryId, const QString &presetName);
std::vector<RecentPresetData> fetchAll() const;
private:
std::vector<RecentPresetData> addRecentToExisting(const RecentPresetData &preset,
std::vector<RecentPresetData> &recents);
static QStringList encodeRecentPresets(const std::vector<RecentPresetData> &recents);
static std::vector<RecentPresetData> decodeRecentPresets(const QVariantList &values);
static RecentPresetData decodeOneRecentPreset(const QString &encoded);
void save(const std::vector<RecentPresetData> &recents);
private:
QSettings *m_settings = nullptr;
int m_max = 10;
};
} // namespace StudioWelcome

View File

@@ -37,8 +37,6 @@ QtcPlugin {
"wizardfactories.h", "wizardfactories.h",
"wizardhandler.cpp", "wizardhandler.cpp",
"wizardhandler.h", "wizardhandler.h",
"recentpresets.cpp",
"recentpresets.h",
"userpresets.cpp", "userpresets.cpp",
"userpresets.h" "userpresets.h"
] ]

View File

@@ -24,43 +24,75 @@
****************************************************************************/ ****************************************************************************/
#include "userpresets.h" #include "userpresets.h"
#include "algorithm.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/algorithm.h> #include <memory>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
using namespace StudioWelcome; using namespace StudioWelcome;
constexpr char PREFIX[] = "UserPresets"; FileStoreIo::FileStoreIo(const QString &fileName)
: m_file{std::make_unique<QFile>(fullFilePath(fileName))}
UserPresetsStore::UserPresetsStore()
{
m_settings = std::make_unique<QSettings>(fullFilePath(), QSettings::IniFormat);
}
UserPresetsStore::UserPresetsStore(std::unique_ptr<QSettings> &&settings)
: m_settings{std::move(settings)}
{} {}
void UserPresetsStore::savePresets(const std::vector<UserPresetData> &presets) QByteArray FileStoreIo::read() const
{ {
m_settings->beginWriteArray(PREFIX, static_cast<int>(presets.size())); m_file->open(QFile::ReadOnly | QFile::Text);
QByteArray data = m_file->readAll();
m_file->close();
for (size_t i = 0; i < presets.size(); ++i) { return data;
m_settings->setArrayIndex(static_cast<int>(i)); }
const auto &preset = presets[i];
m_settings->setValue("categoryId", preset.categoryId); void FileStoreIo::write(const QByteArray &data)
m_settings->setValue("wizardName", preset.wizardName); {
m_settings->setValue("name", preset.name); m_file->open(QFile::WriteOnly | QFile::Text);
m_settings->setValue("screenSize", preset.screenSize); m_file->write(data);
m_settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard); m_file->close();
m_settings->setValue("qtVersion", preset.qtVersion); }
m_settings->setValue("styleName", preset.styleName);
QString FileStoreIo::fullFilePath(const QString &fileName) const
{
return Core::ICore::userResourcePath(fileName).toString();
}
UserPresetsStore::UserPresetsStore(const QString &fileName, StorePolicy policy)
: m_store{std::make_unique<FileStoreIo>(fileName)}
, m_policy{policy}
{}
UserPresetsStore::UserPresetsStore(std::unique_ptr<StoreIo> &&fileStore,
StorePolicy policy)
: m_store{std::move(fileStore)}
, m_policy{policy}
{}
void UserPresetsStore::savePresets(const std::vector<UserPresetData> &presetItems)
{
QJsonArray jsonArray;
for (const auto &preset : presetItems) {
QJsonObject obj({{"categoryId", preset.categoryId},
{"wizardName", preset.wizardName},
{"name", preset.name},
{"screenSize", preset.screenSize},
{"useQtVirtualKeyboard", preset.useQtVirtualKeyboard},
{"qtVersion", preset.qtVersion},
{"styleName", preset.styleName}});
jsonArray.append(QJsonValue{obj});
} }
m_settings->endArray();
m_settings->sync();
QJsonDocument doc(jsonArray);
QByteArray data = doc.toJson();
m_store->write(data);
} }
bool UserPresetsStore::save(const UserPresetData &newPreset) bool UserPresetsStore::save(const UserPresetData &newPreset)
@@ -68,12 +100,30 @@ bool UserPresetsStore::save(const UserPresetData &newPreset)
QTC_ASSERT(newPreset.isValid(), return false); QTC_ASSERT(newPreset.isValid(), return false);
std::vector<UserPresetData> presetItems = fetchAll(); std::vector<UserPresetData> presetItems = fetchAll();
if (Utils::anyOf(presetItems,
[&newPreset](const UserPresetData &p) { return p.name == newPreset.name; })) { if (m_policy == StorePolicy::UniqueNames) {
return false; if (Utils::anyOf(presetItems, [&newPreset](const UserPresetData &p) {
return p.name == newPreset.name;
})) {
return false;
}
} else if (m_policy == StorePolicy::UniqueValues) {
if (Utils::containsItem(presetItems, newPreset))
return false;
}
if (m_reverse)
Utils::prepend(presetItems, newPreset);
else
presetItems.push_back(newPreset);
if (m_maximum > -1 && static_cast<int>(presetItems.size()) > m_maximum) {
if (m_reverse)
presetItems.pop_back();
else
presetItems.erase(std::cbegin(presetItems));
} }
presetItems.push_back(newPreset);
savePresets(presetItems); savePresets(presetItems);
return true; return true;
@@ -92,34 +142,45 @@ void UserPresetsStore::remove(const QString &category, const QString &name)
savePresets(presetItems); savePresets(presetItems);
} }
std::vector<UserPresetData> UserPresetsStore::remove(const UserPresetData &preset)
{
std::vector<UserPresetData> presetItems = fetchAll();
bool erased = Utils::erase_one(presetItems, preset);
if (erased)
savePresets(presetItems);
return presetItems;
}
std::vector<UserPresetData> UserPresetsStore::fetchAll() const std::vector<UserPresetData> UserPresetsStore::fetchAll() const
{ {
QByteArray data = m_store->read();
const QJsonDocument doc = QJsonDocument::fromJson(data);
if (!doc.isArray())
return {};
std::vector<UserPresetData> result; std::vector<UserPresetData> result;
int size = m_settings->beginReadArray(PREFIX); const QJsonArray jsonArray = doc.array();
if (size >= 0)
result.reserve(static_cast<size_t>(size) + 1);
for (int i = 0; i < size; ++i) { for (const QJsonValue &value: jsonArray) {
m_settings->setArrayIndex(i); if (!value.isObject())
continue;
const QJsonObject obj = value.toObject();
UserPresetData preset; UserPresetData preset;
preset.categoryId = m_settings->value("categoryId").toString();
preset.wizardName = m_settings->value("wizardName").toString(); preset.categoryId = obj["categoryId"].toString();
preset.name = m_settings->value("name").toString(); preset.wizardName = obj["wizardName"].toString();
preset.screenSize = m_settings->value("screenSize").toString(); preset.name = obj["name"].toString();
preset.useQtVirtualKeyboard = m_settings->value("useQtVirtualKeyboard").toBool(); preset.screenSize = obj["screenSize"].toString();
preset.qtVersion = m_settings->value("qtVersion").toString(); preset.useQtVirtualKeyboard = obj["useQtVirtualKeyboard"].toBool();
preset.styleName = m_settings->value("styleName").toString(); preset.qtVersion = obj["qtVersion"].toString();
preset.styleName = obj["styleName"].toString();
if (preset.isValid()) if (preset.isValid())
result.push_back(std::move(preset)); result.push_back(preset);
} }
m_settings->endArray();
return result; return result;
} }
QString UserPresetsStore::fullFilePath() const
{
return Core::ICore::userResourcePath("UserPresets.ini").toString();
}

View File

@@ -25,8 +25,10 @@
#pragma once #pragma once
#include <memory>
#include <vector>
#include <QFile>
#include <QDebug> #include <QDebug>
#include <QSettings>
#include <vector> #include <vector>
@@ -70,24 +72,59 @@ inline bool operator==(const UserPresetData &lhs, const UserPresetData &rhs)
return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName
&& lhs.name == rhs.name && lhs.screenSize == rhs.screenSize && lhs.name == rhs.name && lhs.screenSize == rhs.screenSize
&& lhs.useQtVirtualKeyboard == rhs.useQtVirtualKeyboard && lhs.qtVersion == rhs.qtVersion && lhs.useQtVirtualKeyboard == rhs.useQtVirtualKeyboard && lhs.qtVersion == rhs.qtVersion
&& lhs.styleName == rhs.styleName; && lhs.styleName == rhs.styleName;;
} }
enum class StorePolicy {UniqueNames, UniqueValues};
class StoreIo
{
public:
virtual ~StoreIo() {}
virtual QByteArray read() const = 0;
virtual void write(const QByteArray &bytes) = 0;
};
class FileStoreIo : public StoreIo
{
public:
explicit FileStoreIo(const QString &fileName);
FileStoreIo(FileStoreIo &&other): m_file{std::move(other.m_file)} {}
FileStoreIo& operator=(FileStoreIo &&other) { m_file = std::move(other.m_file); return *this; }
QByteArray read() const override;
void write(const QByteArray &data) override;
private:
QString fullFilePath(const QString &fileName) const;
std::unique_ptr<QFile> m_file;
Q_DISABLE_COPY(FileStoreIo)
};
class UserPresetsStore class UserPresetsStore
{ {
public: public:
UserPresetsStore(); UserPresetsStore(const QString &fileName, StorePolicy policy);
UserPresetsStore(std::unique_ptr<QSettings> &&settings); UserPresetsStore(std::unique_ptr<StoreIo> &&store, StorePolicy policy);
bool save(const UserPresetData &preset); bool save(const UserPresetData &preset);
void remove(const QString &category, const QString &name);
std::vector<UserPresetData> fetchAll() const; std::vector<UserPresetData> fetchAll() const;
void remove(const QString &category, const QString &name);
std::vector<UserPresetData> remove(const UserPresetData &preset);
void setMaximum(int maximum) { m_maximum = maximum; }
void setReverseOrder() { m_reverse = true; }
private: private:
QString fullFilePath() const;
void savePresets(const std::vector<UserPresetData> &presets); void savePresets(const std::vector<UserPresetData> &presets);
std::unique_ptr<QSettings> m_settings; std::unique_ptr<StoreIo> m_store;
StorePolicy m_policy = StorePolicy::UniqueNames;
bool m_reverse = false;
int m_maximum = -1;
}; };
} // namespace StudioWelcome } // namespace StudioWelcome

View File

@@ -328,10 +328,13 @@ bool RefactoringFile::apply()
} }
// open / activate / goto position // open / activate / goto position
bool ensureCursorVisible = false;
if (m_openEditor && !m_filePath.isEmpty()) { if (m_openEditor && !m_filePath.isEmpty()) {
int line = -1, column = -1; int line = -1, column = -1;
if (m_editorCursorPosition != -1) if (m_editorCursorPosition != -1) {
lineAndColumn(m_editorCursorPosition, &line, &column); lineAndColumn(m_editorCursorPosition, &line, &column);
ensureCursorVisible = true;
}
m_editor = RefactoringChanges::openEditor(m_filePath, m_activateEditor, line, column); m_editor = RefactoringChanges::openEditor(m_filePath, m_activateEditor, line, column);
m_openEditor = false; m_openEditor = false;
m_activateEditor = false; m_activateEditor = false;
@@ -392,6 +395,9 @@ bool RefactoringFile::apply()
} }
} }
if (m_editor && ensureCursorVisible)
m_editor->ensureCursorVisible();
m_appliedOnce = true; m_appliedOnce = true;
return result; return result;
} }

View File

@@ -17,14 +17,12 @@ add_qtc_test(tst_qml_wizard
SOURCES SOURCES
wizardfactories-test.cpp wizardfactories-test.cpp
stylemodel-test.cpp stylemodel-test.cpp
recentpresets-test.cpp
userpresets-test.cpp userpresets-test.cpp
presetmodel-test.cpp presetmodel-test.cpp
test-utilities.h test-utilities.h
test-main.cpp test-main.cpp
"${StudioWelcomeDir}/wizardfactories.cpp" "${StudioWelcomeDir}/wizardfactories.cpp"
"${StudioWelcomeDir}/stylemodel.cpp" "${StudioWelcomeDir}/stylemodel.cpp"
"${StudioWelcomeDir}/recentpresets.cpp"
"${StudioWelcomeDir}/userpresets.cpp" "${StudioWelcomeDir}/userpresets.cpp"
"${StudioWelcomeDir}/presetmodel.cpp" "${StudioWelcomeDir}/presetmodel.cpp"
) )

View File

@@ -100,6 +100,14 @@ UserPresetData aUserPreset(const QString &categId, const QString &wizardName, co
return preset; return preset;
} }
UserPresetData aRecentPreset(const QString &categId, const QString &wizardName, const QString &screenSizeName)
{
UserPresetData preset = aUserPreset(categId, wizardName, wizardName);
preset.screenSize = screenSizeName;
return preset;
}
MATCHER_P2(PresetIs, category, name, PrintToString(PresetItem{name, category})) MATCHER_P2(PresetIs, category, name, PrintToString(PresetItem{name, category}))
{ {
return arg->categoryId == category && arg->wizardName == name; return arg->categoryId == category && arg->wizardName == name;
@@ -139,6 +147,7 @@ TEST(QdsPresetModel, haveSameArraySizeForPresetsAndCategories)
PresetData data; PresetData data;
data.setData( data.setData(
/*wizard presets*/
{ {
aCategory("A.categ", "A", {"item a", "item b"}), aCategory("A.categ", "A", {"item a", "item b"}),
aCategory("B.categ", "B", {"item c", "item d"}), aCategory("B.categ", "B", {"item c", "item d"}),
@@ -157,6 +166,7 @@ TEST(QdsPresetModel, haveWizardPresetsNoRecents)
// When // When
data.setData( data.setData(
/*wizard presets*/
{ {
aCategory("A.categ", "A", {"item a", "item b"}), aCategory("A.categ", "A", {"item a", "item b"}),
aCategory("B.categ", "B", {"item c", "item d"}), aCategory("B.categ", "B", {"item c", "item d"}),
@@ -179,6 +189,7 @@ TEST(QdsPresetModel, whenHaveUserPresetsButNoWizardPresetsReturnEmpty)
// When // When
data.setData({/*builtin presets*/}, data.setData({/*builtin presets*/},
/*user presets*/
{ {
aUserPreset("A.Mobile", "Scroll", "iPhone5"), aUserPreset("A.Mobile", "Scroll", "iPhone5"),
aUserPreset("B.Desktop", "Launcher", "MacBook"), aUserPreset("B.Desktop", "Launcher", "MacBook"),
@@ -196,9 +207,10 @@ TEST(QdsPresetModel, haveRecentsNoWizardPresets)
data.setData({/*wizardPresets*/}, data.setData({/*wizardPresets*/},
{/*user presets*/}, {/*user presets*/},
/*recent presets*/
{ {
{"A.categ", "Desktop", "640 x 480"}, aRecentPreset("A.categ", "Desktop", "640 x 480"),
{"B.categ", "Mobile", "800 x 600"}, aRecentPreset("B.categ", "Mobile", "800 x 600"),
}); });
ASSERT_THAT(data.categories(), IsEmpty()); ASSERT_THAT(data.categories(), IsEmpty());
@@ -220,8 +232,8 @@ TEST(QdsPresetModel, recentsAddedWithWizardPresets)
{/*user presets*/}, {/*user presets*/},
/*recents*/ /*recents*/
{ {
{"A.categ", "Desktop", "800 x 600"}, aRecentPreset("A.categ", "Desktop", "800 x 600"),
{"B.categ", "Mobile", "640 x 480"}, aRecentPreset("B.categ", "Mobile", "640 x 480"),
}); });
// Then // Then
@@ -247,6 +259,7 @@ TEST(QdsPresetModel, userPresetsAddedWithWizardPresets)
aCategory("A.categ", "A", {"Desktop", "item b"}), aCategory("A.categ", "A", {"Desktop", "item b"}),
aCategory("B.categ", "B", {"Mobile"}), aCategory("B.categ", "B", {"Mobile"}),
}, },
/*user presets*/
{ {
aUserPreset("A.categ", "Desktop", "Windows10"), aUserPreset("A.categ", "Desktop", "Windows10"),
}, },
@@ -272,6 +285,7 @@ TEST(QdsPresetModel, doesNotAddUserPresetsOfNonExistingCategory)
{ {
aCategory("A.categ", "A", {"Desktop"}), // Only category "A.categ" exists aCategory("A.categ", "A", {"Desktop"}), // Only category "A.categ" exists
}, },
/*user presets*/
{ {
aUserPreset("Bad.Categ", "Desktop", "Windows8"), // Bad.Categ does not exist aUserPreset("Bad.Categ", "Desktop", "Windows8"), // Bad.Categ does not exist
}, },
@@ -293,6 +307,7 @@ TEST(QdsPresetModel, doesNotAddUserPresetIfWizardPresetItRefersToDoesNotExist)
{ {
aCategory("A.categ", "A", {"Desktop"}), aCategory("A.categ", "A", {"Desktop"}),
}, },
/*user presets*/
{ {
aUserPreset("B.categ", "BadWizard", "Tablet"), // BadWizard referenced does not exist aUserPreset("B.categ", "BadWizard", "Tablet"), // BadWizard referenced does not exist
}, },
@@ -314,6 +329,7 @@ TEST(QdsPresetModel, userPresetWithSameNameAsWizardPreset)
{ {
aCategory("A.categ", "A", {"Desktop"}), aCategory("A.categ", "A", {"Desktop"}),
}, },
/*user presets*/
{ {
aUserPreset("A.categ", "Desktop", "Desktop"), aUserPreset("A.categ", "Desktop", "Desktop"),
}, },
@@ -326,58 +342,7 @@ TEST(QdsPresetModel, userPresetWithSameNameAsWizardPreset)
ElementsAre(UserPresetIs("A.categ", "Desktop", "Desktop")))); ElementsAre(UserPresetIs("A.categ", "Desktop", "Desktop"))));
} }
TEST(QdsPresetModel, recentOfUserPresetReferringToExistingWizardPreset) TEST(QdsPresetModel, recentOfNonExistentWizardPreset)
{
// Given
PresetData data;
// When
data.setData(
/*wizard presets*/
{
aCategory("A.categ", "A", {"Desktop"}),
},
{
aUserPreset("A.categ", "Desktop", "Windows 7"),
},
/*recents*/
{
{"A.categ", "Windows 7", "200 x 300", /*is user*/true}
});
// Then
ASSERT_THAT(data.categories(), ElementsAre("Recents", "A", "Custom"));
ASSERT_THAT(data.presets(),
ElementsAre(ElementsAre(UserPresetIs("A.categ", "Desktop", "Windows 7")),
ElementsAre(PresetIs("A.categ", "Desktop")),
ElementsAre(UserPresetIs("A.categ", "Desktop", "Windows 7"))));
}
TEST(QdsPresetModel, recentOfUserPresetReferringToNonexistingWizardPreset)
{
// Given
PresetData data;
// When
data.setData(
/*wizard presets*/
{
aCategory("A.categ", "A", {"Desktop"}),
},
{
aUserPreset("A.categ", "Not-Desktop", "Windows 7"), // Non-existing Wizard Preset
},
/*recents*/
{
{"A.categ", "Windows 7", "200 x 300", /*is user*/true}
});
// Then
ASSERT_THAT(data.categories(), ElementsAre("A"));
ASSERT_THAT(data.presets(), ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"))));
}
TEST(QdsPresetModel, recentOfNonExistentUserPreset)
{ {
// Given // Given
PresetData data; PresetData data;
@@ -391,7 +356,7 @@ TEST(QdsPresetModel, recentOfNonExistentUserPreset)
{/*user presets*/}, {/*user presets*/},
/*recents*/ /*recents*/
{ {
{"A.categ", "Windows 7", "200 x 300", /*is user*/true} aRecentPreset("A.categ", "Windows 7", "200 x 300")
}); });
// Then // Then
@@ -415,9 +380,9 @@ TEST(QdsPresetModel, recentsShouldNotBeSorted)
{/*user presets*/}, {/*user presets*/},
/*recents*/ /*recents*/
{ {
{"Z.categ", "Z.desktop", "200 x 300"}, aRecentPreset("Z.categ", "Z.desktop", "200 x 300"),
{"B.categ", "Mobile", "200 x 300"}, aRecentPreset("B.categ", "Mobile", "200 x 300"),
{"A.categ", "Desktop", "200 x 300"}, aRecentPreset("A.categ", "Desktop", "200 x 300"),
}); });
// Then // Then
@@ -442,9 +407,9 @@ TEST(QdsPresetModel, recentsOfSameWizardProjectButDifferentSizesAreRecognizedAsD
{/*user presets*/}, {/*user presets*/},
/*recents*/ /*recents*/
{ {
{"B.categ", "Mobile", "400 x 400"}, aRecentPreset("B.categ", "Mobile", "400 x 400"),
{"B.categ", "Mobile", "200 x 300"}, aRecentPreset("B.categ", "Mobile", "200 x 300"),
{"A.categ", "Desktop", "640 x 480"}, aRecentPreset("A.categ", "Desktop", "640 x 480"),
}); });
// Then // Then
@@ -454,6 +419,35 @@ TEST(QdsPresetModel, recentsOfSameWizardProjectButDifferentSizesAreRecognizedAsD
PresetIs("A.categ", "Desktop", "640 x 480"))); PresetIs("A.categ", "Desktop", "640 x 480")));
} }
TEST(QdsPresetModel, allowRecentsWithTheSameName)
{
// Given
PresetData data;
// When
data.setData(
/*wizard presets*/
{
aCategory("A.categ", "A", {"Desktop"}),
},
{/*user presets*/},
/*recents*/
{
/* NOTE: it is assumed recents with the same name and size have other fields that
* distinguishes them from one another. It is the responsibility of the caller, who
* calls data.setData() to make sure that the recents do not contain duplicates. */
aRecentPreset("A.categ", "Desktop", "200 x 300"),
aRecentPreset("A.categ", "Desktop", "200 x 300"),
aRecentPreset("A.categ", "Desktop", "200 x 300"),
});
// Then
ASSERT_THAT(data.presets()[0],
ElementsAre(PresetIs("A.categ", "Desktop"),
PresetIs("A.categ", "Desktop"),
PresetIs("A.categ", "Desktop")));
}
TEST(QdsPresetModel, outdatedRecentsAreNotShown) TEST(QdsPresetModel, outdatedRecentsAreNotShown)
{ {
// Given // Given
@@ -469,8 +463,8 @@ TEST(QdsPresetModel, outdatedRecentsAreNotShown)
{/*user presets*/}, {/*user presets*/},
/*recents*/ /*recents*/
{ {
{"B.categ", "NoLongerExists", "400 x 400"}, aRecentPreset("B.categ", "NoLongerExists", "400 x 400"),
{"A.categ", "Desktop", "640 x 480"}, aRecentPreset("A.categ", "Desktop", "640 x 480"),
}); });
// Then // Then

View File

@@ -1,303 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "test-utilities.h"
#include <QDir>
#include <QRandomGenerator>
#include <QTime>
#include "recentpresets.h"
#include "utils/filepath.h"
#include "utils/temporarydirectory.h"
using namespace StudioWelcome;
constexpr char GROUP_NAME[] = "RecentPresets";
constexpr char ITEMS[] = "Wizards";
namespace StudioWelcome {
void PrintTo(const RecentPresetData &recent, std::ostream *os)
{
*os << "{categId: " << recent.category << ", name: " << recent.presetName
<< ", size: " << recent.sizeName << ", isUser: " << recent.isUserPreset;
*os << "}";
}
} // namespace StudioWelcome
class QdsRecentPresets : public ::testing::Test
{
protected:
RecentPresetsStore aStoreWithRecents(const QStringList &items)
{
settings.beginGroup(GROUP_NAME);
settings.setValue(ITEMS, items);
settings.endGroup();
return RecentPresetsStore{&settings};
}
RecentPresetsStore aStoreWithOne(const QVariant &item)
{
settings.beginGroup(GROUP_NAME);
settings.setValue(ITEMS, item);
settings.endGroup();
return RecentPresetsStore{&settings};
}
protected:
Utils::TemporaryDirectory tempDir{"recentpresets-XXXXXX"};
QSettings settings{tempDir.filePath("test").toString(), QSettings::IniFormat};
private:
QString settingsPath;
};
/******************* TESTS *******************/
TEST_F(QdsRecentPresets, readFromEmptyStore)
{
RecentPresetsStore store{&settings};
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
TEST_F(QdsRecentPresets, readEmptyRecentPresets)
{
RecentPresetsStore store = aStoreWithOne("");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
TEST_F(QdsRecentPresets, readOneRecentPresetAsList)
{
RecentPresetsStore store = aStoreWithRecents({"category/preset:640 x 480"});
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "640 x 480")));
}
TEST_F(QdsRecentPresets, readOneRecentPresetAsString)
{
RecentPresetsStore store = aStoreWithOne("category/preset:200 x 300");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
}
TEST_F(QdsRecentPresets, readOneRecentUserPresetAsString)
{
RecentPresetsStore store = aStoreWithOne("category/[U]preset:200 x 300");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300", true)));
}
TEST_F(QdsRecentPresets, readBadRecentPresetAsString)
{
RecentPresetsStore store = aStoreWithOne("no_category_only_preset");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
TEST_F(QdsRecentPresets, readBadRecentPresetAsInt)
{
RecentPresetsStore store = aStoreWithOne(32);
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
TEST_F(QdsRecentPresets, readBadRecentPresetsInList)
{
RecentPresetsStore store = aStoreWithRecents({
"bad1", // no category, no size
"categ/name:800 x 600", // good
"categ/bad2", //no size
"categ/bad3:", //no size
"categ 1/bad4:200 x 300", // category has space
"categ/bad5: 400 x 300", // size starts with space
"categ/bad6:400", // bad size
"categ/[U]user:300 x 200", // good
"categ/[u]user2:300 x 200", // small cap "U"
"categ/[x]user3:300 x 200", // must be letter "U"
"categ/[U] user4:300 x 200", // space
});
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("categ", "name", "800 x 600", false),
RecentPresetData("categ", "user", "300 x 200", true)));
}
TEST_F(QdsRecentPresets, readTwoRecentPresets)
{
RecentPresetsStore store = aStoreWithRecents(
{"category_1/preset 1:640 x 480", "category_2/preset 2:320 x 200"});
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("category_1", "preset 1", "640 x 480"),
RecentPresetData("category_2", "preset 2", "320 x 200")));
}
TEST_F(QdsRecentPresets, readRecentsToDifferentKindsOfPresets)
{
RecentPresetsStore store = aStoreWithRecents(
{"category_1/preset 1:640 x 480", "category_2/[U]preset 2:320 x 200"});
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("category_1", "preset 1", "640 x 480", false),
RecentPresetData("category_2", "preset 2", "320 x 200", true)));
}
TEST_F(QdsRecentPresets, addFirstRecentPreset)
{
RecentPresetsStore store{&settings};
store.add("A.Category", "Normal Application", "400 x 600");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, ElementsAre(RecentPresetData("A.Category", "Normal Application", "400 x 600")));
}
TEST_F(QdsRecentPresets, addFirstRecentUserPreset)
{
RecentPresetsStore store{&settings};
store.add("A.Category", "Normal Application", "400 x 600", /*user preset*/ true);
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("A.Category", "Normal Application", "400 x 600", true)));
}
TEST_F(QdsRecentPresets, addExistingFirstRecentPreset)
{
RecentPresetsStore store = aStoreWithRecents({"category/preset:200 x 300"});
ASSERT_THAT(store.fetchAll(), ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
store.add("category", "preset", "200 x 300");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
}
TEST_F(QdsRecentPresets, addRecentUserPresetWithSameNameAsExistingRecentNormalPreset)
{
RecentPresetsStore store = aStoreWithRecents({"category/preset:200 x 300"});
ASSERT_THAT(store.fetchAll(), ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
store.add("category", "preset", "200 x 300", /*user preset*/ true);
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("category", "preset", "200 x 300", true),
RecentPresetData("category", "preset", "200 x 300", false)));
}
TEST_F(QdsRecentPresets, addSecondRecentPreset)
{
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset 1:800 x 600"});
store.add("A.Category", "Preset 2", "640 x 480");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("A.Category", "Preset 2", "640 x 480"),
RecentPresetData("A.Category", "Preset 1", "800 x 600")));
}
TEST_F(QdsRecentPresets, addSecondRecentPresetSameKindButDifferentSize)
{
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset:800 x 600"});
store.add("A.Category", "Preset", "640 x 480");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("A.Category", "Preset", "640 x 480"),
RecentPresetData("A.Category", "Preset", "800 x 600")));
}
TEST_F(QdsRecentPresets, fetchesRecentPresetsInTheReverseOrderTheyWereAdded)
{
RecentPresetsStore store{&settings};
store.add("A.Category", "Preset 1", "640 x 480");
store.add("A.Category", "Preset 2", "640 x 480");
store.add("A.Category", "Preset 3", "800 x 600");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("A.Category", "Preset 3", "800 x 600"),
RecentPresetData("A.Category", "Preset 2", "640 x 480"),
RecentPresetData("A.Category", "Preset 1", "640 x 480")));
}
TEST_F(QdsRecentPresets, addingAnExistingRecentPresetMakesItTheFirst)
{
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset 1:200 x 300",
"A.Category/Preset 2:200 x 300",
"A.Category/Preset 3:640 x 480"});
store.add("A.Category", "Preset 3", "640 x 480");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("A.Category", "Preset 3", "640 x 480"),
RecentPresetData("A.Category", "Preset 1", "200 x 300"),
RecentPresetData("A.Category", "Preset 2", "200 x 300")));
}
TEST_F(QdsRecentPresets, addingTooManyRecentPresetsRemovesTheOldestOne)
{
RecentPresetsStore store = aStoreWithRecents(
{"A.Category/Preset 2:200 x 300", "A.Category/Preset 1:200 x 300"});
store.setMaximum(2);
store.add("A.Category", "Preset 3", "200 x 300");
std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
ElementsAre(RecentPresetData("A.Category", "Preset 3", "200 x 300"),
RecentPresetData("A.Category", "Preset 2", "200 x 300")));
}

View File

@@ -29,6 +29,10 @@
#include <utils/filepath.h> #include <utils/filepath.h>
#include <utils/temporarydirectory.h> #include <utils/temporarydirectory.h>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
namespace StudioWelcome { namespace StudioWelcome {
void PrintTo(const UserPresetData &preset, std::ostream *os) void PrintTo(const UserPresetData &preset, std::ostream *os)
@@ -64,69 +68,85 @@ using namespace StudioWelcome;
constexpr char ARRAY_NAME[] = "UserPresets"; constexpr char ARRAY_NAME[] = "UserPresets";
class FakeStoreIo : public StoreIo
{
public:
QByteArray read() const override
{
return data.toUtf8();
}
void write(const QByteArray &bytes) override
{
data = bytes;
}
QString data;
};
class QdsUserPresets : public ::testing::Test class QdsUserPresets : public ::testing::Test
{ {
protected: protected:
void SetUp() void SetUp()
{ {
settings = std::make_unique<QSettings>(tempDir.filePath("test").toString(), storeIo = std::make_unique<FakeStoreIo>();
QSettings::IniFormat);
} }
UserPresetsStore anEmptyStore() { return UserPresetsStore{std::move(settings)}; } UserPresetsStore anEmptyStore()
{
return UserPresetsStore{std::move(storeIo), StorePolicy::UniqueNames};
}
UserPresetsStore aStoreWithZeroItems() UserPresetsStore aStoreWithZeroItems()
{ {
settings->beginWriteArray(ARRAY_NAME, 0); storeIo->data = "[]";
settings->endArray();
return UserPresetsStore{std::move(settings)}; return UserPresetsStore{std::move(storeIo), StorePolicy::UniqueNames};
} }
UserPresetsStore aStoreWithOne(const UserPresetData &preset) UserPresetsStore aStoreWithOne(const UserPresetData &preset,
StorePolicy policy = StorePolicy::UniqueNames)
{ {
settings->beginWriteArray(ARRAY_NAME, 1); QJsonArray array({QJsonObject{{"categoryId", preset.categoryId},
settings->setArrayIndex(0); {"wizardName", preset.wizardName},
{"name", preset.name},
{"screenSize", preset.screenSize},
{"useQtVirtualKeyboard", preset.useQtVirtualKeyboard},
{"qtVersion", preset.qtVersion},
{"styleName", preset.styleName}}});
QJsonDocument doc{array};
storeIo->data = doc.toJson();
settings->setValue("categoryId", preset.categoryId); return UserPresetsStore{std::move(storeIo), policy};
settings->setValue("wizardName", preset.wizardName);
settings->setValue("name", preset.name);
settings->setValue("screenSize", preset.screenSize);
settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
settings->setValue("qtVersion", preset.qtVersion);
settings->setValue("styleName", preset.styleName);
settings->endArray();
return UserPresetsStore{std::move(settings)};
} }
UserPresetsStore aStoreWithPresets(const std::vector<UserPresetData> &presets) UserPresetsStore aStoreWithPresets(const std::vector<UserPresetData> &presetItems)
{ {
settings->beginWriteArray(ARRAY_NAME, presets.size()); QJsonArray array;
for (size_t i = 0; i < presets.size(); ++i) { for (const auto &preset : presetItems) {
settings->setArrayIndex(i); QJsonObject obj({{"categoryId", preset.categoryId},
const auto &preset = presets[i]; {"wizardName", preset.wizardName},
{"name", preset.name},
{"screenSize", preset.screenSize},
{"useQtVirtualKeyboard", preset.useQtVirtualKeyboard},
{"qtVersion", preset.qtVersion},
{"styleName", preset.styleName}});
settings->setValue("categoryId", preset.categoryId); array.append(QJsonValue{obj});
settings->setValue("wizardName", preset.wizardName);
settings->setValue("name", preset.name);
settings->setValue("screenSize", preset.screenSize);
settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
settings->setValue("qtVersion", preset.qtVersion);
settings->setValue("styleName", preset.styleName);
} }
settings->endArray();
return UserPresetsStore{std::move(settings)}; QJsonDocument doc{array};
storeIo->data = doc.toJson();
return UserPresetsStore{std::move(storeIo), StorePolicy::UniqueNames};
} }
Utils::TemporaryDirectory tempDir{"userpresets-XXXXXX"}; Utils::TemporaryDirectory tempDir{"userpresets-XXXXXX"};
std::unique_ptr<QSettings> settings; std::unique_ptr<FakeStoreIo> storeIo;
private: private:
QString settingsPath; QString storeIoPath;
}; };
/******************* TESTS *******************/ /******************* TESTS *******************/
@@ -234,10 +254,10 @@ TEST_F(QdsUserPresets, saveIncompletePreset)
ASSERT_THAT(presets, ElementsAre(preset)); ASSERT_THAT(presets, ElementsAre(preset));
} }
TEST_F(QdsUserPresets, cannotSavePresetWithSameName) TEST_F(QdsUserPresets, cannotSavePresetWithSameNameForUniqueNamesPolicy)
{ {
UserPresetData existing{"B.categ", "3D App", "Same Name", "400 x 20", true, "Qt 5", "Material Dark"}; UserPresetData existing{"B.categ", "3D App", "Same Name", "400 x 20", true, "Qt 5", "Material Dark"};
auto store = aStoreWithOne(existing); auto store = aStoreWithOne(existing, StorePolicy::UniqueNames);
UserPresetData newPreset{"C.categ", "Empty", "Same Name", "100 x 30", false, "Qt 6", "Fusion"}; UserPresetData newPreset{"C.categ", "Empty", "Same Name", "100 x 30", false, "Qt 6", "Fusion"};
bool saved = store.save(newPreset); bool saved = store.save(newPreset);
@@ -246,6 +266,30 @@ TEST_F(QdsUserPresets, cannotSavePresetWithSameName)
ASSERT_THAT(store.fetchAll(), ElementsAreArray({existing})); ASSERT_THAT(store.fetchAll(), ElementsAreArray({existing}));
} }
TEST_F(QdsUserPresets, canSavePresetWithSameNameForUniqueValuesPolicy)
{
UserPresetData existing{"B.categ", "3D App", "Same Name", "400 x 20", true, "Qt 5", "Material Dark"};
auto store = aStoreWithOne(existing, StorePolicy::UniqueValues);
// NOTE: only Style is different
UserPresetData newPreset{"B.categ", "3D App", "Same Name", "400 x 20", true, "Qt 5", "Fusion"};
bool saved = store.save(newPreset);
ASSERT_TRUE(saved);
ASSERT_THAT(store.fetchAll(), ElementsAreArray({existing, newPreset}));
}
TEST_F(QdsUserPresets, cannotSaveExactCopyForUniqueValuesPolicy)
{
UserPresetData existing{"B.categ", "3D App", "Same Name", "400 x 20", true, "Qt 5", "Material Dark"};
auto store = aStoreWithOne(existing, StorePolicy::UniqueNames);
bool saved = store.save(existing);
ASSERT_FALSE(saved);
ASSERT_THAT(store.fetchAll(), ElementsAreArray({existing}));
}
TEST_F(QdsUserPresets, saveNewPreset) TEST_F(QdsUserPresets, saveNewPreset)
{ {
UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"}; UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
@@ -258,6 +302,54 @@ TEST_F(QdsUserPresets, saveNewPreset)
ASSERT_THAT(presets, ElementsAre(existing, newPreset)); ASSERT_THAT(presets, ElementsAre(existing, newPreset));
} }
TEST_F(QdsUserPresets, canLimitPresetsToAMaximum)
{
std::vector<UserPresetData> existing{
{"A.categ", "AppA", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
{"B.categ", "AppB", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
{"C.categ", "AppC", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
};
auto store = aStoreWithPresets(existing);
store.setMaximum(3);
UserPresetData newPreset{"D.categ", "AppD", "Huawei", "100 x 30", true, "Qt 6", "Fusion"};
store.save(newPreset);
auto presets = store.fetchAll();
ASSERT_THAT(presets, ElementsAre(existing[1], existing[2], newPreset));
}
TEST_F(QdsUserPresets, canLimitPresetsToAMaximumForReverseOrder)
{
std::vector<UserPresetData> existing{
{"A.categ", "AppA", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
{"B.categ", "AppB", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
{"C.categ", "AppC", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
};
auto store = aStoreWithPresets(existing);
store.setMaximum(3);
store.setReverseOrder();
UserPresetData newPreset{"D.categ", "AppD", "Huawei", "100 x 30", true, "Qt 6", "Fusion"};
store.save(newPreset);
auto presets = store.fetchAll();
ASSERT_THAT(presets, ElementsAre(newPreset, existing[0], existing[1]));
}
TEST_F(QdsUserPresets, canSavePresetsInReverseOrder)
{
UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
auto store = aStoreWithOne(existing, StorePolicy::UniqueNames);
store.setReverseOrder();
UserPresetData newPreset{"A.categ", "Empty", "Huawei", "100 x 30", true, "Qt 6", "Fusion"};
store.save(newPreset);
auto presets = store.fetchAll();
ASSERT_THAT(presets, ElementsAre(newPreset, existing));
}
TEST_F(QdsUserPresets, removeUserPresetFromEmptyStore) TEST_F(QdsUserPresets, removeUserPresetFromEmptyStore)
{ {
UserPresetData preset{"C.categ", "2D App", "Android", "", false, "", ""}; UserPresetData preset{"C.categ", "2D App", "Android", "", false, "", ""};

View File

@@ -46,11 +46,11 @@ class Targets:
"Desktop 5.14.1 default"])) "Desktop 5.14.1 default"]))
@staticmethod @staticmethod
def availableTargetClasses(): def availableTargetClasses(ignoreValidity=False):
availableTargets = set(Targets.ALL_TARGETS) availableTargets = set(Targets.ALL_TARGETS)
if not qt4Available: if not qt4Available and not ignoreValidity:
availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT) availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT)
if not qt4Available or platform.system() in ('Windows', 'Microsoft'): if not (qt4Available or ignoreValidity) or platform.system() in ('Windows', 'Microsoft'):
availableTargets.remove(Targets.EMBEDDED_LINUX) availableTargets.remove(Targets.EMBEDDED_LINUX)
elif platform.system() == 'Darwin': elif platform.system() == 'Darwin':
availableTargets.remove(Targets.DESKTOP_5_4_1_GCC) availableTargets.remove(Targets.DESKTOP_5_4_1_GCC)

View File

@@ -207,7 +207,7 @@ def __verifyFileCreation__(path, expectedFiles):
def __modifyAvailableTargets__(available, requiredQt, asStrings=False): def __modifyAvailableTargets__(available, requiredQt, asStrings=False):
versionFinder = re.compile("^Desktop (\\d{1}\.\\d{1,2}\.\\d{1,2}).*$") versionFinder = re.compile("^Desktop (\\d{1}\.\\d{1,2}\.\\d{1,2}).*$")
tmp = list(available) # we need a deep copy tmp = list(available) # we need a deep copy
if Qt5Path.toVersionTuple(requiredQt) > (4,8,7): if Qt5Path.toVersionTuple(requiredQt) > (4,8,7) and qt4Available:
toBeRemoved = Targets.EMBEDDED_LINUX toBeRemoved = Targets.EMBEDDED_LINUX
if asStrings: if asStrings:
toBeRemoved = Targets.getStringForTarget(toBeRemoved) toBeRemoved = Targets.getStringForTarget(toBeRemoved)
@@ -221,6 +221,8 @@ def __modifyAvailableTargets__(available, requiredQt, asStrings=False):
if found: if found:
if Qt5Path.toVersionTuple(found.group(1)) < Qt5Path.toVersionTuple(requiredQt): if Qt5Path.toVersionTuple(found.group(1)) < Qt5Path.toVersionTuple(requiredQt):
available.discard(currentItem) available.discard(currentItem)
elif currentItem.endswith(" (invalid)"):
available.discard(currentItem)
def __getProjectFileName__(projectName, buildSystem): def __getProjectFileName__(projectName, buildSystem):
if buildSystem is None or buildSystem == "CMake": if buildSystem is None or buildSystem == "CMake":
@@ -523,7 +525,9 @@ def __closeSubprocessByPushingStop__(isQtQuickUI):
# configured Qt versions and Toolchains and cannot be looked up the same way # configured Qt versions and Toolchains and cannot be looked up the same way
# if you set getAsStrings to True this function returns a list of strings instead # if you set getAsStrings to True this function returns a list of strings instead
# of the constants defined in Targets # of the constants defined in Targets
def __getSupportedPlatforms__(text, templateName, getAsStrings=False): # ignoreValidity if true kits will be considered available even if they are configured
# to use an invalid Qt
def __getSupportedPlatforms__(text, templateName, getAsStrings=False, ignoreValidity=False):
reqPattern = re.compile("requires qt (?P<version>\d+\.\d+(\.\d+)?)", re.IGNORECASE) reqPattern = re.compile("requires qt (?P<version>\d+\.\d+(\.\d+)?)", re.IGNORECASE)
res = reqPattern.search(text) res = reqPattern.search(text)
if res: if res:
@@ -536,11 +540,12 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False):
supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split("\n") supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split("\n")
result = set() result = set()
if 'Desktop' in supports: if 'Desktop' in supports:
if (version == None or version < "5.0") and not templateName.startswith("Qt Quick 2"): if (version == None or version < "5.0") and not templateName.startswith("Qt Quick"):
if qt4Available: neverIgnoreValidity = templateName in ("Qt Custom Designer Widget", "Code Snippet", "Subdirs Project")
if qt4Available or ignoreValidity and not neverIgnoreValidity:
result.add(Targets.DESKTOP_4_8_7_DEFAULT) result.add(Targets.DESKTOP_4_8_7_DEFAULT)
if platform.system() in ("Linux", "Darwin"): if platform.system() in ("Linux", "Darwin"):
result.add(Targets.EMBEDDED_LINUX) result.add(Targets.EMBEDDED_LINUX)
result = result.union(set([Targets.DESKTOP_5_10_1_DEFAULT, Targets.DESKTOP_5_14_1_DEFAULT])) result = result.union(set([Targets.DESKTOP_5_10_1_DEFAULT, Targets.DESKTOP_5_14_1_DEFAULT]))
if platform.system() != 'Darwin': if platform.system() != 'Darwin':
result.add(Targets.DESKTOP_5_4_1_GCC) result.add(Targets.DESKTOP_5_4_1_GCC)

View File

@@ -366,6 +366,9 @@ def getConfiguredKits():
def __setQtVersionForKit__(kit, kitName, kitsQtVersionName): def __setQtVersionForKit__(kit, kitName, kitsQtVersionName):
mouseClick(waitForObjectItem(":BuildAndRun_QTreeView", kit)) mouseClick(waitForObjectItem(":BuildAndRun_QTreeView", kit))
qtVersionStr = str(waitForObjectExists(":Kits_QtVersion_QComboBox").currentText) qtVersionStr = str(waitForObjectExists(":Kits_QtVersion_QComboBox").currentText)
invalid = qtVersionStr.endswith(" (invalid)")
if invalid:
qtVersionStr = qtVersionStr[:-10]
kitsQtVersionName[kitName] = qtVersionStr kitsQtVersionName[kitName] = qtVersionStr
# end of internal function for iterate kits # end of internal function for iterate kits

View File

@@ -1,6 +1,6 @@
############################################################################ ############################################################################
# #
# Copyright (C) 2016 The Qt Company Ltd. # Copyright (C) 2022 The Qt Company Ltd.
# Contact: https://www.qt.io/licensing/ # Contact: https://www.qt.io/licensing/
# #
# This file is part of Qt Creator. # This file is part of Qt Creator.
@@ -93,8 +93,8 @@ def main():
example = findExampleOrTutorial(listView, ".*", True) example = findExampleOrTutorial(listView, ".*", True)
test.verify(example is None, "Verifying: No example is shown.") test.verify(example is None, "Verifying: No example is shown.")
proFiles = map(lambda p: os.path.join(p, "opengl", "2dpainting", "2dpainting.pro"), proFiles = [os.path.join(p, "opengl", "2dpainting", "2dpainting.pro")
Qt5Path.getPaths(Qt5Path.EXAMPLES)) for p in Qt5Path.getPaths(Qt5Path.EXAMPLES)]
cleanUpUserFiles(proFiles) cleanUpUserFiles(proFiles)
for p in proFiles: for p in proFiles:
removePackagingDirectory(os.path.dirname(p)) removePackagingDirectory(os.path.dirname(p))
@@ -115,8 +115,8 @@ def main():
# go to "Welcome" page and choose another example # go to "Welcome" page and choose another example
switchViewTo(ViewConstants.WELCOME) switchViewTo(ViewConstants.WELCOME)
proFiles = map(lambda p: os.path.join(p, "widgets", "itemviews", "addressbook", "addressbook.pro"), proFiles = [os.path.join(p, "widgets", "itemviews", "addressbook", "addressbook.pro")
Qt5Path.getPaths(Qt5Path.EXAMPLES)) for p in Qt5Path.getPaths(Qt5Path.EXAMPLES)]
cleanUpUserFiles(proFiles) cleanUpUserFiles(proFiles)
for p in proFiles: for p in proFiles:
removePackagingDirectory(os.path.dirname(p)) removePackagingDirectory(os.path.dirname(p))

View File

@@ -156,7 +156,7 @@ def __createProject__(category, template):
origTxt = safeGetTextBrowserText() origTxt = safeGetTextBrowserText()
mouseClick(waitForObjectItem(templatesView, template)) mouseClick(waitForObjectItem(templatesView, template))
waitFor("origTxt != safeGetTextBrowserText() != ''", 2000) waitFor("origTxt != safeGetTextBrowserText() != ''", 2000)
displayedPlatforms = __getSupportedPlatforms__(safeGetTextBrowserText(), template, True)[0] displayedPlatforms = __getSupportedPlatforms__(safeGetTextBrowserText(), template, True, True)[0]
safeClickButton("Choose...") safeClickButton("Choose...")
# don't check because project could exist # don't check because project could exist
__createProjectSetNameAndPath__(os.path.expanduser("~"), 'untitled', False) __createProjectSetNameAndPath__(os.path.expanduser("~"), 'untitled', False)

View File

@@ -54,9 +54,9 @@ def main():
startQC() startQC()
if not startedWithoutPluginError(): if not startedWithoutPluginError():
return return
createProject_Qt_Console(tempDir(), "SquishProject") createProject_Qt_Console(tempDir(), "SquishProject", buildSystem = "qmake")
switchViewTo(ViewConstants.PROJECTS) switchViewTo(ViewConstants.PROJECTS)
verifyProjectsMode(Targets.getTargetsAsStrings(Targets.availableTargetClasses())) verifyProjectsMode(Targets.getTargetsAsStrings(Targets.availableTargetClasses(True)))
iterateKits(True, False, __removeKit__) iterateKits(True, False, __removeKit__)
clickButton(waitForObject(":Options.OK_QPushButton")) clickButton(waitForObject(":Options.OK_QPushButton"))
verifyProjectsMode([]) verifyProjectsMode([])

View File

@@ -165,7 +165,7 @@ def main():
startQC() startQC()
if not startedWithoutPluginError(): if not startedWithoutPluginError():
return return
createProject_Qt_GUI(srcPath, projectName, addToVersionControl = "Git") createProject_Qt_GUI(srcPath, projectName, addToVersionControl = "Git", buildSystem = "qmake")
openVcsLog() openVcsLog()
vcsLog = waitForObject("{type='Core::OutputWindow' unnamed='1' visible='1' " vcsLog = waitForObject("{type='Core::OutputWindow' unnamed='1' visible='1' "
"window=':Qt Creator_Core::Internal::MainWindow'}").plainText "window=':Qt Creator_Core::Internal::MainWindow'}").plainText