forked from qt-creator/qt-creator
DesignSystem: Enable setting a theme active
A collection can have only one theme active. First theme added to an empty collection is made active by default Task-number: QDS-14261 Change-Id: Ibf9a697ae0a817c45c4bef1a6fb4a9bd28462491 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -15,6 +15,21 @@ CollectionModel::CollectionModel(DSThemeManager *collection)
|
||||
updateCache();
|
||||
}
|
||||
|
||||
QStringList CollectionModel::themeNameList() const
|
||||
{
|
||||
QStringList themeNames(m_themeIdList.size());
|
||||
std::transform(m_themeIdList.begin(), m_themeIdList.end(), themeNames.begin(), [this](ThemeId id) {
|
||||
return QString::fromLatin1(m_collection->themeName(id));
|
||||
});
|
||||
return themeNames;
|
||||
}
|
||||
|
||||
void CollectionModel::setActiveTheme(const QString &themeName)
|
||||
{
|
||||
if (const auto themeId = m_collection->themeId(themeName.toLatin1()))
|
||||
m_collection->setActiveTheme(*themeId);
|
||||
}
|
||||
|
||||
int CollectionModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : static_cast<int>(m_collection->themeCount());
|
||||
@@ -39,6 +54,8 @@ QVariant CollectionModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant::fromValue<GroupType>(groupType);
|
||||
case static_cast<int>(Roles::BindingRole):
|
||||
return property->isBinding;
|
||||
case static_cast<int>(Roles::ActiveThemeRole):
|
||||
return m_collection->activeTheme() == themeId;
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -64,8 +81,17 @@ int CollectionModel::rowCount(const QModelIndex &parent) const
|
||||
|
||||
QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
return QString::fromLatin1(m_collection->themeName(findThemeId(section)));
|
||||
if (orientation == Qt::Horizontal) {
|
||||
auto themeId = findThemeId(section);
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QString::fromLatin1(m_collection->themeName(themeId));
|
||||
case static_cast<int>(Roles::ActiveThemeRole):
|
||||
return m_collection->activeTheme() == themeId;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (orientation == Qt::Vertical) {
|
||||
if (auto propInfo = findPropertyName(section)) {
|
||||
@@ -75,7 +101,6 @@ QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, i
|
||||
return QVariant::fromValue<GroupType>(propInfo->first);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -89,6 +114,7 @@ QHash<int, QByteArray> CollectionModel::roleNames() const
|
||||
auto roles = QAbstractItemModel::roleNames();
|
||||
roles.insert(static_cast<int>(Roles::GroupRole), "group");
|
||||
roles.insert(static_cast<int>(Roles::BindingRole), "isBinding");
|
||||
roles.insert(static_cast<int>(Roles::ActiveThemeRole), "isActive");
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -106,6 +132,7 @@ bool CollectionModel::insertColumns([[maybe_unused]] int column, int count, cons
|
||||
beginResetModel();
|
||||
updateCache();
|
||||
endResetModel();
|
||||
emit themeNameChanged();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -122,6 +149,7 @@ bool CollectionModel::removeColumns(int column, int count, const QModelIndex &pa
|
||||
|
||||
updateCache();
|
||||
endResetModel();
|
||||
emit themeNameChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -190,25 +218,26 @@ bool CollectionModel::setHeaderData(int section,
|
||||
const QVariant &value,
|
||||
int role)
|
||||
{
|
||||
if (role != Qt::EditRole)
|
||||
return false;
|
||||
|
||||
if (section < 0 || (orientation == Qt::Horizontal && section >= columnCount())
|
||||
if (role != Qt::EditRole || section < 0
|
||||
|| (orientation == Qt::Horizontal && section >= columnCount())
|
||||
|| (orientation == Qt::Vertical && section >= rowCount())) {
|
||||
return false; // Out of bounds
|
||||
}
|
||||
|
||||
const auto &newName = value.toString().toUtf8();
|
||||
bool success = false;
|
||||
if (orientation == Qt::Horizontal) {
|
||||
// Theme
|
||||
success = m_collection->renameTheme(findThemeId(section), newName);
|
||||
} else {
|
||||
if (orientation == Qt::Vertical) {
|
||||
// Property Name
|
||||
if (auto propInfo = findPropertyName(section)) {
|
||||
auto [groupType, propName] = *propInfo;
|
||||
success = m_collection->renameProperty(groupType, propName, newName);
|
||||
}
|
||||
} else {
|
||||
// Theme
|
||||
const auto themeId = findThemeId(section);
|
||||
success = m_collection->renameTheme(themeId, newName);
|
||||
if (success)
|
||||
emit themeNameChanged();
|
||||
}
|
||||
|
||||
if (success) {
|
||||
|
@@ -17,10 +17,15 @@ class CollectionModel : public QAbstractItemModel
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Roles { GroupRole = Qt::UserRole + 1, BindingRole };
|
||||
enum class Roles { GroupRole = Qt::UserRole + 1, BindingRole, ActiveThemeRole };
|
||||
|
||||
Q_PROPERTY(QStringList themeNames READ themeNameList NOTIFY themeNameChanged FINAL)
|
||||
|
||||
CollectionModel(DSThemeManager *collection);
|
||||
|
||||
QStringList themeNameList() const;
|
||||
Q_INVOKABLE void setActiveTheme(const QString &themeName);
|
||||
|
||||
// QAbstractItemModel Interface
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
@@ -52,6 +57,9 @@ public:
|
||||
const QVariant &value,
|
||||
int role = Qt::EditRole) override;
|
||||
|
||||
signals:
|
||||
void themeNameChanged();
|
||||
|
||||
private:
|
||||
ThemeId findThemeId(int column) const;
|
||||
std::optional<PropInfo> findPropertyName(int row) const;
|
||||
|
@@ -48,6 +48,9 @@ std::optional<ThemeId> DSThemeManager::addTheme(const ThemeName &themeNameHint)
|
||||
if (!m_themes.try_emplace(newThemeId, assignedThemeName).second)
|
||||
return {};
|
||||
|
||||
if (m_themes.size() == 1) // First theme. Make it active.
|
||||
reviewActiveTheme();
|
||||
|
||||
// Copy the new theme properties from an old theme(first one).
|
||||
if (m_themes.size() > 1)
|
||||
duplicateTheme(m_themes.begin()->first, newThemeId);
|
||||
@@ -101,6 +104,12 @@ const std::vector<ThemeId> DSThemeManager::allThemeIds() const
|
||||
return ids;
|
||||
}
|
||||
|
||||
void DSThemeManager::setActiveTheme(ThemeId id)
|
||||
{
|
||||
if (m_themes.contains(id))
|
||||
m_activeTheme = id;
|
||||
}
|
||||
|
||||
void DSThemeManager::forAllGroups(std::function<void(GroupType, DSThemeGroup *)> callback) const
|
||||
{
|
||||
if (!callback)
|
||||
@@ -131,7 +140,8 @@ void DSThemeManager::removeTheme(ThemeId id)
|
||||
for (auto &[gt, group] : m_groups)
|
||||
group->removeTheme(id);
|
||||
|
||||
m_themes.erase(id);
|
||||
if (m_themes.erase(id))
|
||||
reviewActiveTheme();
|
||||
}
|
||||
|
||||
void DSThemeManager::duplicateTheme(ThemeId from, ThemeId to)
|
||||
@@ -217,7 +227,7 @@ void DSThemeManager::decorate(ModelNode rootNode, const QByteArray &nodeType, bo
|
||||
return;
|
||||
|
||||
auto p = rootNode.bindingProperty("currentTheme");
|
||||
p.setDynamicTypeNameAndExpression(nodeType, QString::fromLatin1(m_themes.begin()->second));
|
||||
p.setDynamicTypeNameAndExpression(nodeType, QString::fromLatin1(m_themes.at(m_activeTheme)));
|
||||
if (!isMCU)
|
||||
addGroupAliases(rootNode);
|
||||
auto model = rootNode.model();
|
||||
@@ -390,4 +400,15 @@ PropertyName DSThemeManager::uniquePropertyName(const PropertyName &hint) const
|
||||
});
|
||||
return propName.toUtf8();
|
||||
}
|
||||
|
||||
void DSThemeManager::reviewActiveTheme()
|
||||
{
|
||||
// Active theme removed. Make the first one active
|
||||
if (!m_themes.contains(m_activeTheme)) {
|
||||
if (m_themes.size() > 0)
|
||||
setActiveTheme(m_themes.begin()->first);
|
||||
else
|
||||
m_activeTheme = static_cast<ThemeId>(0);
|
||||
}
|
||||
}
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -39,6 +39,9 @@ public:
|
||||
bool renameTheme(ThemeId id, const ThemeName &newName);
|
||||
const std::vector<ThemeId> allThemeIds() const;
|
||||
|
||||
ThemeId activeTheme() const { return m_activeTheme; }
|
||||
void setActiveTheme(ThemeId id);
|
||||
|
||||
void forAllGroups(std::function<void(GroupType, DSThemeGroup *)> callback) const;
|
||||
|
||||
void removeTheme(ThemeId id);
|
||||
@@ -70,9 +73,12 @@ private:
|
||||
ThemeName uniqueThemeName(const ThemeName &hint) const;
|
||||
PropertyName uniquePropertyName(const PropertyName &hint) const;
|
||||
|
||||
void reviewActiveTheme();
|
||||
|
||||
private:
|
||||
std::map<ThemeId, ThemeName> m_themes;
|
||||
std::map<GroupType, std::shared_ptr<DSThemeGroup>> m_groups;
|
||||
ThemeId m_activeTheme = static_cast<ThemeId>(0);
|
||||
};
|
||||
|
||||
using DSCollections = std::map<QString, DSThemeManager>;
|
||||
|
Reference in New Issue
Block a user