Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/asset_catalog.cc
| Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| const std::string AssetCatalogDefinitionFile::HEADER = | const std::string AssetCatalogDefinitionFile::HEADER = | ||||
| "# This is an Asset Catalog Definition file for Blender.\n" | "# This is an Asset Catalog Definition file for Blender.\n" | ||||
| "#\n" | "#\n" | ||||
| "# Empty lines and lines starting with `#` will be ignored.\n" | "# Empty lines and lines starting with `#` will be ignored.\n" | ||||
| "# The first non-ignored line should be the version indicator.\n" | "# The first non-ignored line should be the version indicator.\n" | ||||
| "# Other lines are of the format \"UUID:catalog/path/for/assets:simple catalog name\"\n"; | "# Other lines are of the format \"UUID:catalog/path/for/assets:simple catalog name\"\n"; | ||||
| AssetCatalogService::AssetCatalogService() | |||||
| : catalog_collection_(std::make_unique<AssetCatalogCollection>()) | |||||
| { | |||||
| } | |||||
| AssetCatalogService::AssetCatalogService(const CatalogFilePath &asset_library_root) | AssetCatalogService::AssetCatalogService(const CatalogFilePath &asset_library_root) | ||||
| : asset_library_root_(asset_library_root) | : catalog_collection_(std::make_unique<AssetCatalogCollection>()), | ||||
| asset_library_root_(asset_library_root) | |||||
| { | { | ||||
| } | } | ||||
| bool AssetCatalogService::is_empty() const | bool AssetCatalogService::is_empty() const | ||||
| { | { | ||||
| return catalogs_.is_empty(); | return catalog_collection_->catalogs_.is_empty(); | ||||
| } | |||||
| OwningAssetCatalogMap &AssetCatalogService::get_catalogs() | |||||
| { | |||||
| return catalog_collection_->catalogs_; | |||||
| } | |||||
| AssetCatalogDefinitionFile *AssetCatalogService::get_catalog_definition_file() | |||||
| { | |||||
| return catalog_collection_->catalog_definition_file_.get(); | |||||
| } | } | ||||
| AssetCatalog *AssetCatalogService::find_catalog(CatalogID catalog_id) const | AssetCatalog *AssetCatalogService::find_catalog(CatalogID catalog_id) const | ||||
| { | { | ||||
| const std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = this->catalogs_.lookup_ptr(catalog_id); | const std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = | ||||
| catalog_collection_->catalogs_.lookup_ptr(catalog_id); | |||||
| if (catalog_uptr_ptr == nullptr) { | if (catalog_uptr_ptr == nullptr) { | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| return catalog_uptr_ptr->get(); | return catalog_uptr_ptr->get(); | ||||
| } | } | ||||
| AssetCatalog *AssetCatalogService::find_catalog_by_path(const AssetCatalogPath &path) const | AssetCatalog *AssetCatalogService::find_catalog_by_path(const AssetCatalogPath &path) const | ||||
| { | { | ||||
| for (const auto &catalog : catalogs_.values()) { | for (const auto &catalog : catalog_collection_->catalogs_.values()) { | ||||
| if (catalog->path == path) { | if (catalog->path == path) { | ||||
| return catalog.get(); | return catalog.get(); | ||||
| } | } | ||||
| } | } | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| Show All 10 Lines | if (!active_catalog) { | ||||
| return AssetCatalogFilter(std::move(matching_catalog_ids)); | return AssetCatalogFilter(std::move(matching_catalog_ids)); | ||||
| } | } | ||||
| /* This cannot just iterate over tree items to get all the required data, because tree items only | /* This cannot just iterate over tree items to get all the required data, because tree items only | ||||
| * represent single UUIDs. It could be used to get the main UUIDs of the children, though, and | * represent single UUIDs. It could be used to get the main UUIDs of the children, though, and | ||||
| * then only do an exact match on the path (instead of the more complex `is_contained_in()` | * then only do an exact match on the path (instead of the more complex `is_contained_in()` | ||||
| * call). Without an extra indexed-by-path acceleration structure, this is still going to require | * call). Without an extra indexed-by-path acceleration structure, this is still going to require | ||||
| * a linear search, though. */ | * a linear search, though. */ | ||||
| for (const auto &catalog_uptr : this->catalogs_.values()) { | for (const auto &catalog_uptr : catalog_collection_->catalogs_.values()) { | ||||
| if (catalog_uptr->path.is_contained_in(active_catalog->path)) { | if (catalog_uptr->path.is_contained_in(active_catalog->path)) { | ||||
| matching_catalog_ids.add(catalog_uptr->catalog_id); | matching_catalog_ids.add(catalog_uptr->catalog_id); | ||||
| } | } | ||||
| } | } | ||||
| return AssetCatalogFilter(std::move(matching_catalog_ids)); | return AssetCatalogFilter(std::move(matching_catalog_ids)); | ||||
| } | } | ||||
| void AssetCatalogService::delete_catalog(CatalogID catalog_id) | void AssetCatalogService::delete_catalog(CatalogID catalog_id) | ||||
| { | { | ||||
| std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = this->catalogs_.lookup_ptr(catalog_id); | std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = catalog_collection_->catalogs_.lookup_ptr( | ||||
| catalog_id); | |||||
| if (catalog_uptr_ptr == nullptr) { | if (catalog_uptr_ptr == nullptr) { | ||||
| /* Catalog cannot be found, which is fine. */ | /* Catalog cannot be found, which is fine. */ | ||||
| return; | return; | ||||
| } | } | ||||
| /* Mark the catalog as deleted. */ | /* Mark the catalog as deleted. */ | ||||
| AssetCatalog *catalog = catalog_uptr_ptr->get(); | AssetCatalog *catalog = catalog_uptr_ptr->get(); | ||||
| catalog->flags.is_deleted = true; | catalog->flags.is_deleted = true; | ||||
| /* Move ownership from this->catalogs_ to this->deleted_catalogs_. */ | /* Move ownership from catalog_collection_->catalogs_ to catalog_collection_->deleted_catalogs_. | ||||
| this->deleted_catalogs_.add(catalog_id, std::move(*catalog_uptr_ptr)); | */ | ||||
| catalog_collection_->deleted_catalogs_.add(catalog_id, std::move(*catalog_uptr_ptr)); | |||||
| /* The catalog can now be removed from the map without freeing the actual AssetCatalog. */ | /* The catalog can now be removed from the map without freeing the actual AssetCatalog. */ | ||||
| this->catalogs_.remove(catalog_id); | catalog_collection_->catalogs_.remove(catalog_id); | ||||
| this->rebuild_tree(); | this->rebuild_tree(); | ||||
| } | } | ||||
| void AssetCatalogService::update_catalog_path(CatalogID catalog_id, | void AssetCatalogService::update_catalog_path(CatalogID catalog_id, | ||||
| const AssetCatalogPath &new_catalog_path) | const AssetCatalogPath &new_catalog_path) | ||||
| { | { | ||||
| AssetCatalog *renamed_cat = this->find_catalog(catalog_id); | AssetCatalog *renamed_cat = this->find_catalog(catalog_id); | ||||
| const AssetCatalogPath old_cat_path = renamed_cat->path; | const AssetCatalogPath old_cat_path = renamed_cat->path; | ||||
| for (auto &catalog_uptr : catalogs_.values()) { | for (auto &catalog_uptr : catalog_collection_->catalogs_.values()) { | ||||
| AssetCatalog *cat = catalog_uptr.get(); | AssetCatalog *cat = catalog_uptr.get(); | ||||
| const AssetCatalogPath new_path = cat->path.rebase(old_cat_path, new_catalog_path); | const AssetCatalogPath new_path = cat->path.rebase(old_cat_path, new_catalog_path); | ||||
| if (!new_path) { | if (!new_path) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| cat->path = new_path; | cat->path = new_path; | ||||
| } | } | ||||
| this->rebuild_tree(); | this->rebuild_tree(); | ||||
| } | } | ||||
| AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalog_path) | AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalog_path) | ||||
| { | { | ||||
| std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path(catalog_path); | std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path(catalog_path); | ||||
| /* So we can std::move(catalog) and still use the non-owning pointer: */ | /* So we can std::move(catalog) and still use the non-owning pointer: */ | ||||
| AssetCatalog *const catalog_ptr = catalog.get(); | AssetCatalog *const catalog_ptr = catalog.get(); | ||||
| /* TODO(@sybren): move the `AssetCatalog::from_path()` function to another place, that can reuse | /* TODO(@sybren): move the `AssetCatalog::from_path()` function to another place, that can reuse | ||||
| * catalogs when a catalog with the given path is already known, and avoid duplicate catalog IDs. | * catalogs when a catalog with the given path is already known, and avoid duplicate catalog IDs. | ||||
| */ | */ | ||||
| BLI_assert_msg(!catalogs_.contains(catalog->catalog_id), "duplicate catalog ID not supported"); | BLI_assert_msg(!catalog_collection_->catalogs_.contains(catalog->catalog_id), | ||||
| catalogs_.add_new(catalog->catalog_id, std::move(catalog)); | "duplicate catalog ID not supported"); | ||||
| catalog_collection_->catalogs_.add_new(catalog->catalog_id, std::move(catalog)); | |||||
| if (catalog_definition_file_) { | if (catalog_collection_->catalog_definition_file_) { | ||||
| /* Ensure the new catalog gets written to disk at some point. If there is no CDF in memory yet, | /* Ensure the new catalog gets written to disk at some point. If there is no CDF in memory yet, | ||||
| * it's enough to have the catalog known to the service as it'll be saved to a new file. */ | * it's enough to have the catalog known to the service as it'll be saved to a new file. */ | ||||
| catalog_definition_file_->add_new(catalog_ptr); | catalog_collection_->catalog_definition_file_->add_new(catalog_ptr); | ||||
| } | } | ||||
| BLI_assert_msg(catalog_tree_, "An Asset Catalog tree should always exist."); | BLI_assert_msg(catalog_tree_, "An Asset Catalog tree should always exist."); | ||||
| catalog_tree_->insert_item(*catalog_ptr); | catalog_tree_->insert_item(*catalog_ptr); | ||||
| return catalog_ptr; | return catalog_ptr; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
| void AssetCatalogService::load_single_file(const CatalogFilePath &catalog_definition_file_path) | void AssetCatalogService::load_single_file(const CatalogFilePath &catalog_definition_file_path) | ||||
| { | { | ||||
| /* TODO(@sybren): check that #catalog_definition_file_path is contained in #asset_library_root_, | /* TODO(@sybren): check that #catalog_definition_file_path is contained in #asset_library_root_, | ||||
| * otherwise some assumptions may fail. */ | * otherwise some assumptions may fail. */ | ||||
| std::unique_ptr<AssetCatalogDefinitionFile> cdf = parse_catalog_file( | std::unique_ptr<AssetCatalogDefinitionFile> cdf = parse_catalog_file( | ||||
| catalog_definition_file_path); | catalog_definition_file_path); | ||||
| BLI_assert_msg(!this->catalog_definition_file_, | BLI_assert_msg(!catalog_collection_->catalog_definition_file_, | ||||
| "Only loading of a single catalog definition file is supported."); | "Only loading of a single catalog definition file is supported."); | ||||
| this->catalog_definition_file_ = std::move(cdf); | catalog_collection_->catalog_definition_file_ = std::move(cdf); | ||||
| } | } | ||||
| std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::parse_catalog_file( | std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::parse_catalog_file( | ||||
| const CatalogFilePath &catalog_definition_file_path) | const CatalogFilePath &catalog_definition_file_path) | ||||
| { | { | ||||
| auto cdf = std::make_unique<AssetCatalogDefinitionFile>(); | auto cdf = std::make_unique<AssetCatalogDefinitionFile>(); | ||||
| cdf->file_path = catalog_definition_file_path; | cdf->file_path = catalog_definition_file_path; | ||||
| auto catalog_parsed_callback = [this, catalog_definition_file_path]( | auto catalog_parsed_callback = [this, catalog_definition_file_path]( | ||||
| std::unique_ptr<AssetCatalog> catalog) { | std::unique_ptr<AssetCatalog> catalog) { | ||||
| if (this->catalogs_.contains(catalog->catalog_id)) { | if (catalog_collection_->catalogs_.contains(catalog->catalog_id)) { | ||||
| // TODO(@sybren): apparently another CDF was already loaded. This is not supported yet. | // TODO(@sybren): apparently another CDF was already loaded. This is not supported yet. | ||||
| std::cerr << catalog_definition_file_path << ": multiple definitions of catalog " | std::cerr << catalog_definition_file_path << ": multiple definitions of catalog " | ||||
| << catalog->catalog_id << " in multiple files, ignoring this one." << std::endl; | << catalog->catalog_id << " in multiple files, ignoring this one." << std::endl; | ||||
| /* Don't store 'catalog'; unique_ptr will free its memory. */ | /* Don't store 'catalog'; unique_ptr will free its memory. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* The AssetCatalog pointer is now owned by the AssetCatalogService. */ | /* The AssetCatalog pointer is now owned by the AssetCatalogService. */ | ||||
| this->catalogs_.add_new(catalog->catalog_id, std::move(catalog)); | catalog_collection_->catalogs_.add_new(catalog->catalog_id, std::move(catalog)); | ||||
| return true; | return true; | ||||
| }; | }; | ||||
| cdf->parse_catalog_file(cdf->file_path, catalog_parsed_callback); | cdf->parse_catalog_file(cdf->file_path, catalog_parsed_callback); | ||||
| return cdf; | return cdf; | ||||
| } | } | ||||
| void AssetCatalogService::merge_from_disk_before_writing() | void AssetCatalogService::merge_from_disk_before_writing() | ||||
| { | { | ||||
| /* TODO(Sybren): expand to support multiple CDFs. */ | /* TODO(Sybren): expand to support multiple CDFs. */ | ||||
| AssetCatalogDefinitionFile *const cdf = catalog_collection_->catalog_definition_file_.get(); | |||||
| if (!catalog_definition_file_ || catalog_definition_file_->file_path.empty() || | if (!cdf || cdf->file_path.empty() || !BLI_is_file(cdf->file_path.c_str())) { | ||||
| !BLI_is_file(catalog_definition_file_->file_path.c_str())) { | |||||
| return; | return; | ||||
| } | } | ||||
| auto catalog_parsed_callback = [this](std::unique_ptr<AssetCatalog> catalog) { | auto catalog_parsed_callback = [this](std::unique_ptr<AssetCatalog> catalog) { | ||||
| const bUUID catalog_id = catalog->catalog_id; | const bUUID catalog_id = catalog->catalog_id; | ||||
| /* The following two conditions could be or'ed together. Keeping them separated helps when | /* The following two conditions could be or'ed together. Keeping them separated helps when | ||||
| * adding debug prints, breakpoints, etc. */ | * adding debug prints, breakpoints, etc. */ | ||||
| if (this->catalogs_.contains(catalog_id)) { | if (catalog_collection_->catalogs_.contains(catalog_id)) { | ||||
| /* This catalog was already seen, so just ignore it. */ | /* This catalog was already seen, so just ignore it. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (this->deleted_catalogs_.contains(catalog_id)) { | if (catalog_collection_->deleted_catalogs_.contains(catalog_id)) { | ||||
| /* This catalog was already seen and subsequently deleted, so just ignore it. */ | /* This catalog was already seen and subsequently deleted, so just ignore it. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* This is a new catalog, so let's keep it around. */ | /* This is a new catalog, so let's keep it around. */ | ||||
| this->catalogs_.add_new(catalog_id, std::move(catalog)); | catalog_collection_->catalogs_.add_new(catalog_id, std::move(catalog)); | ||||
| return true; | return true; | ||||
| }; | }; | ||||
| catalog_definition_file_->parse_catalog_file(catalog_definition_file_->file_path, | cdf->parse_catalog_file(cdf->file_path, catalog_parsed_callback); | ||||
| catalog_parsed_callback); | |||||
| } | } | ||||
| bool AssetCatalogService::write_to_disk_on_blendfile_save(const CatalogFilePath &blend_file_path) | bool AssetCatalogService::write_to_disk_on_blendfile_save(const CatalogFilePath &blend_file_path) | ||||
| { | { | ||||
| /* TODO(Sybren): expand to support multiple CDFs. */ | /* TODO(Sybren): expand to support multiple CDFs. */ | ||||
| /* - Already loaded a CDF from disk? -> Always write to that file. */ | /* - Already loaded a CDF from disk? -> Always write to that file. */ | ||||
| if (this->catalog_definition_file_) { | if (catalog_collection_->catalog_definition_file_) { | ||||
| merge_from_disk_before_writing(); | merge_from_disk_before_writing(); | ||||
| return catalog_definition_file_->write_to_disk(); | return catalog_collection_->catalog_definition_file_->write_to_disk(); | ||||
| } | } | ||||
| if (catalogs_.is_empty() && deleted_catalogs_.is_empty()) { | if (catalog_collection_->catalogs_.is_empty() && | ||||
| catalog_collection_->deleted_catalogs_.is_empty()) { | |||||
| /* Avoid saving anything, when there is nothing to save. */ | /* Avoid saving anything, when there is nothing to save. */ | ||||
| return true; /* Writing nothing when there is nothing to write is still a success. */ | return true; /* Writing nothing when there is nothing to write is still a success. */ | ||||
| } | } | ||||
| const CatalogFilePath cdf_path_to_write = find_suitable_cdf_path_for_writing(blend_file_path); | const CatalogFilePath cdf_path_to_write = find_suitable_cdf_path_for_writing(blend_file_path); | ||||
| this->catalog_definition_file_ = construct_cdf_in_memory(cdf_path_to_write); | catalog_collection_->catalog_definition_file_ = construct_cdf_in_memory(cdf_path_to_write); | ||||
| merge_from_disk_before_writing(); | merge_from_disk_before_writing(); | ||||
| return catalog_definition_file_->write_to_disk(); | return catalog_collection_->catalog_definition_file_->write_to_disk(); | ||||
| } | } | ||||
| CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing( | CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing( | ||||
| const CatalogFilePath &blend_file_path) | const CatalogFilePath &blend_file_path) | ||||
| { | { | ||||
| BLI_assert_msg(!blend_file_path.empty(), | BLI_assert_msg(!blend_file_path.empty(), | ||||
| "A non-empty .blend file path is required to be able to determine where the " | "A non-empty .blend file path is required to be able to determine where the " | ||||
| "catalog definition file should be put"); | "catalog definition file should be put"); | ||||
| Show All 21 Lines | |||||
| } | } | ||||
| std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_in_memory( | std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_in_memory( | ||||
| const CatalogFilePath &file_path) | const CatalogFilePath &file_path) | ||||
| { | { | ||||
| auto cdf = std::make_unique<AssetCatalogDefinitionFile>(); | auto cdf = std::make_unique<AssetCatalogDefinitionFile>(); | ||||
| cdf->file_path = file_path; | cdf->file_path = file_path; | ||||
| for (auto &catalog : catalogs_.values()) { | for (auto &catalog : catalog_collection_->catalogs_.values()) { | ||||
| cdf->add_new(catalog.get()); | cdf->add_new(catalog.get()); | ||||
| } | } | ||||
| return cdf; | return cdf; | ||||
| } | } | ||||
| AssetCatalogTree *AssetCatalogService::get_catalog_tree() | AssetCatalogTree *AssetCatalogService::get_catalog_tree() | ||||
| { | { | ||||
| return catalog_tree_.get(); | return catalog_tree_.get(); | ||||
| } | } | ||||
| std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree() | std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree() | ||||
| { | { | ||||
| auto tree = std::make_unique<AssetCatalogTree>(); | auto tree = std::make_unique<AssetCatalogTree>(); | ||||
| /* Go through the catalogs, insert each path component into the tree where needed. */ | /* Go through the catalogs, insert each path component into the tree where needed. */ | ||||
| for (auto &catalog : catalogs_.values()) { | for (auto &catalog : catalog_collection_->catalogs_.values()) { | ||||
| tree->insert_item(*catalog); | tree->insert_item(*catalog); | ||||
| } | } | ||||
| return tree; | return tree; | ||||
| } | } | ||||
| void AssetCatalogService::rebuild_tree() | void AssetCatalogService::rebuild_tree() | ||||
| { | { | ||||
| create_missing_catalogs(); | create_missing_catalogs(); | ||||
| this->catalog_tree_ = read_into_tree(); | this->catalog_tree_ = read_into_tree(); | ||||
| } | } | ||||
| void AssetCatalogService::create_missing_catalogs() | void AssetCatalogService::create_missing_catalogs() | ||||
| { | { | ||||
| /* Construct an ordered set of paths to check, so that parents are ordered before children. */ | /* Construct an ordered set of paths to check, so that parents are ordered before children. */ | ||||
| std::set<AssetCatalogPath> paths_to_check; | std::set<AssetCatalogPath> paths_to_check; | ||||
| for (auto &catalog : catalogs_.values()) { | for (auto &catalog : catalog_collection_->catalogs_.values()) { | ||||
| paths_to_check.insert(catalog->path); | paths_to_check.insert(catalog->path); | ||||
| } | } | ||||
| std::set<AssetCatalogPath> seen_paths; | std::set<AssetCatalogPath> seen_paths; | ||||
| /* The empty parent should never be created, so always be considered "seen". */ | /* The empty parent should never be created, so always be considered "seen". */ | ||||
| seen_paths.insert(AssetCatalogPath("")); | seen_paths.insert(AssetCatalogPath("")); | ||||
| /* Find and create missing direct parents (so ignoring parents-of-parents). */ | /* Find and create missing direct parents (so ignoring parents-of-parents). */ | ||||
| Show All 17 Lines | while (!paths_to_check.empty()) { | ||||
| /* The parent doesn't exist, so create it and queue it up for checking its parent. */ | /* The parent doesn't exist, so create it and queue it up for checking its parent. */ | ||||
| create_catalog(parent_path); | create_catalog(parent_path); | ||||
| paths_to_check.insert(parent_path); | paths_to_check.insert(parent_path); | ||||
| } | } | ||||
| /* TODO(Sybren): bind the newly created catalogs to a CDF, if we know about it. */ | /* TODO(Sybren): bind the newly created catalogs to a CDF, if we know about it. */ | ||||
| } | } | ||||
| bool AssetCatalogService::is_undo_possbile() const | |||||
| { | |||||
| return !undo_snapshots_.is_empty(); | |||||
| } | |||||
| bool AssetCatalogService::is_redo_possbile() const | |||||
| { | |||||
| return !redo_snapshots_.is_empty(); | |||||
| } | |||||
| void AssetCatalogService::undo() | |||||
| { | |||||
| BLI_assert_msg(is_undo_possbile(), "Undo stack is empty"); | |||||
| redo_snapshots_.append(std::move(catalog_collection_)); | |||||
| catalog_collection_ = std::move(undo_snapshots_.pop_last()); | |||||
| } | |||||
| void AssetCatalogService::redo() | |||||
| { | |||||
| BLI_assert_msg(is_redo_possbile(), "Redo stack is empty"); | |||||
| undo_snapshots_.append(std::move(catalog_collection_)); | |||||
| catalog_collection_ = std::move(redo_snapshots_.pop_last()); | |||||
| } | |||||
| void AssetCatalogService::store_undo_snapshot() | |||||
| { | |||||
| std::unique_ptr<AssetCatalogCollection> snapshot = catalog_collection_->deep_copy(); | |||||
| undo_snapshots_.append(std::move(snapshot)); | |||||
| redo_snapshots_.clear(); | |||||
| } | |||||
| /* ---------------------------------------------------------------------- */ | |||||
| std::unique_ptr<AssetCatalogCollection> AssetCatalogCollection::deep_copy() const | |||||
| { | |||||
| auto copy = std::make_unique<AssetCatalogCollection>(); | |||||
| copy->catalogs_ = std::move(copy_catalog_map(this->catalogs_)); | |||||
| copy->deleted_catalogs_ = std::move(copy_catalog_map(this->deleted_catalogs_)); | |||||
| if (catalog_definition_file_) { | |||||
| copy->catalog_definition_file_ = std::move( | |||||
| catalog_definition_file_->copy_and_remap(copy->catalogs_, copy->deleted_catalogs_)); | |||||
| } | |||||
| return copy; | |||||
| } | |||||
| OwningAssetCatalogMap AssetCatalogCollection::copy_catalog_map(const OwningAssetCatalogMap &orig) | |||||
| { | |||||
| OwningAssetCatalogMap copy; | |||||
| for (const auto &orig_catalog_uptr : orig.values()) { | |||||
| auto copy_catalog_uptr = std::make_unique<AssetCatalog>(*orig_catalog_uptr.get()); | |||||
| copy.add_new(copy_catalog_uptr->catalog_id, std::move(copy_catalog_uptr)); | |||||
| } | |||||
| return copy; | |||||
| } | |||||
| /* ---------------------------------------------------------------------- */ | /* ---------------------------------------------------------------------- */ | ||||
| AssetCatalogTreeItem::AssetCatalogTreeItem(StringRef name, | AssetCatalogTreeItem::AssetCatalogTreeItem(StringRef name, | ||||
| CatalogID catalog_id, | CatalogID catalog_id, | ||||
| StringRef simple_name, | StringRef simple_name, | ||||
| const AssetCatalogTreeItem *parent) | const AssetCatalogTreeItem *parent) | ||||
| : name_(name), catalog_id_(catalog_id), simple_name_(simple_name), parent_(parent) | : name_(name), catalog_id_(catalog_id), simple_name_(simple_name), parent_(parent) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
| void AssetCatalogTree::foreach_root_item(const ItemIterFn callback) | void AssetCatalogTree::foreach_root_item(const ItemIterFn callback) | ||||
| { | { | ||||
| for (auto &[key, item] : root_items_) { | for (auto &[key, item] : root_items_) { | ||||
| callback(item); | callback(item); | ||||
| } | } | ||||
| } | } | ||||
| /* ---------------------------------------------------------------------- */ | |||||
| bool AssetCatalogDefinitionFile::contains(const CatalogID catalog_id) const | bool AssetCatalogDefinitionFile::contains(const CatalogID catalog_id) const | ||||
| { | { | ||||
| return catalogs_.contains(catalog_id); | return catalogs_.contains(catalog_id); | ||||
| } | } | ||||
| void AssetCatalogDefinitionFile::add_new(AssetCatalog *catalog) | void AssetCatalogDefinitionFile::add_new(AssetCatalog *catalog) | ||||
| { | { | ||||
| catalogs_.add_new(catalog->catalog_id, catalog); | catalogs_.add_new(catalog->catalog_id, catalog); | ||||
| ▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | std::cerr << "AssetCatalogService: error creating directory " << directory_path << ": " | ||||
| << err_code << std::endl; | << err_code << std::endl; | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Root directory has been created, work is done. */ | /* Root directory has been created, work is done. */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogDefinitionFile::copy_and_remap( | |||||
| const OwningAssetCatalogMap &catalogs, const OwningAssetCatalogMap &deleted_catalogs) const | |||||
| { | |||||
| auto copy = std::make_unique<AssetCatalogDefinitionFile>(*this); | |||||
| copy->catalogs_.clear(); | |||||
| /* Remap pointers of the copy from the original AssetCatalogCollection to the given one. */ | |||||
| for (CatalogID catalog_id : catalogs_.keys()) { | |||||
| /* The catalog can be in the regular or the deleted map. */ | |||||
| const std::unique_ptr<AssetCatalog> *remapped_catalog_uptr_ptr = catalogs.lookup_ptr( | |||||
| catalog_id); | |||||
| if (remapped_catalog_uptr_ptr) { | |||||
| copy->catalogs_.add_new(catalog_id, remapped_catalog_uptr_ptr->get()); | |||||
| continue; | |||||
| } | |||||
| remapped_catalog_uptr_ptr = deleted_catalogs.lookup_ptr(catalog_id); | |||||
| if (remapped_catalog_uptr_ptr) { | |||||
| copy->catalogs_.add_new(catalog_id, remapped_catalog_uptr_ptr->get()); | |||||
| continue; | |||||
| } | |||||
| BLI_assert(!"A CDF should only reference known catalogs."); | |||||
| } | |||||
| return copy; | |||||
| } | |||||
| AssetCatalog::AssetCatalog(const CatalogID catalog_id, | AssetCatalog::AssetCatalog(const CatalogID catalog_id, | ||||
| const AssetCatalogPath &path, | const AssetCatalogPath &path, | ||||
| const std::string &simple_name) | const std::string &simple_name) | ||||
| : catalog_id(catalog_id), path(path), simple_name(simple_name) | : catalog_id(catalog_id), path(path), simple_name(simple_name) | ||||
| { | { | ||||
| } | } | ||||
| std::unique_ptr<AssetCatalog> AssetCatalog::from_path(const AssetCatalogPath &path) | std::unique_ptr<AssetCatalog> AssetCatalog::from_path(const AssetCatalogPath &path) | ||||
| Show All 32 Lines | |||||