diff options
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_asset_catalog.hh | 14 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/asset_catalog.cc | 41 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/asset_catalog_test.cc | 48 |
3 files changed, 103 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh index 7b54d7cf572..9b8b99f8f6d 100644 --- a/source/blender/blenkernel/BKE_asset_catalog.hh +++ b/source/blender/blenkernel/BKE_asset_catalog.hh @@ -118,6 +118,11 @@ class AssetCatalogService { * written. */ void delete_catalog(CatalogID catalog_id); + /** + * Update the catalog path, also updating the catalog path of all sub-catalogs. + */ + void update_catalog_path(CatalogID catalog_id, const CatalogPath &new_catalog_path); + AssetCatalogTree *get_catalog_tree(); /** Return true only if there are no catalogs known. */ @@ -301,6 +306,15 @@ class AssetCatalog { } flags; /** + * \return true only if this catalog's path is contained within the given path. + * When this catalog's path is equal to the given path, return true as well. + * + * Note that non-normalized paths (so for example starting or ending with a slash) are not + * supported, and result in undefined behaviour. + */ + bool is_contained_in(const CatalogPath &other_path) const; + + /** * Create a new Catalog with the given path, auto-generating a sensible catalog simple-name. * * NOTE: the given path will be cleaned up (trailing spaces removed, etc.), so the returned diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index 8f57f96e771..05e27a93621 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -99,6 +99,25 @@ void AssetCatalogService::delete_catalog(CatalogID catalog_id) this->rebuild_tree(); } +void AssetCatalogService::update_catalog_path(CatalogID catalog_id, + const CatalogPath &new_catalog_path) +{ + AssetCatalog *renamed_cat = this->find_catalog(catalog_id); + const CatalogPath old_cat_path = renamed_cat->path; + + for (auto &catalog_uptr : catalogs_.values()) { + AssetCatalog *cat = catalog_uptr.get(); + if (!cat->is_contained_in(old_cat_path)) { + continue; + } + + const CatalogPath path_suffix = cat->path.substr(old_cat_path.length()); + cat->path = new_catalog_path + path_suffix; + } + + this->rebuild_tree(); +} + AssetCatalog *AssetCatalogService::create_catalog(const CatalogPath &catalog_path) { std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path(catalog_path); @@ -756,4 +775,26 @@ CatalogPath AssetCatalog::cleanup_path(const CatalogPath &path) return clean_path; } +bool AssetCatalog::is_contained_in(const CatalogPath &other_path) const +{ + if (other_path.empty()) { + return true; + } + + if (this->path == other_path) { + return true; + } + + /* To be a child path of 'other_path', our path must be at least a separator and another + * character longer. */ + if (this->path.length() < other_path.length() + 2) { + return false; + } + + const StringRef this_path(this->path); + const bool prefix_ok = this_path.startswith(other_path); + const char next_char = this_path[other_path.length()]; + return prefix_ok && next_char == AssetCatalogService::PATH_SEPARATOR; +} + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc index 5177abd2820..b36c15940b8 100644 --- a/source/blender/blenkernel/intern/asset_catalog_test.cc +++ b/source/blender/blenkernel/intern/asset_catalog_test.cc @@ -711,6 +711,37 @@ TEST_F(AssetCatalogTest, delete_catalog_write_to_disk) EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_RUZENA_FACE)); } +TEST_F(AssetCatalogTest, update_catalog_path) +{ + AssetCatalogService service(asset_library_root_); + service.load_from_disk(asset_library_root_ + "/" + + AssetCatalogService::DEFAULT_CATALOG_FILENAME); + + const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA); + const CatalogPath orig_path = orig_cat->path; + + service.update_catalog_path(UUID_POSES_RUZENA, "charlib/Ružena"); + + EXPECT_EQ(nullptr, service.find_catalog_by_path(orig_path)) + << "The original (pre-rename) path should not be associated with a catalog any more."; + + const AssetCatalog *renamed_cat = service.find_catalog(UUID_POSES_RUZENA); + ASSERT_NE(nullptr, renamed_cat); + ASSERT_EQ(orig_cat, renamed_cat) << "Changing the path should not reallocate the catalog."; + EXPECT_EQ(orig_cat->simple_name, renamed_cat->simple_name) + << "Changing the path should not change the simple name."; + EXPECT_EQ(orig_cat->catalog_id, renamed_cat->catalog_id) + << "Changing the path should not change the catalog ID."; + + EXPECT_EQ("charlib/Ružena", renamed_cat->path) + << "Changing the path should change the path. Surprise."; + + EXPECT_EQ("charlib/Ružena/hand", service.find_catalog(UUID_POSES_RUZENA_HAND)->path) + << "Changing the path should update children."; + EXPECT_EQ("charlib/Ružena/face", service.find_catalog(UUID_POSES_RUZENA_FACE)->path) + << "Changing the path should update children."; +} + TEST_F(AssetCatalogTest, merge_catalog_files) { const CatalogFilePath cdf_dir = create_temp_path(); @@ -813,4 +844,21 @@ TEST_F(AssetCatalogTest, order_by_path) } } +TEST_F(AssetCatalogTest, is_contained_in) +{ + const AssetCatalog cat(BLI_uuid_generate_random(), "simple/path/child", ""); + + EXPECT_FALSE(cat.is_contained_in("unrelated")); + EXPECT_FALSE(cat.is_contained_in("sim")); + EXPECT_FALSE(cat.is_contained_in("simple/pathx")); + EXPECT_FALSE(cat.is_contained_in("simple/path/c")); + EXPECT_FALSE(cat.is_contained_in("simple/path/child/grandchild")); + EXPECT_FALSE(cat.is_contained_in("simple/path/")) + << "Non-normalized paths are not expected to work."; + + EXPECT_TRUE(cat.is_contained_in("")); + EXPECT_TRUE(cat.is_contained_in("simple")); + EXPECT_TRUE(cat.is_contained_in("simple/path")); +} + } // namespace blender::bke::tests |