Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2021-02-16 17:24:22 +0300
committerJulian Eisel <julian@blender.org>2021-02-16 17:34:32 +0300
commite81fca1ed38ea447a1023dae3841f8980def28e4 (patch)
treed0d07de23c839fa147850fdc728d512eb17a6141 /source/blender/windowmanager/intern
parent500bc99da5dbcdf7c728833326fc29babaf529e0 (diff)
Assets: Remove appended asset when dropping operation fails
When dropping an asset somewhere, it is appended and then a drop operation is called to actually add it to the scene based on current context. If this drop operation fails, the appended data-block is now still in the .blend. The user may not notice and not expect this. Instead idea is to rollback any changes done by dropping code if the operation fails, namely removing the appended data-block again. Adds a new `cancel()` callback which is called if the drop operator returns `OPERATOR_CANCELLED` to drop-boxes and a generic function to deal with assets on drop failure. Also removes the `free_id_on_error` property of the `NODE_OT_add_group` operator, which was used as ad-hoc solution to get this same behavior.
Diffstat (limited to 'source/blender/windowmanager/intern')
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c41
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c8
2 files changed, 47 insertions, 2 deletions
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 6fdcbab889c..9684c21605a 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
#include "GPU_shader.h"
#include "GPU_state.h"
@@ -95,11 +96,13 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
wmDropBox *WM_dropbox_add(ListBase *lb,
const char *idname,
bool (*poll)(bContext *, wmDrag *, const wmEvent *, const char **),
- void (*copy)(wmDrag *, wmDropBox *))
+ void (*copy)(wmDrag *, wmDropBox *),
+ void (*cancel)(struct Main *, wmDrag *, wmDropBox *))
{
wmDropBox *drop = MEM_callocN(sizeof(wmDropBox), "wmDropBox");
drop->poll = poll;
drop->copy = copy;
+ drop->cancel = cancel;
drop->ot = WM_operatortype_find(idname, 0);
drop->opcontext = WM_OP_INVOKE_DEFAULT;
@@ -382,6 +385,9 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
/**
* When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
* that depending on what was chosen by the drag-box (currently append only in fact).
+ *
+ * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
+ * import is rolled back if the drop operator fails.
*/
ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
{
@@ -402,6 +408,39 @@ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
return wm_drag_asset_id_import(asset_drag);
}
+/**
+ * \brief Free asset ID imported for cancelled drop.
+ *
+ * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()`
+ * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop
+ * operator cancels.
+ * This is for use as #wmDropBox.cancel() callback.
+ */
+void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *drop)
+{
+ if (drag->type != WM_DRAG_ASSET) {
+ return;
+ }
+
+ wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
+ if (!asset_drag) {
+ return;
+ }
+
+ /* Get name from property, not asset data - it may have changed after importing to ensure
+ * uniqueness (name is assumed to be set from the imported ID name). */
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(drop->ptr, "name", name);
+ if (!name[0]) {
+ return;
+ }
+
+ ID *id = BKE_libblock_find_name(bmain, asset_drag->id_type, name);
+ if (id) {
+ BKE_id_delete(bmain, id);
+ }
+}
+
/* ************** draw ***************** */
static void wm_drop_operator_draw(const char *name, int x, int y)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index e132caede0d..7b047e68aee 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2820,8 +2820,14 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
ListBase single_lb = {drag, drag};
event->customdata = &single_lb;
- wm_operator_call_internal(
+ int op_retval = wm_operator_call_internal(
C, drop->ot, drop->ptr, NULL, drop->opcontext, false, event);
+ OPERATOR_RETVAL_CHECK(op_retval);
+
+ if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) {
+ drop->cancel(CTX_data_main(C), drag, drop);
+ }
+
action |= WM_HANDLER_BREAK;
/* Free the drags. */