forked from qt-creator/qt-creator
QDS New Project Dialog fix: recents should include all project properties
Previously, only the wizard category, name, and size were saved for recent presets. Solved the problem by using the same kind of store (and struct type) for Recent presets as for User/Custom presets - this way we can save all properties. Other changes introduced: * After user creates custom preset C, then creates a project from it (resulting in the creation of a Recent preset R), if the user then deletes custom preset C, then the recent preset R will remain - previously, all recents of the custom preset were deleted * Now we can have multiple recent presets with the same name and size - so, no distinguishing feature inside the Presets view. User will have to look at Details and Styles panes to view differences. * Replaced .ini format with *.json file format. Change-Id: I500e9ac9378d4b9a393c3b0833ef6a34f785585c Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -13,7 +13,6 @@ add_qtc_plugin(StudioWelcome
|
||||
wizardfactories.cpp wizardfactories.h
|
||||
createproject.cpp createproject.h
|
||||
wizardhandler.cpp wizardhandler.h
|
||||
recentpresets.cpp recentpresets.h
|
||||
userpresets.cpp userpresets.h
|
||||
screensizemodel.h
|
||||
algorithm.h
|
||||
|
@@ -42,6 +42,16 @@ template<typename C, typename F>
|
||||
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
|
||||
template<typename C, typename T = typename C::value_type>
|
||||
[[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>
|
||||
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);
|
||||
if (i == std::cend(container))
|
||||
return;
|
||||
return false;
|
||||
|
||||
container.erase(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename C, typename T>
|
||||
|
@@ -47,7 +47,7 @@ QString PresetData::recentsTabName()
|
||||
|
||||
void PresetData::setData(const PresetsByCategory &presetsByCategory,
|
||||
const std::vector<UserPresetData> &userPresetsData,
|
||||
const std::vector<RecentPresetData> &loadedRecentsData)
|
||||
const std::vector<UserPresetData> &loadedRecentsData)
|
||||
{
|
||||
QTC_ASSERT(!presetsByCategory.empty(), return );
|
||||
m_recents = loadedRecentsData;
|
||||
@@ -60,16 +60,13 @@ void PresetData::setData(const PresetsByCategory &presetsByCategory,
|
||||
|
||||
PresetItems wizardPresets = Utils::flatten(m_presets);
|
||||
|
||||
PresetItems userPresetItems = makeUserPresets(wizardPresets);
|
||||
PresetItems userPresetItems = makeUserPresets(wizardPresets, m_userPresets);
|
||||
if (!userPresetItems.empty()) {
|
||||
m_categories.push_back(CustomTabName);
|
||||
m_presets.push_back(userPresetItems);
|
||||
}
|
||||
|
||||
PresetItems allWizardPresets = std::move(wizardPresets);
|
||||
Utils::concat(allWizardPresets, userPresetItems);
|
||||
|
||||
PresetItems recentPresets = makeRecentPresets(allWizardPresets);
|
||||
PresetItems recentPresets = makeUserPresets(wizardPresets, m_recents);
|
||||
if (!recentPresets.empty()) {
|
||||
Utils::prepend(m_categories, RecentsTabName);
|
||||
Utils::prepend(m_presets, recentPresets);
|
||||
@@ -79,7 +76,7 @@ void PresetData::setData(const PresetsByCategory &presetsByCategory,
|
||||
}
|
||||
|
||||
void PresetData::reload(const std::vector<UserPresetData> &userPresetsData,
|
||||
const std::vector<RecentPresetData> &loadedRecentsData)
|
||||
const std::vector<UserPresetData> &loadedRecentsData)
|
||||
{
|
||||
m_categories.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;
|
||||
|
||||
for (const UserPresetData &userPresetData : m_userPresets) {
|
||||
for (const UserPresetData &userPresetData : data) {
|
||||
std::shared_ptr<PresetItem> foundPreset = findPresetItemForUserPreset(userPresetData,
|
||||
wizardPresets);
|
||||
if (!foundPreset)
|
||||
@@ -128,35 +126,6 @@ PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets)
|
||||
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(const PresetData *data, QObject *parent)
|
||||
|
@@ -33,7 +33,6 @@
|
||||
#include <utils/optional.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include "recentpresets.h"
|
||||
#include "userpresets.h"
|
||||
|
||||
namespace Utils {
|
||||
@@ -169,10 +168,10 @@ class PresetData
|
||||
{
|
||||
public:
|
||||
void reload(const std::vector<UserPresetData> &userPresets,
|
||||
const std::vector<RecentPresetData> &loadedRecents);
|
||||
const std::vector<UserPresetData> &loadedRecents);
|
||||
void setData(const PresetsByCategory &presets,
|
||||
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 Categories &categories() const { return m_categories; }
|
||||
@@ -180,16 +179,13 @@ public:
|
||||
static QString recentsTabName();
|
||||
|
||||
private:
|
||||
PresetItems makeRecentPresets(const PresetItems &wizardPresets);
|
||||
PresetItems makeUserPresets(const PresetItems &wizardPresets);
|
||||
|
||||
PresetItems makeUserPresets(const PresetItems &wizardPresets, const std::vector<UserPresetData> &data);
|
||||
std::shared_ptr<PresetItem> findPresetItemForUserPreset(const UserPresetData &preset, const PresetItems &wizardPresets);
|
||||
std::shared_ptr<PresetItem> findPresetItemForRecent(const RecentPresetData &recent, const PresetItems &wizardPresets);
|
||||
|
||||
private:
|
||||
std::vector<PresetItems> m_presets;
|
||||
Categories m_categories;
|
||||
std::vector<RecentPresetData> m_recents;
|
||||
std::vector<UserPresetData> m_recents;
|
||||
std::vector<UserPresetData> m_userPresets;
|
||||
PresetsByCategory m_presetsByCategory;
|
||||
};
|
||||
|
@@ -72,10 +72,14 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
|
||||
, m_presetModel{new PresetModel(&m_presetData, this)}
|
||||
, m_screenSizeModel{new ScreenSizeModel(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);
|
||||
|
||||
m_recentsStore.setReverseOrder();
|
||||
m_recentsStore.setMaximum(10);
|
||||
|
||||
m_dialog->setResizeMode(QQuickWidget::SizeRootObjectToView); // SizeViewToRootObject
|
||||
m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"),
|
||||
new Internal::NewProjectDialogImageProvider());
|
||||
@@ -190,8 +194,11 @@ void QdsNewDialog::updateScreenSizes()
|
||||
|
||||
void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandardItemModel *styleModel)
|
||||
{
|
||||
m_screenSizeModel->setBackendModel(screenSizeModel);
|
||||
m_styleModel->setBackendModel(styleModel);
|
||||
if (screenSizeModel)
|
||||
m_screenSizeModel->setBackendModel(screenSizeModel);
|
||||
|
||||
if (styleModel)
|
||||
m_styleModel->setBackendModel(styleModel);
|
||||
|
||||
auto userPreset = m_currentPreset->asUserPreset();
|
||||
|
||||
@@ -326,7 +333,7 @@ void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
|
||||
|
||||
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();
|
||||
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.
|
||||
*/
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
onWizardCreated(nullptr, nullptr);
|
||||
}
|
||||
|
||||
QString QdsNewDialog::recentsTabName() const
|
||||
@@ -431,7 +418,8 @@ void QdsNewDialog::accept()
|
||||
std::shared_ptr<PresetItem> item = m_wizard.preset();
|
||||
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->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 targetQtVersion = "";
|
||||
@@ -489,12 +477,19 @@ void QdsNewDialog::savePresetDialogAccept()
|
||||
|
||||
UserPresetData preset = {m_currentPreset->categoryId,
|
||||
m_currentPreset->wizardName,
|
||||
m_qmlPresetName,
|
||||
displayName,
|
||||
screenSize,
|
||||
useVirtualKeyboard,
|
||||
targetQtVersion,
|
||||
styleName};
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
||||
void QdsNewDialog::savePresetDialogAccept()
|
||||
{
|
||||
UserPresetData preset = currentUserPresetData(m_qmlPresetName);
|
||||
|
||||
if (!m_userPresetsStore.save(preset)) {
|
||||
QMessageBox::warning(m_dialog,
|
||||
tr("Save Preset"),
|
||||
@@ -503,7 +498,7 @@ void QdsNewDialog::savePresetDialogAccept()
|
||||
}
|
||||
|
||||
// reload model
|
||||
std::vector<RecentPresetData> recents = m_recentsStore.fetchAll();
|
||||
std::vector<UserPresetData> recents = m_recentsStore.fetchAll();
|
||||
std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
|
||||
m_presetData.reload(userPresets, recents);
|
||||
|
||||
@@ -520,8 +515,8 @@ void QdsNewDialog::removeCurrentPreset()
|
||||
}
|
||||
|
||||
// remove preset & reload model
|
||||
std::vector<RecentPresetData> recents = m_recentsStore.remove(m_currentPreset->categoryId,
|
||||
m_currentPreset->displayName());
|
||||
UserPresetData currentPreset = currentUserPresetData(m_qmlPresetName);
|
||||
std::vector<UserPresetData> recents = m_recentsStore.remove(currentPreset);
|
||||
|
||||
auto userPreset = m_currentPreset->asUserPreset();
|
||||
m_userPresetsStore.remove(userPreset->categoryId, userPreset->displayName());
|
||||
|
@@ -34,7 +34,6 @@
|
||||
#include "presetmodel.h"
|
||||
#include "screensizemodel.h"
|
||||
#include "stylemodel.h"
|
||||
#include "recentpresets.h"
|
||||
#include "userpresets.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@@ -153,6 +152,7 @@ private:
|
||||
|
||||
void updateScreenSizes();
|
||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||
UserPresetData currentUserPresetData(const QString &displayName) const;
|
||||
|
||||
private slots:
|
||||
void onDeletingWizard();
|
||||
@@ -194,7 +194,7 @@ private:
|
||||
std::shared_ptr<PresetItem> m_currentPreset;
|
||||
|
||||
WizardHandler m_wizard;
|
||||
RecentPresetsStore m_recentsStore;
|
||||
UserPresetsStore m_recentsStore;
|
||||
UserPresetsStore m_userPresetsStore;
|
||||
};
|
||||
|
||||
|
@@ -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());
|
||||
});
|
||||
}
|
@@ -1,101 +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 <vector>
|
||||
#include <QPair>
|
||||
#include <QSettings>
|
||||
|
||||
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
|
@@ -37,8 +37,6 @@ QtcPlugin {
|
||||
"wizardfactories.h",
|
||||
"wizardhandler.cpp",
|
||||
"wizardhandler.h",
|
||||
"recentpresets.cpp",
|
||||
"recentpresets.h",
|
||||
"userpresets.cpp",
|
||||
"userpresets.h"
|
||||
]
|
||||
|
@@ -24,43 +24,75 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "userpresets.h"
|
||||
#include "algorithm.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <memory>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace StudioWelcome;
|
||||
|
||||
constexpr char PREFIX[] = "UserPresets";
|
||||
|
||||
UserPresetsStore::UserPresetsStore()
|
||||
{
|
||||
m_settings = std::make_unique<QSettings>(fullFilePath(), QSettings::IniFormat);
|
||||
}
|
||||
|
||||
UserPresetsStore::UserPresetsStore(std::unique_ptr<QSettings> &&settings)
|
||||
: m_settings{std::move(settings)}
|
||||
FileStoreIo::FileStoreIo(const QString &fileName)
|
||||
: m_file{std::make_unique<QFile>(fullFilePath(fileName))}
|
||||
{}
|
||||
|
||||
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) {
|
||||
m_settings->setArrayIndex(static_cast<int>(i));
|
||||
const auto &preset = presets[i];
|
||||
return data;
|
||||
}
|
||||
|
||||
m_settings->setValue("categoryId", preset.categoryId);
|
||||
m_settings->setValue("wizardName", preset.wizardName);
|
||||
m_settings->setValue("name", preset.name);
|
||||
m_settings->setValue("screenSize", preset.screenSize);
|
||||
m_settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
|
||||
m_settings->setValue("qtVersion", preset.qtVersion);
|
||||
m_settings->setValue("styleName", preset.styleName);
|
||||
void FileStoreIo::write(const QByteArray &data)
|
||||
{
|
||||
m_file->open(QFile::WriteOnly | QFile::Text);
|
||||
m_file->write(data);
|
||||
m_file->close();
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -68,12 +100,30 @@ bool UserPresetsStore::save(const UserPresetData &newPreset)
|
||||
QTC_ASSERT(newPreset.isValid(), return false);
|
||||
|
||||
std::vector<UserPresetData> presetItems = fetchAll();
|
||||
if (Utils::anyOf(presetItems,
|
||||
[&newPreset](const UserPresetData &p) { return p.name == newPreset.name; })) {
|
||||
return false;
|
||||
|
||||
if (m_policy == StorePolicy::UniqueNames) {
|
||||
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);
|
||||
|
||||
return true;
|
||||
@@ -92,34 +142,45 @@ void UserPresetsStore::remove(const QString &category, const QString &name)
|
||||
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
|
||||
{
|
||||
QByteArray data = m_store->read();
|
||||
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
if (!doc.isArray())
|
||||
return {};
|
||||
|
||||
std::vector<UserPresetData> result;
|
||||
int size = m_settings->beginReadArray(PREFIX);
|
||||
if (size >= 0)
|
||||
result.reserve(static_cast<size_t>(size) + 1);
|
||||
const QJsonArray jsonArray = doc.array();
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
m_settings->setArrayIndex(i);
|
||||
for (const QJsonValue &value: jsonArray) {
|
||||
if (!value.isObject())
|
||||
continue;
|
||||
|
||||
const QJsonObject obj = value.toObject();
|
||||
UserPresetData preset;
|
||||
preset.categoryId = m_settings->value("categoryId").toString();
|
||||
preset.wizardName = m_settings->value("wizardName").toString();
|
||||
preset.name = m_settings->value("name").toString();
|
||||
preset.screenSize = m_settings->value("screenSize").toString();
|
||||
preset.useQtVirtualKeyboard = m_settings->value("useQtVirtualKeyboard").toBool();
|
||||
preset.qtVersion = m_settings->value("qtVersion").toString();
|
||||
preset.styleName = m_settings->value("styleName").toString();
|
||||
|
||||
preset.categoryId = obj["categoryId"].toString();
|
||||
preset.wizardName = obj["wizardName"].toString();
|
||||
preset.name = obj["name"].toString();
|
||||
preset.screenSize = obj["screenSize"].toString();
|
||||
preset.useQtVirtualKeyboard = obj["useQtVirtualKeyboard"].toBool();
|
||||
preset.qtVersion = obj["qtVersion"].toString();
|
||||
preset.styleName = obj["styleName"].toString();
|
||||
|
||||
if (preset.isValid())
|
||||
result.push_back(std::move(preset));
|
||||
result.push_back(preset);
|
||||
}
|
||||
m_settings->endArray();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString UserPresetsStore::fullFilePath() const
|
||||
{
|
||||
return Core::ICore::userResourcePath("UserPresets.ini").toString();
|
||||
}
|
||||
|
@@ -25,8 +25,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <QSettings>
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
|
||||
namespace StudioWelcome {
|
||||
|
||||
@@ -68,24 +70,59 @@ inline bool operator==(const UserPresetData &lhs, const UserPresetData &rhs)
|
||||
return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName
|
||||
&& lhs.name == rhs.name && lhs.screenSize == rhs.screenSize
|
||||
&& 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
|
||||
{
|
||||
public:
|
||||
UserPresetsStore();
|
||||
UserPresetsStore(std::unique_ptr<QSettings> &&settings);
|
||||
UserPresetsStore(const QString &fileName, StorePolicy policy);
|
||||
UserPresetsStore(std::unique_ptr<StoreIo> &&store, StorePolicy policy);
|
||||
|
||||
bool save(const UserPresetData &preset);
|
||||
void remove(const QString &category, const QString &name);
|
||||
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:
|
||||
QString fullFilePath() const;
|
||||
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
|
||||
|
@@ -17,14 +17,12 @@ add_qtc_test(tst_qml_wizard
|
||||
SOURCES
|
||||
wizardfactories-test.cpp
|
||||
stylemodel-test.cpp
|
||||
recentpresets-test.cpp
|
||||
userpresets-test.cpp
|
||||
presetmodel-test.cpp
|
||||
test-utilities.h
|
||||
test-main.cpp
|
||||
"${StudioWelcomeDir}/wizardfactories.cpp"
|
||||
"${StudioWelcomeDir}/stylemodel.cpp"
|
||||
"${StudioWelcomeDir}/recentpresets.cpp"
|
||||
"${StudioWelcomeDir}/userpresets.cpp"
|
||||
"${StudioWelcomeDir}/presetmodel.cpp"
|
||||
)
|
||||
|
@@ -100,6 +100,14 @@ UserPresetData aUserPreset(const QString &categId, const QString &wizardName, co
|
||||
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}))
|
||||
{
|
||||
return arg->categoryId == category && arg->wizardName == name;
|
||||
@@ -139,6 +147,7 @@ TEST(QdsPresetModel, haveSameArraySizeForPresetsAndCategories)
|
||||
PresetData data;
|
||||
|
||||
data.setData(
|
||||
/*wizard presets*/
|
||||
{
|
||||
aCategory("A.categ", "A", {"item a", "item b"}),
|
||||
aCategory("B.categ", "B", {"item c", "item d"}),
|
||||
@@ -157,6 +166,7 @@ TEST(QdsPresetModel, haveWizardPresetsNoRecents)
|
||||
|
||||
// When
|
||||
data.setData(
|
||||
/*wizard presets*/
|
||||
{
|
||||
aCategory("A.categ", "A", {"item a", "item b"}),
|
||||
aCategory("B.categ", "B", {"item c", "item d"}),
|
||||
@@ -179,6 +189,7 @@ TEST(QdsPresetModel, whenHaveUserPresetsButNoWizardPresetsReturnEmpty)
|
||||
|
||||
// When
|
||||
data.setData({/*builtin presets*/},
|
||||
/*user presets*/
|
||||
{
|
||||
aUserPreset("A.Mobile", "Scroll", "iPhone5"),
|
||||
aUserPreset("B.Desktop", "Launcher", "MacBook"),
|
||||
@@ -196,9 +207,10 @@ TEST(QdsPresetModel, haveRecentsNoWizardPresets)
|
||||
|
||||
data.setData({/*wizardPresets*/},
|
||||
{/*user presets*/},
|
||||
/*recent presets*/
|
||||
{
|
||||
{"A.categ", "Desktop", "640 x 480"},
|
||||
{"B.categ", "Mobile", "800 x 600"},
|
||||
aRecentPreset("A.categ", "Desktop", "640 x 480"),
|
||||
aRecentPreset("B.categ", "Mobile", "800 x 600"),
|
||||
});
|
||||
|
||||
ASSERT_THAT(data.categories(), IsEmpty());
|
||||
@@ -220,8 +232,8 @@ TEST(QdsPresetModel, recentsAddedWithWizardPresets)
|
||||
{/*user presets*/},
|
||||
/*recents*/
|
||||
{
|
||||
{"A.categ", "Desktop", "800 x 600"},
|
||||
{"B.categ", "Mobile", "640 x 480"},
|
||||
aRecentPreset("A.categ", "Desktop", "800 x 600"),
|
||||
aRecentPreset("B.categ", "Mobile", "640 x 480"),
|
||||
});
|
||||
|
||||
// Then
|
||||
@@ -247,6 +259,7 @@ TEST(QdsPresetModel, userPresetsAddedWithWizardPresets)
|
||||
aCategory("A.categ", "A", {"Desktop", "item b"}),
|
||||
aCategory("B.categ", "B", {"Mobile"}),
|
||||
},
|
||||
/*user presets*/
|
||||
{
|
||||
aUserPreset("A.categ", "Desktop", "Windows10"),
|
||||
},
|
||||
@@ -272,6 +285,7 @@ TEST(QdsPresetModel, doesNotAddUserPresetsOfNonExistingCategory)
|
||||
{
|
||||
aCategory("A.categ", "A", {"Desktop"}), // Only category "A.categ" exists
|
||||
},
|
||||
/*user presets*/
|
||||
{
|
||||
aUserPreset("Bad.Categ", "Desktop", "Windows8"), // Bad.Categ does not exist
|
||||
},
|
||||
@@ -293,6 +307,7 @@ TEST(QdsPresetModel, doesNotAddUserPresetIfWizardPresetItRefersToDoesNotExist)
|
||||
{
|
||||
aCategory("A.categ", "A", {"Desktop"}),
|
||||
},
|
||||
/*user presets*/
|
||||
{
|
||||
aUserPreset("B.categ", "BadWizard", "Tablet"), // BadWizard referenced does not exist
|
||||
},
|
||||
@@ -314,6 +329,7 @@ TEST(QdsPresetModel, userPresetWithSameNameAsWizardPreset)
|
||||
{
|
||||
aCategory("A.categ", "A", {"Desktop"}),
|
||||
},
|
||||
/*user presets*/
|
||||
{
|
||||
aUserPreset("A.categ", "Desktop", "Desktop"),
|
||||
},
|
||||
@@ -326,58 +342,7 @@ TEST(QdsPresetModel, userPresetWithSameNameAsWizardPreset)
|
||||
ElementsAre(UserPresetIs("A.categ", "Desktop", "Desktop"))));
|
||||
}
|
||||
|
||||
TEST(QdsPresetModel, recentOfUserPresetReferringToExistingWizardPreset)
|
||||
{
|
||||
// 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)
|
||||
TEST(QdsPresetModel, recentOfNonExistentWizardPreset)
|
||||
{
|
||||
// Given
|
||||
PresetData data;
|
||||
@@ -391,7 +356,7 @@ TEST(QdsPresetModel, recentOfNonExistentUserPreset)
|
||||
{/*user presets*/},
|
||||
/*recents*/
|
||||
{
|
||||
{"A.categ", "Windows 7", "200 x 300", /*is user*/true}
|
||||
aRecentPreset("A.categ", "Windows 7", "200 x 300")
|
||||
});
|
||||
|
||||
// Then
|
||||
@@ -415,9 +380,9 @@ TEST(QdsPresetModel, recentsShouldNotBeSorted)
|
||||
{/*user presets*/},
|
||||
/*recents*/
|
||||
{
|
||||
{"Z.categ", "Z.desktop", "200 x 300"},
|
||||
{"B.categ", "Mobile", "200 x 300"},
|
||||
{"A.categ", "Desktop", "200 x 300"},
|
||||
aRecentPreset("Z.categ", "Z.desktop", "200 x 300"),
|
||||
aRecentPreset("B.categ", "Mobile", "200 x 300"),
|
||||
aRecentPreset("A.categ", "Desktop", "200 x 300"),
|
||||
});
|
||||
|
||||
// Then
|
||||
@@ -442,9 +407,9 @@ TEST(QdsPresetModel, recentsOfSameWizardProjectButDifferentSizesAreRecognizedAsD
|
||||
{/*user presets*/},
|
||||
/*recents*/
|
||||
{
|
||||
{"B.categ", "Mobile", "400 x 400"},
|
||||
{"B.categ", "Mobile", "200 x 300"},
|
||||
{"A.categ", "Desktop", "640 x 480"},
|
||||
aRecentPreset("B.categ", "Mobile", "400 x 400"),
|
||||
aRecentPreset("B.categ", "Mobile", "200 x 300"),
|
||||
aRecentPreset("A.categ", "Desktop", "640 x 480"),
|
||||
});
|
||||
|
||||
// Then
|
||||
@@ -454,6 +419,35 @@ TEST(QdsPresetModel, recentsOfSameWizardProjectButDifferentSizesAreRecognizedAsD
|
||||
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)
|
||||
{
|
||||
// Given
|
||||
@@ -469,8 +463,8 @@ TEST(QdsPresetModel, outdatedRecentsAreNotShown)
|
||||
{/*user presets*/},
|
||||
/*recents*/
|
||||
{
|
||||
{"B.categ", "NoLongerExists", "400 x 400"},
|
||||
{"A.categ", "Desktop", "640 x 480"},
|
||||
aRecentPreset("B.categ", "NoLongerExists", "400 x 400"),
|
||||
aRecentPreset("A.categ", "Desktop", "640 x 480"),
|
||||
});
|
||||
|
||||
// Then
|
||||
|
@@ -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")));
|
||||
}
|
@@ -29,6 +29,10 @@
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace StudioWelcome {
|
||||
|
||||
void PrintTo(const UserPresetData &preset, std::ostream *os)
|
||||
@@ -64,69 +68,85 @@ using namespace StudioWelcome;
|
||||
|
||||
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
|
||||
{
|
||||
protected:
|
||||
void SetUp()
|
||||
{
|
||||
settings = std::make_unique<QSettings>(tempDir.filePath("test").toString(),
|
||||
QSettings::IniFormat);
|
||||
storeIo = std::make_unique<FakeStoreIo>();
|
||||
}
|
||||
|
||||
UserPresetsStore anEmptyStore() { return UserPresetsStore{std::move(settings)}; }
|
||||
UserPresetsStore anEmptyStore()
|
||||
{
|
||||
return UserPresetsStore{std::move(storeIo), StorePolicy::UniqueNames};
|
||||
}
|
||||
|
||||
UserPresetsStore aStoreWithZeroItems()
|
||||
{
|
||||
settings->beginWriteArray(ARRAY_NAME, 0);
|
||||
settings->endArray();
|
||||
storeIo->data = "[]";
|
||||
|
||||
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);
|
||||
settings->setArrayIndex(0);
|
||||
QJsonArray array({QJsonObject{{"categoryId", preset.categoryId},
|
||||
{"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);
|
||||
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)};
|
||||
return UserPresetsStore{std::move(storeIo), policy};
|
||||
}
|
||||
|
||||
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) {
|
||||
settings->setArrayIndex(i);
|
||||
const auto &preset = presets[i];
|
||||
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}});
|
||||
|
||||
settings->setValue("categoryId", preset.categoryId);
|
||||
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);
|
||||
array.append(QJsonValue{obj});
|
||||
}
|
||||
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"};
|
||||
std::unique_ptr<QSettings> settings;
|
||||
std::unique_ptr<FakeStoreIo> storeIo;
|
||||
|
||||
private:
|
||||
QString settingsPath;
|
||||
QString storeIoPath;
|
||||
};
|
||||
|
||||
/******************* TESTS *******************/
|
||||
@@ -234,10 +254,10 @@ TEST_F(QdsUserPresets, saveIncompletePreset)
|
||||
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"};
|
||||
auto store = aStoreWithOne(existing);
|
||||
auto store = aStoreWithOne(existing, StorePolicy::UniqueNames);
|
||||
|
||||
UserPresetData newPreset{"C.categ", "Empty", "Same Name", "100 x 30", false, "Qt 6", "Fusion"};
|
||||
bool saved = store.save(newPreset);
|
||||
@@ -246,6 +266,30 @@ TEST_F(QdsUserPresets, cannotSavePresetWithSameName)
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
UserPresetData preset{"C.categ", "2D App", "Android", "", false, "", ""};
|
||||
|
Reference in New Issue
Block a user