2026-01-01
This commit is contained in:
@@ -30,9 +30,10 @@ intefaces in Blender.
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class
|
||||
from bpy.utils import unregister_class
|
||||
from ..utils import compat
|
||||
from .. import config
|
||||
from ..stats import unused
|
||||
from ..stats import unused_parallel
|
||||
from .utils import nuke
|
||||
from .utils import clean
|
||||
from ..ui.utils import ui_layouts
|
||||
@@ -157,8 +158,10 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
|
||||
unused_lights = []
|
||||
unused_materials = []
|
||||
unused_node_groups = []
|
||||
unused_objects = []
|
||||
unused_particles = []
|
||||
unused_textures = []
|
||||
unused_armatures = []
|
||||
unused_worlds = []
|
||||
|
||||
def draw(self, context):
|
||||
@@ -167,67 +170,74 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
|
||||
col = layout.column()
|
||||
col.label(text="Remove the following data-blocks?")
|
||||
|
||||
collections = sorted(unused.collections_deep())
|
||||
# Use cached values from invoke() instead of recalculating
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Collections",
|
||||
items=collections,
|
||||
items=sorted(self.unused_collections),
|
||||
icon="OUTLINER_OB_GROUP_INSTANCE"
|
||||
)
|
||||
|
||||
images = sorted(unused.images_deep())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Images",
|
||||
items=images,
|
||||
items=sorted(self.unused_images),
|
||||
icon="IMAGE_DATA"
|
||||
)
|
||||
|
||||
lights = sorted(unused.lights_deep())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Lights",
|
||||
items=lights,
|
||||
items=sorted(self.unused_lights),
|
||||
icon="OUTLINER_OB_LIGHT"
|
||||
)
|
||||
|
||||
materials = sorted(unused.materials_deep())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Materials",
|
||||
items=materials,
|
||||
items=sorted(self.unused_materials),
|
||||
icon="MATERIAL"
|
||||
)
|
||||
|
||||
node_groups = sorted(unused.node_groups_deep())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Node Groups",
|
||||
items=node_groups,
|
||||
items=sorted(self.unused_node_groups),
|
||||
icon="NODETREE"
|
||||
)
|
||||
|
||||
particles = sorted(unused.particles_deep())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Objects",
|
||||
items=sorted(self.unused_objects),
|
||||
icon="OBJECT_DATA"
|
||||
)
|
||||
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Particle Systems",
|
||||
items=particles,
|
||||
items=sorted(self.unused_particles),
|
||||
icon="PARTICLES"
|
||||
)
|
||||
|
||||
textures = sorted(unused.textures_deep())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Textures",
|
||||
items=textures,
|
||||
items=sorted(self.unused_textures),
|
||||
icon="TEXTURE"
|
||||
)
|
||||
|
||||
worlds = sorted(unused.worlds())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Armatures",
|
||||
items=sorted(self.unused_armatures),
|
||||
icon="ARMATURE_DATA"
|
||||
)
|
||||
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Worlds",
|
||||
items=worlds,
|
||||
items=sorted(self.unused_worlds),
|
||||
icon="WORLD"
|
||||
)
|
||||
|
||||
@@ -240,8 +250,10 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
|
||||
clean.lights()
|
||||
clean.materials()
|
||||
clean.node_groups()
|
||||
clean.objects()
|
||||
clean.particles()
|
||||
clean.textures()
|
||||
clean.armatures()
|
||||
clean.worlds()
|
||||
|
||||
return {'FINISHED'}
|
||||
@@ -249,14 +261,19 @@ class ATOMIC_OT_clean_all(bpy.types.Operator):
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
|
||||
self.unused_collections = unused.collections_deep()
|
||||
self.unused_images = unused.images_deep()
|
||||
self.unused_lights = unused.lights_deep()
|
||||
self.unused_materials = unused.materials_deep()
|
||||
self.unused_node_groups = unused.node_groups_deep()
|
||||
self.unused_particles = unused.particles_deep()
|
||||
self.unused_textures = unused.textures_deep()
|
||||
self.unused_worlds = unused.worlds()
|
||||
# Use parallel execution for better performance
|
||||
all_unused = unused_parallel.get_all_unused_parallel()
|
||||
|
||||
self.unused_collections = all_unused['collections']
|
||||
self.unused_images = all_unused['images']
|
||||
self.unused_lights = all_unused['lights']
|
||||
self.unused_materials = all_unused['materials']
|
||||
self.unused_node_groups = all_unused['node_groups']
|
||||
self.unused_objects = all_unused['objects']
|
||||
self.unused_particles = all_unused['particles']
|
||||
self.unused_textures = all_unused['textures']
|
||||
self.unused_armatures = all_unused['armatures']
|
||||
self.unused_worlds = all_unused['worlds']
|
||||
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
@@ -790,4 +807,4 @@ def register():
|
||||
|
||||
def unregister():
|
||||
for item in reg_list:
|
||||
unregister_class(item)
|
||||
compat.safe_unregister_class(item)
|
||||
|
||||
@@ -26,11 +26,18 @@ operators.
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class
|
||||
from bpy.utils import unregister_class
|
||||
from ..utils import compat
|
||||
from .utils import delete
|
||||
from .utils import duplicate
|
||||
|
||||
|
||||
def _check_library_or_override(datablock):
|
||||
"""Check if datablock is library-linked or override, return error message if so."""
|
||||
if compat.is_library_or_override(datablock):
|
||||
return "Cannot modify library-linked or override datablocks"
|
||||
return None
|
||||
|
||||
|
||||
# Atomic Data Manager Inspection Rename Operator
|
||||
class ATOMIC_OT_inspection_rename(bpy.types.Operator):
|
||||
"""Give this data-block a new name"""
|
||||
@@ -51,35 +58,75 @@ class ATOMIC_OT_inspection_rename(bpy.types.Operator):
|
||||
name = atom.rename_field
|
||||
|
||||
if inspection == 'COLLECTIONS':
|
||||
bpy.data.collections[atom.collections_field].name = name
|
||||
collection = bpy.data.collections[atom.collections_field]
|
||||
error = _check_library_or_override(collection)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
collection.name = name
|
||||
atom.collections_field = name
|
||||
|
||||
if inspection == 'IMAGES':
|
||||
bpy.data.images[atom.images_field].name = name
|
||||
image = bpy.data.images[atom.images_field]
|
||||
error = _check_library_or_override(image)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
image.name = name
|
||||
atom.images_field = name
|
||||
|
||||
if inspection == 'LIGHTS':
|
||||
bpy.data.lights[atom.lights_field].name = name
|
||||
light = bpy.data.lights[atom.lights_field]
|
||||
error = _check_library_or_override(light)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
light.name = name
|
||||
atom.lights_field = name
|
||||
|
||||
if inspection == 'MATERIALS':
|
||||
bpy.data.materials[atom.materials_field].name = name
|
||||
material = bpy.data.materials[atom.materials_field]
|
||||
error = _check_library_or_override(material)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
material.name = name
|
||||
atom.materials_field = name
|
||||
|
||||
if inspection == 'NODE_GROUPS':
|
||||
bpy.data.node_groups[atom.node_groups_field].name = name
|
||||
node_group = bpy.data.node_groups[atom.node_groups_field]
|
||||
error = _check_library_or_override(node_group)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
node_group.name = name
|
||||
atom.node_groups_field = name
|
||||
|
||||
if inspection == 'PARTICLES':
|
||||
bpy.data.particles[atom.particles_field].name = name
|
||||
particle = bpy.data.particles[atom.particles_field]
|
||||
error = _check_library_or_override(particle)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
particle.name = name
|
||||
atom.particles_field = name
|
||||
|
||||
if inspection == 'TEXTURES':
|
||||
bpy.data.textures[atom.textures_field].name = name
|
||||
texture = bpy.data.textures[atom.textures_field]
|
||||
error = _check_library_or_override(texture)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
texture.name = name
|
||||
atom.textures_field = name
|
||||
|
||||
if inspection == 'WORLDS':
|
||||
bpy.data.worlds[atom.worlds_field].name = name
|
||||
world = bpy.data.worlds[atom.worlds_field]
|
||||
error = _check_library_or_override(world)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
world.name = name
|
||||
atom.worlds_field = name
|
||||
|
||||
atom.rename_field = ""
|
||||
@@ -172,44 +219,72 @@ class ATOMIC_OT_inspection_replace(bpy.types.Operator):
|
||||
|
||||
if inspection == 'IMAGES' and \
|
||||
atom.replace_field in bpy.data.images.keys():
|
||||
bpy.data.images[atom.images_field].user_remap(
|
||||
bpy.data.images[atom.replace_field])
|
||||
image = bpy.data.images[atom.images_field]
|
||||
error = _check_library_or_override(image)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
image.user_remap(bpy.data.images[atom.replace_field])
|
||||
atom.images_field = atom.replace_field
|
||||
|
||||
if inspection == 'LIGHTS' and \
|
||||
atom.replace_field in bpy.data.lights.keys():
|
||||
bpy.data.lights[atom.lights_field].user_remap(
|
||||
bpy.data.lights[atom.replace_field])
|
||||
light = bpy.data.lights[atom.lights_field]
|
||||
error = _check_library_or_override(light)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
light.user_remap(bpy.data.lights[atom.replace_field])
|
||||
atom.lights_field = atom.replace_field
|
||||
|
||||
if inspection == 'MATERIALS' and \
|
||||
atom.replace_field in bpy.data.materials.keys():
|
||||
bpy.data.materials[atom.materials_field].user_remap(
|
||||
bpy.data.materials[atom.replace_field])
|
||||
material = bpy.data.materials[atom.materials_field]
|
||||
error = _check_library_or_override(material)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
material.user_remap(bpy.data.materials[atom.replace_field])
|
||||
atom.materials_field = atom.replace_field
|
||||
|
||||
if inspection == 'NODE_GROUPS' and \
|
||||
atom.replace_field in bpy.data.node_groups.keys():
|
||||
bpy.data.node_groups[atom.node_groups_field].user_remap(
|
||||
bpy.data.node_groups[atom.replace_field])
|
||||
node_group = bpy.data.node_groups[atom.node_groups_field]
|
||||
error = _check_library_or_override(node_group)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
node_group.user_remap(bpy.data.node_groups[atom.replace_field])
|
||||
atom.node_groups_field = atom.replace_field
|
||||
|
||||
if inspection == 'PARTICLES' and \
|
||||
atom.replace_field in bpy.data.particles.keys():
|
||||
bpy.data.particles[atom.particles_field].user_remap(
|
||||
bpy.data.particles[atom.replace_field])
|
||||
particle = bpy.data.particles[atom.particles_field]
|
||||
error = _check_library_or_override(particle)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
particle.user_remap(bpy.data.particles[atom.replace_field])
|
||||
atom.particles_field = atom.replace_field
|
||||
|
||||
if inspection == 'TEXTURES' and \
|
||||
atom.replace_field in bpy.data.textures.keys():
|
||||
bpy.data.textures[atom.textures_field].user_remap(
|
||||
bpy.data.textures[atom.replace_field])
|
||||
texture = bpy.data.textures[atom.textures_field]
|
||||
error = _check_library_or_override(texture)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
texture.user_remap(bpy.data.textures[atom.replace_field])
|
||||
atom.textures_field = atom.replace_field
|
||||
|
||||
if inspection == 'WORLDS' and \
|
||||
atom.replace_field in bpy.data.worlds.keys():
|
||||
bpy.data.worlds[atom.worlds_field].user_remap(
|
||||
bpy.data.worlds[atom.replace_field])
|
||||
world = bpy.data.worlds[atom.worlds_field]
|
||||
error = _check_library_or_override(world)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
world.user_remap(bpy.data.worlds[atom.replace_field])
|
||||
atom.worlds_field = atom.replace_field
|
||||
|
||||
atom.replace_field = ""
|
||||
@@ -232,38 +307,59 @@ class ATOMIC_OT_inspection_toggle_fake_user(bpy.types.Operator):
|
||||
|
||||
if inspection == 'IMAGES':
|
||||
image = bpy.data.images[atom.images_field]
|
||||
bpy.data.images[atom.images_field].use_fake_user = \
|
||||
not image.use_fake_user
|
||||
error = _check_library_or_override(image)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
image.use_fake_user = not image.use_fake_user
|
||||
|
||||
if inspection == 'LIGHTS':
|
||||
light = bpy.data.lights[atom.lights_field]
|
||||
bpy.data.lights[atom.lights_field].use_fake_user = \
|
||||
not light.use_fake_user
|
||||
error = _check_library_or_override(light)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
light.use_fake_user = not light.use_fake_user
|
||||
|
||||
if inspection == 'MATERIALS':
|
||||
material = bpy.data.materials[atom.materials_field]
|
||||
bpy.data.materials[atom.materials_field].use_fake_user = \
|
||||
not material.use_fake_user
|
||||
error = _check_library_or_override(material)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
material.use_fake_user = not material.use_fake_user
|
||||
|
||||
if inspection == 'NODE_GROUPS':
|
||||
node_group = bpy.data.node_groups[atom.node_groups_field]
|
||||
bpy.data.node_groups[atom.node_groups_field].use_fake_user = \
|
||||
not node_group.use_fake_user
|
||||
error = _check_library_or_override(node_group)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
node_group.use_fake_user = not node_group.use_fake_user
|
||||
|
||||
if inspection == 'PARTICLES':
|
||||
particle = bpy.data.particles[atom.particles_field]
|
||||
bpy.data.particles[atom.particles_field].use_fake_user = \
|
||||
not particle.use_fake_user
|
||||
error = _check_library_or_override(particle)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
particle.use_fake_user = not particle.use_fake_user
|
||||
|
||||
if inspection == 'TEXTURES':
|
||||
texture = bpy.data.textures[atom.textures_field]
|
||||
bpy.data.textures[atom.textures_field].use_fake_user = \
|
||||
not texture.use_fake_user
|
||||
error = _check_library_or_override(texture)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
texture.use_fake_user = not texture.use_fake_user
|
||||
|
||||
if inspection == 'WORLDS':
|
||||
world = bpy.data.worlds[atom.worlds_field]
|
||||
bpy.data.worlds[atom.worlds_field].use_fake_user = \
|
||||
not world.use_fake_user
|
||||
error = _check_library_or_override(world)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
world.use_fake_user = not world.use_fake_user
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@@ -283,6 +379,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
collections = bpy.data.collections
|
||||
|
||||
if key in collections.keys():
|
||||
collection = collections[key]
|
||||
error = _check_library_or_override(collection)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.collection(key)
|
||||
atom.collections_field = copy_key
|
||||
|
||||
@@ -291,6 +392,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
images = bpy.data.images
|
||||
|
||||
if key in images.keys():
|
||||
image = images[key]
|
||||
error = _check_library_or_override(image)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.image(key)
|
||||
atom.images_field = copy_key
|
||||
|
||||
@@ -299,6 +405,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
lights = bpy.data.lights
|
||||
|
||||
if key in lights.keys():
|
||||
light = lights[key]
|
||||
error = _check_library_or_override(light)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.light(key)
|
||||
atom.lights_field = copy_key
|
||||
|
||||
@@ -307,6 +418,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
materials = bpy.data.materials
|
||||
|
||||
if key in materials.keys():
|
||||
material = materials[key]
|
||||
error = _check_library_or_override(material)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.material(key)
|
||||
atom.materials_field = copy_key
|
||||
|
||||
@@ -315,6 +431,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
node_groups = bpy.data.node_groups
|
||||
|
||||
if key in node_groups.keys():
|
||||
node_group = node_groups[key]
|
||||
error = _check_library_or_override(node_group)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.node_group(key)
|
||||
atom.node_groups_field = copy_key
|
||||
|
||||
@@ -323,6 +444,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
particles = bpy.data.particles
|
||||
|
||||
if key in particles.keys():
|
||||
particle = particles[key]
|
||||
error = _check_library_or_override(particle)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.particle(key)
|
||||
atom.particles_field = copy_key
|
||||
|
||||
@@ -331,6 +457,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
textures = bpy.data.textures
|
||||
|
||||
if key in textures.keys():
|
||||
texture = textures[key]
|
||||
error = _check_library_or_override(texture)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.texture(key)
|
||||
atom.textures_field = copy_key
|
||||
|
||||
@@ -339,6 +470,11 @@ class ATOMIC_OT_inspection_duplicate(bpy.types.Operator):
|
||||
worlds = bpy.data.worlds
|
||||
|
||||
if key in worlds.keys():
|
||||
world = worlds[key]
|
||||
error = _check_library_or_override(world)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
copy_key = duplicate.world(key)
|
||||
atom.worlds_field = copy_key
|
||||
|
||||
@@ -360,6 +496,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
collections = bpy.data.collections
|
||||
|
||||
if key in collections.keys():
|
||||
collection = collections[key]
|
||||
error = _check_library_or_override(collection)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.collection(key)
|
||||
atom.collections_field = ""
|
||||
|
||||
@@ -368,6 +509,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
images = bpy.data.images
|
||||
|
||||
if key in images.keys():
|
||||
image = images[key]
|
||||
error = _check_library_or_override(image)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.image(key)
|
||||
atom.images_field = ""
|
||||
|
||||
@@ -376,6 +522,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
lights = bpy.data.lights
|
||||
|
||||
if key in lights.keys():
|
||||
light = lights[key]
|
||||
error = _check_library_or_override(light)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.light(key)
|
||||
atom.lights_field = ""
|
||||
|
||||
@@ -384,6 +535,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
materials = bpy.data.materials
|
||||
|
||||
if key in materials.keys():
|
||||
material = materials[key]
|
||||
error = _check_library_or_override(material)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.material(key)
|
||||
atom.materials_field = ""
|
||||
|
||||
@@ -392,6 +548,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
node_groups = bpy.data.node_groups
|
||||
|
||||
if key in node_groups.keys():
|
||||
node_group = node_groups[key]
|
||||
error = _check_library_or_override(node_group)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.node_group(key)
|
||||
atom.node_groups_field = ""
|
||||
|
||||
@@ -399,6 +560,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
key = atom.particles_field
|
||||
particles = bpy.data.particles
|
||||
if key in particles.keys():
|
||||
particle = particles[key]
|
||||
error = _check_library_or_override(particle)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.particle(key)
|
||||
atom.particles_field = ""
|
||||
|
||||
@@ -407,6 +573,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
textures = bpy.data.textures
|
||||
|
||||
if key in textures.keys():
|
||||
texture = textures[key]
|
||||
error = _check_library_or_override(texture)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.texture(key)
|
||||
atom.textures_field = ""
|
||||
|
||||
@@ -415,6 +586,11 @@ class ATOMIC_OT_inspection_delete(bpy.types.Operator):
|
||||
worlds = bpy.data.worlds
|
||||
|
||||
if key in worlds.keys():
|
||||
world = worlds[key]
|
||||
error = _check_library_or_override(world)
|
||||
if error:
|
||||
self.report({'ERROR'}, error)
|
||||
return {'CANCELLED'}
|
||||
delete.world(key)
|
||||
atom.worlds_field = ""
|
||||
|
||||
@@ -437,4 +613,4 @@ def register():
|
||||
|
||||
def unregister():
|
||||
for item in reg_list:
|
||||
unregister_class(item)
|
||||
compat.safe_unregister_class(item)
|
||||
|
||||
@@ -26,8 +26,9 @@ various selection operations.
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class
|
||||
from bpy.utils import unregister_class
|
||||
from ..utils import compat
|
||||
from ..stats import unused
|
||||
from ..stats import unused_parallel
|
||||
from .utils import clean
|
||||
from .utils import nuke
|
||||
from ..ui.utils import ui_layouts
|
||||
@@ -57,7 +58,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel collections property is toggled
|
||||
if atom.collections:
|
||||
collections = sorted(bpy.data.collections.keys())
|
||||
from ..utils import compat
|
||||
collections = sorted([c.name for c in bpy.data.collections
|
||||
if not compat.is_library_or_override(c)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Collections",
|
||||
@@ -67,7 +70,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel images property is toggled
|
||||
if atom.images:
|
||||
images = sorted(bpy.data.images.keys())
|
||||
from ..utils import compat
|
||||
images = sorted([i.name for i in bpy.data.images
|
||||
if not compat.is_library_or_override(i)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Images",
|
||||
@@ -77,7 +82,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel lights property is toggled
|
||||
if atom.lights:
|
||||
lights = sorted(bpy.data.lights.keys())
|
||||
from ..utils import compat
|
||||
lights = sorted([l.name for l in bpy.data.lights
|
||||
if not compat.is_library_or_override(l)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Lights",
|
||||
@@ -87,7 +94,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel materials property is toggled
|
||||
if atom.materials:
|
||||
materials = sorted(bpy.data.materials.keys())
|
||||
from ..utils import compat
|
||||
materials = sorted([m.name for m in bpy.data.materials
|
||||
if not compat.is_library_or_override(m)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Materials",
|
||||
@@ -97,7 +106,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel node groups property is toggled
|
||||
if atom.node_groups:
|
||||
node_groups = sorted(bpy.data.node_groups.keys())
|
||||
from ..utils import compat
|
||||
node_groups = sorted([ng.name for ng in bpy.data.node_groups
|
||||
if not compat.is_library_or_override(ng)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Node Groups",
|
||||
@@ -107,7 +118,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel particle systems property is toggled
|
||||
if atom.particles:
|
||||
particles = sorted(bpy.data.particles.keys())
|
||||
from ..utils import compat
|
||||
particles = sorted([p.name for p in bpy.data.particles
|
||||
if not compat.is_library_or_override(p)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Particle Systems",
|
||||
@@ -117,7 +130,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel textures property is toggled
|
||||
if atom.textures:
|
||||
textures = sorted(bpy.data.textures.keys())
|
||||
from ..utils import compat
|
||||
textures = sorted([t.name for t in bpy.data.textures
|
||||
if not compat.is_library_or_override(t)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Textures",
|
||||
@@ -127,7 +142,9 @@ class ATOMIC_OT_nuke(bpy.types.Operator):
|
||||
|
||||
# display when the main panel worlds property is toggled
|
||||
if atom.worlds:
|
||||
worlds = sorted(bpy.data.worlds.keys())
|
||||
from ..utils import compat
|
||||
worlds = sorted([w.name for w in bpy.data.worlds
|
||||
if not compat.is_library_or_override(w)])
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Worlds",
|
||||
@@ -184,8 +201,10 @@ class ATOMIC_OT_clean(bpy.types.Operator):
|
||||
unused_lights = []
|
||||
unused_materials = []
|
||||
unused_node_groups = []
|
||||
unused_objects = []
|
||||
unused_particles = []
|
||||
unused_textures = []
|
||||
unused_armatures = []
|
||||
unused_worlds = []
|
||||
|
||||
def draw(self, context):
|
||||
@@ -197,8 +216,9 @@ class ATOMIC_OT_clean(bpy.types.Operator):
|
||||
|
||||
# display if no main panel properties are toggled
|
||||
if not (atom.collections or atom.images or atom.lights or
|
||||
atom.materials or atom.node_groups or atom.particles
|
||||
or atom.textures or atom.worlds):
|
||||
atom.materials or atom.node_groups or atom.objects or
|
||||
atom.particles or atom.textures or atom.armatures or
|
||||
atom.worlds):
|
||||
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
@@ -249,6 +269,15 @@ class ATOMIC_OT_clean(bpy.types.Operator):
|
||||
icon="NODETREE"
|
||||
)
|
||||
|
||||
# display when the main panel objects property is toggled
|
||||
if atom.objects:
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Objects",
|
||||
items=self.unused_objects,
|
||||
icon="OBJECT_DATA"
|
||||
)
|
||||
|
||||
# display when the main panel particle systems property is toggled
|
||||
if atom.particles:
|
||||
ui_layouts.box_list(
|
||||
@@ -260,14 +289,22 @@ class ATOMIC_OT_clean(bpy.types.Operator):
|
||||
|
||||
# display when the main panel textures property is toggled
|
||||
if atom.textures:
|
||||
textures = sorted(unused.textures_deep())
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Textures",
|
||||
items=textures,
|
||||
items=self.unused_textures,
|
||||
icon="TEXTURE"
|
||||
)
|
||||
|
||||
# display when the main panel armatures property is toggled
|
||||
if atom.armatures:
|
||||
ui_layouts.box_list(
|
||||
layout=layout,
|
||||
title="Armatures",
|
||||
items=self.unused_armatures,
|
||||
icon="ARMATURE_DATA"
|
||||
)
|
||||
|
||||
# display when the main panel worlds property is toggled
|
||||
if atom.worlds:
|
||||
ui_layouts.box_list(
|
||||
@@ -297,12 +334,18 @@ class ATOMIC_OT_clean(bpy.types.Operator):
|
||||
if atom.node_groups:
|
||||
clean.node_groups()
|
||||
|
||||
if atom.objects:
|
||||
clean.objects()
|
||||
|
||||
if atom.particles:
|
||||
clean.particles()
|
||||
|
||||
if atom.textures:
|
||||
clean.textures()
|
||||
|
||||
if atom.armatures:
|
||||
clean.armatures()
|
||||
|
||||
if atom.worlds:
|
||||
clean.worlds()
|
||||
|
||||
@@ -314,29 +357,38 @@ class ATOMIC_OT_clean(bpy.types.Operator):
|
||||
wm = context.window_manager
|
||||
atom = bpy.context.scene.atomic
|
||||
|
||||
# Use parallel execution for better performance
|
||||
all_unused = unused_parallel.get_all_unused_parallel()
|
||||
|
||||
if atom.collections:
|
||||
self.unused_collections = unused.collections_deep()
|
||||
self.unused_collections = all_unused['collections']
|
||||
|
||||
if atom.images:
|
||||
self.unused_images = unused.images_deep()
|
||||
self.unused_images = all_unused['images']
|
||||
|
||||
if atom.lights:
|
||||
self.unused_lights = unused.lights_deep()
|
||||
self.unused_lights = all_unused['lights']
|
||||
|
||||
if atom.materials:
|
||||
self.unused_materials = unused.materials_deep()
|
||||
self.unused_materials = all_unused['materials']
|
||||
|
||||
if atom.node_groups:
|
||||
self.unused_node_groups = unused.node_groups_deep()
|
||||
self.unused_node_groups = all_unused['node_groups']
|
||||
|
||||
if atom.objects:
|
||||
self.unused_objects = all_unused['objects']
|
||||
|
||||
if atom.particles:
|
||||
self.unused_particles = unused.particles_deep()
|
||||
self.unused_particles = all_unused['particles']
|
||||
|
||||
if atom.textures:
|
||||
self.unused_textures = unused.textures_deep()
|
||||
self.unused_textures = all_unused['textures']
|
||||
|
||||
if atom.armatures:
|
||||
self.unused_armatures = all_unused['armatures']
|
||||
|
||||
if atom.worlds:
|
||||
self.unused_worlds = unused.worlds()
|
||||
self.unused_worlds = all_unused['worlds']
|
||||
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
@@ -359,30 +411,20 @@ class ATOMIC_OT_smart_select(bpy.types.Operator):
|
||||
bl_label = "Smart Select"
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
bpy.context.scene.atomic.collections = \
|
||||
any(unused.collections_deep())
|
||||
|
||||
bpy.context.scene.atomic.images = \
|
||||
any(unused.images_deep())
|
||||
|
||||
bpy.context.scene.atomic.lights = \
|
||||
any(unused.lights_deep())
|
||||
|
||||
bpy.context.scene.atomic.materials = \
|
||||
any(unused.materials_deep())
|
||||
|
||||
bpy.context.scene.atomic.node_groups = \
|
||||
any(unused.node_groups_deep())
|
||||
|
||||
bpy.context.scene.atomic.particles = \
|
||||
any(unused.particles_deep())
|
||||
|
||||
bpy.context.scene.atomic.textures = \
|
||||
any(unused.textures_deep())
|
||||
|
||||
bpy.context.scene.atomic.worlds = \
|
||||
any(unused.worlds())
|
||||
# Use parallel execution for better performance
|
||||
unused_flags = unused_parallel.get_unused_for_smart_select()
|
||||
|
||||
atom = bpy.context.scene.atomic
|
||||
atom.collections = unused_flags['collections']
|
||||
atom.images = unused_flags['images']
|
||||
atom.lights = unused_flags['lights']
|
||||
atom.materials = unused_flags['materials']
|
||||
atom.node_groups = unused_flags['node_groups']
|
||||
atom.objects = unused_flags['objects']
|
||||
atom.particles = unused_flags['particles']
|
||||
atom.textures = unused_flags['textures']
|
||||
atom.armatures = unused_flags['armatures']
|
||||
atom.worlds = unused_flags['worlds']
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@@ -441,4 +483,4 @@ def register():
|
||||
|
||||
def unregister():
|
||||
for item in reg_list:
|
||||
unregister_class(item)
|
||||
compat.safe_unregister_class(item)
|
||||
|
||||
@@ -31,7 +31,7 @@ attempting to reload missing project files.
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class
|
||||
from bpy.utils import unregister_class
|
||||
from ..utils import compat
|
||||
from ..stats import missing
|
||||
from ..ui.utils import ui_layouts
|
||||
|
||||
@@ -192,4 +192,4 @@ def register():
|
||||
|
||||
def unregister():
|
||||
for item in reg_list:
|
||||
unregister_class(item)
|
||||
compat.safe_unregister_class(item)
|
||||
|
||||
@@ -28,7 +28,7 @@ support page in the web browser.
|
||||
import bpy
|
||||
import webbrowser
|
||||
from bpy.utils import register_class
|
||||
from bpy.utils import unregister_class
|
||||
from ..utils import compat
|
||||
|
||||
|
||||
# Atomic Data Manager Open Support Me Operator
|
||||
@@ -52,4 +52,4 @@ def register():
|
||||
|
||||
def unregister():
|
||||
for cls in reg_list:
|
||||
unregister_class(cls)
|
||||
compat.safe_unregister_class(cls)
|
||||
|
||||
@@ -72,3 +72,15 @@ def worlds():
|
||||
# removes all unused worlds from the project
|
||||
for world_key in unused.worlds():
|
||||
bpy.data.worlds.remove(bpy.data.worlds[world_key])
|
||||
|
||||
|
||||
def objects():
|
||||
# removes all unused objects from the project
|
||||
for object_key in unused.objects_deep():
|
||||
bpy.data.objects.remove(bpy.data.objects[object_key])
|
||||
|
||||
|
||||
def armatures():
|
||||
# removes all unused armatures from the project
|
||||
for armature_key in unused.armatures_deep():
|
||||
bpy.data.armatures.remove(bpy.data.armatures[armature_key])
|
||||
|
||||
@@ -24,11 +24,18 @@ data categories.
|
||||
"""
|
||||
|
||||
import bpy
|
||||
from ...utils import compat
|
||||
|
||||
|
||||
def nuke_data(data):
|
||||
# removes all data-blocks from the indicated set of data
|
||||
# Skip library-linked and override datablocks
|
||||
keys_to_remove = []
|
||||
for key in data.keys():
|
||||
datablock = data[key]
|
||||
if not compat.is_library_or_override(datablock):
|
||||
keys_to_remove.append(key)
|
||||
for key in keys_to_remove:
|
||||
data.remove(data[key])
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user