Blender  V3.3
BKE_asset_catalog.hh
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #pragma once
8 
9 #ifndef __cplusplus
10 # error This is a C++ header. The C interface is yet to be implemented/designed.
11 #endif
12 
13 #include "BLI_function_ref.hh"
14 #include "BLI_map.hh"
15 #include "BLI_set.hh"
16 #include "BLI_string_ref.hh"
17 #include "BLI_uuid.h"
18 #include "BLI_vector.hh"
19 
21 
22 #include <map>
23 #include <memory>
24 #include <set>
25 #include <string>
26 
27 namespace blender::bke {
28 
29 class AssetCatalog;
30 class AssetCatalogCollection;
31 class AssetCatalogDefinitionFile;
32 class AssetCatalogFilter;
33 class AssetCatalogTree;
34 
35 using CatalogID = bUUID;
36 using CatalogPathComponent = std::string;
37 /* Would be nice to be able to use `std::filesystem::path` for this, but it's currently not
38  * available on the minimum macOS target version. */
39 using CatalogFilePath = std::string;
41 
42 /* Manages the asset catalogs of a single asset library (i.e. of catalogs defined in a single
43  * directory hierarchy). */
45  public:
47 
48  public:
50  explicit AssetCatalogService(const CatalogFilePath &asset_library_root);
51 
59  void tag_has_unsaved_changes(AssetCatalog *edited_catalog);
60  bool has_unsaved_changes() const;
61 
63  void load_from_disk();
65  void load_from_disk(const CatalogFilePath &file_or_directory_path);
66 
84  bool write_to_disk(const CatalogFilePath &blend_file_path);
85 
94 
103  void reload_catalogs();
104 
106  AssetCatalog *find_catalog(CatalogID catalog_id) const;
107 
115 
119  bool is_catalog_known(CatalogID catalog_id) const;
120 
127  AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const;
128 
131  AssetCatalog *create_catalog(const AssetCatalogPath &catalog_path);
132 
136  void prune_catalogs_by_path(const AssetCatalogPath &path);
137 
142  void prune_catalogs_by_id(CatalogID catalog_id);
143 
147  void update_catalog_path(CatalogID catalog_id, const AssetCatalogPath &new_catalog_path);
148 
150 
152  bool is_empty() const;
153 
157  void undo_push();
162  void undo();
163  bool is_undo_possbile() const;
167  void redo();
168  bool is_redo_possbile() const;
169 
170  protected:
171  std::unique_ptr<AssetCatalogCollection> catalog_collection_;
172  std::unique_ptr<AssetCatalogTree> catalog_tree_ = std::make_unique<AssetCatalogTree>();
174 
177 
178  void load_directory_recursive(const CatalogFilePath &directory_path);
179  void load_single_file(const CatalogFilePath &catalog_definition_file_path);
180 
182  bool write_to_disk_ex(const CatalogFilePath &blend_file_path);
184  bool is_catalog_known_with_unsaved_changes(CatalogID catalog_id) const;
185 
193  void purge_catalogs_not_listed(const Set<CatalogID> &catalogs_to_keep);
194 
203  void delete_catalog_by_id_soft(CatalogID catalog_id);
204 
208  void delete_catalog_by_id_hard(CatalogID catalog_id);
209 
210  std::unique_ptr<AssetCatalogDefinitionFile> parse_catalog_file(
211  const CatalogFilePath &catalog_definition_file_path);
212 
216  std::unique_ptr<AssetCatalogDefinitionFile> construct_cdf_in_memory(
217  const CatalogFilePath &file_path);
218 
226  const CatalogFilePath &blend_file_path);
227 
228  std::unique_ptr<AssetCatalogTree> read_into_tree();
229  void rebuild_tree();
230 
235 
240 
241  /* For access by subclasses, as those will not be marked as friend by #AssetCatalogCollection. */
245 };
246 
253  friend AssetCatalogService;
254 
255  public:
258  AssetCatalogCollection(AssetCatalogCollection &&other) noexcept = default;
259 
260  std::unique_ptr<AssetCatalogCollection> deep_copy() const;
261 
262  protected:
265 
270 
271  /* For now only a single catalog definition file is supported.
272  * The aim is to support an arbitrary number of such files per asset library in the future. */
273  std::unique_ptr<AssetCatalogDefinitionFile> catalog_definition_file_;
274 
276  bool has_unsaved_changes_ = false;
277 
279 };
280 
285  friend class AssetCatalogTree;
286 
287  public:
290  using ChildMap = std::map<std::string, AssetCatalogTreeItem>;
292 
294  CatalogID catalog_id,
295  StringRef simple_name,
296  const AssetCatalogTreeItem *parent = nullptr);
297 
298  CatalogID get_catalog_id() const;
300  StringRefNull get_name() const;
301  bool has_unsaved_changes() const;
305  int count_parents() const;
306  bool has_children() const;
307 
310  void foreach_child(const ItemIterFn callback);
311 
312  protected:
319  std::string simple_name_;
321  bool has_unsaved_changes_ = false;
322 
325  const AssetCatalogTreeItem *parent_ = nullptr;
326 
327  private:
328  static void foreach_item_recursive(ChildMap &children_, ItemIterFn callback);
329 };
330 
341  using ChildMap = AssetCatalogTreeItem::ChildMap;
343 
344  public:
346  void insert_item(const AssetCatalog &catalog);
347 
352 
353  protected:
355  ChildMap root_items_;
356 };
357 
362  public:
363  /* For now this is the only version of the catalog definition files that is supported.
364  * Later versioning code may be added to handle older files. */
365  const static int SUPPORTED_VERSION;
366  /* String that's matched in the catalog definition file to know that the line is the version
367  * declaration. It has to start with a space to ensure it won't match any hypothetical future
368  * field that starts with "VERSION". */
369  const static std::string VERSION_MARKER;
370  const static std::string HEADER;
371 
373 
375 
380  bool write_to_disk() const;
388  bool write_to_disk(const CatalogFilePath &dest_file_path) const;
389 
390  bool contains(CatalogID catalog_id) const;
392  void add_overwrite(AssetCatalog *catalog);
394  void add_new(AssetCatalog *catalog);
395 
397  void forget(CatalogID catalog_id);
398 
399  using AssetCatalogParsedFn = FunctionRef<bool(std::unique_ptr<AssetCatalog>)>;
400  void parse_catalog_file(const CatalogFilePath &catalog_definition_file_path,
402 
403  std::unique_ptr<AssetCatalogDefinitionFile> copy_and_remap(
404  const OwningAssetCatalogMap &catalogs, const OwningAssetCatalogMap &deleted_catalogs) const;
405 
406  protected:
407  /* Catalogs stored in this file. They are mapped by ID to make it possible to query whether a
408  * catalog is already known, without having to find the corresponding `AssetCatalog*`. */
410 
411  bool parse_version_line(StringRef line);
412  std::unique_ptr<AssetCatalog> parse_catalog_line(StringRef line);
413 
418  bool write_to_disk_unsafe(const CatalogFilePath &dest_file_path) const;
419  bool ensure_directory_exists(const CatalogFilePath directory_path) const;
420 };
421 
425  public:
426  AssetCatalog() = default;
427  AssetCatalog(CatalogID catalog_id, const AssetCatalogPath &path, const std::string &simple_name);
428 
438  std::string simple_name;
439 
440  struct Flags {
441  /* Treat this catalog as deleted. Keeping deleted catalogs around is necessary to support
442  * merging of on-disk changes with in-memory changes. */
443  bool is_deleted = false;
444 
445  /* Sort this catalog first when there are multiple catalogs with the same catalog path. This
446  * ensures that in a situation where missing catalogs were auto-created, and then
447  * load-and-merged with a file that also has these catalogs, the first one in that file is
448  * always sorted first, regardless of the sort order of its UUID. */
449  bool is_first_loaded = false;
450 
451  /* Merging on-disk changes into memory will not overwrite this catalog.
452  * For example, when a catalog was renamed (i.e. changed path) in this Blender session,
453  * reloading the catalog definition file should not overwrite that change.
454  *
455  * Note that this flag is ignored when is_deleted=true; deleted catalogs that are still in
456  * memory are considered "unsaved" by definition. */
457  bool has_unsaved_changes = false;
458  } flags;
459 
466  static std::unique_ptr<AssetCatalog> from_path(const AssetCatalogPath &path);
467 
469  void simple_name_refresh();
470 
471  protected:
473  static std::string sensible_simple_name_for_path(const AssetCatalogPath &path);
474 };
475 
478  bool operator()(const AssetCatalog *lhs, const AssetCatalog *rhs) const
479  {
480  if (lhs->path != rhs->path) {
481  return lhs->path < rhs->path;
482  }
483 
484  if (lhs->flags.is_first_loaded != rhs->flags.is_first_loaded) {
485  return lhs->flags.is_first_loaded;
486  }
487 
488  return lhs->catalog_id < rhs->catalog_id;
489  }
490 };
491 
495 using AssetCatalogOrderedSet = std::set<const AssetCatalog *, AssetCatalogLessThan>;
496 using MutableAssetCatalogOrderedSet = std::set<AssetCatalog *, AssetCatalogLessThan>;
497 
504  public:
505  bool contains(CatalogID asset_catalog_id) const;
506 
507  /* So that all unknown catalogs can be shown under "Unassigned". */
508  bool is_known(CatalogID asset_catalog_id) const;
509 
510  protected:
514 
517 };
518 
519 } // namespace blender::bke
struct bUUID bUUID
Universally Unique Identifier according to RFC4122.
AssetCatalogCollection(const AssetCatalogCollection &other)=delete
static OwningAssetCatalogMap copy_catalog_map(const OwningAssetCatalogMap &orig)
AssetCatalogCollection(AssetCatalogCollection &&other) noexcept=default
std::unique_ptr< AssetCatalogCollection > deep_copy() const
std::unique_ptr< AssetCatalogDefinitionFile > catalog_definition_file_
void parse_catalog_file(const CatalogFilePath &catalog_definition_file_path, AssetCatalogParsedFn callback)
bool ensure_directory_exists(const CatalogFilePath directory_path) const
bool write_to_disk_unsafe(const CatalogFilePath &dest_file_path) const
Map< CatalogID, AssetCatalog * > catalogs_
std::unique_ptr< AssetCatalog > parse_catalog_line(StringRef line)
std::unique_ptr< AssetCatalogDefinitionFile > copy_and_remap(const OwningAssetCatalogMap &catalogs, const OwningAssetCatalogMap &deleted_catalogs) const
const Set< CatalogID > matching_catalog_ids
bool is_known(CatalogID asset_catalog_id) const
const Set< CatalogID > known_catalog_ids
bool contains(CatalogID asset_catalog_id) const
AssetCatalogFilter(Set< CatalogID > &&matching_catalog_ids, Set< CatalogID > &&known_catalog_ids)
std::unique_ptr< AssetCatalogDefinitionFile > parse_catalog_file(const CatalogFilePath &catalog_definition_file_path)
void load_directory_recursive(const CatalogFilePath &directory_path)
std::unique_ptr< AssetCatalogTree > catalog_tree_
AssetCatalog * create_catalog(const AssetCatalogPath &catalog_path)
bool write_to_disk(const CatalogFilePath &blend_file_path)
AssetCatalog * find_catalog_by_path(const AssetCatalogPath &path) const
void update_catalog_path(CatalogID catalog_id, const AssetCatalogPath &new_catalog_path)
void tag_has_unsaved_changes(AssetCatalog *edited_catalog)
AssetCatalogDefinitionFile * get_catalog_definition_file()
AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const
std::unique_ptr< AssetCatalogDefinitionFile > construct_cdf_in_memory(const CatalogFilePath &file_path)
AssetCatalog * find_catalog(CatalogID catalog_id) const
static CatalogFilePath find_suitable_cdf_path_for_writing(const CatalogFilePath &blend_file_path)
std::unique_ptr< AssetCatalogTree > read_into_tree()
Vector< std::unique_ptr< AssetCatalogCollection > > undo_snapshots_
void load_single_file(const CatalogFilePath &catalog_definition_file_path)
bool is_catalog_known_with_unsaved_changes(CatalogID catalog_id) const
std::unique_ptr< AssetCatalogCollection > catalog_collection_
void prune_catalogs_by_path(const AssetCatalogPath &path)
void purge_catalogs_not_listed(const Set< CatalogID > &catalogs_to_keep)
static const CatalogFilePath DEFAULT_CATALOG_FILENAME
Vector< std::unique_ptr< AssetCatalogCollection > > redo_snapshots_
bool is_catalog_known(CatalogID catalog_id) const
bool write_to_disk_ex(const CatalogFilePath &blend_file_path)
AssetCatalogTreeItem(StringRef name, CatalogID catalog_id, StringRef simple_name, const AssetCatalogTreeItem *parent=nullptr)
FunctionRef< void(AssetCatalogTreeItem &)> ItemIterFn
std::map< std::string, AssetCatalogTreeItem > ChildMap
const AssetCatalogTreeItem * parent_
void insert_item(const AssetCatalog &catalog)
void foreach_item(const AssetCatalogTreeItem::ItemIterFn callback)
void foreach_root_item(const ItemIterFn callback)
struct blender::bke::AssetCatalog::Flags flags
static std::unique_ptr< AssetCatalog > from_path(const AssetCatalogPath &path)
static std::string sensible_simple_name_for_path(const AssetCatalogPath &path)
DEGForeachIDComponentCallback callback
SyclQueue void void size_t num_bytes void
std::set< AssetCatalog *, AssetCatalogLessThan > MutableAssetCatalogOrderedSet
std::string CatalogFilePath
std::set< const AssetCatalog *, AssetCatalogLessThan > AssetCatalogOrderedSet
std::string CatalogPathComponent
Universally Unique Identifier according to RFC4122.
bool operator()(const AssetCatalog *lhs, const AssetCatalog *rhs) const