Blender V5.0
asset_list.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14
15#include <optional>
16#include <string>
17
18#include "AS_asset_library.hh"
20
21#include "BKE_context.hh"
22#include "BKE_main.hh"
23#include "BKE_screen.hh"
24
25#include "BLI_listbase.h"
26#include "BLI_map.hh"
27#include "BLI_string.h"
28#include "BLI_utility_mixins.hh"
29
30#include "DNA_space_types.h"
31
32#include "WM_api.hh"
33
34/* XXX uses private header of file-space. */
37
38#include "ED_asset_indexer.hh"
39#include "ED_asset_list.hh"
40#include "ED_fileselect.hh"
41#include "ED_screen.hh"
42
44
46
47/* -------------------------------------------------------------------- */
52
57 static void filelist_free_fn(FileList *list)
58 {
60 }
61
62 std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_;
63
64 public:
65 explicit FileListWrapper(eFileSelectType filesel_type)
66 : file_list_(filelist_new(filesel_type), filelist_free_fn)
67 {
68 }
69 FileListWrapper(FileListWrapper &&other) = default;
72 {
73 /* Destructs the owned pointer. */
74 file_list_ = nullptr;
75 }
76
77 operator FileList *() const
78 {
79 return file_list_.get();
80 }
81};
82
84 FileListWrapper filelist_;
85 AssetLibraryReference library_ref_;
86
87 public:
88 AssetList() = delete;
89 AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref);
90 AssetList(AssetList &&other) = default;
91 ~AssetList() = default;
92
93 static bool listen(const wmNotifier &notifier);
94
95 void setup();
96 void fetch(const bContext &C);
97 void ensure_blocking(const bContext &C);
100
101 bool needs_refetch() const;
102 bool is_loaded() const;
104 void iterate(AssetListIterFn fn) const;
105 int size() const;
106 void tag_main_data_dirty() const;
107 void remap_id(ID *id_old, ID *id_new) const;
108};
109
110AssetList::AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref)
111 : filelist_(filesel_type), library_ref_(asset_library_ref)
112{
113}
114
116{
117 FileList *files = filelist_;
118 std::string asset_lib_path = AS_asset_library_root_path_from_library_ref(library_ref_);
119
120 /* Relevant bits from file_refresh(). */
121 /* TODO pass options properly. */
124 filelist_setlibrary(files, &library_ref_);
126 files,
127 true,
128 true,
129 true, /* Just always hide parent, prefer to not add an extra user option for this. */
132 true,
133 "",
134 "");
135
136 const bool use_asset_indexer = !USER_DEVELOPER_TOOL_TEST(&U, no_asset_indexing);
138
139 char dirpath[FILE_MAX_LIBEXTRA] = "";
140 if (!asset_lib_path.empty()) {
141 STRNCPY(dirpath, asset_lib_path.c_str());
142 }
143 filelist_setdir(files, dirpath);
144}
145
147{
148 FileList *files = filelist_;
149
150 if (filelist_needs_force_reset(files)) {
153 }
154
155 if (filelist_needs_reading(files)) {
156 if (!filelist_pending(files)) {
158 }
159 }
160 filelist_sort(files);
161 filelist_filter(files);
162}
163
165{
166 FileList *files = filelist_;
167
168 if (filelist_needs_force_reset(files)) {
170 }
171
172 if (filelist_needs_reading(files)) {
174 }
175
176 filelist_sort(files);
177 filelist_filter(files);
178}
179
181{
182 return filelist_needs_force_reset(filelist_) || filelist_needs_reading(filelist_);
183}
184
186{
187 return filelist_is_ready(filelist_);
188}
189
194
196{
197 FileList *files = filelist_;
198 const int numfiles = filelist_files_ensure(files);
199
200 for (int i = 0; i < numfiles; i++) {
202 if (!asset) {
203 continue;
204 }
205
206 if (!fn(*asset)) {
207 break;
208 }
209 }
210}
211
213{
214 /* Based on #ED_fileselect_clear() */
215
216 FileList *files = filelist_;
218 filelist_freelib(files);
219 filelist_clear(files);
221
223}
224
226{
227 /* Based on #ED_fileselect_clear_main_assets() */
228
229 FileList *files = filelist_;
231 filelist_freelib(files);
235
237}
238
242bool AssetList::listen(const wmNotifier &notifier)
243{
244 switch (notifier.category) {
245 case NC_ID: {
246 if (ELEM(notifier.action, NA_RENAME)) {
247 return true;
248 }
249 break;
250 }
251 case NC_ASSET:
253 return true;
254 }
255 if (ELEM(notifier.action, NA_ADDED, NA_REMOVED, NA_EDITED)) {
256 return true;
257 }
258 break;
259 }
260
261 return false;
262}
263
268{
269 return filelist_files_ensure(filelist_);
270}
271
273{
276 }
277}
278
279void AssetList::remap_id(ID * /*id_old*/, ID * /*id_new*/) const
280{
281 /* Trigger full re-fetch of the file list if main data was changed, don't even attempt remap
282 * pointers. We could give file list types a id-remap callback, but it's probably not worth it.
283 * Refreshing local file lists is relatively cheap. */
284 this->tag_main_data_dirty();
285}
286
288
289/* -------------------------------------------------------------------- */
292
293static void clear(const AssetLibraryReference *library_reference, wmWindowManager *wm);
294static void on_save_post(Main *main, PointerRNA **pointers, int num_pointers, void *arg);
295
300
313
318{
319 static GlobalStorage global_storage;
320 return global_storage.list_map;
321}
322
323static AssetList *lookup_list(const AssetLibraryReference &library_ref)
324{
325 return libraries_map().lookup_ptr(library_ref);
326}
327
329{
330 for (AssetList &list : libraries_map().values()) {
331 list.tag_main_data_dirty();
332 }
333}
334
335void storage_id_remap(ID *id_old, ID *id_new)
336{
337 for (AssetList &list : libraries_map().values()) {
338 list.remap_id(id_old, id_new);
339 }
340}
341
342static std::optional<eFileSelectType> asset_library_reference_to_fileselect_type(
343 const AssetLibraryReference &library_reference)
344{
345 switch (eAssetLibraryType(library_reference.type)) {
350 return FILE_ASSET_LIBRARY;
352 return FILE_MAIN_ASSET;
353 }
354
355 return std::nullopt;
356}
357
358using is_new_t = bool;
359static std::tuple<AssetList &, is_new_t> ensure_list_storage(
360 const AssetLibraryReference &library_reference, eFileSelectType filesel_type)
361{
362 AssetListMap &storage = libraries_map();
363
364 if (AssetList *list = storage.lookup_ptr(library_reference)) {
365 return {*list, false};
366 }
367 storage.add(library_reference, AssetList(filesel_type, library_reference));
368 return {storage.lookup(library_reference), true};
369}
370
372
374{
375 const wmNotifier *wmn = params->notifier;
376 ARegion *region = params->region;
377
378 switch (wmn->category) {
379 case NC_ASSET:
382 }
383 break;
384 }
385}
386
387static void on_save_post(Main *main,
388 PointerRNA ** /*pointers*/,
389 int /*num_pointers*/,
390 void * /*arg*/)
391{
392 wmWindowManager *wm = static_cast<wmWindowManager *>(main->wm.first);
393 const AssetLibraryReference current_file_library =
395 clear(&current_file_library, wm);
396}
397
398/* -------------------------------------------------------------------- */
401
402void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
403{
404 std::optional filesel_type = asset_library_reference_to_fileselect_type(*library_reference);
405 if (!filesel_type) {
406 return;
407 }
408
409 auto [list, is_new] = ensure_list_storage(*library_reference, *filesel_type);
410 if (is_new || list.needs_refetch()) {
411 list.setup();
412 list.fetch(*C);
413 }
414}
415
416void storage_fetch_blocking(const AssetLibraryReference &library_reference, const bContext &C)
417{
418 std::optional filesel_type = asset_library_reference_to_fileselect_type(library_reference);
419 if (!filesel_type) {
420 /* TODO: Warn? */
421 return;
422 }
423
424 auto [list, is_new] = ensure_list_storage(library_reference, *filesel_type);
425 if (is_new || list.needs_refetch()) {
426 list.setup();
427 list.ensure_blocking(C);
428 }
429}
430
431bool is_loaded(const AssetLibraryReference *library_reference)
432{
433 AssetList *list = lookup_list(*library_reference);
434 if (!list) {
435 return false;
436 }
437 if (list->needs_refetch()) {
438 return false;
439 }
440 return list->is_loaded();
441}
442
444 const AssetLibraryReference &library_reference,
445 const wmWindowManager *wm,
446 const FunctionRef<void(SpaceFile &sfile)> fn)
447{
448 LISTBASE_FOREACH (const wmWindow *, win, &wm->windows) {
449 const bScreen *screen = WM_window_get_active_screen(win);
450 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
451 /* Only needs to cover visible file/asset browsers, since others are already cleared through
452 * area exiting. */
453 if (area->spacetype == SPACE_FILE) {
454 SpaceFile *sfile = reinterpret_cast<SpaceFile *>(area->spacedata.first);
455 if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) {
456 if (sfile->asset_params && sfile->asset_params->asset_library_ref == library_reference) {
457 fn(*sfile);
458 }
459 }
460 }
461 }
462 }
463}
464
465void clear(const AssetLibraryReference *library_reference, wmWindowManager *wm)
466{
467 AssetList *list = lookup_list(*library_reference);
468 if (list) {
469 list->clear(wm);
470 }
471
472 /* Only needs to cover visible file/asset browsers, since others are already cleared through area
473 * exiting. */
475 *library_reference, wm, [&](SpaceFile &sfile) { ED_fileselect_clear(wm, &sfile); });
476
477 /* Always clear the all library when clearing a nested one. */
478 if (library_reference->type != ASSET_LIBRARY_ALL) {
480 AssetList *all_lib_list = lookup_list(all_lib_ref);
481
482 /* If the cleared nested library is the current file one, only clear current file assets. */
483 if (library_reference->type == ASSET_LIBRARY_LOCAL) {
484 if (all_lib_list) {
485 all_lib_list->clear_current_file_assets(wm);
486 }
487
489 all_lib_ref, wm, [&](SpaceFile &sfile) { ED_fileselect_clear_main_assets(wm, &sfile); });
490 }
491 else {
492 if (all_lib_list) {
493 all_lib_list->clear(wm);
494 }
495
497 all_lib_ref, wm, [&](SpaceFile &sfile) { ED_fileselect_clear(wm, &sfile); });
498 }
499 }
500}
501
502void clear(const AssetLibraryReference *library_reference, const bContext *C)
503{
504 clear(library_reference, CTX_wm_manager(C));
505}
506
508{
510 clear(&all_lib_ref, CTX_wm_manager(C));
511}
512
514{
515 return lookup_list(*library_reference) != nullptr;
516}
517
519 const bContext *C)
520{
521 bool has_asset_browser = false;
523 *library_reference, CTX_wm_manager(C), [&](SpaceFile & /*sfile*/) {
524 has_asset_browser = true;
525 });
526
527 return has_asset_browser;
528}
529
530void iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn)
531{
532 AssetList *list = lookup_list(library_reference);
533 if (list) {
534 list->iterate(fn);
535 }
536}
537
539 const AssetLibraryReference &library_reference)
540{
541 const AssetList *list = lookup_list(library_reference);
542 if (!list) {
543 return nullptr;
544 }
545 return list->asset_library();
546}
547
548bool listen(const wmNotifier *notifier)
549{
550 return AssetList::listen(*notifier);
551}
552
553int size(const AssetLibraryReference *library_reference)
554{
555 AssetList *list = lookup_list(*library_reference);
556 if (list) {
557 return list->size();
558 }
559 return -1;
560}
561
563{
565}
566
568
569} // namespace blender::ed::asset::list
std::string AS_asset_library_root_path_from_library_ref(const AssetLibraryReference &library_reference)
Main runtime representation of an asset.
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
Definition callbacks.cc:74
@ BKE_CB_EVT_SAVE_POST
wmWindowManager * CTX_wm_manager(const bContext *C)
#define LISTBASE_FOREACH(type, var, list)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define ELEM(...)
#define FILTER_ID_ALL
Definition DNA_ID.h:1239
eAssetLibraryType
@ ASSET_LIBRARY_CUSTOM
@ ASSET_LIBRARY_ESSENTIALS
@ ASSET_LIBRARY_LOCAL
@ ASSET_LIBRARY_ALL
@ FILE_SORT_ASSET_CATALOG
eFileSelectType
@ FILE_ASSET_LIBRARY
@ FILE_MAIN_ASSET
@ FILE_ASSET_LIBRARY_ALL
@ FILE_TYPE_BLENDERLIB
@ SPACE_FILE
@ FILE_BROWSE_MODE_ASSETS
#define FILE_MAX_LIBEXTRA
#define FILE_SELECT_MAX_RECURSIONS
#define USER_DEVELOPER_TOOL_TEST(userdef, member)
void ED_fileselect_clear_main_assets(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1305
void ED_fileselect_clear(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1291
void ED_region_tag_refresh_ui(ARegion *region)
Definition area.cc:647
#define C
Definition RandGen.cpp:29
#define ND_ASSET_LIST_READING
Definition WM_types.hh:550
#define NC_ID
Definition WM_types.hh:395
#define NA_ADDED
Definition WM_types.hh:586
#define NA_EDITED
Definition WM_types.hh:584
#define ND_ASSET_LIST_PREVIEW
Definition WM_types.hh:549
#define NC_ASSET
Definition WM_types.hh:404
#define NA_REMOVED
Definition WM_types.hh:587
#define ND_ASSET_LIST
Definition WM_types.hh:548
#define NA_RENAME
Definition WM_types.hh:588
#define U
void clear()
Definition BLI_map.hh:1038
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
NonCopyable(const NonCopyable &other)=delete
static bool listen(const wmNotifier &notifier)
AssetList(AssetList &&other)=default
void remap_id(ID *id_old, ID *id_new) const
asset_system::AssetLibrary * asset_library() const
void fetch(const bContext &C)
void clear(wmWindowManager *wm)
void iterate(AssetListIterFn fn) const
void clear_current_file_assets(wmWindowManager *wm)
void ensure_blocking(const bContext &C)
FileListWrapper & operator=(FileListWrapper &&other)=default
FileListWrapper(eFileSelectType filesel_type)
Definition asset_list.cc:65
FileListWrapper(FileListWrapper &&other)=default
const FileIndexerType file_indexer_noop
void filelist_freelib(FileList *filelist)
Definition filelist.cc:1032
void filelist_tag_force_reset(FileList *filelist)
Definition filelist.cc:1135
void filelist_readjob_start(FileList *filelist, int space_notifier, const bContext *C)
Definition filelist.cc:3346
blender::asset_system::AssetLibrary * filelist_asset_library(FileList *filelist)
Definition filelist.cc:1027
bool filelist_needs_force_reset(const FileList *filelist)
Definition filelist.cc:1130
void filelist_readjob_blocking_run(FileList *filelist, int space_notifier, const bContext *C)
Definition filelist.cc:3351
void filelist_setrecursion(FileList *filelist, int recursion_level)
Definition filelist.cc:1122
void filelist_clear_from_reset_tag(FileList *filelist)
Definition filelist.cc:988
bool filelist_pending(const FileList *filelist)
Definition filelist.cc:1158
void filelist_setdir(FileList *filelist, char dirpath[1282])
void filelist_free(FileList *filelist)
Definition filelist.cc:1002
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
Definition filelist.cc:166
void filelist_setfilter_options(FileList *filelist, bool do_filter, bool hide_dot, bool hide_parent, uint64_t filter, uint64_t filter_id, bool filter_assets_only, const char *filter_glob, const char *filter_search)
void filelist_clear(FileList *filelist)
Definition filelist.cc:983
void filelist_tag_reload_asset_library(FileList *filelist)
Definition filelist.cc:1148
FileList * filelist_new(short type)
Definition filelist.cc:845
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition filelist.cc:3356
int filelist_needs_reading(const FileList *filelist)
Definition filelist.cc:1904
void filelist_setsorting(FileList *filelist, short sort, bool invert_sort)
void filelist_filter(FileList *filelist)
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition filelist.cc:1140
bool filelist_needs_reset_on_main_changes(const FileList *filelist)
Definition filelist.cc:1163
int filelist_files_ensure(FileList *filelist)
Definition filelist.cc:1168
void filelist_sort(FileList *filelist)
void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
Definition filelist.cc:118
bool filelist_is_ready(const FileList *filelist)
Definition filelist.cc:1153
blender::asset_system::AssetRepresentation * filelist_entry_get_asset_representation(const FileList *filelist, const int index)
Definition filelist.cc:1338
#define main()
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
AssetLibraryReference all_library_reference()
AssetLibraryReference current_file_library_reference()
const FileIndexerType file_indexer_asset
void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
void iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn)
int size(const AssetLibraryReference *library_reference)
void storage_id_remap(ID *id_old, ID *id_new)
bool has_asset_browser_storage_for_library(const AssetLibraryReference *library_reference, const bContext *C)
static void on_save_post(Main *main, PointerRNA **pointers, int num_pointers, void *arg)
static std::tuple< AssetList &, is_new_t > ensure_list_storage(const AssetLibraryReference &library_reference, eFileSelectType filesel_type)
asset_system::AssetLibrary * library_get_once_available(const AssetLibraryReference &library_reference)
void storage_fetch_blocking(const AssetLibraryReference &library_reference, const bContext &C)
void clear(const AssetLibraryReference *library_reference, const bContext *C)
bool listen(const wmNotifier *notifier)
static std::optional< eFileSelectType > asset_library_reference_to_fileselect_type(const AssetLibraryReference &library_reference)
void clear_all_library(const bContext *C)
bool has_list_storage_for_library(const AssetLibraryReference *library_reference)
bool is_loaded(const AssetLibraryReference *library_reference)
static AssetList * lookup_list(const AssetLibraryReference &library_ref)
Map< AssetLibraryReference, AssetList > AssetListMap
static void foreach_visible_asset_browser_showing_library(const AssetLibraryReference &library_reference, const wmWindowManager *wm, const FunctionRef< void(SpaceFile &sfile)> fn)
FunctionRef< bool(asset_system::AssetRepresentation &)> AssetListIterFn
static AssetListMap & libraries_map()
void asset_reading_region_listen_fn(const wmRegionListenerParams *params)
AssetLibraryReference asset_library_ref
Definition DNA_ID.h:414
FileAssetSelectParams * asset_params
ListBase areabase
unsigned int data
Definition WM_types.hh:358
unsigned int action
Definition WM_types.hh:358
unsigned int category
Definition WM_types.hh:358
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
bScreen * WM_window_get_active_screen(const wmWindow *win)