Fix T50369: Objects can't be deleted from scene when using "link group objects to scene"

Main issue here was that in old usercount system 'user_real' did simply
not allow that kind of thing to work. With new pait of 'USER_EXTRA'
tags, it becomes possible to handle the case correctly, by merely refining
checks about indirectly use objects whene removing them from a scene.

Incidently, found another related bug, 'link group objects to scene' was not
incrementing objects' usercount - bad, very very bad!
This commit is contained in:
Bastien Montagne 2017-01-04 10:25:27 +01:00
parent c0c48cdacc
commit 351a9d084f
Notes: blender-bot 2023-02-14 09:43:37 +01:00
Referenced by issue #50369, Objects can't be deleted from scene when using "link group objects to scene"
4 changed files with 15 additions and 7 deletions

View File

@ -883,9 +883,10 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
* Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
* removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
* fully unlinked.
* But only for local objects, not linked ones!
* Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
*/
if ((GS(id->name) == ID_OB) && (id->us == 1)) {
if ((GS(id->name) == ID_OB) && (id->us == 1) && (id->lib == NULL)) {
id_us_clear_real(id);
}

View File

@ -1111,7 +1111,9 @@ static void object_delete_check_glsl_update(Object *ob)
/* note: now unlinks constraints as well */
void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base)
{
if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
{
/* We cannot delete indirectly used object... */
printf("WARNING, undeletable object '%s', should have been catched before reaching this function!",
base->object->id.name + 2);
@ -1145,7 +1147,7 @@ static int object_delete_exec(bContext *C, wmOperator *op)
BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
continue;
}
else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
BKE_reportf(op->reports, RPT_WARNING,
"Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
base->object->id.name + 2, scene->id.name + 2);
@ -1179,7 +1181,7 @@ static int object_delete_exec(bContext *C, wmOperator *op)
if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) {
base_other = BKE_scene_base_find(scene_iter, base->object);
if (base_other) {
if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
BKE_reportf(op->reports, RPT_WARNING,
"Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
base->object->id.name + 2, scene_iter->id.name + 2);

View File

@ -411,7 +411,9 @@ static void object_delete_cb(
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
return;
}
else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
{
BKE_reportf(reports, RPT_WARNING,
"Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
base->object->id.name + 2, scene->id.name + 2);
@ -525,7 +527,7 @@ static void group_linkobs2scene_cb(
if (!base) {
/* link to scene */
base = BKE_scene_base_add(scene, gob->ob);
id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */
id_us_plus(&gob->ob->id);
}
base->object->flag |= SELECT;
base->flag |= SELECT;
@ -842,7 +844,9 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
return base_next;
}
else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
{
BKE_reportf(reports, RPT_WARNING,
"Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
base->object->id.name + 2, scene->id.name + 2);

View File

@ -277,6 +277,7 @@ typedef enum ID_Type {
#define ID_FAKE_USERS(id) ((((ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0)
#define ID_REAL_USERS(id) (((ID *)id)->us - ID_FAKE_USERS(id))
#define ID_EXTRA_USERS(id) (((ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0)
#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM))