Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2016-06-22 19:05:55 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-06-22 19:05:55 +0300
commit7547c6a250cd6f36c9894605b822380a1261febf (patch)
tree1b68ea4b2ac56927a212f10cd5d491a581e366c0 /source/blender/editors/space_outliner
parentfb1f7fad78e4a0a1220c7472e1332043b2ee0f85 (diff)
ID-Remap, step two: add some user-level tools.
This commit adds operators and Outliner menu entries to reload or relocate a library, and to delete or replace a datablock. RNA ID API is also extended to allow ID deletion and remapping from python. Review task: D2027 (https://developer.blender.org/D2027). Reviewed by campbellbarton, thanks a bunch.
Diffstat (limited to 'source/blender/editors/space_outliner')
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c368
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h15
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c71
4 files changed, 405 insertions, 53 deletions
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 8cee696b2ac..687869ae727 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -29,17 +29,23 @@
* \ingroup spoutliner
*/
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_group_types.h"
+#include "DNA_ID.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_material_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "BLI_mempool.h"
+#include "BLI_stack.h"
+#include "BLI_string.h"
#include "BLT_translation.h"
@@ -47,7 +53,9 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
@@ -55,6 +63,8 @@
#include "BKE_material.h"
#include "BKE_group.h"
+#include "../blenloader/BLO_readfile.h"
+
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -70,6 +80,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "GPU_material.h"
#include "outliner_intern.h"
@@ -291,64 +304,294 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* Library delete --------------------------------------------------- */
+/* ID delete --------------------------------------------------- */
-static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
+static void id_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
- Library *lib = (Library *)tselem->id;
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
+ Main *bmain = CTX_data_main(C);
+ ID *id = tselem->id;
- BLI_assert(te->idcode == ID_LI && lib != NULL);
+ BLI_assert(te->idcode != 0 && id != NULL);
+ BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == 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_libblock_delete(bmain, id);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+}
+
+void id_delete_cb(
+ bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem,
+ void *UNUSED(user_data))
+{
+ id_delete(C, te, tselem);
+}
+
+static int outliner_id_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 != 0 && tselem->id) {
+ if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ return OPERATOR_CANCELLED;
+ }
+ id_delete(C, te, tselem);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ for (te = te->subtree.first; te; te = te->next) {
+ int ret;
+ if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) {
+ return ret;
}
}
}
- BKE_reportf(reports, RPT_WARNING,
- "Please save and reload .blend file to complete deletion of '%s' library",
- ((Library *)tselem->id)->filepath);
+ return 0;
}
-void lib_delete_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *te,
+static int outliner_id_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_id_delete_invoke_do(C, op->reports, te, fmval))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_id_delete(wmOperatorType *ot)
+{
+ ot->name = "Delete Datablock";
+ ot->idname = "OUTLINER_OT_id_delete";
+ ot->description = "Delete the ID under cursor";
+
+ ot->invoke = outliner_id_delete_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* ID remap --------------------------------------------------- */
+
+static int outliner_id_remap_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
+ ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id"));
+ ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"));
+
+ /* check for invalid states */
+ if (soops == NULL)
+ return OPERATOR_CANCELLED;
+
+ if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ return OPERATOR_CANCELLED;
+ }
+
+ 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 */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y)
+{
+ TreeElement *te;
+
+ for (te = tree->first; te; te = te->next) {
+ if (y > te->ys && y < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->type == 0 && tselem->id) {
+ printf("found id %s (%p)!\n", tselem->id->name, 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)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = 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(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]);
+ }
+
+ return WM_operator_props_dialog_popup(C, op, 200, 100);
+}
+
+static EnumPropertyItem *outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem item_tmp = {0}, *item = NULL;
+ int totitem = 0;
+ int i = 0;
+
+ short id_type = (short)RNA_enum_get(ptr, "id_type");
+ ID *id = which_libbase(CTX_data_main(C), id_type)->first;
+
+ for (; id; 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";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = outliner_id_remap_invoke;
+ ot->exec = outliner_id_remap_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+
+ 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, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(prop, 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, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
+}
+
+void id_remap_cb(
+ bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- lib_delete(C, te, tselem, CTX_wm_reports(C));
+ wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
+ PointerRNA op_props;
+
+ BLI_assert(tselem->id != NULL);
+
+ 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);
+
+ WM_operator_properties_free(&op_props);
}
-static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+/* Library relocate/reload --------------------------------------------------- */
+
+static int lib_relocate(
+ bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
+{
+ PointerRNA op_props;
+ int ret = 0;
+
+ BLI_assert(te->idcode == ID_LI && tselem->id != NULL);
+ UNUSED_VARS_NDEBUG(te);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_string_set(&op_props, "library", tselem->id->name + 2);
+
+ if (reload) {
+ Library *lib = (Library *)tselem->id;
+ char dir[FILE_MAXDIR], filename[FILE_MAX];
+
+ BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename));
+
+ printf("%s, %s\n", tselem->id->name, lib->filepath);
+
+ /* We assume if both paths in lib are not the same then lib->name was relative... */
+ RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0);
+
+ RNA_string_set(&op_props, "directory", dir);
+ RNA_string_set(&op_props, "filename", filename);
+
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ }
+ else {
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props);
+ }
+
+ WM_operator_properties_free(&op_props);
+
+ return ret;
+}
+
+static int outliner_lib_relocate_invoke_do(
+ bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
{
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) {
+ if (((Library *)tselem->id)->parent && !reload) {
BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
- "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ "Cannot relocate indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
return OPERATOR_CANCELLED;
}
+ else {
+ wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false);
- lib_delete(C, te, tselem, reports);
- return OPERATOR_FINISHED;
+ return lib_relocate(C, te, tselem, ot, reload);
+ }
}
}
else {
for (te = te->subtree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) {
return ret;
}
}
@@ -357,7 +600,7 @@ static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeE
return 0;
}
-static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -371,7 +614,7 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
for (te = soops->tree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) {
return ret;
}
}
@@ -379,16 +622,69 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
-void OUTLINER_OT_lib_delete(wmOperatorType *ot)
+void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
{
- ot->name = "Delete Library";
- ot->idname = "OUTLINER_OT_lib_delete";
- ot->description = "Delete the library under cursor (needs a save/reload)";
+ ot->name = "Relocate Library";
+ ot->idname = "OUTLINER_OT_lib_relocate";
+ ot->description = "Relocate the library under cursor";
- ot->invoke = outliner_lib_delete_invoke;
+ ot->invoke = outliner_lib_relocate_invoke;
ot->poll = ED_operator_outliner_active;
}
+/* XXX This does not work with several items
+ * (it is only called once in the end, due to the 'deffered' filebrowser invocation through event system...). */
+void lib_relocate_cb(
+ bContext *C, Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
+
+ lib_relocate(C, te, tselem, ot, false);
+}
+
+
+static int outliner_lib_reload_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_relocate_invoke_do(C, op->reports, te, fmval, true))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_lib_reload(wmOperatorType *ot)
+{
+ ot->name = "Reload Library";
+ ot->idname = "OUTLINER_OT_lib_reload";
+ ot->description = "Reload the library under cursor";
+
+ ot->invoke = outliner_lib_reload_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+void lib_reload_cb(
+ bContext *C, Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false);
+
+ lib_relocate(C, te, tselem, ot, true);
+}
+
/* ************************************************************** */
/* Setting Toggling Operators */
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 2e46ffa6437..d68815c5e57 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -179,8 +179,17 @@ void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, Tree
void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void lib_relocate_cb(
+ struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void lib_reload_cb(
+ struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void lib_delete_cb(
+void id_delete_cb(
+ struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void id_remap_cb(
struct bContext *C, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
@@ -190,8 +199,10 @@ TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float f
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_relocate(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_reload(struct wmOperatorType *ot);
-void OUTLINER_OT_lib_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_id_delete(struct wmOperatorType *ot);
void OUTLINER_OT_show_one_level(struct wmOperatorType *ot);
void OUTLINER_OT_show_active(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 720cfe12567..776717c8443 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -47,13 +47,15 @@ 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_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_data_operation);
WM_operatortype_append(OUTLINER_OT_animdata_operation);
WM_operatortype_append(OUTLINER_OT_action_set);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 2a210e382a2..265df4a8def 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -850,6 +850,7 @@ enum {
OL_OP_SELECT_HIERARCHY,
OL_OP_DELETE,
OL_OP_DELETE_HIERARCHY,
+ OL_OP_REMAP,
OL_OP_LOCALIZED, /* disabled, see below */
OL_OP_TOGVIS,
OL_OP_TOGSEL,
@@ -863,6 +864,8 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
+ {OL_OP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead a new chosen one"},
{OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
{OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
{OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
@@ -932,6 +935,10 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Object Hierarchy";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
+ else if (event == OL_OP_REMAP) {
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_remap_cb, NULL);
+ str = "Remap ID";
+ }
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
@@ -989,6 +996,8 @@ typedef enum eOutliner_PropGroupOps {
OL_GROUPOP_UNLINK = 1,
OL_GROUPOP_LOCAL,
OL_GROUPOP_LINK,
+ OL_GROUPOP_DELETE,
+ OL_GROUPOP_REMAP,
OL_GROUPOP_INSTANCE,
OL_GROUPOP_TOGVIS,
OL_GROUPOP_TOGSEL,
@@ -1000,6 +1009,9 @@ static EnumPropertyItem prop_group_op_types[] = {
{OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
{OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
{OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
+ {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", "WARNING: no undo"},
+ {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead current (clicked) one"},
{OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
{OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""},
{OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
@@ -1032,6 +1044,14 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
break;
case OL_GROUPOP_INSTANCE:
outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb, NULL);
+ /* works without this except if you try render right after, see: 22027 */
+ DAG_relations_tag_update(CTX_data_main(C));
+ break;
+ case OL_GROUPOP_DELETE:
+ WM_operator_name_call(C, "OUTLINER_OT_id_delete", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
+ case OL_GROUPOP_REMAP:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_remap_cb, NULL);
break;
case OL_GROUPOP_TOGVIS:
outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
@@ -1049,11 +1069,6 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
BLI_assert(0);
}
- if (event == 3) { /* instance */
- /* works without this except if you try render right after, see: 22027 */
- DAG_relations_tag_update(CTX_data_main(C));
- }
-
ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
@@ -1086,6 +1101,8 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_SINGLE,
+ OUTLINER_IDOP_DELETE,
+ OUTLINER_IDOP_REMAP,
OUTLINER_IDOP_FAKE_ADD,
OUTLINER_IDOP_FAKE_CLEAR,
@@ -1099,6 +1116,9 @@ static EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
+ {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
+ {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected datablocks to use instead current (clicked) one"},
{OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User",
"Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"},
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
@@ -1188,6 +1208,20 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
break;
}
+ case OUTLINER_IDOP_DELETE:
+ {
+ if (idlevel > 0) {
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_delete_cb, NULL);
+ }
+ break;
+ }
+ case OUTLINER_IDOP_REMAP:
+ {
+ if (idlevel > 0) {
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_remap_cb, NULL);
+ }
+ break;
+ }
case OUTLINER_IDOP_FAKE_ADD:
{
/* set fake user */
@@ -1259,13 +1293,16 @@ typedef enum eOutlinerLibOpTypes {
OL_LIB_RENAME,
OL_LIB_DELETE,
+ OL_LIB_RELOCATE,
+ OL_LIB_RELOAD,
} 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)"},
+ {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"},
+ {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"},
+ {OL_LIB_RELOAD, "RELOAD", 0, "Reload", "Reload all data from this library"},
{0, NULL, 0, NULL, NULL}
-
};
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
@@ -1295,13 +1332,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
case OL_LIB_DELETE:
{
- /* delete */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb, NULL);
-
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
- /* Note: no undo possible here really, not 100% sure why...
- * Probably because of library optimizations in undo/redo process? */
- /* ED_undo_push(C, "Rename"); */
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_delete_cb, NULL);
+ break;
+ }
+ case OL_LIB_RELOCATE:
+ {
+ /* rename */
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_relocate_cb, NULL);
+ break;
+ }
+ case OL_LIB_RELOAD:
+ {
+ /* rename */
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_reload_cb, NULL);
break;
}
default: