diff --git a/doomsday/libs/core/include/de/filesys/folder.h b/doomsday/libs/core/include/de/filesys/folder.h index 4aea0df5b4..c16bd6621d 100644 --- a/doomsday/libs/core/include/de/filesys/folder.h +++ b/doomsday/libs/core/include/de/filesys/folder.h @@ -75,7 +75,7 @@ class DE_PUBLIC Folder : public File PopulateAsync = 0x4, ///< Do not block until complete. PopulateAsyncFullTree = PopulateAsync | PopulateFullTree, - PopulateCalledRecursively = 0x1000, // internal use + DisableNotification = 0x1000, // internal use }; using PopulationBehaviors = Flags; @@ -127,10 +127,11 @@ class DE_PUBLIC Folder : public File List subfolders() const; /** - * Empties the contents of the folder: all contained file instances are - * deleted. Attached feeds are not notified, which means the source data - * they translate into the folder remains untouched. This is called - * automatically when the Folder instance is deleted. + * Unpopulates the folder, i.e., deletes all contained File objects. + * The attached feeds are not notified, which means the source data they translate + * remains untouched. + * + * Called automatically when the Folder instance is deleted. */ void clear(); diff --git a/doomsday/libs/core/src/filesys/folder.cpp b/doomsday/libs/core/src/filesys/folder.cpp index 91d2304500..9cb706fd56 100644 --- a/doomsday/libs/core/src/filesys/folder.cpp +++ b/doomsday/libs/core/src/filesys/folder.cpp @@ -202,7 +202,7 @@ void Folder::clear() // Destroy all the file objects. for (Contents::iterator i = d->contents.begin(); i != d->contents.end(); ++i) { - i->second->setParent(0); + i->second->setParent(nullptr); delete i->second; } d->contents.clear(); @@ -302,7 +302,7 @@ void Folder::populate(PopulationBehaviors behavior) // Call populate on subfolders. for (Folder *folder : d->subfolders()) { - folder->populate(behavior | PopulateCalledRecursively); + folder->populate(behavior | DisableNotification); } } @@ -327,7 +327,7 @@ void Folder::populate(PopulationBehaviors behavior) // Each population gets an individual notification since they're done synchronously. // However, only notify once a full hierarchy of populations has finished. - if (!(behavior & PopulateCalledRecursively)) + if (!(behavior & DisableNotification)) { internal::populationNotifier.notify(); } diff --git a/doomsday/libs/gui/include/de/DirectoryTreeData b/doomsday/libs/gui/include/de/DirectoryTreeData new file mode 100644 index 0000000000..d1c2e0de78 --- /dev/null +++ b/doomsday/libs/gui/include/de/DirectoryTreeData @@ -0,0 +1,2 @@ +#include "gui/directorytreedata.h" + diff --git a/doomsday/libs/gui/include/de/gui/directorytreedata.h b/doomsday/libs/gui/include/de/gui/directorytreedata.h new file mode 100644 index 0000000000..6d75725dcf --- /dev/null +++ b/doomsday/libs/gui/include/de/gui/directorytreedata.h @@ -0,0 +1,64 @@ +/** @file directorytreedata.h Native filesystem directory tree. + * + * @authors Copyright (c) 2019 Jaakko Keränen + * + * @par License + * LGPL: http://www.gnu.org/licenses/lgpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + +#pragma once + +#include "../ui/Item" +#include "../ui/TreeData" +#include + +namespace de { + +class LIBGUI_PUBLIC DirectoryTreeData : public ui::TreeData +{ +public: + /** + * Item in the directory tree data model (i.e., file or subdirectory). + */ + class LIBGUI_PUBLIC DirectoryItem : public ui::Item + { + public: + DirectoryItem(const String &name, const File::Status &status, const Path &directory) + : ui::Item(DefaultSemantics, name) + , _status(status) + , _directory(directory) + { + setLabel(name); + } + + String name() const { return label(); } + File::Status status() const { return _status; } + Path path() const { return _directory / name(); } + + private: + File::Status _status; + const Path & _directory; + }; + +public: + DirectoryTreeData(); + + // Implements ui::TreeData. + bool contains(const Path &path) const override; + const ui::Data &items(const Path &path) const override; + +private: + DE_PRIVATE(d) +}; + +} // namespace de diff --git a/doomsday/libs/gui/include/de/gui/treedata.h b/doomsday/libs/gui/include/de/gui/treedata.h new file mode 100644 index 0000000000..64dcbd6274 --- /dev/null +++ b/doomsday/libs/gui/include/de/gui/treedata.h @@ -0,0 +1,42 @@ +/** @file treedata.h Data model for a tree of lists. + * + * @authors Copyright (c) 2019 Jaakko Keränen + * + * @par License + * LGPL: http://www.gnu.org/licenses/lgpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + +#pragma once + +#include "../ui/Data" +#include + +namespace de { +namespace ui { + +/** + * Data model representing a tree of lists. + * + * @ingroup uidata + */ +class LIBGUI_PUBLIC TreeData +{ +public: + virtual ~TreeData() = default; + + virtual bool contains(const Path &path) const = 0; + virtual const Data &items(const Path &path) const = 0; +}; + +} // namespace ui +} // namespace de diff --git a/doomsday/libs/gui/include/de/ui/TreeData b/doomsday/libs/gui/include/de/ui/TreeData new file mode 100644 index 0000000000..744c9cb422 --- /dev/null +++ b/doomsday/libs/gui/include/de/ui/TreeData @@ -0,0 +1,2 @@ +#include "../gui/treedata.h" + diff --git a/doomsday/libs/gui/include/de/widgets/browserwidget.h b/doomsday/libs/gui/include/de/widgets/browserwidget.h index c846000681..e75b76247c 100644 --- a/doomsday/libs/gui/include/de/widgets/browserwidget.h +++ b/doomsday/libs/gui/include/de/widgets/browserwidget.h @@ -16,8 +16,7 @@ * http://www.gnu.org/licenses */ -#ifndef LIBAPPFW_BROWSERWIDGET_H -#define LIBAPPFW_BROWSERWIDGET_H +#pragma once #include @@ -38,5 +37,3 @@ class LIBGUI_PUBLIC BrowserWidget : public GuiWidget }; } // namespace de - -#endif // LIBAPPFW_BROWSERWIDGET_H diff --git a/doomsday/libs/gui/src/directorytreedata.cpp b/doomsday/libs/gui/src/directorytreedata.cpp new file mode 100644 index 0000000000..811f6537a2 --- /dev/null +++ b/doomsday/libs/gui/src/directorytreedata.cpp @@ -0,0 +1,74 @@ +/** @file directorytreedata.cpp Native filesystem directory tree. + * + * @authors Copyright (c) 2019 Jaakko Keränen + * + * @par License + * LGPL: http://www.gnu.org/licenses/lgpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + +#include "de/DirectoryTreeData" +#include "de/ui/ListData" + +#include +#include + +namespace de { + +DE_PIMPL(DirectoryTreeData) +{ + NativePath dir; + ui::ListDataT items; + + Impl(Public *i) : Base(i) + {} + + void populate(const NativePath &path) + { + // Get rid of the previous contents. + items.clear(); + + // Populate a folder with the directory contents. + dir = path; + Folder folder(path.fileName()); + folder.attach(new DirectoryFeed(dir)); + folder.populate(Folder::PopulateOnlyThisFolder | Folder::DisableNotification); + + // Create corresponding data items. + for (const auto &entry : folder.contents()) + { + items << new DirectoryItem(entry.first, entry.second->status(), dir); + } + + items.sort(); + } +}; + +DirectoryTreeData::DirectoryTreeData() + : d(new Impl(this)) +{} + +bool DirectoryTreeData::contains(const Path &path) const +{ + return NativePath(path).isDirectory(); +} + +const ui::Data &DirectoryTreeData::items(const Path &path) const +{ + if (NativePath(path) != d->dir) + { + d->populate(path); + } + return d->items; +} + +} // namespace de