From aecf6dd1db70e30da1d5fe79bed19754e4f06e63 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 24 Jul 2023 14:53:33 +0200 Subject: [PATCH] File Browser: Add proper warning when trying to list content of invalid library. In case a blend file opening fails (in the context of library content listing, e.g. for linking or appending), the File Browser would just show an emtpy window. With the new comnpatibility policy, this will now become a fairly common situation, which requires giving proper explanations to the user. This commit re-uses and extends the system used to display errors messages from the Asset browser. Part of #109151 (PR !110109). --- .../blender/editors/space_file/file_draw.cc | 125 +++++++++++++++--- .../blender/editors/space_file/file_intern.h | 7 + source/blender/editors/space_file/filelist.cc | 5 + source/blender/editors/space_file/filelist.h | 4 + .../blender/editors/space_file/space_file.cc | 9 ++ 5 files changed, 133 insertions(+), 17 deletions(-) diff --git a/source/blender/editors/space_file/file_draw.cc b/source/blender/editors/space_file/file_draw.cc index 80ab76a11c7..e6c53bf8b98 100644 --- a/source/blender/editors/space_file/file_draw.cc +++ b/source/blender/editors/space_file/file_draw.cc @@ -26,6 +26,7 @@ #include "BKE_blendfile.h" #include "BKE_context.h" +#include "BKE_report.h" #include "BLT_translation.h" @@ -1177,12 +1178,11 @@ void file_draw_list(const bContext *C, ARegion *region) layout->curr_size = params->thumbnail_size; } -static void file_draw_invalid_library_hint(const bContext *C, - const SpaceFile *sfile, - ARegion *region) +static void file_draw_invalid_asset_library_hint(const bContext *C, + const SpaceFile *sfile, + ARegion *region, + FileAssetSelectParams *asset_params) { - const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); - char library_ui_path[PATH_MAX]; file_path_to_ui_path(asset_params->base_params.dir, library_ui_path, sizeof(library_ui_path)); @@ -1237,21 +1237,112 @@ static void file_draw_invalid_library_hint(const bContext *C, } } +static void file_draw_invalid_library_hint(const bContext * /*C*/, + const SpaceFile *sfile, + ARegion *region, + const char *blendfile_path, + ReportList *reports) +{ + uchar text_col[4]; + UI_GetThemeColor4ubv(TH_TEXT, text_col); + + const View2D *v2d = ®ion->v2d; + const int pad = sfile->layout->tile_border_x; + const int width = BLI_rctf_size_x(&v2d->tot) - (2 * pad); + const int line_height = sfile->layout->textheight; + int sx = v2d->tot.xmin + pad; + /* For some reason no padding needed. */ + int sy = v2d->tot.ymax; + + { + const char *message = TIP_("Unreadable Blender library file:"); + file_draw_string_multiline(sx, sy, message, width, line_height, text_col, nullptr, &sy); + + sy -= line_height; + file_draw_string(sx, sy, blendfile_path, width, line_height, UI_STYLE_TEXT_LEFT, text_col); + } + + /* Separate a bit further. */ + sy -= line_height * 2.2f; + + LISTBASE_FOREACH (Report *, report, &reports->list) { + const short report_type = report->type; + if (report_type <= RPT_INFO) { + continue; + } + + int icon = ICON_INFO; + if (report_type > RPT_WARNING) { + icon = ICON_ERROR; + } + UI_icon_draw(sx, sy - UI_UNIT_Y, icon); + + file_draw_string_multiline(sx + UI_UNIT_X, + sy, + TIP_(report->message), + width - UI_UNIT_X, + line_height, + text_col, + nullptr, + &sy); + sy -= line_height; + } +} + bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region) { - FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); - /* Only for asset browser. */ - if (!ED_fileselect_is_asset_browser(sfile)) { - return false; - } - /* Check if the library exists. */ - if ((asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) || - filelist_is_dir(sfile->files, asset_params->base_params.dir)) - { - return false; + char blendfile_path[FILE_MAX_LIBEXTRA]; + const bool is_asset_browser = ED_fileselect_is_asset_browser(sfile); + const bool is_library_browser = !is_asset_browser && + filelist_islibrary(sfile->files, blendfile_path, nullptr); + + if (is_asset_browser) { + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + + /* Check if the asset library exists. */ + if (!((asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) || + filelist_is_dir(sfile->files, asset_params->base_params.dir))) + { + file_draw_invalid_asset_library_hint(C, sfile, region, asset_params); + return true; + } } - file_draw_invalid_library_hint(C, sfile, region); + /* Check if the blendfile library is valid (has entries). */ + if (is_library_browser) { + if (!filelist_is_ready(sfile->files)) { + return false; + } - return true; + const int numfiles = filelist_files_num_entries(sfile->files); + if (numfiles > 0) { + return false; + } + + /* This could all be part of the file-list loading: + * - When loading fails this could be saved in the file-list, e.g. when + * `BLO_blendhandle_from_file()` returns null in `filelist_readjob_list_lib()`, a + * `FL_HAS_INVALID_LIBRARY` file-list flag could be set. + * - Reports from it could also be stored in `FileList` rather than being ignored + * (`RPT_STORE` must be set!). + * - Then we could just check for `is_library_browser` and the `FL_HAS_INVALID_LIBRARY` flag + * here, and draw the hint with the reports in the file-list. (We would not draw a hint for + * recursive loading, even if the file-list has the "has invalid library" flag set, which + * seems like the wanted behavior.) + * - The call to BKE_blendfile_is_readable() would not be needed then. + */ + if (!sfile->runtime->is_blendfile_status_set) { + BKE_reports_clear(&sfile->runtime->is_blendfile_readable_reports); + sfile->runtime->is_blendfile_readable = BKE_blendfile_is_readable( + blendfile_path, &sfile->runtime->is_blendfile_readable_reports); + sfile->runtime->is_blendfile_status_set = true; + } + if (!sfile->runtime->is_blendfile_readable) { + file_draw_invalid_library_hint( + C, sfile, region, blendfile_path, &sfile->runtime->is_blendfile_readable_reports); + return true; + } + } + + return false; } diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 7c7b339d5a3..a9353bb0797 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -9,6 +9,7 @@ #pragma once #include "DNA_space_types.h" +#include "DNA_windowmanager_types.h" #ifdef __cplusplus extern "C" { @@ -180,6 +181,12 @@ typedef struct SpaceFile_Runtime { * Use file_on_reload_callback_register() to register a callback. */ onReloadFn on_reload; onReloadFnData on_reload_custom_data; + + /* Indicates, if the current filepath is a blendfile library one, if its status has been checked, + * and if it is readable. */ + bool is_blendfile_status_set; + bool is_blendfile_readable; + ReportList is_blendfile_readable_reports; } SpaceFile_Runtime; /** diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc index 9fb94c518f8..2814574604e 100644 --- a/source/blender/editors/space_file/filelist.cc +++ b/source/blender/editors/space_file/filelist.cc @@ -1961,6 +1961,11 @@ BlendHandle *filelist_lib(FileList *filelist) return filelist->libfiledata; } +int filelist_files_num_entries(FileList *filelist) +{ + return filelist->filelist.entries_num; +} + static const char *fileentry_uiname(const char *root, FileListInternEntry *entry, char *buff) { if (entry->asset) { diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 56a9e3445d9..3b263e89035 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -206,6 +206,10 @@ struct BlendHandle *filelist_lib(struct FileList *filelist); bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group); void filelist_freelib(struct FileList *filelist); +/** Return the total raw number of entries listed in the given `filelist`, whether they are + * filtered out or not. */ +int filelist_files_num_entries(struct FileList *filelist); + void filelist_readjob_start(struct FileList *filelist, int space_notifier, const struct bContext *C); diff --git a/source/blender/editors/space_file/space_file.cc b/source/blender/editors/space_file/space_file.cc index a3e07776129..c057779bebc 100644 --- a/source/blender/editors/space_file/space_file.cc +++ b/source/blender/editors/space_file/space_file.cc @@ -20,6 +20,7 @@ #include "BKE_global.h" #include "BKE_lib_remap.h" #include "BKE_main.h" +#include "BKE_report.h" #include "BKE_screen.h" #include "RNA_access.h" @@ -126,6 +127,9 @@ static void file_free(SpaceLink *sl) MEM_SAFE_FREE(sfile->params); MEM_SAFE_FREE(sfile->asset_params); + if (sfile->runtime != nullptr) { + BKE_reports_clear(&sfile->runtime->is_blendfile_readable_reports); + } MEM_SAFE_FREE(sfile->runtime); MEM_SAFE_FREE(sfile->layout); @@ -143,6 +147,7 @@ static void file_init(wmWindowManager * /*wm*/, ScrArea *area) if (sfile->runtime == nullptr) { sfile->runtime = static_cast( MEM_callocN(sizeof(*sfile->runtime), __func__)); + BKE_reports_init(&sfile->runtime->is_blendfile_readable_reports, RPT_STORE); } /* Validate the params right after file read. */ fileselect_refresh_params(sfile); @@ -206,6 +211,10 @@ static void file_refresh(const bContext *C, ScrArea *area) fileselect_refresh_params(sfile); folder_history_list_ensure_for_active_browse_mode(sfile); + if (sfile->runtime != nullptr) { + sfile->runtime->is_blendfile_status_set = false; + } + if (sfile->files && (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES) && filelist_needs_reset_on_main_changes(sfile->files)) {