Blender V5.0
io_drop_import_file.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
5#include "BLI_path_utils.hh"
6#include "BLI_string.h"
7
8#include "BLT_translation.hh"
9
10#include "BKE_file_handler.hh"
11
12#include "CLG_log.h"
13
14#include "DNA_space_types.h"
15
16#include "RNA_access.hh"
17#include "RNA_define.hh"
18#include "RNA_prototypes.hh"
19
20#include "WM_api.hh"
21#include "WM_types.hh"
22
23#include "UI_interface.hh"
25
27#include "io_utils.hh"
28
29static CLG_LogRef LOG = {"io.drop_import_file"};
30
37 const bContext *C, const blender::Span<std::string> paths, const bool quiet = true)
38{
39 using namespace blender;
40 auto file_handlers = bke::file_handlers_poll_file_drop(C, paths);
41 file_handlers.remove_if([quiet](const bke::FileHandlerType *file_handler) {
42 return WM_operatortype_find(file_handler->import_operator, quiet) == nullptr;
43 });
44 return file_handlers;
45}
46
51 const blender::bke::FileHandlerType *file_handler,
52 PointerRNA &props,
54{
55
56 const auto supported_paths = file_handler->filter_supported_paths(paths);
57
58 PropertyRNA *filepath_prop = RNA_struct_find_property_check(props, "filepath", PROP_STRING);
59 if (filepath_prop) {
60 RNA_property_string_set(&props, filepath_prop, paths[supported_paths[0]].c_str());
61 }
62
63 PropertyRNA *directory_prop = RNA_struct_find_property_check(props, "directory", PROP_STRING);
64 char dir[FILE_MAX];
65 BLI_path_split_dir_part(paths[0].c_str(), dir, sizeof(dir));
66 if (directory_prop) {
67 RNA_property_string_set(&props, directory_prop, dir);
68 }
69
71 props, "files", &RNA_OperatorFileListElement);
72 if (files_prop) {
73 RNA_property_collection_clear(&props, files_prop);
74 for (const auto &index : supported_paths) {
75 char file[FILE_MAX];
76 STRNCPY(file, paths[index].c_str());
77 BLI_path_rel(file, dir);
78
79 PointerRNA item_ptr{};
80 RNA_property_collection_add(&props, files_prop, &item_ptr);
81 BLI_assert_msg(BLI_path_is_rel(file), "Expected path to be relative (start with '//')");
82 RNA_string_set(&item_ptr, "name", file + 2);
83 }
84 }
85 const bool has_any_filepath_prop = filepath_prop || directory_prop || files_prop;
86 if (!has_any_filepath_prop) {
88 "The '%s' file handler import operator ('%s') is missing the required operator "
89 "properties.",
90 file_handler->idname,
91 file_handler->import_operator);
92 }
93 if (directory_prop && !files_prop) {
95 &LOG,
96 "The '%s' file handler import operator ('%s') is missing the 'files' operator property.",
97 file_handler->idname,
98 file_handler->import_operator);
99 }
100 if (!directory_prop && files_prop) {
101 CLOG_WARN(&LOG,
102 "The '%s' file handler import operator ('%s') is missing the 'directory' operator "
103 "property.",
104 file_handler->idname,
105 file_handler->import_operator);
106 }
107}
108
110{
112 if (paths.is_empty()) {
113 return OPERATOR_CANCELLED;
114 }
115
116 auto file_handlers = drop_import_file_poll_file_handlers(C, paths, false);
117 if (file_handlers.is_empty()) {
118 return OPERATOR_CANCELLED;
119 }
120
121 wmOperatorType *ot = WM_operatortype_find(file_handlers[0]->import_operator, false);
122 PointerRNA file_props;
124 file_handler_import_operator_write_ptr(file_handlers[0], file_props, paths);
125
127 C, ot, blender::wm::OpCallContext::InvokeDefault, &file_props, nullptr);
128 WM_operator_properties_free(&file_props);
129 return OPERATOR_FINISHED;
130}
131
133 wmOperator *op,
134 const wmEvent * /*event*/)
135{
137 if (paths.is_empty()) {
138 return OPERATOR_CANCELLED;
139 }
140
141 auto file_handlers = drop_import_file_poll_file_handlers(C, paths, false);
142 if (file_handlers.size() == 1) {
143 return wm_drop_import_file_exec(C, op);
144 }
145
150 uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
151 uiLayout *layout = UI_popup_menu_layout(pup);
153
154 for (auto *file_handler : file_handlers) {
155 wmOperatorType *ot = WM_operatortype_find(file_handler->import_operator, false);
156 PointerRNA file_props = layout->op(ot,
157 CTX_TIP_(ot->translation_context, ot->name),
158 ICON_NONE,
161 file_handler_import_operator_write_ptr(file_handler, file_props, paths);
162 }
163
164 UI_popup_menu_end(C, pup);
165 return OPERATOR_INTERFACE;
166}
167
169{
170 ot->name = "Drop to Import File";
171 ot->description = "Operator that allows file handlers to receive file drops";
172 ot->idname = "WM_OT_drop_import_file";
173 ot->flag = OPTYPE_INTERNAL;
176
177 PropertyRNA *prop;
178
180 ot->srna, "directory", nullptr, FILE_MAX, "Directory", "Directory of the file");
182
183 prop = RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
185}
186
191
192static bool drop_import_file_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
193{
194 if (drag->type != WM_DRAG_PATH) {
195 return false;
196 }
197 const auto paths = WM_drag_get_paths(drag);
198 return !drop_import_file_poll_file_handlers(C, paths, true).is_empty();
199}
200
202 wmDrag *drag,
203 const int /*xy*/[2],
204 wmDropBox * /*drop*/)
205{
206 const auto paths = WM_drag_get_paths(drag);
207 const auto file_handlers = drop_import_file_poll_file_handlers(C, paths, true);
208 if (file_handlers.size() == 1) {
209 wmOperatorType *ot = WM_operatortype_find(file_handlers[0]->import_operator, false);
210 return TIP_(ot->name);
211 }
212
213 return TIP_("Multiple file handlers can be used, drop to pick which to use");
214}
215
217{
220 "WM_OT_drop_import_file",
223 nullptr,
225}
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define FILE_MAX
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define TIP_(msgid)
#define CTX_TIP_(context, msgid)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
@ RGN_TYPE_WINDOW
@ SPACE_EMPTY
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ PROP_STRING
Definition RNA_types.hh:165
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
#define UI_ITEM_NONE
@ WM_DRAG_PATH
Definition WM_types.hh:1208
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
static wmOperatorStatus wm_drop_import_file_invoke(bContext *C, wmOperator *op, const wmEvent *)
static blender::Vector< blender::bke::FileHandlerType * > drop_import_file_poll_file_handlers(const bContext *C, const blender::Span< std::string > paths, const bool quiet=true)
static std::string drop_import_file_tooltip(bContext *C, wmDrag *drag, const int[2], wmDropBox *)
static void file_handler_import_operator_write_ptr(const blender::bke::FileHandlerType *file_handler, PointerRNA &props, const blender::Span< std::string > paths)
static wmOperatorStatus wm_drop_import_file_exec(bContext *C, wmOperator *op)
void WM_OT_drop_import_file(wmOperatorType *ot)
static void drop_import_file_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static bool drop_import_file_poll(bContext *C, wmDrag *drag, const wmEvent *)
void ED_dropbox_drop_import_file()
#define LOG(level)
Definition log.h:97
blender::Vector< FileHandlerType * > file_handlers_poll_file_drop(const bContext *C, const blender::Span< std::string > paths)
Vector< std::string > paths_from_operator_properties(PointerRNA *ptr)
Definition io_utils.cc:75
void paths_to_operator_properties(PointerRNA *ptr, const Span< std::string > paths)
Definition io_utils.cc:117
PropertyRNA * RNA_struct_find_collection_property_check(PointerRNA &props, const char *name, const StructRNA *struct_type_check)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property_check(PointerRNA &props, const char *name, const PropertyType property_type_check)
void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr)
void RNA_property_collection_clear(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_string_dir_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
char import_operator[OP_MAX_TYPENAME]
blender::Vector< int64_t > filter_supported_paths(const blender::Span< std::string > paths) const
void operator_context_set(blender::wm::OpCallContext opcontext)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
eWM_DragDataType type
Definition WM_types.hh:1331
PointerRNA * ptr
Definition WM_types.hh:1420
struct PointerRNA * ptr
wmDropBox * WM_dropbox_add(ListBase *lb, const char *idname, bool(*poll)(bContext *C, wmDrag *drag, const wmEvent *event), void(*copy)(bContext *C, wmDrag *drag, wmDropBox *drop), void(*cancel)(Main *bmain, wmDrag *drag, wmDropBox *drop), WMDropboxTooltipFunc tooltip)
blender::Span< std::string > WM_drag_get_paths(const wmDrag *drag)
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
wmOperatorType * ot
Definition wm_files.cc:4237
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)