- missing return values
[blender.git] / release / scripts / op / wm.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8-80 compliant>
20
21 import bpy
22
23 from bpy.props import *
24
25 class MESH_OT_delete_edgeloop(bpy.types.Operator):
26     '''Export a single object as a stanford PLY with normals,
27     colours and texture coordinates.'''
28     bl_idname = "mesh.delete_edgeloop"
29     bl_label = "Delete Edge Loop"
30
31     def execute(self, context):
32         bpy.ops.tfm.edge_slide(value=1.0)
33         bpy.ops.mesh.select_more()
34         bpy.ops.mesh.remove_doubles()
35         return ('FINISHED',)
36
37 rna_path_prop = StringProperty(name="Context Attributes",
38         description="rna context string", maxlen=1024, default="")
39
40 rna_reverse_prop = BoolProperty(name="Reverse",
41         description="Cycle backwards", default=False)
42
43 class NullPathMember:
44     pass
45
46
47 def context_path_validate(context, path):
48     import sys
49     try:
50         value = eval("context.%s" % path)
51     except AttributeError:
52         if "'NoneType'" in str(sys.exc_info()[1]):
53             # One of the items in the rna path is None, just ignore this
54             value = NullPathMember
55         else:
56             # We have a real error in the rna path, dont ignore that
57             raise
58
59     return value
60
61
62 def execute_context_assign(self, context):
63     if context_path_validate(context, self.path) == NullPathMember:
64         return ('PASS_THROUGH',)
65
66     exec("context.%s=self.value" % self.path)
67     return ('FINISHED',)
68
69
70 class WM_OT_context_set_boolean(bpy.types.Operator):
71     '''Set a context value.'''
72     bl_idname = "wm.context_set_boolean"
73     bl_label = "Context Set"
74
75     path = rna_path_prop
76     value = BoolProperty(name="Value",
77             description="Assignment value", default=True)
78
79     execute = execute_context_assign
80
81
82 class WM_OT_context_set_int(bpy.types.Operator): # same as enum
83     '''Set a context value.'''
84     bl_idname = "wm.context_set_int"
85     bl_label = "Context Set"
86
87     path = rna_path_prop
88     value = IntProperty(name="Value", description="Assign value", default=0)
89
90     execute = execute_context_assign
91
92
93 class WM_OT_context_set_float(bpy.types.Operator): # same as enum
94     '''Set a context value.'''
95     bl_idname = "wm.context_set_int"
96     bl_label = "Context Set"
97
98     path = rna_path_prop
99     value = FloatProperty(name="Value",
100             description="Assignment value", default=0.0)
101
102     execute = execute_context_assign
103
104
105 class WM_OT_context_set_string(bpy.types.Operator): # same as enum
106     '''Set a context value.'''
107     bl_idname = "wm.context_set_string"
108     bl_label = "Context Set"
109
110     path = rna_path_prop
111     value = StringProperty(name="Value",
112             description="Assign value", maxlen=1024, default="")
113
114     execute = execute_context_assign
115
116
117 class WM_OT_context_set_enum(bpy.types.Operator):
118     '''Set a context value.'''
119     bl_idname = "wm.context_set_enum"
120     bl_label = "Context Set"
121
122     path = rna_path_prop
123     value = StringProperty(name="Value",
124             description="Assignment value (as a string)",
125             maxlen=1024, default="")
126
127     execute = execute_context_assign
128
129
130 class WM_OT_context_toggle(bpy.types.Operator):
131     '''Toggle a context value.'''
132     bl_idname = "wm.context_toggle"
133     bl_label = "Context Toggle"
134     path = rna_path_prop
135
136     def execute(self, context):
137
138         if context_path_validate(context, self.path) == NullPathMember:
139             return ('PASS_THROUGH',)
140
141         exec("context.%s=not (context.%s)" % (self.path, self.path))
142         return ('FINISHED',)
143
144
145 class WM_OT_context_toggle_enum(bpy.types.Operator):
146     '''Toggle a context value.'''
147     bl_idname = "wm.context_toggle_enum"
148     bl_label = "Context Toggle Values"
149
150     path = rna_path_prop
151     value_1 = StringProperty(name="Value", \
152                 description="Toggle enum", maxlen=1024, default="")
153
154     value_2 = StringProperty(name="Value", \
155                 description="Toggle enum", maxlen=1024, default="")
156
157     def execute(self, context):
158
159         if context_path_validate(context, self.path) == NullPathMember:
160             return ('PASS_THROUGH',)
161
162         exec("context.%s = ['%s', '%s'][context.%s!='%s']" % \
163             (self.path, self.value_1, self.value_2, self.path, self.value_2))
164
165         return ('FINISHED',)
166
167
168 class WM_OT_context_cycle_int(bpy.types.Operator):
169     '''Set a context value. Useful for cycling active material,
170     vertex keys, groups' etc.'''
171     bl_idname = "wm.context_cycle_int"
172     bl_label = "Context Int Cycle"
173     path = rna_path_prop
174     reverse = rna_reverse_prop
175
176     def execute(self, context):
177
178         value = context_path_validate(context, self.path)
179         if value == NullPathMember:
180             return ('PASS_THROUGH',)
181
182         self.value = value
183         if self.reverse:
184             self.value -= 1
185         else:
186             self.value += 1
187         execute_context_assign(self, context)
188
189         if self.value != eval("context.%s" % self.path):
190             # relies on rna clamping int's out of the range
191             if self.reverse:
192                 self.value = (1 << 32)
193             else:
194                 self.value = - (1 << 32)
195             execute_context_assign(self, context)
196
197         return ('FINISHED',)
198
199
200 class WM_OT_context_cycle_enum(bpy.types.Operator):
201     '''Toggle a context value.'''
202     bl_idname = "wm.context_cycle_enum"
203     bl_label = "Context Enum Cycle"
204
205     path = rna_path_prop
206     reverse = rna_reverse_prop
207
208     def execute(self, context):
209
210         value = context_path_validate(context, self.path)
211         if value == NullPathMember:
212             return ('PASS_THROUGH',)
213
214         orig_value = value
215
216         # Have to get rna enum values
217         rna_struct_str, rna_prop_str = self.path.rsplit('.', 1)
218         i = rna_prop_str.find('[')
219
220         # just incse we get "context.foo.bar[0]"
221         if i != -1:
222             rna_prop_str = rna_prop_str[0:i]
223
224         rna_struct = eval("context.%s.rna_type" % rna_struct_str)
225
226         rna_prop = rna_struct.properties[rna_prop_str]
227
228         if type(rna_prop) != bpy.types.EnumProperty:
229             raise Exception("expected an enum property")
230
231         enums = rna_struct.properties[rna_prop_str].items.keys()
232         orig_index = enums.index(orig_value)
233
234         # Have the info we need, advance to the next item
235         if self.reverse:
236             if orig_index == 0:
237                 advance_enum = enums[-1]
238             else:
239                 advance_enum = enums[orig_index-1]
240         else:
241             if orig_index == len(enums) - 1:
242                 advance_enum = enums[0]
243             else:
244                 advance_enum = enums[orig_index + 1]
245
246         # set the new value
247         exec("context.%s=advance_enum" % self.path)
248         return ('FINISHED',)
249
250 doc_id = StringProperty(name="Doc ID",
251         description="ID for the documentation", maxlen=1024, default="")
252
253 doc_new = StringProperty(name="Doc New",
254         description="", maxlen=1024, default="")
255
256
257 class WM_OT_doc_view(bpy.types.Operator):
258     '''Load online reference docs'''
259     bl_idname = "wm.doc_view"
260     bl_label = "View Documentation"
261
262     doc_id = doc_id
263     _prefix = 'http://www.blender.org/documentation/250PythonDoc'
264
265     def _nested_class_string(self, class_string):
266         ls = []
267         class_obj = getattr(bpy.types, class_string, None).bl_rna
268         while class_obj:
269             ls.insert(0, class_obj)
270             class_obj = class_obj.nested
271         return '.'.join([class_obj.identifier for class_obj in ls])
272
273     def execute(self, context):
274         id_split = self.doc_id.split('.')
275         if len(id_split) == 1: # rna, class
276             url = '%s/bpy.types.%s-class.html' % (self._prefix, id_split[0])
277         elif len(id_split) == 2: # rna, class.prop
278             class_name, class_prop = id_split
279
280             # It so happens that epydoc nests these
281             class_name_full = self._nested_class_string(class_name)
282
283             if hasattr(bpy.types, class_name.upper() + '_OT_' + class_prop):
284                 url = '%s/bpy.ops.%s-module.html#%s' % \
285                         (self._prefix, class_name_full, class_prop)
286             else:
287                 url = '%s/bpy.types.%s-class.html#%s' % \
288                         (self._prefix, class_name_full, class_prop)
289
290         else:
291             return ('PASS_THROUGH',)
292
293         import webbrowser
294         webbrowser.open(url)
295
296         return ('FINISHED',)
297
298
299 class WM_OT_doc_edit(bpy.types.Operator):
300     '''Load online reference docs'''
301     bl_idname = "wm.doc_edit"
302     bl_label = "Edit Documentation"
303
304     doc_id = doc_id
305     doc_new = doc_new
306
307     _url = "http://www.mindrones.com/blender/svn/xmlrpc.php"
308
309     def _send_xmlrpc(self, data_dict):
310         print("sending data:", data_dict)
311
312         import xmlrpc.client
313         user = 'blenderuser'
314         pwd = 'blender>user'
315
316         docblog = xmlrpc.client.ServerProxy(self._url)
317         docblog.metaWeblog.newPost(1, user, pwd, data_dict, 1)
318
319     def execute(self, context):
320
321         class_name, class_prop = self.doc_id.split('.')
322
323         if not self.doc_new:
324             return ('CANCELLED',)
325
326         # check if this is an operator
327         op_name = class_name.upper() + '_OT_' + class_prop
328         op_class = getattr(bpy.types, op_name, None)
329
330         # Upload this to the web server
331         upload = {}
332
333         if op_class:
334             rna = op_class.bl_rna
335             doc_orig = rna.description
336             if doc_orig == self.doc_new:
337                 return ('CANCELLED',)
338
339             print("op - old:'%s' -> new:'%s'" % (doc_orig, self.doc_new))
340             upload["title"] = 'OPERATOR %s:%s' % (self.doc_id, doc_orig)
341             upload["description"] = self.doc_new
342
343             self._send_xmlrpc(upload)
344
345         else:
346             rna = getattr(bpy.types, class_name).bl_rna
347             doc_orig = rna.properties[class_prop].description
348             if doc_orig == self.doc_new:
349                 return ('CANCELLED',)
350
351             print("rna - old:'%s' -> new:'%s'" % (doc_orig, self.doc_new))
352             upload["title"] = 'RNA %s:%s' % s(self.doc_id, doc_orig)
353
354         upload["description"] = self.doc_new
355
356         self._send_xmlrpc(upload)
357
358         return ('FINISHED',)
359
360     def invoke(self, context, event):
361         wm = context.manager
362         wm.invoke_props_popup(self, event)
363         return ('RUNNING_MODAL',)
364
365
366 bpy.ops.add(MESH_OT_delete_edgeloop)
367
368 bpy.ops.add(WM_OT_context_set_boolean)
369 bpy.ops.add(WM_OT_context_set_int)
370 bpy.ops.add(WM_OT_context_set_float)
371 bpy.ops.add(WM_OT_context_set_string)
372 bpy.ops.add(WM_OT_context_set_enum)
373 bpy.ops.add(WM_OT_context_toggle)
374 bpy.ops.add(WM_OT_context_toggle_enum)
375 bpy.ops.add(WM_OT_context_cycle_enum)
376 bpy.ops.add(WM_OT_context_cycle_int)
377
378 bpy.ops.add(WM_OT_doc_view)
379 bpy.ops.add(WM_OT_doc_edit)