Outliner: Remove the 'Remap data-block usages' operation.

This feature is very advanced, and the way it was exposed in the
Outliner was very confusing at best.

It remains available through the Python API (`ID.user_remap`) e.g.
This commit is contained in:
Bastien Montagne 2022-05-11 11:23:24 +02:00
parent 2d9a6e4f68
commit 30534deced
Notes: blender-bot 2023-05-26 09:41:56 +02:00
Referenced by commit 8c9805fc62, Revert "Outliner: Remove the 'Remap data-block usages' operation."
Referenced by issue #98069, 3.3.0 alpha, missing Remap Users menu
Referenced by issue #108285, Remap Users operator doesn't work on Objects
4 changed files with 0 additions and 217 deletions

View File

@ -575,187 +575,6 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name ID Remap Operator
* \{ */
static int outliner_id_remap_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
ID *old_id = reinterpret_cast<ID *>(
BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
ID *new_id = reinterpret_cast<ID *>(
BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
/* check for invalid states */
if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
BKE_reportf(op->reports,
RPT_ERROR_INVALID_INPUT,
"Invalid old/new ID pair ('%s' / '%s')",
old_id ? old_id->name : "Invalid ID",
new_id ? new_id->name : "Invalid ID");
return OPERATOR_CANCELLED;
}
if (ID_IS_LINKED(old_id)) {
BKE_reportf(op->reports,
RPT_WARNING,
"Old ID '%s' is linked from a library, indirect usages of this data-block will "
"not be remapped",
old_id->name);
}
BKE_libblock_remap(
bmain, old_id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
BKE_main_lib_objects_recalc_all(bmain);
/* recreate dependency graph to include new objects */
DEG_relations_tag_update(bmain);
/* Free gpu materials, some materials depend on existing objects,
* such as lights so freeing correctly refreshes. */
GPU_materials_free(bmain);
WM_event_add_notifier(C, NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
static bool outliner_id_remap_find_tree_element(bContext *C,
wmOperator *op,
ListBase *tree,
const float y)
{
LISTBASE_FOREACH (TreeElement *, te, tree) {
if (y > te->ys && y < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
if ((tselem->type == TSE_SOME_ID) && tselem->id) {
RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
return true;
}
}
if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
return true;
}
}
return false;
}
static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
ARegion *region = CTX_wm_region(C);
float fmval[2];
if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
}
return WM_operator_props_dialog_popup(C, op, 400);
}
static const EnumPropertyItem *outliner_id_itemf(bContext *C,
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
if (C == nullptr) {
return DummyRNA_NULL_items;
}
EnumPropertyItem item_tmp = {0}, *item = nullptr;
int totitem = 0;
int i = 0;
short id_type = (short)RNA_enum_get(ptr, "id_type");
ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
for (; id; id = reinterpret_cast<ID *>(id->next)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
void OUTLINER_OT_id_remap(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Outliner ID Data Remap";
ot->idname = "OUTLINER_OT_id_remap";
/* callbacks */
ot->invoke = outliner_id_remap_invoke;
ot->exec = outliner_id_remap_exec;
ot->poll = ED_operator_outliner_active;
/* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
/* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
*/
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN));
ot->prop = RNA_def_enum(ot->srna,
"new_id",
DummyRNA_NULL_items,
0,
"New ID",
"New ID to remap all selected IDs' users to");
RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf);
RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
}
void id_remap_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
PointerRNA op_props;
BLI_assert(tselem->id != nullptr);
WM_operator_properties_create_ptr(&op_props, ot);
RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
WM_operator_properties_free(&op_props);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name ID Copy Operator
* \{ */

View File

@ -442,13 +442,6 @@ void id_delete_fn(struct bContext *C,
struct TreeStoreElem *tsep,
struct TreeStoreElem *tselem,
void *user_data);
void id_remap_fn(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
struct TreeElement *te,
struct TreeStoreElem *tsep,
struct TreeStoreElem *tselem,
void *user_data);
/**
* To retrieve coordinates with redrawing the entire tree.
@ -523,7 +516,6 @@ void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
void OUTLINER_OT_id_copy(struct wmOperatorType *ot);
void OUTLINER_OT_id_paste(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);

View File

@ -31,7 +31,6 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_lib_relocate);
WM_operatortype_append(OUTLINER_OT_id_operation);
WM_operatortype_append(OUTLINER_OT_id_delete);
WM_operatortype_append(OUTLINER_OT_id_remap);
WM_operatortype_append(OUTLINER_OT_id_copy);
WM_operatortype_append(OUTLINER_OT_id_paste);
WM_operatortype_append(OUTLINER_OT_data_operation);

View File

@ -1692,7 +1692,6 @@ enum {
OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
OL_OP_REMAP,
OL_OP_RENAME,
};
@ -1700,11 +1699,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_REMAP,
"REMAP",
0,
"Remap Users",
"Make all users of selected data-blocks to use instead a new chosen one"},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
{0, nullptr, 0, nullptr, nullptr},
};
@ -1759,12 +1753,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Deselect Objects";
selection_changed = true;
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(
C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
else if (event == OL_OP_RENAME) {
outliner_do_object_operation(
C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
@ -1973,7 +1961,6 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
OUTLINER_IDOP_REMAP,
OUTLINER_IDOP_COPY,
OUTLINER_IDOP_PASTE,
@ -1991,11 +1978,6 @@ static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""},
{OUTLINER_IDOP_REMAP,
"REMAP",
0,
"Remap Users",
"Make all users of selected data-blocks to use instead current (clicked) one"},
{0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
@ -2414,15 +2396,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
break;
}
case OUTLINER_IDOP_REMAP: {
if (idlevel > 0) {
outliner_do_libdata_operation(
C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
break;
}
case OUTLINER_IDOP_COPY: {
wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);