API method
If you know the collection you wish to dupe, and the collection you wish to parent to, consider something like below. Because a collection can have many parents, I'm not totally sure without using the outliner how to determine which instance of the collection is being duped, and hence where in the hierarchy to paste.
As a test, I've copied the context collection to to the scene collection, with and without linked data. Using a method that recursively creates a new collection and populates it with object copies from the source.
EDIT. Have added a look up table with original -> dupe to change a dupes parent to a dupe (if duped). Other things to consider here are driver variable targets, constraint objects, modifier objects.
import bpy
from collections import defaultdict
def copy_objects(from_col, to_col, linked, dupe_lut):
for o in from_col.objects:
dupe = o.copy()
if not linked and o.data:
dupe.data = dupe.data.copy()
to_col.objects.link(dupe)
dupe_lut[o] = dupe
def copy(parent, collection, linked=False):
dupe_lut = defaultdict(lambda : None)
def _copy(parent, collection, linked=False):
cc = bpy.data.collections.new(collection.name)
copy_objects(collection, cc, linked, dupe_lut)
for c in collection.children:
_copy(cc, c, linked)
parent.children.link(cc)
_copy(parent, collection, linked)
print(dupe_lut)
for o, dupe in tuple(dupe_lut.items()):
parent = dupe_lut[o.parent]
if parent:
dupe.parent = parent
# test call
context = bpy.context
scene = context.scene
col = context.collection
print(col, scene.collection)
assert(col is not scene.collection)
parent_col = context.scene.collection
copy(scene.collection, col)
# and linked copy
copy(scene.collection, col, linked=True)
Note
For a totally linked copy, ie the objects and collections within are linked copies then
cc = collection.copy()
will do the trick.
Related
Change active collection