forked from qt-creator/qt-creator
QmlDesigner: Load DesignSystem automatically
* Connect to onCollectionsChanged and trigger load model in QML frontend * Connect to project and document changes and load design system * Fix DesignSystemView::loadDesignSystem * Add saving of design system collection * Fix late collections clear * Change load to refresh button * Add IgnoreErrors to design system view * Add clear model function in frontend When a project is loaded we now load the design system. We also load the design system if a file in Generated/DesignSystem is changed. Here we have to take care of reflection. Change-Id: Ie6b8b4becfee4ed05760e31b766d8d0a9b79a666 Reviewed-by: Vikas Pachdha <vikas.pachdha@qt.io> Reviewed-by: Henning Gründl <henning.gruendl@qt.io>
This commit is contained in:
committed by
Thomas Hartmann
parent
50e10af7c0
commit
c993e33613
@@ -44,7 +44,21 @@ Rectangle {
|
||||
height: 400
|
||||
color: StudioTheme.Values.themePanelBackground
|
||||
|
||||
function clearModel() {
|
||||
root.currentCollectionName = ""
|
||||
tableView.model = null
|
||||
|
||||
topLeftCell.visible = false
|
||||
createModeButton.enabled = false
|
||||
modelConnections.target = null
|
||||
}
|
||||
|
||||
function loadModel(name) {
|
||||
if (name === undefined) {
|
||||
clearModel()
|
||||
return
|
||||
}
|
||||
|
||||
root.currentCollectionName = name
|
||||
tableView.model = DesignSystemBackend.dsInterface.model(name)
|
||||
|
||||
@@ -256,6 +270,7 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
actionIndicatorVisible: false
|
||||
model: DesignSystemBackend.dsInterface.collections
|
||||
enabled: collectionsComboBox.count
|
||||
onActivated: root.loadModel(collectionsComboBox.currentText)
|
||||
}
|
||||
|
||||
@@ -264,7 +279,8 @@ Rectangle {
|
||||
style: StudioTheme.Values.viewBarControlStyle
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
actionIndicatorVisible: false
|
||||
model: tableView.model.themeNames
|
||||
model: tableView.model?.themeNames ?? null
|
||||
enabled: tableView.model
|
||||
onActivated: tableView.model.setActiveTheme(themesComboBox.currentText)
|
||||
}
|
||||
|
||||
@@ -274,6 +290,7 @@ Rectangle {
|
||||
buttonIcon: StudioTheme.Constants.more_medium
|
||||
checkable: true
|
||||
checked: moreMenu.visible
|
||||
tooltip: qsTr("More options")
|
||||
|
||||
onToggled: {
|
||||
if (moreMenu.visible)
|
||||
@@ -307,12 +324,21 @@ Rectangle {
|
||||
}
|
||||
|
||||
// TODO this is only for debugging purposes
|
||||
Button {
|
||||
Connections {
|
||||
target: DesignSystemBackend.dsInterface
|
||||
function onCollectionsChanged() {
|
||||
root.loadModel(DesignSystemBackend.dsInterface.collections[0])
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.IconTextButton {
|
||||
id: refreshButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("load")
|
||||
buttonIcon: StudioTheme.Constants.updateContent_medium
|
||||
tooltip: qsTr("Refresh")
|
||||
onClicked: {
|
||||
DesignSystemBackend.dsInterface.loadDesignSystem()
|
||||
root.loadModel(DesignSystemBackend.dsInterface.collections[0])
|
||||
//root.loadModel(DesignSystemBackend.dsInterface.collections[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,10 +10,14 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
CollectionModel::CollectionModel(DSThemeManager *collection, const DSStore *store)
|
||||
CollectionModel::CollectionModel(DSThemeManager *collection, DSStore *store)
|
||||
: m_collection(collection)
|
||||
, m_store(store)
|
||||
{
|
||||
m_saveCompressionTimer.setSingleShot(true);
|
||||
m_saveCompressionTimer.setInterval(200);
|
||||
connect(&m_saveCompressionTimer, &QTimer::timeout, this, &CollectionModel::save);
|
||||
|
||||
updateCache();
|
||||
}
|
||||
|
||||
@@ -28,8 +32,10 @@ QStringList CollectionModel::themeNameList() const
|
||||
|
||||
void CollectionModel::setActiveTheme(const QString &themeName)
|
||||
{
|
||||
if (const auto themeId = m_collection->themeId(themeName.toLatin1()))
|
||||
if (const auto themeId = m_collection->themeId(themeName.toLatin1())) {
|
||||
m_collection->setActiveTheme(*themeId);
|
||||
aboutToSave();
|
||||
}
|
||||
}
|
||||
|
||||
int CollectionModel::columnCount(const QModelIndex &parent) const
|
||||
@@ -149,6 +155,7 @@ bool CollectionModel::insertColumns([[maybe_unused]] int column, int count, cons
|
||||
beginResetModel();
|
||||
updateCache();
|
||||
endResetModel();
|
||||
aboutToSave();
|
||||
emit themeNameChanged();
|
||||
}
|
||||
return true;
|
||||
@@ -166,6 +173,7 @@ bool CollectionModel::removeColumns(int column, int count, const QModelIndex &pa
|
||||
|
||||
updateCache();
|
||||
endResetModel();
|
||||
aboutToSave();
|
||||
emit themeNameChanged();
|
||||
return true;
|
||||
}
|
||||
@@ -183,6 +191,7 @@ bool CollectionModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
}
|
||||
updateCache();
|
||||
endResetModel();
|
||||
aboutToSave();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -207,6 +216,8 @@ void CollectionModel::addProperty(GroupType group, const QString &name, const QV
|
||||
beginResetModel();
|
||||
updateCache();
|
||||
endResetModel();
|
||||
|
||||
aboutToSave();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +238,9 @@ bool CollectionModel::setData(const QModelIndex &index, const QVariant &value, i
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
aboutToSave();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -261,6 +275,8 @@ bool CollectionModel::setHeaderData(int section,
|
||||
beginResetModel();
|
||||
updateCache();
|
||||
endResetModel();
|
||||
|
||||
aboutToSave();
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -277,4 +293,16 @@ std::optional<PropInfo> CollectionModel::findPropertyName(int row) const
|
||||
QTC_ASSERT(row > -1 && row < static_cast<int>(m_propertyInfoList.size()), return {});
|
||||
return m_propertyInfoList[row];
|
||||
}
|
||||
|
||||
void CollectionModel::save()
|
||||
{
|
||||
QTC_ASSERT(m_store, return);
|
||||
m_store->save();
|
||||
}
|
||||
|
||||
void CollectionModel::aboutToSave()
|
||||
{
|
||||
m_saveCompressionTimer.start();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <designsystem/dsconstants.h>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QTimer>
|
||||
|
||||
#include <optional>
|
||||
|
||||
@@ -29,7 +30,7 @@ public:
|
||||
|
||||
Q_PROPERTY(QStringList themeNames READ themeNameList NOTIFY themeNameChanged FINAL)
|
||||
|
||||
CollectionModel(DSThemeManager *collection, const DSStore *store);
|
||||
CollectionModel(DSThemeManager *collection, DSStore *store);
|
||||
|
||||
QStringList themeNameList() const;
|
||||
Q_INVOKABLE void setActiveTheme(const QString &themeName);
|
||||
@@ -72,12 +73,17 @@ private:
|
||||
ThemeId findThemeId(int column) const;
|
||||
std::optional<PropInfo> findPropertyName(int row) const;
|
||||
|
||||
void save();
|
||||
void aboutToSave();
|
||||
|
||||
private:
|
||||
DSThemeManager *m_collection = nullptr;
|
||||
const DSStore *m_store;
|
||||
DSStore *m_store;
|
||||
|
||||
// cache
|
||||
std::vector<ThemeId> m_themeIdList;
|
||||
std::vector<PropInfo> m_propertyInfoList;
|
||||
|
||||
QTimer m_saveCompressionTimer;
|
||||
};
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -24,7 +24,10 @@ DesignSystemInterface::~DesignSystemInterface() {}
|
||||
void DesignSystemInterface::loadDesignSystem()
|
||||
{
|
||||
m_models.clear();
|
||||
m_store->load();
|
||||
|
||||
if (auto err = m_store->load())
|
||||
qDebug() << err;
|
||||
|
||||
emit collectionsChanged();
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,13 @@
|
||||
#include "designsystemwidget.h"
|
||||
#include "dsstore.h"
|
||||
|
||||
#include <qmldesignertr.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QQuickWidget>
|
||||
@@ -21,7 +27,21 @@ DesignSystemView::DesignSystemView(ExternalDependenciesInterface &externalDepend
|
||||
, m_externalDependencies(externalDependencies)
|
||||
, m_dsStore(std::make_unique<DSStore>(m_externalDependencies, projectStorageDependencies))
|
||||
, m_dsInterface(m_dsStore.get())
|
||||
{}
|
||||
{
|
||||
connect(ProjectExplorer::ProjectManager::instance(),
|
||||
&ProjectExplorer::ProjectManager::startupProjectChanged,
|
||||
this,
|
||||
[this](ProjectExplorer::Project *) { loadDesignSystem(); });
|
||||
|
||||
connect(Core::EditorManager::instance(),
|
||||
&Core::EditorManager::saved,
|
||||
this,
|
||||
[this](Core::IDocument *document) {
|
||||
if (document->filePath().contains("Generated/DesignSystem")) {
|
||||
loadDesignSystem();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DesignSystemView::~DesignSystemView() {}
|
||||
|
||||
@@ -33,7 +53,9 @@ WidgetInfo DesignSystemView::widgetInfo()
|
||||
return createWidgetInfo(m_designSystemWidget,
|
||||
"DesignSystemView",
|
||||
WidgetInfo::RightPane,
|
||||
tr("Design System"));
|
||||
Tr::tr("Design System"),
|
||||
Tr::tr("Design System view"),
|
||||
DesignerWidgetFlags::IgnoreErrors);
|
||||
}
|
||||
|
||||
bool DesignSystemView::hasWidget() const
|
||||
@@ -43,8 +65,10 @@ bool DesignSystemView::hasWidget() const
|
||||
|
||||
void DesignSystemView::loadDesignSystem()
|
||||
{
|
||||
if (auto err = m_dsStore->load())
|
||||
qDebug() << *err;
|
||||
/*This is only used to load internally - when saving we have to take care of reflection.
|
||||
* Saving should not trigger a load again.
|
||||
*/
|
||||
m_dsInterface.loadDesignSystem();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QScopeGuard>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -113,14 +114,17 @@ std::optional<QString> DSStore::load()
|
||||
|
||||
std::optional<QString> DSStore::load(const Utils::FilePath &dsModuleDirPath)
|
||||
{
|
||||
if (m_blockLoading)
|
||||
return {};
|
||||
|
||||
m_collections.clear();
|
||||
|
||||
// read qmldir
|
||||
const auto qmldirFile = dsModuleDirPath / "qmldir";
|
||||
const Utils::expected_str<QByteArray> contents = qmldirFile.fileContents();
|
||||
if (!contents)
|
||||
return tr("Can not read Design System qmldir");
|
||||
|
||||
m_collections.clear();
|
||||
|
||||
// Parse qmldir
|
||||
QString qmldirData = QString::fromUtf8(*contents);
|
||||
QmlDirParser qmlDirParser;
|
||||
@@ -160,6 +164,9 @@ std::optional<QString> DSStore::save(const Utils::FilePath &moduleDirPath, bool
|
||||
if (!QDir().mkpath(moduleDirPath.absoluteFilePath().toUrlishString()))
|
||||
return tr("Can not create design system module directory %1.").arg(moduleDirPath.toUrlishString());
|
||||
|
||||
const QScopeGuard cleanup([&] { m_blockLoading = false; });
|
||||
m_blockLoading = true;
|
||||
|
||||
// dump collections
|
||||
QStringList singletons;
|
||||
QStringList errors;
|
||||
|
@@ -52,5 +52,6 @@ private:
|
||||
ExternalDependenciesInterface &m_ed;
|
||||
ProjectStorageDependencies m_projectStorageDependencies;
|
||||
DSCollections m_collections;
|
||||
bool m_blockLoading = false;
|
||||
};
|
||||
} // namespace QmlDesigner
|
||||
|
Reference in New Issue
Block a user