Blender  V3.3
asset_list.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
12 #include <optional>
13 #include <string>
14 
15 #include "BKE_context.h"
16 
17 #include "BLI_map.hh"
18 #include "BLI_path_util.h"
19 #include "BLI_utility_mixins.hh"
20 
21 #include "DNA_space_types.h"
22 
23 #include "BKE_preferences.h"
24 
25 #include "ED_fileselect.h"
26 
27 #include "WM_api.h"
28 
29 /* XXX uses private header of file-space. */
30 #include "../space_file/file_indexer.h"
31 #include "../space_file/filelist.h"
32 
33 #include "ED_asset_handle.h"
34 #include "ED_asset_indexer.h"
35 #include "ED_asset_list.h"
36 #include "ED_asset_list.hh"
38 
39 namespace blender::ed::asset {
40 
41 /* -------------------------------------------------------------------- */
51  static void filelist_free_fn(FileList *list)
52  {
53  filelist_free(list);
54  MEM_freeN(list);
55  }
56 
57  std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_;
58 
59  public:
60  explicit FileListWrapper(eFileSelectType filesel_type)
61  : file_list_(filelist_new(filesel_type), filelist_free_fn)
62  {
63  }
64  FileListWrapper(FileListWrapper &&other) = default;
67  {
68  /* Destructs the owned pointer. */
69  file_list_ = nullptr;
70  }
71 
72  operator FileList *() const
73  {
74  return file_list_.get();
75  }
76 };
77 
78 class PreviewTimer {
79  /* Non-owning! The Window-Manager registers and owns this. */
80  wmTimer *timer_ = nullptr;
81 
82  public:
83  void ensureRunning(const bContext *C)
84  {
85  if (!timer_) {
88  }
89  }
90 
91  void stop(const bContext *C)
92  {
93  if (timer_) {
95  timer_ = nullptr;
96  }
97  }
98 };
99 
101  FileListWrapper filelist_;
102  AssetLibraryReference library_ref_;
103  PreviewTimer previews_timer_;
104 
105  public:
106  AssetList() = delete;
107  AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref);
108  AssetList(AssetList &&other) = default;
109  ~AssetList() = default;
110 
111  void setup();
112  void fetch(const bContext &C);
113  void ensurePreviewsJob(bContext *C);
114  void clear(bContext *C);
115 
116  bool needsRefetch() const;
117  void iterate(AssetListIterFn fn) const;
118  bool listen(const wmNotifier &notifier) const;
119  int size() const;
120  void tagMainDataDirty() const;
121  void remapID(ID *id_old, ID *id_new) const;
122  StringRef filepath() const;
123 };
124 
125 AssetList::AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref)
126  : filelist_(filesel_type), library_ref_(asset_library_ref)
127 {
128 }
129 
131 {
132  FileList *files = filelist_;
133 
134  bUserAssetLibrary *user_library = nullptr;
135 
136  /* Ensure valid repository, or fall-back to local one. */
137  if (library_ref_.type == ASSET_LIBRARY_CUSTOM) {
138  BLI_assert(library_ref_.custom_library_index >= 0);
139 
141  &U, library_ref_.custom_library_index);
142  }
143 
144  /* Relevant bits from file_refresh(). */
145  /* TODO pass options properly. */
147  filelist_setsorting(files, FILE_SORT_ALPHA, false);
148  filelist_setlibrary(files, &library_ref_);
150  files,
151  false,
152  true,
153  true, /* Just always hide parent, prefer to not add an extra user option for this. */
156  true,
157  "",
158  "");
159 
160  const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing);
161  filelist_setindexer(files, use_asset_indexer ? &file_indexer_asset : &file_indexer_noop);
162 
163  char path[FILE_MAXDIR] = "";
164  if (user_library) {
165  BLI_strncpy(path, user_library->path, sizeof(path));
166  filelist_setdir(files, path);
167  }
168  else {
169  filelist_setdir(files, path);
170  }
171 }
172 
174 {
175  FileList *files = filelist_;
176 
177  if (filelist_needs_force_reset(files)) {
180  }
181 
182  if (filelist_needs_reading(files)) {
183  if (!filelist_pending(files)) {
185  }
186  }
187  filelist_sort(files);
188  filelist_filter(files);
189 }
190 
192 {
193  return filelist_needs_force_reset(filelist_) || filelist_needs_reading(filelist_);
194 }
195 
197 {
198  FileList *files = filelist_;
199  int numfiles = filelist_files_ensure(files);
200 
201  for (int i = 0; i < numfiles; i++) {
202  FileDirEntry *file = filelist_file(files, i);
203  if ((file->typeflag & FILE_TYPE_ASSET) == 0) {
204  continue;
205  }
206 
207  AssetHandle asset_handle = {file};
208  if (!fn(asset_handle)) {
209  /* If the callback returns false, we stop iterating. */
210  break;
211  }
212  }
213 }
214 
216 {
217  FileList *files = filelist_;
218  int numfiles = filelist_files_ensure(files);
219 
220  filelist_cache_previews_set(files, true);
222  /* TODO fetch all previews for now. */
223  filelist_file_cache_block(files, numfiles / 2);
225 
226  {
227  const bool previews_running = filelist_cache_previews_running(files) &&
229  if (previews_running) {
230  previews_timer_.ensureRunning(C);
231  }
232  else {
233  /* Preview is not running, no need to keep generating update events! */
234  previews_timer_.stop(C);
235  }
236  }
237 }
238 
240 {
241  /* Based on #ED_fileselect_clear() */
242 
243  FileList *files = filelist_;
245  filelist_freelib(files);
246  filelist_clear(files);
247 
249 }
250 
254 bool AssetList::listen(const wmNotifier &notifier) const
255 {
256  switch (notifier.category) {
257  case NC_ID: {
258  if (ELEM(notifier.action, NA_RENAME)) {
259  return true;
260  }
261  break;
262  }
263  case NC_ASSET:
265  return true;
266  }
267  if (ELEM(notifier.action, NA_ADDED, NA_REMOVED, NA_EDITED)) {
268  return true;
269  }
270  break;
271  }
272 
273  return false;
274 }
275 
279 int AssetList::size() const
280 {
281  return filelist_files_ensure(filelist_);
282 }
283 
285 {
286  if (filelist_needs_reset_on_main_changes(filelist_)) {
288  }
289 }
290 
291 void AssetList::remapID(ID * /*id_old*/, ID * /*id_new*/) const
292 {
293  /* Trigger full re-fetch of the file list if main data was changed, don't even attempt remap
294  * pointers. We could give file list types a id-remap callback, but it's probably not worth it.
295  * Refreshing local file lists is relatively cheap. */
297 }
298 
300 {
301  return filelist_dir(filelist_);
302 }
303 
306 /* -------------------------------------------------------------------- */
315 
316  public:
317  /* Purely static class, can't instantiate this. */
318  AssetListStorage() = delete;
319 
320  static void fetch_library(const AssetLibraryReference &library_reference, const bContext &C);
321  static void destruct();
322  static AssetList *lookup_list(const AssetLibraryReference &library_ref);
323  static void tagMainDataDirty();
324  static void remapID(ID *id_new, ID *id_old);
325 
326  private:
327  static std::optional<eFileSelectType> asset_library_reference_to_fileselect_type(
328  const AssetLibraryReference &library_reference);
329 
330  using is_new_t = bool;
331  static std::tuple<AssetList &, is_new_t> ensure_list_storage(
332  const AssetLibraryReference &library_reference, eFileSelectType filesel_type);
333 
334  static AssetListMap &global_storage();
335 };
336 
338  const bContext &C)
339 {
340  std::optional filesel_type = asset_library_reference_to_fileselect_type(library_reference);
341  if (!filesel_type) {
342  return;
343  }
344 
345  auto [list, is_new] = ensure_list_storage(library_reference, *filesel_type);
346  if (is_new || list.needsRefetch()) {
347  list.setup();
348  list.fetch(C);
349  }
350 }
351 
353 {
354  global_storage().~AssetListMap();
355 }
356 
358 {
359  return global_storage().lookup_ptr(library_ref);
360 }
361 
363 {
364  for (AssetList &list : global_storage().values()) {
365  list.tagMainDataDirty();
366  }
367 }
368 
369 void AssetListStorage::remapID(ID *id_new, ID *id_old)
370 {
371  for (AssetList &list : global_storage().values()) {
372  list.remapID(id_new, id_old);
373  }
374 }
375 
376 std::optional<eFileSelectType> AssetListStorage::asset_library_reference_to_fileselect_type(
377  const AssetLibraryReference &library_reference)
378 {
379  switch (library_reference.type) {
381  return FILE_ASSET_LIBRARY;
382  case ASSET_LIBRARY_LOCAL:
383  return FILE_MAIN_ASSET;
384  }
385 
386  return std::nullopt;
387 }
388 
389 std::tuple<AssetList &, AssetListStorage::is_new_t> AssetListStorage::ensure_list_storage(
390  const AssetLibraryReference &library_reference, eFileSelectType filesel_type)
391 {
392  AssetListMap &storage = global_storage();
393 
394  if (AssetList *list = storage.lookup_ptr(library_reference)) {
395  return {*list, false};
396  }
397  storage.add(library_reference, AssetList(filesel_type, library_reference));
398  return {storage.lookup(library_reference), true};
399 }
400 
404 AssetListStorage::AssetListMap &AssetListStorage::global_storage()
405 {
406  static AssetListMap global_storage_;
407  return global_storage_;
408 }
409 
412 } // namespace blender::ed::asset
413 
414 /* -------------------------------------------------------------------- */
418 using namespace blender::ed::asset;
419 
420 void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
421 {
422  AssetListStorage::fetch_library(*library_reference, *C);
423 }
424 
426 {
427 
428  AssetList *list = AssetListStorage::lookup_list(*library_reference);
429  if (list) {
430  list->ensurePreviewsJob(C);
431  }
432 }
433 
434 void ED_assetlist_clear(const AssetLibraryReference *library_reference, bContext *C)
435 {
436  AssetList *list = AssetListStorage::lookup_list(*library_reference);
437  if (list) {
438  list->clear(C);
439  }
440 }
441 
443 {
444  return AssetListStorage::lookup_list(*library_reference) != nullptr;
445 }
446 
448 {
449  AssetList *list = AssetListStorage::lookup_list(library_reference);
450  if (list) {
451  list->iterate(fn);
452  }
453 }
454 
455 /* TODO hack to use the File Browser path, so we can keep all the import logic handled by the asset
456  * API. Get rid of this once the File Browser is integrated better with the asset list. */
458 {
459  SpaceFile *sfile = CTX_wm_space_file(C);
460  if (!sfile || !ED_fileselect_is_asset_browser(sfile)) {
461  return nullptr;
462  }
463 
464  FileAssetSelectParams *asset_select_params = ED_fileselect_get_asset_params(sfile);
465  if (!asset_select_params) {
466  return nullptr;
467  }
468 
469  return filelist_dir(sfile->files);
470 }
471 
473  const AssetLibraryReference &library_reference,
474  const AssetHandle &asset_handle)
475 {
476  if (ED_asset_handle_get_local_id(&asset_handle) ||
477  !ED_asset_handle_get_metadata(&asset_handle)) {
478  return {};
479  }
480  const char *library_path = ED_assetlist_library_path(&library_reference);
481  if (!library_path && C) {
483  }
484  if (!library_path) {
485  return {};
486  }
487  const char *asset_relpath = asset_handle.file_data->relpath;
488 
489  char path[FILE_MAX_LIBEXTRA];
490  BLI_join_dirfile(path, sizeof(path), library_path, asset_relpath);
491 
492  return path;
493 }
494 
496 {
497  ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);
498  if (imbuf) {
499  return imbuf;
500  }
501 
502  return filelist_geticon_image_ex(asset_handle->file_data);
503 }
504 
505 const char *ED_assetlist_library_path(const AssetLibraryReference *library_reference)
506 {
507  AssetList *list = AssetListStorage::lookup_list(*library_reference);
508  if (list) {
509  return list->filepath().data();
510  }
511  return nullptr;
512 }
513 
514 bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
515  const wmNotifier *notifier)
516 {
517  AssetList *list = AssetListStorage::lookup_list(*library_reference);
518  if (list) {
519  return list->listen(*notifier);
520  }
521  return false;
522 }
523 
524 int ED_assetlist_size(const AssetLibraryReference *library_reference)
525 {
526  AssetList *list = AssetListStorage::lookup_list(*library_reference);
527  if (list) {
528  return list->size();
529  }
530  return -1;
531 }
532 
534 {
536 }
537 
538 void ED_assetlist_storage_id_remap(ID *id_old, ID *id_new)
539 {
540  AssetListStorage::remapID(id_old, id_new);
541 }
542 
544 {
546 }
547 
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct SpaceFile * CTX_wm_space_file(const bContext *C)
Definition: context.c:842
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
struct bUserAssetLibrary * BKE_preferences_asset_library_find_from_index(const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define FILE_MAXDIR
void BLI_join_dirfile(char *__restrict dst, size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1531
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define ELEM(...)
#define FILTER_ID_ALL
Definition: DNA_ID.h:939
@ ASSET_LIBRARY_CUSTOM
@ ASSET_LIBRARY_LOCAL
@ FILE_SORT_ALPHA
eFileSelectType
@ FILE_ASSET_LIBRARY
@ FILE_MAIN_ASSET
@ FILE_TYPE_ASSET
@ FILE_TYPE_BLENDERLIB
#define FILE_MAX_LIBEXTRA
#define FILE_SELECT_MAX_RECURSIONS
#define USER_EXPERIMENTAL_TEST(userdef, member)
struct ID * ED_asset_handle_get_local_id(const struct AssetHandle *asset)
struct AssetMetaData * ED_asset_handle_get_metadata(const struct AssetHandle *asset)
const FileIndexerType file_indexer_asset
struct FileAssetSelectParams * ED_fileselect_get_asset_params(const struct SpaceFile *sfile)
bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile)
#define C
Definition: RandGen.cpp:25
#define ND_ASSET_LIST_READING
Definition: WM_types.h:491
#define NC_ID
Definition: WM_types.h:345
#define NA_ADDED
Definition: WM_types.h:525
#define NA_EDITED
Definition: WM_types.h:523
#define ND_ASSET_LIST_PREVIEW
Definition: WM_types.h:490
#define NC_ASSET
Definition: WM_types.h:354
#define NA_REMOVED
Definition: WM_types.h:526
#define ND_ASSET_LIST
Definition: WM_types.h:489
#define NA_RENAME
Definition: WM_types.h:527
void ED_assetlist_storage_tag_main_data_dirty()
Definition: asset_list.cc:533
void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn)
Definition: asset_list.cc:447
bool ED_assetlist_listen(const AssetLibraryReference *library_reference, const wmNotifier *notifier)
Definition: asset_list.cc:514
void ED_assetlist_clear(const AssetLibraryReference *library_reference, bContext *C)
Definition: asset_list.cc:434
void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
Definition: asset_list.cc:420
void ED_assetlist_storage_exit()
Definition: asset_list.cc:543
static const char * assetlist_library_path_from_sfile_get_hack(const bContext *C)
Definition: asset_list.cc:457
ImBuf * ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
Definition: asset_list.cc:495
const char * ED_assetlist_library_path(const AssetLibraryReference *library_reference)
Definition: asset_list.cc:505
std::string ED_assetlist_asset_filepath_get(const bContext *C, const AssetLibraryReference &library_reference, const AssetHandle &asset_handle)
Definition: asset_list.cc:472
int ED_assetlist_size(const AssetLibraryReference *library_reference)
Definition: asset_list.cc:524
void ED_assetlist_storage_id_remap(ID *id_old, ID *id_new)
Definition: asset_list.cc:538
bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference)
Definition: asset_list.cc:442
void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, bContext *C)
Definition: asset_list.cc:425
unsigned int U
Definition: btGjkEpa3.h:78
const Value * lookup_ptr(const Key &key) const
Definition: BLI_map.hh:463
constexpr const char * data() const
static AssetList * lookup_list(const AssetLibraryReference &library_ref)
Definition: asset_list.cc:357
static void remapID(ID *id_new, ID *id_old)
Definition: asset_list.cc:369
static void fetch_library(const AssetLibraryReference &library_reference, const bContext &C)
Definition: asset_list.cc:337
StringRef filepath() const
Definition: asset_list.cc:299
void remapID(ID *id_old, ID *id_new) const
Definition: asset_list.cc:291
AssetList(AssetList &&other)=default
bool listen(const wmNotifier &notifier) const
Definition: asset_list.cc:254
void ensurePreviewsJob(bContext *C)
Definition: asset_list.cc:215
void fetch(const bContext &C)
Definition: asset_list.cc:173
void iterate(AssetListIterFn fn) const
Definition: asset_list.cc:196
FileListWrapper(FileListWrapper &&other)=default
FileListWrapper(eFileSelectType filesel_type)
Definition: asset_list.cc:60
FileListWrapper & operator=(FileListWrapper &&other)=default
void stop(const bContext *C)
Definition: asset_list.cc:91
void ensureRunning(const bContext *C)
Definition: asset_list.cc:83
FILE * file
const FileIndexerType file_indexer_noop
Definition: file_indexer.cc:81
void filelist_free(struct FileList *filelist)
Definition: filelist.c:2019
void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
Definition: filelist.c:2630
void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
Definition: filelist.c:753
int filelist_needs_reading(FileList *filelist)
Definition: filelist.c:2873
void filelist_sort(struct FileList *filelist)
Definition: filelist.c:720
void filelist_clear_from_reset_tag(FileList *filelist)
Definition: filelist.c:2005
bool filelist_cache_previews_running(FileList *filelist)
Definition: filelist.c:2712
void filelist_freelib(struct FileList *filelist)
Definition: filelist.c:2047
void filelist_setfilter_options(FileList *filelist, const bool do_filter, const bool hide_dot, const bool hide_parent, const uint64_t filter, const uint64_t filter_id, const bool filter_assets_only, const char *filter_glob, const char *filter_search)
Definition: filelist.c:1116
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
Definition: filelist.c:1219
bool filelist_cache_previews_done(FileList *filelist)
Definition: filelist.c:2719
void filelist_setdir(struct FileList *filelist, char *r_dir)
Definition: filelist.c:2116
void filelist_clear(FileList *filelist)
Definition: filelist.c:2000
FileList * filelist_new(short type)
Definition: filelist.c:1875
void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
Definition: filelist.c:2132
bool filelist_cache_previews_update(FileList *filelist)
Definition: filelist.c:2655
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition: filelist.c:4118
bool filelist_file_cache_block(struct FileList *filelist, const int index)
Definition: filelist.c:2416
void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
Definition: filelist.c:2348
ImBuf * filelist_geticon_image_ex(const FileDirEntry *file)
Definition: filelist.c:1308
FileDirEntry * filelist_file(struct FileList *filelist, int index)
Definition: filelist.c:2280
bool filelist_pending(struct FileList *filelist)
Definition: filelist.c:2163
struct FileList FileList
void filelist_filter(FileList *filelist)
Definition: filelist.c:1061
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition: filelist.c:2150
bool filelist_needs_reset_on_main_changes(const FileList *filelist)
Definition: filelist.c:2168
int filelist_files_ensure(FileList *filelist)
Definition: filelist.c:2173
void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
Definition: filelist.c:1172
ImBuf * filelist_file_getimage(const FileDirEntry *file)
Definition: filelist.c:1303
bool filelist_needs_force_reset(FileList *filelist)
Definition: filelist.c:2140
void filelist_readjob_start(FileList *filelist, const int space_notifier, const bContext *C)
Definition: filelist.c:4057
const char * filelist_dir(struct FileList *filelist)
Definition: filelist.c:2106
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
const struct FileDirEntry * file_data
Definition: DNA_ID.h:368
struct FileList * files
unsigned int data
Definition: WM_types.h:308
unsigned int action
Definition: WM_types.h:308
unsigned int category
Definition: WM_types.h:308
void WM_main_add_notifier(unsigned int type, void *reference)
wmTimer * WM_event_add_timer_notifier(wmWindowManager *wm, wmWindow *win, unsigned int type, double timestep)
Definition: wm_window.c:1647
void WM_event_remove_timer_notifier(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
Definition: wm_window.c:1713