From a77feabb51470b9cfb71be7f0ea7e774d6591799 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 6 Mar 2019 15:09:16 +0100 Subject: Collection duplication from Outliner: add a 'duplicate hierarchy' operation. Point is, you may want to duplicate your set of collections, but not duplicate all their objects. Some notes: * Am rather skeptical about the practice of using operator name to define behavior of some common exec code. Imho, that should be a single operator with an enum to refine its behavior (@cambpellbarton may also have an opinion here?). Left it as-is for now, because this seems to be used by other operators too in that code. :/ * @dfelinto, @pablovazquez, @billreynish am not so happy with current names, but cannot find really good short ones either... Also, shouldn't we move those into a dedicated `Duplicate` sub-menu? --- source/blender/blenkernel/BKE_collection.h | 4 ++- source/blender/blenkernel/intern/collection.c | 42 ++++++++++++---------- .../editors/space_outliner/outliner_collections.c | 30 ++++++++++++---- .../editors/space_outliner/outliner_intern.h | 3 +- .../blender/editors/space_outliner/outliner_ops.c | 3 +- 5 files changed, 53 insertions(+), 29 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 3ddc28dafdb..0390078fc7f 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -57,7 +57,9 @@ struct Collection *BKE_collection_copy(struct Main *bmain, struct Collection *pa void BKE_collection_copy_data(struct Main *bmain, struct Collection *collection_dst, const struct Collection *collection_src, const int flag); void BKE_collection_make_local(struct Main *bmain, struct Collection *collection, const bool lib_local); -struct Collection *BKE_collection_duplicate(struct Main *bmain, struct Collection *parent, struct Collection *collection, const bool do_hierarchy, const bool do_deep_copy); +struct Collection *BKE_collection_duplicate( + struct Main *bmain, struct Collection *parent, struct Collection *collection, + const bool do_hierarchy, const bool do_objects, const bool do_obdata); struct Collection *BKE_collection_copy_master(struct Main *bmain, struct Collection *collection, const int flag); /* Master Collection for Scene */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 3776c6bd8ca..beefe4b5ac2 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -211,11 +211,12 @@ void BKE_collection_copy_data( } static Collection *collection_duplicate_recursive( - Main *bmain, Collection *parent, Collection *collection_old, const bool do_hierarchy, const bool do_deep_copy) + Main *bmain, Collection *parent, Collection *collection_old, + const bool do_hierarchy, const bool do_objects, const bool do_obdata) { Collection *collection_new; bool do_full_process = false; - const int object_dupflag = (do_deep_copy) ? U.dupflag : 0; + const int object_dupflag = (do_obdata) ? U.dupflag : 0; if (!do_hierarchy || collection_old->id.newid == NULL) { BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new); @@ -250,19 +251,21 @@ static Collection *collection_duplicate_recursive( return collection_new; } - /* We can loop on collection_old's objects, that list is currently identical the collection_new' objects, - * and won't be changed here. */ - for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) { - Object *ob_old = cob->ob; - Object *ob_new = (Object *)ob_old->id.newid; + if (do_objects) { + /* We can loop on collection_old's objects, that list is currently identical the collection_new' objects, + * and won't be changed here. */ + for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) { + Object *ob_old = cob->ob; + Object *ob_new = (Object *)ob_old->id.newid; - if (ob_new == NULL) { - ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag); - ID_NEW_SET(ob_old, ob_new); - } + if (ob_new == NULL) { + ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag); + ID_NEW_SET(ob_old, ob_new); + } - collection_object_add(bmain, collection_new, ob_new, 0, true); - collection_object_remove(bmain, collection_new, ob_old, false); + collection_object_add(bmain, collection_new, ob_new, 0, true); + collection_object_remove(bmain, collection_new, ob_old, false); + } } /* We can loop on collection_old's children, that list is currently identical the collection_new' children, @@ -270,7 +273,7 @@ static Collection *collection_duplicate_recursive( for (CollectionChild *child = collection_old->children.first; child; child = child->next) { Collection *child_collection_old = child->collection; - collection_duplicate_recursive(bmain, collection_new, child_collection_old, do_hierarchy, do_deep_copy); + collection_duplicate_recursive(bmain, collection_new, child_collection_old, do_hierarchy, do_objects, do_obdata); collection_child_remove(collection_new, child_collection_old); } @@ -285,7 +288,7 @@ static Collection *collection_duplicate_recursive( */ Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection) { - return BKE_collection_duplicate(bmain, parent, collection, false, false); + return BKE_collection_duplicate(bmain, parent, collection, false, false, false); } /** @@ -296,11 +299,12 @@ Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *col * \warning If any 'deep copy' behavior is enabled, this functions will clear all \a bmain id.idnew pointers. * * \param do_hierarchy If true, it will recursively make shallow copies of children collections and objects. - * \param do_deep_copy If true, it will also make deep duplicates of objects, using behavior defined in user settings - * (U.dupflag). This one does nothing if \a do_hierarchy is not set. + * \param do_obdata If true, it will also make deep duplicates of objects, using behavior defined in user settings + * (U.dupflag). This one does nothing if \a do_hierarchy is not set. */ Collection *BKE_collection_duplicate( - Main *bmain, Collection *parent, Collection *collection, const bool do_hierarchy, const bool do_deep_copy) + Main *bmain, Collection *parent, Collection *collection, + const bool do_hierarchy, const bool do_objects, const bool do_obdata) { /* It's not allowed to copy the master collection. */ if (collection->flag & COLLECTION_IS_MASTER) { @@ -314,7 +318,7 @@ Collection *BKE_collection_duplicate( } Collection *collection_new = collection_duplicate_recursive( - bmain, parent, collection, do_hierarchy, do_deep_copy); + bmain, parent, collection, do_hierarchy, do_objects, do_obdata); /* This code will follows into all ID links using an ID tagged with LIB_TAG_NEW.*/ BKE_libblock_relink_to_newid(&collection_new->id); diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 750c78d76b9..7403525c293 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -448,7 +448,8 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); SpaceOutliner *soops = CTX_wm_space_outliner(C); TreeElement *te = outliner_active_collection(C); - bool linked = strstr(op->idname, "linked") != NULL; + const bool hierarchy = strstr(op->idname, "hierarchy") != NULL; + const bool linked = strstr(op->idname, "linked") != NULL; /* Can happen when calling from a key binding. */ if (te == NULL) { @@ -468,7 +469,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) case SO_SCENES: case SO_VIEW_LAYER: case SO_LIBRARIES: - BKE_collection_duplicate(bmain, parent, collection, true, !linked); + BKE_collection_duplicate(bmain, parent, collection, true, !hierarchy, !linked); break; } @@ -478,12 +479,12 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void OUTLINER_OT_collection_duplicate(wmOperatorType *ot) +void OUTLINER_OT_collection_duplicate_hierarchy(wmOperatorType *ot) { /* identifiers */ - ot->name = "Duplicate Collection"; - ot->idname = "OUTLINER_OT_collection_duplicate"; - ot->description = "Duplicate all objects and collections and make them single user"; + ot->name = "Duplicate Collection Hierarchy"; + ot->idname = "OUTLINER_OT_collection_duplicate_hierarchy"; + ot->description = "Recursively duplicate the collection and all its children, with linked objects"; /* api callbacks */ ot->exec = collection_duplicate_exec; @@ -498,7 +499,22 @@ void OUTLINER_OT_collection_duplicate_linked(wmOperatorType *ot) /* identifiers */ ot->name = "Duplicate Linked Collection"; ot->idname = "OUTLINER_OT_collection_duplicate_linked"; - ot->description = "Duplicate all objects and collections with linked object data"; + ot->description = "Recursively duplicate the collection, all its children and objects, with linked object data"; + + /* api callbacks */ + ot->exec = collection_duplicate_exec; + ot->poll = ED_outliner_collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Collection"; + ot->idname = "OUTLINER_OT_collection_duplicate"; + ot->description = "Recursively duplicate the collection, all its children, objects and object data"; /* api callbacks */ ot->exec = collection_duplicate_exec; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 0851d5ce9f4..5af8e2252ef 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -315,8 +315,9 @@ bool outliner_is_collection_tree_element(const TreeElement *te); struct Collection *outliner_collection_from_tree_element(const TreeElement *te); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); -void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot); +void OUTLINER_OT_collection_duplicate_hierarchy(struct wmOperatorType *ot); void OUTLINER_OT_collection_duplicate_linked(struct wmOperatorType *ot); +void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot); void OUTLINER_OT_collection_delete(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index eea06fc0b0c..af73e88aa73 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -93,8 +93,9 @@ void outliner_operatortypes(void) /* collections */ WM_operatortype_append(OUTLINER_OT_collection_new); - WM_operatortype_append(OUTLINER_OT_collection_duplicate); + WM_operatortype_append(OUTLINER_OT_collection_duplicate_hierarchy); WM_operatortype_append(OUTLINER_OT_collection_duplicate_linked); + WM_operatortype_append(OUTLINER_OT_collection_duplicate); WM_operatortype_append(OUTLINER_OT_collection_delete); WM_operatortype_append(OUTLINER_OT_collection_objects_select); WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); -- cgit v1.2.3