diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp index 58077be2b05..8f0da771143 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp @@ -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(m_collection->themeCount()); @@ -39,6 +54,8 @@ QVariant CollectionModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(groupType); case static_cast(Roles::BindingRole): return property->isBinding; + case static_cast(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(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(propInfo->first); } } - return {}; } @@ -89,6 +114,7 @@ QHash CollectionModel::roleNames() const auto roles = QAbstractItemModel::roleNames(); roles.insert(static_cast(Roles::GroupRole), "group"); roles.insert(static_cast(Roles::BindingRole), "isBinding"); + roles.insert(static_cast(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) { diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h index 3b7a6d0a0ab..3ab0250822b 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h @@ -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 findPropertyName(int row) const; diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp index 30e86ce95e8..08e430c77a3 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp @@ -48,6 +48,9 @@ std::optional 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 DSThemeManager::allThemeIds() const return ids; } +void DSThemeManager::setActiveTheme(ThemeId id) +{ + if (m_themes.contains(id)) + m_activeTheme = id; +} + void DSThemeManager::forAllGroups(std::function 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(0); + } +} } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h index 1286aea72d3..c36bcfed831 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h @@ -39,6 +39,9 @@ public: bool renameTheme(ThemeId id, const ThemeName &newName); const std::vector allThemeIds() const; + ThemeId activeTheme() const { return m_activeTheme; } + void setActiveTheme(ThemeId id); + void forAllGroups(std::function 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 m_themes; std::map> m_groups; + ThemeId m_activeTheme = static_cast(0); }; using DSCollections = std::map;