Orphan Slayer - Clears Scenes and Removes Unused Objects

I’m working on this tool for clearing scenes and removing unused objects from a Blender project. Not sure whether or not I’m reinventing any wheels here but … here it is! :evilgrin:


# orphan_slayer.py (c) 2011 Phil Cote (cotejrp1)
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

bl_info = {
    'name': 'Orphan Slayer',
    'author': 'Phil Cote, cotejrp1, (http://www.blenderaddons.com)',
    'version': (0,1),
    "blender": (2, 5, 9),
    "api": 35853,
    'location': 'VIEW 3D -> TOOLS',
    'description': 'Deletes objects from a scene and from the bpy.data modules',
    'warning': '', # used for warning icon and text in addons panel
    'category': 'System'}

import bpy, random, time
from pdb import set_trace

    
class DeleteSceneObsOp(bpy.types.Operator):
    '''.'''
    bl_idname = "ba.delete_scene_obs"
    bl_label = "Delete Scene Objects"

    def execute(self, context):
        for ob in context.scene.objects:
            context.scene.objects.unlink(ob)
        return {'FINISHED'}


class DeleteOrphansOp(bpy.types.Operator):
    
    bl_idname="ba.delete_data_obs"
    bl_label="Delete Orphans"
    
    def execute(self, context):
        target_coll = eval("bpy.data." + context.scene.mod_list)
        print("chosen target collection: " + str(target_coll))
        print( "size of target collection: %d" % len(target_coll) )
        for item in target_coll:
            if item.users == 0:
                target_coll.remove(item)
        
        return {'FINISHED'}
    

class OrphanSlayerPanel( bpy.types.Panel ):
    
    bl_label = "Orphan Slayer"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "objectmode"
    
    def draw( self, context ):
        scn = context.scene
        
        layout = self.layout
        col = layout.column()
        layout.column().prop(scn, "mod_list")
        col.operator("ba.delete_scene_obs")
        col.operator("ba.delete_data_obs")
    

def register():

    mod_data = [tuple(["actions"]*3), tuple(["armatures"]*3), 
                 tuple(["cameras"]*3), tuple(["curves"]*3),
                 tuple(["fonts"]*3), tuple(["grease_pencil"]*3),
                 tuple(["groups"]*3), tuple(["images"]*3),
                 tuple(["lamps"]*3), tuple(["lattices"]*3),
                 tuple(["libraries"]*3), tuple(["materials"]*3),
                 tuple(["meshes"]*3), tuple(["metaballs"]*3),
                 tuple(["node_groups"]*3), tuple(["objects"]*3),
                 tuple(["sounds"]*3), tuple(["texts"]*3), 
                 tuple(["textures"]*3),]
    
    
    bpy.types.Scene.mod_list = bpy.props.EnumProperty(name="Orphan Target", 
                                                        items=mod_data, 
                                                        description="Module choice made for orphan deletion")
    bpy.utils.register_class(DeleteSceneObsOp)
    bpy.utils.register_class(DeleteOrphansOp)
    bpy.utils.register_class(OrphanSlayerPanel)
    

def unregister():
    bpy.utils.unregister_class(DeleteSceneObsOp)
    bpy.utils.unregister_class(DeleteOrphansOp)
    bpy.utils.unregister_class(OrphanSlayerPanel)


if __name__ == "__main__":
    register()

Thank you!
I needed to destroy old materials for the cycles render engine lately , very handy!

Glad you found it useful, Tungee.

A few quick changes to the script…

  1. Dumped the silly name. Changed it to “Orphan Cleanup”. (still officially Orphan Slayer in Github)
  2. Dumped the “Delete scene objects” button. It didn’t really need to be there and had potential for being mistaken for a “delete by type” button.

Here’s the update.


# orphan_cleanup.py (c) 2011 Phil Cote (cotejrp1)
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

bl_info = {
    'name': 'Orphan Slayer',
    'author': 'Phil Cote, cotejrp1, (http://www.blenderaddons.com)',
    'version': (0,1),
    "blender": (2, 5, 9),
    "api": 35853,
    'location': 'VIEW 3D -> TOOLS',
    'description': 'Deletes unused objects from the bpy.data modules',
    'warning': '', # used for warning icon and text in addons panel
    'category': 'System'}

import bpy, random, time
from pdb import set_trace

class DeleteOrphansOp(bpy.types.Operator):
    '''Remove all orphaned objects of a selected type from the project.'''
    bl_idname="ba.delete_data_obs"
    bl_label="Delete Orphans"
    
    def execute(self, context):
        target = context.scene.mod_list
        target_coll = eval("bpy.data." + target)
        
        num_deleted = 0
        
        for item in target_coll:
            if item.users == 0:
                target_coll.remove(item)
                num_deleted += 1
        
        msg = "Removed %d orphaned %s objects" % (num_deleted, target)
        self.report( { 'INFO' }, msg  )
        return {'FINISHED'}
    

class OrphanCleanupPanel( bpy.types.Panel ):
    '''Main Panel for Orphan Cleanup script'''
    bl_label = "Orphan Cleanup"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "objectmode"
    
    def draw( self, context ):
        scn = context.scene
        layout = self.layout
        new_col = self.layout.column
        
        new_col().column().prop(scn, "mod_list")
        new_col().column().operator("ba.delete_data_obs")
    

def register():

    mod_data = [tuple(["actions"]*3), tuple(["armatures"]*3), 
                 tuple(["cameras"]*3), tuple(["curves"]*3),
                 tuple(["fonts"]*3), tuple(["grease_pencil"]*3),
                 tuple(["groups"]*3), tuple(["images"]*3),
                 tuple(["lamps"]*3), tuple(["lattices"]*3),
                 tuple(["libraries"]*3), tuple(["materials"]*3),
                 tuple(["meshes"]*3), tuple(["metaballs"]*3),
                 tuple(["node_groups"]*3), tuple(["objects"]*3),
                 tuple(["sounds"]*3), tuple(["texts"]*3), 
                 tuple(["textures"]*3),]
    
    
    bpy.types.Scene.mod_list = bpy.props.EnumProperty(name="Target", 
                           items=mod_data, 
                           description="Module choice made for orphan deletion")

    bpy.utils.register_class(DeleteOrphansOp)
    bpy.utils.register_class(OrphanCleanupPanel)
    

def unregister():
    bpy.utils.unregister_class(OrphanCleanupPanel)
    bpy.utils.unregister_class(DeleteOrphansOp)


if __name__ == "__main__":
    register()

Good works. instead of individualorphan, im look forward deleting “All” orphan could be nice.

example

mod_data = [tuple([“actions”]*3), tuple([“armatures”]*3), tuple([“cameras”]*3), tuple([“curves”]*3), tuple([“fonts”]*3), tuple([“grease_pencil”]*3), tuple([“groups”]*3), tuple([“images”]*3), tuple([“lamps”]*3), tuple([“lattices”]*3), tuple([“libraries”]*3), tuple([“materials”]*3), tuple([“meshes”]*3), tuple([“metaballs”]*3), tuple([“node_groups”]*3), tuple([“objects”]*3), tuple([“sounds”]*3), tuple([“texts”]*3), tuple([“textures”]*3),tuple([“All”]*3) ]
Drop menu “All” inserted.may be “while” or “for” loop used.

Thank you!

Welcome to the forums MetalDX. I’m a little hesitant to add the all feature because it seems like it would make it a little too powerful. I think it’s better that the artist think through what resources they do and don’t want to get rid of even as orphans are concerned.

this is very helpful, i was wondering… for stripping blend files down, cleaning them up…
the UV image editor stores image names etc… render result,
and the names of the textures that you have used thus far in the bulding process(yes i used thus :slight_smile:

anyhow, could you orphan slay these words in the uv image editor?


for some reason appending the meshes out of the blend file doesnt work either… <br>
those uv editor words come with it… strange…
:confused:

Oh i think i figured it out… <br>
IF you orphan slay the material and textures then save and append the meshes into a fresh file,<br>
you will only get the names of the stuff in the current file.<br>
there should be a button (Remove all materials and textures, Strip Blend File)
then after you click it it will say “are you sure, all materials and textures in the blend file will be removed”<br>
(a safety feature)

An interesting idea. I never thought to do anything that would mess with the blend file itself, just the project in memory. I’ll look into it and see what I can do.

Got back to this project today and did some updates so it could delete speakers in 2.6. Also updated the deletion message so users know how many non-orphaned assets remain for a particular type.

Holyenigma. You don’t need to save into a new file in order to remove images. After poking around, I discovered you can shift click the ‘X’ in that image list in the UV editor. That should unlink and thus orphan them. Then you can use my tool to get rid of them like any other resource.

As for the stripping all textures and materials from a blend file on disk, that goes a little beyond the scope of what I was going for in this add-on. It’s not a bad idea, just one that I think would be best done with a separate tool. Here’s the update at any rate.


# orphan_cleanup.py (c) 2011 Phil Cote (cotejrp1)
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

bl_info = {
    'name': 'Orphan Cleanup',
    'author': 'Phil Cote, cotejrp1, (http://www.blenderaddons.com)',
    'version': (0,2),
    "blender": (2, 6, 0),
    "api": 41098,
    'location': 'VIEW 3D -&gt; TOOLS',
    'description': 'Deletes unused objects from the bpy.data modules',
    'warning': 'Know what it is you are deleting. Check datablocks view within outliner if there are any doubts!', # used for warning icon and text in addons panel
    'category': 'System'}

import bpy, random, time
from pdb import set_trace

mod_data = [tuple(["actions"]*3), tuple(["armatures"]*3), 
                 tuple(["cameras"]*3), tuple(["curves"]*3),
                 tuple(["fonts"]*3), tuple(["grease_pencil"]*3),
                 tuple(["groups"]*3), tuple(["images"]*3),
                 tuple(["lamps"]*3), tuple(["lattices"]*3),
                 tuple(["libraries"]*3), tuple(["materials"]*3),
                 tuple(["meshes"]*3), tuple(["metaballs"]*3),
                 tuple(["node_groups"]*3), tuple(["objects"]*3),
                 tuple(["sounds"]*3), tuple(["texts"]*3), 
                 tuple(["textures"]*3),]

if bpy.app.version[1] &gt;= 60:
    mod_data.append( tuple(["speakers"]*3), )


class DeleteOrphansOp(bpy.types.Operator):
    '''Remove all orphaned objects of a selected type from the project.'''
    bl_idname="ba.delete_data_obs"
    bl_label="Delete Orphans"
    
    def execute(self, context):
        target = context.scene.mod_list
        target_coll = eval("bpy.data." + target)
        
        num_deleted = len([x for x in target_coll if x.users==0])
        num_kept = len([x for x in target_coll if x.users==1])
        
        for item in target_coll:
            if item.users == 0:
                target_coll.remove(item)
        
        msg = "Removed %d orphaned %s objects. Kept %d non-orphans" % (num_deleted, target,
                                                            num_kept)
        self.report( { 'INFO' }, msg  )
        return {'FINISHED'}
    

class OrphanCleanupPanel( bpy.types.Panel ):
    '''Main Panel for Orphan Cleanup script'''
    bl_label = "Orphan Cleanup"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "objectmode"
    
    def draw( self, context ):
        scn = context.scene
        layout = self.layout
        new_col = self.layout.column
        
        new_col().column().prop(scn, "mod_list")
        new_col().column().operator("ba.delete_data_obs")
    

def register():
    
    
    bpy.types.Scene.mod_list = bpy.props.EnumProperty(name="Target", 
                           items=mod_data, 
                           description="Module choice made for orphan deletion")

    bpy.utils.register_class(DeleteOrphansOp)
    bpy.utils.register_class(OrphanCleanupPanel)
    

def unregister():
    bpy.utils.unregister_class(OrphanCleanupPanel)
    bpy.utils.unregister_class(DeleteOrphansOp)


if __name__ == "__main__":
    register()


Interesting script. Thanks!

Just a quick feedback after trying this script: I experience an heavy flickering effect while choosing which type of object I want to be cleaned. The menu content is hardly readable, it shows up and disappear continuously.

Edit: nevermind, probably an issue on my side because I got the same weird flickering with the standard W menu. Gonna reboot and see if it happen again.

Oh yeah! I was having annoying issues with packing a file for Greenbutton - Solved! Thanks so much. We love you orphan slayer :wink:

Can this kill screen view setups too? I have a couple that crash blender in a project with dubious scenes.

I’m not sure how I would pull that off. For all the other types that this tool supports, it assumes the existence of a remove() function as part of the data list. The list of screens doesn’t come with a remove option. I wish it did because I think it’s a really good idea.

This script is one of my absolute favourites but I’ve encountered an inability to remove Grease Pencil orphans.
Blender 2.61.2 r43328 Linux64

Here’s the error incase you’d like to look into it:

File “~/.blender/2.61/scripts/addons/orphan_cleanup.py”, line 65, in execute
target_coll.remove(item)
AttributeError: ‘bpy_prop_collection’ object has no attribute ‘remove’

location:<unknown location>:-1

location:<unknown location>:-1

Thanks

thanks,very usefull script.

You don’t need to save into a new file in order to remove images. After poking around, I discovered you can shift click the ‘X’ in that image list in the UV editor. That should unlink and thus orphan them. Then you can use my tool to get rid of them like any other resource.

please add this usage note as part of download.

Hi, I’m new here as well as in Blender, I’ve tried to install this addon, but Report an error. I’ll be doing something wrong?

Just an fyi:
I’ve been away from Blender for way too long and I admit I’ve let myself get a bit rusty. That being said, I started working on a new git branch update on orphan slayer. It’s absolutely a buggy untested WIP right now but here’s the url to that in case anyone is curious.

Update:
A somewhat closer to comprehensive set of options for deletable datablocks. I wasn’t able to test everything because I don’t know how to create every data block out there under “normal” circumstances. Here’s the update at any rate.


# orphan_cleanup.py (c) 2011 Phil Cote (cotejrp1)
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

bl_info = {
    'name': 'Orphan Cleanup',
    'author': 'Phil Cote, cotejrp1, (http://www.blenderaddons.com)',
    'version': (0,2),
    "blender": (2, 7, 6),
    'location': 'VIEW 3D -&gt; TOOLS',
    'description': 'Deletes unused objects from the bpy.data modules',
    'warning': 'Know what it is you are deleting. Check datablocks view within outliner if there are any doubts!', # used for warning icon and text in addons panel
    'category': 'System'}

"""
Special note on image removal.
It's not necessary to save into a new file in order to remove images.
Shift-click the X in the image list in the UV editor.  That should unlink and thus
orphan them.  From there, you can use this tool to get rid of the images just like
you would any other resource.
"""

import bpy, random, time

mod_data = [tuple(["actions"]*3),
            tuple(["armatures"]*3),
            tuple(["brushes"]*3),
            tuple(["cameras"]*3),
            tuple(["curves"]*3),
            tuple(["fonts"]*3),
            tuple(["grease_pencil"]*3),
            tuple(["groups"]*3),
            tuple(["images"]*3),
            tuple(["lamps"]*3),
            tuple(["lattices"]*3),
            tuple(["libraries"]*3),
            tuple(["linestyles"]*3),
            tuple(["materials"]*3),
            tuple(["masks"]*3),
            tuple(["meshes"]*3),
            tuple(["metaballs"]*3),
            tuple(["movieclips"]*3),
            tuple(["node_groups"]*3),
            tuple(["objects"]*3),
            tuple(["particles"]*3),
            tuple(["sounds"]*3),
            tuple(["scenes"]*3),
            tuple(["speakers"]*3),
            tuple(["texts"]*3),
            tuple(["textures"]*3),
            tuple(["worlds"]*3),
]



class DeleteOrphansOp(bpy.types.Operator):
    '''Remove all orphaned objects of a selected type from the project'''
    bl_idname="ba.delete_data_obs"
    bl_label="Delete Orphans"
    
    def execute(self, context):
        target = context.scene.mod_list
        target_coll = eval("bpy.data." + target)
        
        num_deleted = len([x for x in target_coll if x.users==0])
        num_kept = len([x for x in target_coll if x.users==1])
        
        for item in target_coll:
            if item.users == 0:
                target_coll.remove(item)
        
        msg = "Removed %d orphaned %s objects. Kept %d non-orphans" % (num_deleted, target,
                                                            num_kept)
        self.report( { 'INFO' }, msg  )
        return {'FINISHED'}
    

class OrphanCleanupPanel( bpy.types.Panel ):
    '''Main Panel for Orphan Cleanup script'''
    bl_label = "Orphan Cleanup"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "objectmode"
    
    def draw( self, context ):
        scn = context.scene
        layout = self.layout
        new_col = self.layout.column
        
        new_col().column().prop(scn, "mod_list")
        new_col().column().operator("ba.delete_data_obs")
        
        
        
    

def register():
    #set_trace()
    #screen_names = [ (screen.name, screen.name, screen.name ) 
    #                    for screen in bpy.data.screens ]
    #bpy.types.Scene.screen_names = bpy.props.EnumProperty(name="Views",
    #                        items=screen_names,
    #                        description = "Possible views to delete"
    #)
    bpy.types.Scene.mod_list = bpy.props.EnumProperty(name="Target", 
                           items=mod_data, 
                           description="Module choice made for orphan deletion")

    bpy.utils.register_class(DeleteOrphansOp)
    bpy.utils.register_class(OrphanCleanupPanel)
    

def unregister():
    bpy.utils.unregister_class(OrphanCleanupPanel)
    bpy.utils.unregister_class(DeleteOrphansOp)


if __name__ == "__main__":
    register()

Another update. Decided to add an “all of the above” option for orphaned datablocks.


# orphan_cleanup.py (c) 2011 Phil Cote (cotejrp1)
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****

bl_info = {
    'name': 'Orphan Cleanup',
    'author': 'Phil Cote, cotejrp1, (http://www.blenderaddons.com)',
    'version': (0,2),
    "blender": (2, 7, 6),
    'location': 'VIEW 3D -&gt; TOOLS',
    'description': 'Deletes unused objects from the bpy.data modules',
    'warning': 'Know what it is you are deleting. Check datablocks view within outliner if there are any doubts!', # used for warning icon and text in addons panel
    'category': 'System'}

"""
Special note on image removal.
It's not necessary to save into a new file in order to remove images.
Shift-click the X in the image list in the UV editor.  That should unlink and thus
orphan them.  From there, you can use this tool to get rid of the images just like
you would any other resource.
"""

import bpy, random, time
from collections import namedtuple


mod_data = [tuple(["actions"]*3),
            tuple(["armatures"]*3),
            tuple(["brushes"]*3),
            tuple(["cameras"]*3),
            tuple(["curves"]*3),
            tuple(["fonts"]*3),
            tuple(["grease_pencil"]*3),
            tuple(["groups"]*3),
            tuple(["images"]*3),
            tuple(["lamps"]*3),
            tuple(["lattices"]*3),
            tuple(["libraries"]*3),
            tuple(["linestyles"]*3),
            tuple(["materials"]*3),
            tuple(["masks"]*3),
            tuple(["meshes"]*3),
            tuple(["metaballs"]*3),
            tuple(["movieclips"]*3),
            tuple(["node_groups"]*3),
            tuple(["objects"]*3),
            tuple(["particles"]*3),
            tuple(["sounds"]*3),
            tuple(["scenes"]*3),
            tuple(["speakers"]*3),
            tuple(["texts"]*3),
            tuple(["textures"]*3),
            tuple(["worlds"]*3),
            tuple(["everything"]*3),
]



class DeleteOrphansOp(bpy.types.Operator):
    '''Remove all orphaned objects of a selected type from the project'''
    bl_idname="ba.delete_data_obs"
    bl_label="Delete Orphans"
    
    def execute(self, context):    
        
        target = context.scene.mod_list
        every_block_name = 
[list(x)[0] for x in bpy.types.Scene.mod_list[1]["items"] 
                        if list(x)[0] != "everything"]
        
        def _delete_orphans(target_coll):
            DeletionStats = namedtuple("DeletionStats", ["num_deleted", "num_kept"])
            num_deleted = len([x for x in target_coll if x.users==0])
            num_kept = len([x for x in target_coll if x.users==1])

            for item in target_coll:
                if item.users == 0:
                    target_coll.remove(item)

            return DeletionStats(num_deleted, num_kept)

        num_deleted, num_kept = 0, 0
        if target == "everything":
            for block_name in every_block_name:
                target_coll = eval("bpy.data.{}".format(block_name))
                deleted, kept = _delete_orphans(target_coll)
                num_deleted += deleted
                num_kept += kept

        else:
            target_coll = eval("bpy.data." + target)
            num_deleted, num_kept = _delete_orphans(target_coll)
        
        msg = "Removed %d orphaned %s objects. Kept %d non-orphans" % (num_deleted, target,
                                                            num_kept)
        self.report( { 'INFO' }, msg  )
        return {'FINISHED'}
    

class OrphanCleanupPanel( bpy.types.Panel ):
    '''Main Panel for Orphan Cleanup script'''
    bl_label = "Orphan Cleanup"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "objectmode"
    
    def draw( self, context ):
        scn = context.scene
        layout = self.layout
        new_col = self.layout.column
        
        new_col().column().prop(scn, "mod_list")
        new_col().column().operator("ba.delete_data_obs")
        
        
        
    

def register():
    #set_trace()
    #screen_names = [ (screen.name, screen.name, screen.name ) 
    #                    for screen in bpy.data.screens ]
    #bpy.types.Scene.screen_names = bpy.props.EnumProperty(name="Views",
    #                        items=screen_names,
    #                        description = "Possible views to delete"
    #)
    bpy.types.Scene.mod_list = bpy.props.EnumProperty(name="Target", 
                           items=mod_data, 
                           description="Module choice made for orphan deletion")

    bpy.utils.register_class(DeleteOrphansOp)
    bpy.utils.register_class(OrphanCleanupPanel)
    

def unregister():
    bpy.utils.unregister_class(OrphanCleanupPanel)
    bpy.utils.unregister_class(DeleteOrphansOp)


if __name__ == "__main__":
    register()