[Bf-blender-cvs] [824733ea47d] master: Assets: Additions/fixes to the catalog system in preparation for the UI
Julian Eisel
noreply at git.blender.org
Mon Sep 27 17:49:36 CEST 2021
Commit: 824733ea47d13030c18faa618c1dc31a08dfa43d
Author: Julian Eisel
Date: Mon Sep 27 17:45:02 2021 +0200
Branches: master
https://developer.blender.org/rB824733ea47d13030c18faa618c1dc31a08dfa43d
Assets: Additions/fixes to the catalog system in preparation for the UI
* Fixes missing update of the catalog tree when adding catalogs.
* Adds iterators for the catalogs, needed for UI code.
* Store catalog ID in the catalog tree items, needed for UI code.
* Other smaller API additions for the UI.
* Improve comments and smaller cleanups.
New functions are covered with unit tests.
Differential Revision: https://developer.blender.org/D12618
Reviewed by: Sybren Stüvel
===================================================================
M source/blender/blenkernel/BKE_asset_catalog.hh
M source/blender/blenkernel/intern/asset_catalog.cc
M source/blender/blenkernel/intern/asset_catalog_test.cc
===================================================================
diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh
index cf9d581b148..07373caf701 100644
--- a/source/blender/blenkernel/BKE_asset_catalog.hh
+++ b/source/blender/blenkernel/BKE_asset_catalog.hh
@@ -86,6 +86,10 @@ class AssetCatalogService {
/** Return catalog with the given ID. Return nullptr if not found. */
AssetCatalog *find_catalog(CatalogID catalog_id);
+ /** Return first catalog with the given path. Return nullptr if not found. This is not an
+ * efficient call as it's just a linear search over the catalogs. */
+ AssetCatalog *find_catalog_by_path(const CatalogPath &path) const;
+
/** Create a catalog with some sensible auto-generated catalog ID.
* The catalog will be saved to the default catalog file.*/
AssetCatalog *create_catalog(const CatalogPath &catalog_path);
@@ -124,48 +128,74 @@ class AssetCatalogService {
void rebuild_tree();
};
+/**
+ * Representation of a catalog path in the #AssetCatalogTree.
+ */
class AssetCatalogTreeItem {
- friend class AssetCatalogService;
+ friend class AssetCatalogTree;
public:
+ /** Container for child items. Uses a #std::map to keep items ordered by their name (i.e. their
+ * last catalog component). */
using ChildMap = std::map<std::string, AssetCatalogTreeItem>;
- using ItemIterFn = FunctionRef<void(const AssetCatalogTreeItem &)>;
+ using ItemIterFn = FunctionRef<void(AssetCatalogTreeItem &)>;
- AssetCatalogTreeItem(StringRef name, const AssetCatalogTreeItem *parent = nullptr);
+ AssetCatalogTreeItem(StringRef name,
+ CatalogID catalog_id,
+ const AssetCatalogTreeItem *parent = nullptr);
+ CatalogID get_catalog_id() const;
StringRef get_name() const;
/** Return the full catalog path, defined as the name of this catalog prefixed by the full
* catalog path of its parent and a separator. */
CatalogPath catalog_path() const;
int count_parents() const;
+ bool has_children() const;
- static void foreach_item_recursive(const ChildMap &children_, const ItemIterFn callback);
+ /** Iterate over children calling \a callback for each of them, but do not recurse into their
+ * children. */
+ void foreach_child(const ItemIterFn callback);
protected:
/** Child tree items, ordered by their names. */
ChildMap children_;
/** The user visible name of this component. */
CatalogPathComponent name_;
+ CatalogID catalog_id_;
/** Pointer back to the parent item. Used to reconstruct the hierarchy from an item (e.g. to
* build a path). */
const AssetCatalogTreeItem *parent_ = nullptr;
+
+ private:
+ static void foreach_item_recursive(ChildMap &children_, ItemIterFn callback);
};
/**
* A representation of the catalog paths as tree structure. Each component of the catalog tree is
- * represented by a #AssetCatalogTreeItem.
+ * represented by an #AssetCatalogTreeItem. The last path component of an item is used as its name,
+ * which may also be shown to the user.
+ * An item can not have multiple children with the same name. That means the name uniquely
+ * identifies an item within its parent.
+ *
* There is no single root tree element, the #AssetCatalogTree instance itself represents the root.
*/
class AssetCatalogTree {
- friend class AssetCatalogService;
+ using ChildMap = AssetCatalogTreeItem::ChildMap;
+ using ItemIterFn = AssetCatalogTreeItem::ItemIterFn;
public:
- void foreach_item(const AssetCatalogTreeItem::ItemIterFn callback) const;
+ /** Ensure an item representing \a path is in the tree, adding it if necessary. */
+ void insert_item(const AssetCatalog &catalog);
+
+ void foreach_item(const AssetCatalogTreeItem::ItemIterFn callback);
+ /** Iterate over root items calling \a callback for each of them, but do not recurse into their
+ * children. */
+ void foreach_root_item(const ItemIterFn callback);
protected:
/** Child tree items, ordered by their names. */
- AssetCatalogTreeItem::ChildMap children_;
+ ChildMap root_items_;
};
/** Keeps track of which catalogs are defined in a certain file on disk.
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index 4f1de09e148..b65ae12e5a7 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -64,6 +64,17 @@ AssetCatalog *AssetCatalogService::find_catalog(CatalogID catalog_id)
return catalog_uptr_ptr->get();
}
+AssetCatalog *AssetCatalogService::find_catalog_by_path(const CatalogPath &path) const
+{
+ for (auto &catalog : catalogs_.values()) {
+ if (catalog->path == path) {
+ return catalog.get();
+ }
+ }
+
+ return nullptr;
+}
+
void AssetCatalogService::delete_catalog(CatalogID catalog_id)
{
std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = this->catalogs_.lookup_ptr(catalog_id);
@@ -104,6 +115,12 @@ AssetCatalog *AssetCatalogService::create_catalog(const CatalogPath &catalog_pat
catalog_definition_file_->add_new(catalog_ptr);
}
+ /* The tree may not exist; this happens when no catalog definition file has been loaded yet. When
+ * the tree is created any in-memory catalogs will be added, so it doesn't need to happen now. */
+ if (catalog_tree_) {
+ catalog_tree_->insert_item(*catalog_ptr);
+ }
+
return catalog_ptr;
}
@@ -268,34 +285,7 @@ std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree()
/* Go through the catalogs, insert each path component into the tree where needed. */
for (auto &catalog : catalogs_.values()) {
- const AssetCatalogTreeItem *parent = nullptr;
- AssetCatalogTreeItem::ChildMap *insert_to_map = &tree->children_;
-
- BLI_assert_msg(!ELEM(catalog->path[0], '/', '\\'),
- "Malformed catalog path; should not start with a separator");
-
- const char *next_slash_ptr;
- /* Looks more complicated than it is, this just iterates over path components. E.g.
- * "just/some/path" iterates over "just", then "some" then "path". */
- for (const char *name_begin = catalog->path.data(); name_begin && name_begin[0];
- /* Jump to one after the next slash if there is any. */
- name_begin = next_slash_ptr ? next_slash_ptr + 1 : nullptr) {
- next_slash_ptr = BLI_path_slash_find(name_begin);
-
- /* Note that this won't be null terminated. */
- StringRef component_name = next_slash_ptr ?
- StringRef(name_begin, next_slash_ptr - name_begin) :
- /* Last component in the path. */
- name_begin;
-
- /* Insert new tree element - if no matching one is there yet! */
- auto [item, was_inserted] = insert_to_map->emplace(
- component_name, AssetCatalogTreeItem(component_name, parent));
-
- /* Walk further into the path (no matter if a new item was created or not). */
- parent = &item->second;
- insert_to_map = &item->second.children_;
- }
+ tree->insert_item(*catalog);
}
return tree;
@@ -306,9 +296,18 @@ void AssetCatalogService::rebuild_tree()
this->catalog_tree_ = read_into_tree();
}
-AssetCatalogTreeItem::AssetCatalogTreeItem(StringRef name, const AssetCatalogTreeItem *parent)
- : name_(name), parent_(parent)
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogTreeItem::AssetCatalogTreeItem(StringRef name,
+ CatalogID catalog_id,
+ const AssetCatalogTreeItem *parent)
+ : name_(name), catalog_id_(catalog_id), parent_(parent)
+{
+}
+
+CatalogID AssetCatalogTreeItem::get_catalog_id() const
{
+ return catalog_id_;
}
StringRef AssetCatalogTreeItem::get_name() const
@@ -334,20 +333,100 @@ int AssetCatalogTreeItem::count_parents() const
return i;
}
-void AssetCatalogTree::foreach_item(const AssetCatalogTreeItem::ItemIterFn callback) const
+bool AssetCatalogTreeItem::has_children() const
+{
+ return !children_.empty();
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Iterate over path components, calling \a callback for each component. E.g. "just/some/path"
+ * iterates over "just", then "some" then "path".
+ */
+static void iterate_over_catalog_path_components(
+ const CatalogPath &path,
+ FunctionRef<void(StringRef component_name, bool is_last_component)> callback)
+{
+ const char *next_slash_ptr;
+
+ for (const char *path_component = path.data(); path_component && path_component[0];
+ /* Jump to one after the next slash if there is any. */
+ path_component = next_slash_ptr ? next_slash_ptr + 1 : nullptr) {
+ next_slash_ptr = BLI_path_slash_find(path_component);
+
+ const bool is_last_component = next_slash_ptr == nullptr;
+ /* Note that this won't be null terminated. */
+ const StringRef component_name = is_last_component ?
+ path_component :
+ StringRef(path_component,
+ next_slash_ptr - path_component);
+
+ callback(component_name, is_last_component);
+ }
+}
+
+void AssetCatalogTree::insert_item(const AssetCatalog &catalog)
+{
+ const AssetCatalogTreeItem *parent = nullptr;
+ /* The children for the currently iterated component, where the following component should be
+ * added to (if not there yet). */
+ AssetCatalogTreeItem::ChildMap *current_item_children = &root_items_;
+
+ BLI_assert_msg(!ELEM(catalog.path[0], '/', '\\'),
+ "Malformed catalog path; should not start with a separator");
+
+ const CatalogID nil_id{};
+
+ iterate_over_catalog_path_components(
+ catalog.path, [&](StringRef component_name, const bool is_last_component) {
+ /* Insert new tree element - if no matching one is there yet! */
+ auto [key_and_item, was_inserted] = current_item_children->emplace(
+ component_name,
+ AssetCatalogTreeItem(
+ component_name, is_last_component ? catalog.catalog_id : nil_id, parent));
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list