diff --git a/source/blender/editors/io/io_drop_import_file.cc b/source/blender/editors/io/io_drop_import_file.cc index a9e89109052..b5480bf2cfc 100644 --- a/source/blender/editors/io/io_drop_import_file.cc +++ b/source/blender/editors/io/io_drop_import_file.cc @@ -23,31 +23,10 @@ #include "UI_interface.hh" #include "io_drop_import_file.hh" +#include "io_utils.hh" static CLG_LogRef LOG = {"io.drop_import_file"}; -/** Returns the list of file paths stored in #WM_OT_drop_import_file operator properties. */ -static blender::Vector drop_import_file_paths(const wmOperator *op) -{ - blender::Vector result; - char dir[FILE_MAX], file[FILE_MAX]; - - RNA_string_get(op->ptr, "directory", dir); - - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "files"); - int files_len = RNA_property_collection_length(op->ptr, prop); - - for (int i = 0; i < files_len; i++) { - PointerRNA fileptr; - RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); - RNA_string_get(&fileptr, "name", file); - char file_path[FILE_MAX]; - BLI_path_join(file_path, sizeof(file_path), dir, file); - result.append(file_path); - } - return result; -} - /** * Return a vector of file handlers that support any file path in `paths` and the call to * `poll_drop` returns #true. Unlike `bke::file_handlers_poll_file_drop`, it ensures that file @@ -121,7 +100,7 @@ static PointerRNA file_handler_import_operator_create_ptr( static int wm_drop_import_file_exec(bContext *C, wmOperator *op) { - auto paths = drop_import_file_paths(op); + const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr); if (paths.is_empty()) { return OPERATOR_CANCELLED; } @@ -141,7 +120,7 @@ static int wm_drop_import_file_exec(bContext *C, wmOperator *op) static int wm_drop_import_file_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { - const auto paths = drop_import_file_paths(op); + const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr); if (paths.is_empty()) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/io/io_gpencil_import.cc b/source/blender/editors/io/io_gpencil_import.cc index 2cb59db23b2..a5bd481f0f5 100644 --- a/source/blender/editors/io/io_gpencil_import.cc +++ b/source/blender/editors/io/io_gpencil_import.cc @@ -100,29 +100,16 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op) /* Loop all selected files to import them. All SVG imported shared the same import * parameters, but they are created in separated grease pencil objects. */ - PropertyRNA *prop; - if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - char *directory = RNA_string_get_alloc(op->ptr, "directory", nullptr, 0, nullptr); - - if ((prop = RNA_struct_find_property(op->ptr, "files"))) { - char file_path[FILE_MAX]; - RNA_PROP_BEGIN (op->ptr, itemptr, prop) { - char *filename = RNA_string_get_alloc(&itemptr, "name", nullptr, 0, nullptr); - BLI_path_join(file_path, sizeof(file_path), directory, filename); - MEM_freeN(filename); - - /* Do Import. */ - WM_cursor_wait(true); - RNA_string_get(&itemptr, "name", params.filename); - const bool done = gpencil_io_import(file_path, ¶ms); - WM_cursor_wait(false); - if (!done) { - BKE_reportf(op->reports, RPT_WARNING, "Unable to import '%s'", file_path); - } - } - RNA_PROP_END; + const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr); + for (const auto &path : paths) { + /* Do Import. */ + WM_cursor_wait(true); + BLI_path_split_file_part(path.c_str(), params.filename, ARRAY_SIZE(params.filename)); + const bool done = gpencil_io_import(path.c_str(), ¶ms); + WM_cursor_wait(false); + if (!done) { + BKE_reportf(op->reports, RPT_WARNING, "Unable to import '%s'", path.c_str()); } - MEM_freeN(directory); } return OPERATOR_FINISHED; diff --git a/source/blender/editors/io/io_obj.cc b/source/blender/editors/io/io_obj.cc index 4742e5a5549..7fb310a5494 100644 --- a/source/blender/editors/io/io_obj.cc +++ b/source/blender/editors/io/io_obj.cc @@ -390,7 +390,6 @@ void WM_OT_obj_export(wmOperatorType *ot) static int wm_obj_import_exec(bContext *C, wmOperator *op) { OBJImportParams import_params{}; - RNA_string_get(op->ptr, "filepath", import_params.filepath); import_params.global_scale = RNA_float_get(op->ptr, "global_scale"); import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size"); import_params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis")); @@ -405,32 +404,18 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op) import_params.relative_paths = ((U.flag & USER_RELPATHS) != 0); import_params.clear_selection = true; - int files_len = RNA_collection_length(op->ptr, "files"); - if (files_len) { - /* Importing multiple files: loop over them and import one by one. */ - PointerRNA fileptr; - PropertyRNA *prop; - char dir_only[FILE_MAX], file_only[FILE_MAX]; + const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr); - RNA_string_get(op->ptr, "directory", dir_only); - prop = RNA_struct_find_property(op->ptr, "files"); - for (int i = 0; i < files_len; i++) { - RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); - RNA_string_get(&fileptr, "name", file_only); - BLI_path_join(import_params.filepath, sizeof(import_params.filepath), dir_only, file_only); - import_params.clear_selection = (i == 0); - OBJ_import(C, &import_params); - } - } - else if (RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) { - /* Importing one file. */ - RNA_string_get(op->ptr, "filepath", import_params.filepath); - OBJ_import(C, &import_params); - } - else { + if (paths.is_empty()) { BKE_report(op->reports, RPT_ERROR, "No filepath given"); return OPERATOR_CANCELLED; } + for (const auto &path : paths) { + STRNCPY(import_params.filepath, path.c_str()); + OBJ_import(C, &import_params); + /* Only first import clears selection. */ + import_params.clear_selection = false; + }; Scene *scene = CTX_data_scene(C); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/io/io_ply_ops.cc b/source/blender/editors/io/io_ply_ops.cc index c0b603b968d..646f54befec 100644 --- a/source/blender/editors/io/io_ply_ops.cc +++ b/source/blender/editors/io/io_ply_ops.cc @@ -251,30 +251,16 @@ static int wm_ply_import_exec(bContext *C, wmOperator *op) params.import_attributes = RNA_boolean_get(op->ptr, "import_attributes"); params.vertex_colors = ePLYVertexColorMode(RNA_enum_get(op->ptr, "import_colors")); - int files_len = RNA_collection_length(op->ptr, "files"); + const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr); - if (files_len) { - PointerRNA fileptr; - PropertyRNA *prop; - char dir_only[FILE_MAX], file_only[FILE_MAX]; - - RNA_string_get(op->ptr, "directory", dir_only); - prop = RNA_struct_find_property(op->ptr, "files"); - for (int i = 0; i < files_len; i++) { - RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); - RNA_string_get(&fileptr, "name", file_only); - BLI_path_join(params.filepath, sizeof(params.filepath), dir_only, file_only); - PLY_import(C, ¶ms, op); - } - } - else if (RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) { - RNA_string_get(op->ptr, "filepath", params.filepath); - PLY_import(C, ¶ms, op); - } - else { + if (paths.is_empty()) { BKE_report(op->reports, RPT_ERROR, "No filepath given"); return OPERATOR_CANCELLED; } + for (const auto &path : paths) { + STRNCPY(params.filepath, path.c_str()); + PLY_import(C, ¶ms, op); + }; Scene *scene = CTX_data_scene(C); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/io/io_stl_ops.cc b/source/blender/editors/io/io_stl_ops.cc index 6c9a1f11de9..76258d555ae 100644 --- a/source/blender/editors/io/io_stl_ops.cc +++ b/source/blender/editors/io/io_stl_ops.cc @@ -189,30 +189,16 @@ static int wm_stl_import_exec(bContext *C, wmOperator *op) params.global_scale = RNA_float_get(op->ptr, "global_scale"); params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate"); - int files_len = RNA_collection_length(op->ptr, "files"); + const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr); - if (files_len) { - PointerRNA fileptr; - PropertyRNA *prop; - char dir_only[FILE_MAX], file_only[FILE_MAX]; - - RNA_string_get(op->ptr, "directory", dir_only); - prop = RNA_struct_find_property(op->ptr, "files"); - for (int i = 0; i < files_len; i++) { - RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); - RNA_string_get(&fileptr, "name", file_only); - BLI_path_join(params.filepath, sizeof(params.filepath), dir_only, file_only); - STL_import(C, ¶ms); - } - } - else if (RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) { - RNA_string_get(op->ptr, "filepath", params.filepath); - STL_import(C, ¶ms); - } - else { + if (paths.is_empty()) { BKE_report(op->reports, RPT_ERROR, "No filepath given"); return OPERATOR_CANCELLED; } + for (const auto &path : paths) { + STRNCPY(params.filepath, path.c_str()); + STL_import(C, ¶ms); + } Scene *scene = CTX_data_scene(C); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/io/io_utils.cc b/source/blender/editors/io/io_utils.cc index 599dc78d055..28f540a84f3 100644 --- a/source/blender/editors/io/io_utils.cc +++ b/source/blender/editors/io/io_utils.cc @@ -2,6 +2,8 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_path_util.h" + #include "BKE_context.hh" #include "DNA_space_types.h" @@ -9,6 +11,7 @@ #include "ED_fileselect.hh" #include "RNA_access.hh" +#include "RNA_prototypes.h" #include "WM_api.hh" @@ -47,4 +50,35 @@ bool poll_file_object_drop(const bContext *C, blender::bke::FileHandlerType * /* } return false; } + +Vector paths_from_operator_properties(PointerRNA *ptr) +{ + Vector paths; + PropertyRNA *directory_prop = RNA_struct_find_property(ptr, "directory"); + if (RNA_property_is_set(ptr, directory_prop)) { + char directory[FILE_MAX], name[FILE_MAX]; + + RNA_string_get(ptr, "directory", directory); + + PropertyRNA *files_prop = RNA_struct_find_collection_property_check( + *ptr, "files", &RNA_OperatorFileListElement); + + BLI_assert(files_prop); + + RNA_PROP_BEGIN (ptr, file_ptr, files_prop) { + RNA_string_get(&file_ptr, "name", name); + char path[FILE_MAX]; + BLI_path_join(path, sizeof(path), directory, name); + paths.append_non_duplicates(path); + } + RNA_PROP_END; + } + PropertyRNA *filepath_prop = RNA_struct_find_property(ptr, "filepath"); + if (filepath_prop && RNA_property_is_set(ptr, filepath_prop)) { + char filepath[FILE_MAX]; + RNA_string_get(ptr, "filepath", filepath); + paths.append_non_duplicates(filepath); + } + return paths; +} } // namespace blender::ed::io diff --git a/source/blender/editors/io/io_utils.hh b/source/blender/editors/io/io_utils.hh index 911a4c9d07a..7a1235d774a 100644 --- a/source/blender/editors/io/io_utils.hh +++ b/source/blender/editors/io/io_utils.hh @@ -6,6 +6,8 @@ #include "WM_types.hh" +#include "BLI_vector.hh" + struct wmOperator; struct wmOperatorType; struct wmDrag; @@ -23,4 +25,12 @@ namespace blender::ed::io { int filesel_drop_import_invoke(bContext *C, wmOperator *op, const wmEvent *event); bool poll_file_object_drop(const bContext *C, blender::bke::FileHandlerType *fh); + +/** + * Return all paths stored in the pointer. + * Properties in pointer should include a `directory` #PropertySubType::PROP_FILEPATH property and + * a `files` #RNA_OperatorFileListElement collection property. + * If the pointer has a `filepath` property is also returned as fallback. + */ +Vector paths_from_operator_properties(PointerRNA *ptr); } // namespace blender::ed::io