Fix T99462: Deleting Missing Libraries Crashes Blender.

Usual same issue with outliner operations, where you apply it on one
item, and then try to apply it again on same item listed somewhere else
in the tree...

Fixed by using the 'multi-tagged deletion' code we now have for IDs,
that way tree-walking function just tags IDs for deletion, and they all
get deleted at once at the end.
This commit is contained in:
Bastien Montagne 2022-07-06 10:53:22 +02:00
parent 26f721b516
commit 4b0e7fe511
Notes: blender-bot 2023-02-14 09:03:55 +01:00
Referenced by issue #99462, Deleting Missing Libraries Crashes Blender
3 changed files with 49 additions and 31 deletions

View File

@ -447,7 +447,7 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
/** \name ID Delete Operator
* \{ */
static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
static void id_delete_tag(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
Main *bmain = CTX_data_main(C);
ID *id = tselem->id;
@ -484,35 +484,39 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
return;
}
if (te->idcode == ID_WS) {
BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
if (id->tag & LIB_TAG_DOIT) {
BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_PRE_EXISTING);
if (id->tag & LIB_TAG_PRE_EXISTING) {
BKE_reportf(
reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
return;
}
BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
}
BKE_id_delete(bmain, id);
id->tag |= LIB_TAG_DOIT;
WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
void id_delete_fn(bContext *C,
ReportList *reports,
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
void *UNUSED(user_data))
void id_delete_tag_fn(bContext *C,
ReportList *reports,
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
id_delete(C, reports, te, tselem);
id_delete_tag(C, reports, te, tselem);
}
static int outliner_id_delete_invoke_do(bContext *C,
ReportList *reports,
TreeElement *te,
const float mval[2])
static int outliner_id_delete_tag(bContext *C,
ReportList *reports,
TreeElement *te,
const float mval[2])
{
int id_tagged_num = 0;
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
@ -522,26 +526,27 @@ static int outliner_id_delete_invoke_do(bContext *C,
RPT_ERROR_INVALID_INPUT,
"Cannot delete indirectly linked library '%s'",
((Library *)tselem->id)->filepath_abs);
return OPERATOR_CANCELLED;
}
id_delete(C, reports, te, tselem);
return OPERATOR_FINISHED;
else {
id_delete_tag(C, reports, te, tselem);
id_tagged_num++;
}
}
}
else {
LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
int ret;
if ((ret = outliner_id_delete_invoke_do(C, reports, te_sub, mval))) {
return ret;
if ((id_tagged_num += outliner_id_delete_tag(C, reports, te_sub, mval)) != 0) {
break;
}
}
}
return 0;
return id_tagged_num;
}
static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
ARegion *region = CTX_wm_region(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
float fmval[2];
@ -550,15 +555,21 @@ static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
int id_tagged_num = 0;
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
int ret;
if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) {
return ret;
if ((id_tagged_num += outliner_id_delete_tag(C, op->reports, te, fmval)) != 0) {
break;
}
}
if (id_tagged_num == 0) {
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
return OPERATOR_CANCELLED;
}
return OPERATOR_CANCELLED;
BKE_id_multi_tagged_delete(bmain);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
return OPERATOR_FINISHED;
}
void OUTLINER_OT_id_delete(wmOperatorType *ot)

View File

@ -437,7 +437,7 @@ void lib_reload_fn(struct bContext *C,
struct TreeStoreElem *tselem,
void *user_data);
void id_delete_fn(struct bContext *C,
void id_delete_tag_fn(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
struct TreeElement *te,

View File

@ -2185,6 +2185,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@ -2381,8 +2382,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_DELETE: {
if (idlevel > 0) {
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
outliner_do_libdata_operation(
C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
BKE_id_multi_tagged_delete(bmain);
ED_undo_push(C, "Delete");
}
break;
@ -2507,6 +2510,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = {
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
@ -2522,7 +2526,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_DELETE: {
outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
outliner_do_libdata_operation(
C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
BKE_id_multi_tagged_delete(bmain);
ED_undo_push(C, "Delete Library");
break;
}