diff --git a/src/libs/utils/treemodel.cpp b/src/libs/utils/treemodel.cpp index 19f3fc72c48..b4684eedfe1 100644 --- a/src/libs/utils/treemodel.cpp +++ b/src/libs/utils/treemodel.cpp @@ -689,6 +689,20 @@ void TreeItem::insertChild(int pos, TreeItem *item) } } +void TreeItem::removeChildAt(int pos) +{ + QTC_ASSERT(0 <= pos && pos < m_children.count(), return); + + if (m_model) { + QModelIndex idx = index(); + m_model->beginRemoveRows(idx, pos, pos); + removeItemAt(pos); + m_model->endRemoveRows(); + } else { + removeItemAt(pos); + } +} + void TreeItem::removeChildren() { if (childCount() == 0) @@ -863,6 +877,15 @@ void TreeItem::clear() } } +void TreeItem::removeItemAt(int pos) +{ + TreeItem *item = m_children.at(pos); + item->m_model = nullptr; + item->m_parent = nullptr; + delete item; + m_children.removeAt(pos); +} + void TreeItem::expand() { QTC_ASSERT(m_model, return); diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h index d62670867be..8e0c4407d2f 100644 --- a/src/libs/utils/treemodel.h +++ b/src/libs/utils/treemodel.h @@ -54,6 +54,7 @@ public: void prependChild(TreeItem *item); void appendChild(TreeItem *item); void insertChild(int pos, TreeItem *item); + void removeChildAt(int pos); void removeChildren(); void sortChildren(const std::function &cmp); void update(); @@ -90,6 +91,7 @@ private: void operator=(const TreeItem &) = delete; void clear(); + void removeItemAt(int pos); void propagateModel(BaseTreeModel *m); TreeItem *m_parent; // Not owned. diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 0ad7c639db4..f6aad7fa53e 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -189,7 +189,10 @@ void FlatModel::addOrRebuildProjectModel(Project *project) if (ProjectNode *projectNode = project->rootProjectNode()) { addFolderNode(container, projectNode, &seen); - } else { + if (m_trimEmptyDirectories) + trimEmptyDirectories(container); + } + if (container->childCount() == 0) { FileNode *projectFileNode = new FileNode(project->projectFilePath(), FileType::Project, false); seen.insert(projectFileNode); container->appendChild(new WrapperNode(projectFileNode)); @@ -317,6 +320,18 @@ void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet< } } +bool FlatModel::trimEmptyDirectories(WrapperNode *parent) +{ + if (!parent->m_node->asFolderNode()) + return false; + + for (int i = parent->childCount() - 1; i >= 0; --i) { + if (trimEmptyDirectories(parent->childAt(i))) + parent->removeChildAt(i); + } + return parent->childCount() == 0; +} + Qt::DropActions FlatModel::supportedDragActions() const { return Qt::MoveAction; @@ -363,10 +378,20 @@ void FlatModel::setProjectFilterEnabled(bool filter) void FlatModel::setGeneratedFilesFilterEnabled(bool filter) { + if (filter == m_filterGeneratedFiles) + return; m_filterGeneratedFiles = filter; rebuildModel(); } +void FlatModel::setTrimEmptyDirectories(bool filter) +{ + if (filter == m_trimEmptyDirectories) + return; + m_trimEmptyDirectories = filter; + rebuildModel(); +} + bool FlatModel::projectFilterEnabled() { return m_filterProjects; diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h index 18129a7ddce..a0041a7bcd0 100644 --- a/src/plugins/projectexplorer/projectmodels.h +++ b/src/plugins/projectexplorer/projectmodels.h @@ -76,6 +76,7 @@ public: bool generatedFilesFilterEnabled(); void setProjectFilterEnabled(bool filter); void setGeneratedFilesFilterEnabled(bool filter); + void setTrimEmptyDirectories(bool filter); void onExpanded(const QModelIndex &idx); void onCollapsed(const QModelIndex &idx); @@ -87,12 +88,14 @@ signals: private: bool m_filterProjects = false; bool m_filterGeneratedFiles = true; + bool m_trimEmptyDirectories = true; static const QLoggingCategory &logger(); void updateSubtree(FolderNode *node); void rebuildModel(); void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet *seen); + bool trimEmptyDirectories(WrapperNode *parent); ExpandData expandDataForNode(const Node *node) const; void loadExpandData(); diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index 2a98fbe86e7..5b1471504ee 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -194,6 +194,12 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent) connect(m_filterGeneratedFilesAction, &QAction::toggled, this, &ProjectTreeWidget::setGeneratedFilesFilter); + m_trimEmptyDirectoriesAction = new QAction(tr("Hide Empty Directories"), this); + m_trimEmptyDirectoriesAction->setCheckable(true); + m_trimEmptyDirectoriesAction->setChecked(true); + connect(m_trimEmptyDirectoriesAction, &QAction::toggled, + this, &ProjectTreeWidget::setTrimEmptyDirectories); + // connections connect(m_model, &FlatModel::renamed, this, &ProjectTreeWidget::renamed); @@ -433,6 +439,12 @@ void ProjectTreeWidget::setGeneratedFilesFilter(bool filter) m_filterGeneratedFilesAction->setChecked(filter); } +void ProjectTreeWidget::setTrimEmptyDirectories(bool filter) +{ + m_model->setTrimEmptyDirectories(filter); + m_trimEmptyDirectoriesAction->setChecked(filter); +} + bool ProjectTreeWidget::generatedFilesFilter() { return m_model->generatedFilesFilterEnabled(); @@ -466,6 +478,7 @@ NavigationView ProjectTreeWidgetFactory::createWidget() auto filterMenu = new QMenu(filter); filterMenu->addAction(ptw->m_filterProjectsAction); filterMenu->addAction(ptw->m_filterGeneratedFilesAction); + filterMenu->addAction(ptw->m_trimEmptyDirectoriesAction); filter->setMenu(filterMenu); n.dockToolBarWidgets << filter << ptw->toggleSync(); diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h index 69102fedb0d..4d87b6ad0fa 100644 --- a/src/plugins/projectexplorer/projecttreewidget.h +++ b/src/plugins/projectexplorer/projecttreewidget.h @@ -70,6 +70,7 @@ public: private: void setProjectFilter(bool filter); void setGeneratedFilesFilter(bool filter); + void setTrimEmptyDirectories(bool filter); void handleCurrentItemChange(const QModelIndex ¤t); void showContextMenu(const QPoint &pos); @@ -83,8 +84,9 @@ private: QTreeView *m_view = nullptr; FlatModel *m_model = nullptr; QAction *m_filterProjectsAction = nullptr; - QAction *m_filterGeneratedFilesAction; - QToolButton *m_toggleSync; + QAction *m_filterGeneratedFilesAction = nullptr; + QAction *m_trimEmptyDirectoriesAction = nullptr; + QToolButton *m_toggleSync = nullptr; QString m_modelId; bool m_autoSync = true;