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.
This commit is contained in:
parent
8512e284a0
commit
842310a9b0
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue