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:
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
|
@ -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(®ion->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
|
||||
* \{ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue