Remove workaround for uuid, resolved with the Python3.4x and MSVC2013 move.
[blender-addons.git] / object_edit_linked.py
blobcbb75654ffe13e0137cea42de5f709eb66ce1244
1 # ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 # ***** END GPL LICENCE BLOCK *****
20 bl_info = {
21 "name": "Edit Linked Library",
22 "author": "Jason van Gumster (Fweeb), Bassam Kurdali, Pablo Vazquez",
23 "version": (0, 8, 0),
24 "blender": (2, 65, 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.6/Py/Scripts/Object/Edit_Linked_Library",
28 "tracker_url": "https://developer.blender.org/T29630",
29 "category": "Object"}
32 import bpy
33 from bpy.app.handlers import persistent
34 import os
36 settings = {
37 "original_file": "",
38 "linked_file": "",
39 "linked_objects": [],
43 @persistent
44 def linked_file_check(context):
45 if settings["linked_file"] != "":
46 if os.path.samefile(settings["linked_file"], bpy.data.filepath):
47 print("Editing a linked library.")
48 bpy.ops.object.select_all(action='DESELECT')
49 for ob_name in settings["linked_objects"]:
50 bpy.data.objects[ob_name].select = True # XXX Assumes selected object is in the active scene
51 if len(settings["linked_objects"]) == 1:
52 bpy.context.scene.objects.active = bpy.data.objects[settings["linked_objects"][0]]
53 else:
54 # For some reason, the linked editing session ended
55 # (failed to find a file or opened a different file
56 # before returning to the originating .blend)
57 settings["original_file"] = ""
58 settings["linked_file"] = ""
61 class EditLinked(bpy.types.Operator):
62 """Edit Linked Library"""
63 bl_idname = "object.edit_linked"
64 bl_label = "Edit Linked Library"
66 use_autosave = bpy.props.BoolProperty(
67 name="Autosave",
68 description="Save the current file before opening the linked library",
69 default=True)
70 use_instance = bpy.props.BoolProperty(
71 name="New Blender Instance",
72 description="Open in a new Blender instance",
73 default=False)
75 @classmethod
76 def poll(cls, context):
77 return settings["original_file"] == "" and context.active_object is not None and (
78 (context.active_object.dupli_group and
79 context.active_object.dupli_group.library is not None) or
80 (context.active_object.proxy and
81 context.active_object.proxy.library is not None) or
82 context.active_object.library is not None)
83 #return context.active_object is not None
85 def execute(self, context):
86 #print(bpy.context.active_object.library)
87 target = context.active_object
89 if target.dupli_group and target.dupli_group.library:
90 targetpath = target.dupli_group.library.filepath
91 settings["linked_objects"].extend({ob.name for ob in target.dupli_group.objects})
92 elif target.library:
93 targetpath = target.library.filepath
94 settings["linked_objects"].append(target.name)
95 elif target.proxy:
96 target = target.proxy
97 targetpath = target.library.filepath
98 settings["linked_objects"].append(target.name)
100 if targetpath:
101 print(target.name + " is linked to " + targetpath)
103 if self.use_autosave:
104 bpy.ops.wm.save_mainfile()
106 settings["original_file"] = bpy.data.filepath
107 settings["linked_file"] = bpy.path.abspath(targetpath)
109 if self.use_instance:
110 import subprocess
111 try:
112 subprocess.Popen([bpy.app.binary_path, settings["linked_file"]])
113 except:
114 print("Error on the new Blender instance")
115 import traceback
116 traceback.print_exc()
117 else:
118 bpy.ops.wm.open_mainfile(filepath=settings["linked_file"])
120 print("Opened linked file!")
121 else:
122 self.report({'WARNING'}, target.name + " is not linked")
123 print(target.name + " is not linked")
125 return {'FINISHED'}
128 class ReturnToOriginal(bpy.types.Operator):
129 """Load the original file"""
130 bl_idname = "wm.return_to_original"
131 bl_label = "Return to Original File"
133 use_autosave = bpy.props.BoolProperty(
134 name="Autosave",
135 description="Save the current file before opening original file",
136 default=True)
138 @classmethod
139 def poll(cls, context):
140 return (settings["original_file"] != "")
142 def execute(self, context):
143 if self.use_autosave:
144 bpy.ops.wm.save_mainfile()
146 bpy.ops.wm.open_mainfile(filepath=settings["original_file"])
148 settings["original_file"] = ""
149 settings["linked_objects"] = []
150 print("Back to the original!")
151 return {'FINISHED'}
154 # UI
155 # TODO:Add operators to the File menu?
156 # Hide the entire panel for non-linked objects?
157 class PanelLinkedEdit(bpy.types.Panel):
158 bl_label = "Edit Linked Library"
159 bl_space_type = "VIEW_3D"
160 bl_region_type = "TOOLS"
161 bl_category = "Relations"
163 @classmethod
164 def poll(cls, context):
165 return (context.active_object is not None) or (settings["original_file"] != "")
167 def draw(self, context):
168 layout = self.layout
169 scene = context.scene
170 icon = "OUTLINER_DATA_" + context.active_object.type
172 target = None
174 if context.active_object.proxy:
175 target = context.active_object.proxy
176 else:
177 target = context.active_object.dupli_group
179 if settings["original_file"] == "" and (
180 (target and
181 target.library is not None) or
182 context.active_object.library is not None):
184 if (target is not None):
185 props = layout.operator("object.edit_linked", icon="LINK_BLEND",
186 text="Edit Library: %s" % target.name)
187 else:
188 props = layout.operator("object.edit_linked", icon="LINK_BLEND",
189 text="Edit Library: %s" % context.active_object.name)
190 props.use_autosave = scene.use_autosave
191 props.use_instance = scene.use_instance
193 layout.prop(scene, "use_autosave")
194 layout.prop(scene, "use_instance")
196 if (target is not None):
197 layout.label(text="Path: %s" %
198 target.library.filepath)
199 else:
200 layout.label(text="Path: %s" %
201 context.active_object.library.filepath)
203 elif settings["original_file"] != "":
205 if scene.use_instance:
206 layout.operator("wm.return_to_original",
207 text="Reload Current File",
208 icon="FILE_REFRESH").use_autosave = False
210 layout.separator()
212 #XXX - This is for nested linked assets... but it only works
213 # when launching a new Blender instance. Nested links don't
214 # currently work when using a single instance of Blender.
215 props = layout.operator("object.edit_linked",
216 text="Edit Library: %s" % context.active_object.dupli_group.name,
217 icon="LINK_BLEND")
218 props.use_autosave = scene.use_autosave
219 props.use_instance = scene.use_instance
220 layout.prop(scene, "use_autosave")
221 layout.prop(scene, "use_instance")
223 layout.label(text="Path: %s" %
224 context.active_object.dupli_group.library.filepath)
226 else:
227 props = layout.operator("wm.return_to_original", icon="LOOP_BACK")
228 props.use_autosave = scene.use_autosave
230 layout.prop(scene, "use_autosave")
232 else:
233 layout.label(text="%s is not linked" % context.active_object.name,
234 icon=icon)
237 addon_keymaps = []
240 def register():
241 bpy.app.handlers.load_post.append(linked_file_check)
242 bpy.utils.register_class(EditLinked)
243 bpy.utils.register_class(ReturnToOriginal)
244 bpy.utils.register_class(PanelLinkedEdit)
246 # Is there a better place to store this properties?
247 bpy.types.Scene.use_autosave = bpy.props.BoolProperty(
248 name="Autosave",
249 description="Save the current file before opening a linked file",
250 default=True)
251 bpy.types.Scene.use_instance = bpy.props.BoolProperty(
252 name="New Blender Instance",
253 description="Open in a new Blender instance",
254 default=False)
256 # Keymapping (deactivated by default; activated when a library object is selected)
257 kc = bpy.context.window_manager.keyconfigs.addon
258 km = kc.keymaps.new(name="3D View", space_type='VIEW_3D')
259 kmi = km.keymap_items.new("object.edit_linked", 'NUMPAD_SLASH', 'PRESS', shift=True)
260 kmi.active = True
261 addon_keymaps.append((km, kmi))
262 kmi = km.keymap_items.new("wm.return_to_original", 'NUMPAD_SLASH', 'PRESS', shift=True)
263 kmi.active = True
264 addon_keymaps.append((km, kmi))
267 def unregister():
268 bpy.utils.unregister_class(EditLinked)
269 bpy.utils.unregister_class(ReturnToOriginal)
270 bpy.utils.unregister_class(PanelLinkedEdit)
271 bpy.app.handlers.load_post.remove(linked_file_check)
273 del bpy.types.Scene.use_autosave
274 del bpy.types.Scene.use_instance
276 # handle the keymap
277 for km, kmi in addon_keymaps:
278 km.keymap_items.remove(kmi)
279 addon_keymaps.clear()
282 if __name__ == "__main__":
283 register()