From 785da8b434c6108e97e71fbaac66bf6eea70d243 Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Wed, 9 Oct 2024 14:02:12 +0300 Subject: [PATCH] QmlDesigner: Track folders expanded/collapsed state in AssetsLibrary Fixes: QDS-13791 Change-Id: I6d30e6d1d79da99466f0fa7b762267701bc2d2e2 Reviewed-by: Miikka Heikkinen --- .../assetsLibraryQmlSources/AssetDelegate.qml | 15 ++++++ .../assetsLibraryQmlSources/AssetsView.qml | 36 ++++++------- .../assetslibrary/assetslibrarymodel.cpp | 50 ++++++++++++++++++- .../assetslibrary/assetslibrarymodel.h | 6 +++ .../assetslibrary/assetslibrarywidget.cpp | 16 ++++-- 5 files changed, 96 insertions(+), 27 deletions(-) diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml index 32485a61a1e..e49aba96ec8 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml @@ -48,6 +48,19 @@ TreeViewDelegate { root.depth -= root.assetsView.rootPathDepth root.initialDepth = root.depth } + + // expand/collapse folder based on its stored expanded state + if (root.__isDirectory) { + // if the folder expand state is not stored yet, stores it as true (expanded) + root.assetsModel.initializeExpandState(root.__itemPath) + + let expandState = assetsModel.folderExpandState(root.__itemPath) + + if (expandState) + root.assetsView.expand(root.__currentRow) + else + root.assetsView.collapse(root.__currentRow) + } } // workaround for a bug -- might be fixed by https://codereview.qt-project.org/c/qt/qtdeclarative/+/442721 @@ -295,6 +308,8 @@ TreeViewDelegate { } else { root.assetsView.expand(root.__currentRow) } + + assetsModel.saveExpandState(root.__itemPath, root.expanded) } function reloadImage() { diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml index e11fab92f17..e404d2f3580 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml @@ -93,7 +93,6 @@ TreeView { function onDirectoryCreated(path) { root.__createdDirectories.push(path) - updateRowsTimer.restart() } @@ -118,15 +117,7 @@ TreeView { // updating rows for safety: the rows might have been created before the // directory (esp. the root path) has been loaded, so we must make sure all rows are // expanded -- otherwise, the tree may not become visible. - updateRowsTimer.restart() - - let idx = assetsModel.indexForPath(path) - let row = root.rowAtIndex(idx) - let column = root.columnAtIndex(idx) - - if (row >= root.rootPathRow && !root.isExpanded(row)) - root.expand(row) } function onRootPathChanged() @@ -180,9 +171,9 @@ TreeView { let index = assetsModel.indexForPath(dirPath) let row = root.rowAtIndex(index) - if (row > 0) + if (row > 0) { root.expand(row) - else if (row === -1 && assetsModel.indexIsValid(index)) { + } else if (row === -1 && assetsModel.indexIsValid(index)) { // It is possible that this directory, dirPath, was created inside of a parent // directory that was not yet expanded in the TreeView. This can happen with the // bridge plugin. In such a situation, we don't have a "row" for it yet, so we have @@ -194,6 +185,8 @@ TreeView { root.expand(row) }) } + + assetsModel.saveExpandState(dirPath, root.isExpanded(row)) } // we have no way to know beyond doubt here if updateRows() was called due @@ -215,10 +208,10 @@ TreeView { function __doExpandAll() { let expandedAny = false - for (let nRow = 0; nRow < root.rows; ++nRow) { - let index = root.__modelIndex(nRow) - if (assetsModel.isDirectory(index) && !root.isExpanded(nRow)) { - root.expand(nRow); + for (let r = 0; r < root.rows; ++r) { + let index = root.__modelIndex(r) + if (assetsModel.isDirectory(index) && !root.isExpanded(r)) { + root.expand(r) expandedAny = true } } @@ -352,15 +345,14 @@ TreeView { } Keys.onRightPressed: { - root.toggleDirectoryState("expand") + root.expandFolder(true) } Keys.onLeftPressed: { - root.toggleDirectoryState("collapse") + root.expandFolder(false) } - function toggleDirectoryState(action) { - + function expandFolder(expand) { let index = root.currentFilePath ? assetsModel.indexForPath(root.currentFilePath) : root.__modelIndex(root.firstRow) @@ -369,9 +361,11 @@ TreeView { let row = root.rowAtIndex(index) - if (action === "expand") + assetsModel.saveExpandState(root.currentFilePath, expand) + + if (expand) root.expand(row) - else if (action === "collapse") + else root.collapse(row) } diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index 19c7319d2c0..15d7a056c55 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -177,8 +177,18 @@ bool AssetsLibraryModel::deleteFolderRecursively(const QModelIndex &folderIndex) { auto idx = mapToSource(folderIndex); bool ok = m_sourceFsModel->remove(idx); - if (!ok) + + if (ok) { + Utils::FilePath parentPath = Utils::FilePath::fromString(filePath(folderIndex)); + const QStringList paths = s_folderExpandStateHash.keys(); + + for (const QString &path : paths) { + if (Utils::FilePath::fromString(path).isChildOf(parentPath)) + s_folderExpandStateHash.remove(path); + } + } else { qWarning() << __FUNCTION__ << " could not remove folder recursively: " << m_sourceFsModel->filePath(idx); + } return ok; } @@ -205,6 +215,44 @@ bool AssetsLibraryModel::isSameOrDescendantPath(const QUrl &source, const QStrin return srcPath == targetPath || targetPath.isChildOf(srcPath); } +bool AssetsLibraryModel::folderExpandState(const QString &path) const +{ + return s_folderExpandStateHash.value(path); +} + +void AssetsLibraryModel::initializeExpandState(const QString &path) +{ + if (!s_folderExpandStateHash.contains(path)) + saveExpandState(path, true); +} + +void AssetsLibraryModel::saveExpandState(const QString &path, bool expand) +{ + s_folderExpandStateHash.insert(path, expand); +} + +void AssetsLibraryModel::updateExpandPath(const Utils::FilePath &oldPath, const Utils::FilePath &newPath) +{ + // update parent folder expand state + bool value = s_folderExpandStateHash.take(oldPath.toFSPathString()); + saveExpandState(newPath.toFSPathString(), value); + + const QStringList paths = s_folderExpandStateHash.keys(); + + for (const QString &path : paths) { + Utils::FilePath childPath = Utils::FilePath::fromString(path); + + // update subfolders expand states + if (childPath.isChildOf(oldPath)) { + QString relativePath = Utils::FilePath::calcRelativePath(path, oldPath.toFSPathString()); + Utils::FilePath newChildPath = newPath.pathAppended(relativePath); + + value = s_folderExpandStateHash.take(path); + saveExpandState(newChildPath.toFSPathString(), value); + } + } +} + bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QString path = m_sourceFsModel->filePath(sourceParent); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h index 5b5525a01bf..10adc72425b 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h @@ -7,6 +7,7 @@ namespace Utils { class FileSystemWatcher; +class FilePath; } QT_FORWARD_DECLARE_CLASS(QFileSystemModel) @@ -51,6 +52,10 @@ public: Q_INVOKABLE bool allFilePathsAreTextures(const QStringList &filePaths) const; Q_INVOKABLE bool allFilePathsAreComposedEffects(const QStringList &filePaths) const; Q_INVOKABLE bool isSameOrDescendantPath(const QUrl &source, const QString &target) const; + Q_INVOKABLE bool folderExpandState(const QString &path) const; + Q_INVOKABLE void initializeExpandState(const QString &path); + Q_INVOKABLE void saveExpandState(const QString &path, bool expand); + void updateExpandPath(const Utils::FilePath &oldPath, const Utils::FilePath &newPath); int columnCount(const QModelIndex &parent = QModelIndex()) const override { @@ -80,6 +85,7 @@ private: QFileSystemModel *m_sourceFsModel = nullptr; bool m_isEmpty = true; Utils::FileSystemWatcher *m_fileWatcher = nullptr; + inline static QHash s_folderExpandStateHash; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index e2df20ab8ce..ebcc325790c 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -427,11 +427,17 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList &urls, const QStrin } } - if (!src.renameFile(dest) && src.isDir()) { - QString message = tr("Failed to move folder \"%1\". " - "The folder might contain subfolders or one of its files is in use.") - .arg(src.fileName()); - Core::AsynchronousMessageBox::warning(tr("Folder move failure"), message); + bool isDir = src.isDir(); + + if (src.renameFile(dest)) { + if (isDir) + m_assetsModel->updateExpandPath(src, dest); + } else if (isDir) { + Core::AsynchronousMessageBox::warning( + tr("Folder move failure"), + tr("Failed to move folder \"%1\". The folder might contain subfolders or one of its files is in use.") + .arg(src.fileName()) + ); } }