clean-up to simplify maintenance: remove non optimized export. Clean to minimize...
[blender-addons-contrib.git] / object_edit_linked.py
1 # ***** BEGIN GPL LICENSE BLOCK *****
2 #
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 #
18 # ***** END GPL LICENCE BLOCK *****
19
20 bl_info = {
21     "name": "Edit Linked Library",
22     "author": "Jason van Gumster (Fweeb)",
23     "version": (0, 7, 0),
24     "blender": (2, 6, 0),
25     "location": "View3D > Toolshelf > Edit Linked Library",
26     "description": "Allows editing of objects linked from a .blend library.",
27     "wiki_url": "http://wiki.blender.org/index.php?title=Extensions:2.5/Py/Scripts/Object/Edit_Linked_Library",
28     "tracker_url": "http://projects.blender.org/tracker/index.php?func=detail&aid=29630&group_id=153&atid=467",
29     "category": "Object"}
30     
31
32 import bpy
33 from bpy.app.handlers import persistent
34
35 settings = {
36     "original_file": "",
37     "linked_file": "",
38     "linked_objects": [],
39     }
40
41 @persistent
42 def linked_file_check(context):
43     if settings["linked_file"] != "":
44         if settings["linked_file"] in {bpy.data.filepath, bpy.path.abspath(bpy.data.filepath)}:
45             print("Editing a linked library.")
46             bpy.ops.object.select_all(action = 'DESELECT')
47             for ob_name in settings["linked_objects"]:
48                 bpy.data.objects[ob_name].select = True
49             if len(settings["linked_objects"]) == 1:
50                 bpy.context.scene.objects.active = bpy.data.objects[settings["linked_objects"][0]]
51         else:
52             # For some reason, the linked editing session ended (failed to find a file or opened a different file before returning to the originating .blend)
53             settings["original_file"] = ""
54             settings["linked_file"] = ""
55
56
57
58 class EditLinked(bpy.types.Operator):
59     '''Edit Linked Library'''
60     bl_idname = "object.edit_linked"
61     bl_label = "Edit Linked Library"
62
63     autosave = bpy.props.BoolProperty(name = "Autosave", description = "Automatically save the current file before opening the linked library", default = True)
64
65     @classmethod
66     def poll(cls, context):
67         return context.active_object is not None
68
69     def execute(self, context):
70         #print(bpy.context.active_object.library)
71         target = context.active_object
72
73         if target.dupli_group and target.dupli_group.library:
74             targetpath = target.dupli_group.library.filepath
75             settings["linked_objects"].extend([ob.name for ob in target.dupli_group.objects])
76         elif target.library:
77             targetpath = target.library.filepath
78             settings["linked_objects"].append(target.name)
79
80         if targetpath:
81             print(target.name + " is linked to " + targetpath)
82
83             if self.properties.autosave == True:
84                 bpy.ops.wm.save_mainfile()
85
86             settings["original_file"] = bpy.data.filepath
87
88             # XXX: need to test for proxied rigs
89             settings["linked_file"] = bpy.path.abspath(targetpath)
90
91             bpy.ops.wm.open_mainfile(filepath=settings["linked_file"])
92             print("Opened linked file!")
93         else:
94             self.report({'WARNING'}, target.name + " is not linked")
95             print(target.name + " is not linked")
96
97         return {'FINISHED'}
98
99
100 class ReturnToOriginal(bpy.types.Operator):
101     '''Return to the original file after editing the linked library .blend'''
102     bl_idname = "wm.return_to_original"
103     bl_label = "Return to Original File"
104
105     autosave = bpy.props.BoolProperty(name = "Autosave", description = "Automatically save the current file before opening original file", default = True)
106
107     @classmethod
108     def poll(cls, context):
109         # Probably the wrong context to check for here...
110         return context.active_object is not None
111     
112     def execute(self, context):
113         if self.properties.autosave == True:
114             bpy.ops.wm.save_mainfile()
115         bpy.ops.wm.open_mainfile(filepath=settings["original_file"])
116         settings["original_file"] = ""
117         settings["linked_objects"] = []
118         print("Back to the original!")
119         return {'FINISHED'}
120
121
122 # UI
123 # TODO: Add operators to the File menu? Hide the entire panel for non-linked objects?
124 class PanelLinkedEdit(bpy.types.Panel):
125     bl_label = "Edit Linked Library"
126     bl_space_type = "VIEW_3D"
127     bl_region_type = "TOOLS"
128
129
130     def draw(self, context):
131         kc = bpy.context.window_manager.keyconfigs.addon
132         km = kc.keymaps["3D View"]
133         kmi_edit = km.keymap_items["object.edit_linked"]
134         kmi_return = km.keymap_items["wm.return_to_original"]
135
136         if settings["original_file"] == "" and ((context.active_object.dupli_group and context.active_object.dupli_group.library is not None) or context.active_object.library is not None):
137             kmi_edit.active = True
138             kmi_return.active = False
139             self.layout.operator("object.edit_linked").autosave = context.scene.edit_linked_autosave
140             self.layout.prop(context.scene, "edit_linked_autosave")
141         elif settings["original_file"] != "":
142             kmi_edit.active = False
143             kmi_return.active = True
144             self.layout.operator("wm.return_to_original").autosave = context.scene.edit_linked_autosave
145             self.layout.prop(context.scene, "edit_linked_autosave")
146         else:
147             kmi_edit.active = False
148             kmi_return.active = False
149             self.layout.label(text = "Active object is not linked")
150
151
152 bpy.app.handlers.load_post.append(linked_file_check)
153
154
155 def register():
156     bpy.utils.register_class(EditLinked)
157     bpy.utils.register_class(ReturnToOriginal)
158     bpy.utils.register_class(PanelLinkedEdit)
159
160     # Is there a better place to store this property?
161     bpy.types.Scene.edit_linked_autosave = bpy.props.BoolProperty(name = "Autosave", description = "Automatically save the current file before opening a linked file", default = True)
162
163     # Keymapping (deactivated by default; activated when a library object is selected)
164     kc = bpy.context.window_manager.keyconfigs.addon
165     km = kc.keymaps.new(name = "3D View", space_type='VIEW_3D')
166     kmi = km.keymap_items.new("object.edit_linked", 'NUMPAD_SLASH', 'PRESS', shift = True)
167     kmi.active = False
168     kmi = km.keymap_items.new("wm.return_to_original", 'NUMPAD_SLASH', 'PRESS', shift = True)
169     kmi.active = False
170
171
172 def unregister():
173     bpy.utils.unregister_class(EditLinked)
174     bpy.utils.unregister_class(SaveAndResume)
175     bpy.utils.unregister_class(PanelLinkedEdit)
176
177     del bpy.types.Scene.edit_linked_autosave
178
179     kc = bpy.context.window_manager.keyconfigs.addon
180     km = kc.keymaps["3D View"]
181     km.keymap_items.remove(km.keymap_items["object.edit_linked"])
182     km.keymap_items.remove(km.keymap_items["wm.return_to_original"])
183
184
185 if __name__ == "__main__":
186     register()