From 842310a9b0d70b48634e18e44775359bbd18ed4f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 1 Dec 2015 15:33:44 +0100 Subject: Outliner: add an option to "delete" libraries. Caminandes team request. In current master it's not possible to do this in a total clean way, so we are simply setting all user counts of given lib's datablocks to zero (similar to rna_ID_user_clear()'s doing). This is a bit crappy because it still lets datablocks floating around (with invalid user count values), and requires a save & reload cycle to be finalized. But for now it should be good enough. Propper implementation will be added to id-remap. --- .../blender/editors/space_outliner/outliner_edit.c | 97 ++++++++++++++++++++ .../editors/space_outliner/outliner_intern.h | 7 ++ .../blender/editors/space_outliner/outliner_ops.c | 2 + .../editors/space_outliner/outliner_tools.c | 100 +++++++++++++++++++-- 4 files changed, 201 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 6d420674f3e..094407b7bff 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -290,6 +290,103 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } +/* Library delete --------------------------------------------------- */ + +static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) +{ + Library *lib = (Library *)tselem->id; + ListBase *lbarray[MAX_LIBARRAY]; + int a; + + BLI_assert(te->idcode == ID_LI && lib != NULL); + UNUSED_VARS_NDEBUG(te); + + /* We simply set all ID from given lib (including lib itself) to zero user count. + * It is not possible to do a proper cleanup without a save/reload in current master. */ + a = set_listbasepointers(CTX_data_main(C), lbarray); + while (a--) { + ListBase *lb = lbarray[a]; + ID *id; + + for (id = lb->first; id; id = id->next) { + if (id->lib == lib) { + id_fake_user_clear(id); + id->us = 0; + } + } + } + + BKE_reportf(reports, RPT_WARNING, + "Please save and reload .blend file to complete deletion of '%s' library", + ((Library *)tselem->id)->filepath); +} + +void lib_delete_cb( + bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) +{ + lib_delete(C, te, tselem, CTX_wm_reports(C)); +} + +static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2]) +{ + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (te->idcode == ID_LI && tselem->id) { + if (((Library *)tselem->id)->parent) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, + "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath); + return OPERATOR_CANCELLED; + } + + lib_delete(C, te, tselem, reports); + return OPERATOR_FINISHED; + } + } + else { + for (te = te->subtree.first; te; te = te->next) { + int ret; + if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) { + return ret; + } + } + } + + return 0; +} + +static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + + BLI_assert(ar && soops); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + for (te = soops->tree.first; te; te = te->next) { + int ret; + + if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) { + return ret; + } + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_lib_delete(wmOperatorType *ot) +{ + ot->name = "Delete Library"; + ot->idname = "OUTLINER_OT_lib_delete"; + ot->description = "Delete the library under cursorn (needs a save/reload)"; + + ot->invoke = outliner_lib_delete_invoke; + ot->poll = ED_operator_outliner_active; +} + /* ************************************************************** */ /* Setting Toggling Operators */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f10e6be2fa9..262aa9b6209 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -176,6 +176,10 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem); +void lib_delete_cb( + struct bContext *C, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem); + TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); /* ...................................................... */ @@ -183,6 +187,8 @@ void OUTLINER_OT_item_activate(struct wmOperatorType *ot); void OUTLINER_OT_item_openclose(struct wmOperatorType *ot); void OUTLINER_OT_item_rename(struct wmOperatorType *ot); +void OUTLINER_OT_lib_delete(struct wmOperatorType *ot); + void OUTLINER_OT_show_one_level(struct wmOperatorType *ot); void OUTLINER_OT_show_active(struct wmOperatorType *ot); void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot); @@ -218,6 +224,7 @@ void OUTLINER_OT_operation(struct wmOperatorType *ot); void OUTLINER_OT_scene_operation(struct wmOperatorType *ot); void OUTLINER_OT_object_operation(struct wmOperatorType *ot); void OUTLINER_OT_group_operation(struct wmOperatorType *ot); +void OUTLINER_OT_lib_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_operation(struct wmOperatorType *ot); void OUTLINER_OT_data_operation(struct wmOperatorType *ot); void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 839d44df25d..9710c3fc36b 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -47,10 +47,12 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_select_border); WM_operatortype_append(OUTLINER_OT_item_openclose); WM_operatortype_append(OUTLINER_OT_item_rename); + WM_operatortype_append(OUTLINER_OT_lib_delete); WM_operatortype_append(OUTLINER_OT_operation); WM_operatortype_append(OUTLINER_OT_scene_operation); WM_operatortype_append(OUTLINER_OT_object_operation); WM_operatortype_append(OUTLINER_OT_group_operation); + WM_operatortype_append(OUTLINER_OT_lib_operation); WM_operatortype_append(OUTLINER_OT_id_operation); WM_operatortype_append(OUTLINER_OT_data_operation); WM_operatortype_append(OUTLINER_OT_animdata_operation); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 313a75f373a..dd0b29c9548 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -119,6 +119,7 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, case ID_MA: case ID_TE: case ID_IP: case ID_IM: case ID_SO: case ID_KE: case ID_WO: case ID_AC: case ID_NLA: case ID_TXT: case ID_GR: case ID_LS: + case ID_LI: if (*idlevel == 0) *idlevel = idcode; else if (*idlevel != idcode) *idlevel = -1; break; @@ -846,7 +847,7 @@ enum { OL_OP_TOGVIS, OL_OP_TOGSEL, OL_OP_TOGREN, - OL_OP_RENAME + OL_OP_RENAME, }; static EnumPropertyItem prop_object_op_types[] = { @@ -1246,6 +1247,88 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot) /* **************************************** */ +typedef enum eOutlinerLibOpTypes { + OL_LIB_INVALID = 0, + + OL_LIB_RENAME, + OL_LIB_DELETE, +} eOutlinerLibOpTypes; + +static EnumPropertyItem outliner_lib_op_type_items[] = { + {OL_LIB_RENAME, "RENAME", 0, "Rename", ""}, + {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"}, + {0, NULL, 0, NULL, NULL} + +}; + +static int outliner_lib_operation_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutlinerIdOpTypes event; + + /* check for invalid states */ + if (soops == NULL) + return OPERATOR_CANCELLED; + + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + event = RNA_enum_get(op->ptr, "type"); + + switch (event) { + case OL_LIB_RENAME: + { + /* rename */ + outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + ED_undo_push(C, "Rename"); + break; + } + case OL_LIB_DELETE: + { + /* delete */ + outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + /* Note: no undo possible here really, not 100% sure why... Probably because of library optimisations + * in undo/redo process? */ + /* ED_undo_push(C, "Rename"); */ + break; + } + default: + /* invalid - unhandled */ + break; + } + + /* wrong notifier still... */ + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + + /* XXX: this is just so that outliner is always up to date */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + return OPERATOR_FINISHED; +} + + +void OUTLINER_OT_lib_operation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Outliner Library Operation"; + ot->idname = "OUTLINER_OT_lib_operation"; + ot->description = ""; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_lib_operation_exec; + ot->poll = ED_operator_outliner_active; + + ot->prop = RNA_def_enum(ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", ""); +} + +/* **************************************** */ + static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *lb, ID *newid, void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *)) { @@ -1703,10 +1786,17 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S BKE_report(reports, RPT_WARNING, "Mixed selection"); } else { - if (idlevel == ID_GR) - WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); - else - WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); + switch (idlevel) { + case ID_GR: + WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); + break; + case ID_LI: + WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL); + break; + default: + WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); + break; + } } } else if (datalevel) { -- cgit v1.2.3