074a6ca499be5c984891535e6ed2c664052e5662
[blender.git] / source / blender / python / intern / bpy_operator.c
1
2 /**
3  * $Id$
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 #include "bpy_operator.h"
27 #include "bpy_opwrapper.h"
28 #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
29 #include "bpy_compat.h"
30
31 //#include "blendef.h"
32 #include "BLI_dynstr.h"
33
34 #include "WM_api.h"
35 #include "WM_types.h"
36
37 #include "MEM_guardedalloc.h"
38 //#include "BKE_idprop.h"
39 #include "BKE_report.h"
40
41 extern ListBase global_ops; /* evil, temp use */
42
43
44
45 /* This function is only used by operators right now
46  * Its used for taking keyword args and filling in property values */
47 int PYOP_props_from_dict(PointerRNA *ptr, PyObject *kw)
48 {
49         int error_val = 0;
50         int totkw;
51         const char *arg_name= NULL;
52         PyObject *item;
53
54         PropertyRNA *prop, *iterprop;
55         CollectionPropertyIterator iter;
56
57         iterprop= RNA_struct_iterator_property(ptr);
58         RNA_property_collection_begin(ptr, iterprop, &iter);
59
60         totkw = kw ? PyDict_Size(kw):0;
61
62         for(; iter.valid; RNA_property_collection_next(&iter)) {
63                 prop= iter.ptr.data;
64
65                 arg_name= RNA_property_identifier(&iter.ptr, prop);
66
67                 if (strcmp(arg_name, "rna_type")==0) continue;
68
69                 if (kw==NULL) {
70                         PyErr_Format( PyExc_AttributeError, "no args, expected \"%s\"", arg_name ? arg_name : "<UNKNOWN>");
71                         error_val= -1;
72                         break;
73                 }
74
75                 item= PyDict_GetItemString(kw, arg_name);
76
77                 if (item == NULL) {
78                         PyErr_Format( PyExc_AttributeError, "argument \"%s\" missing", arg_name ? arg_name : "<UNKNOWN>");
79                         error_val = -1; /* pyrna_py_to_prop sets the error */
80                         break;
81                 }
82
83                 if (pyrna_py_to_prop(ptr, prop, item)) {
84                         error_val= -1;
85                         break;
86                 }
87
88                 totkw--;
89         }
90
91         RNA_property_collection_end(&iter);
92
93         if (error_val==0 && totkw > 0) { /* some keywords were given that were not used :/ */
94                 PyObject *key, *value;
95                 Py_ssize_t pos = 0;
96
97                 while (PyDict_Next(kw, &pos, &key, &value)) {
98                         arg_name= _PyUnicode_AsString(key);
99                         if (RNA_struct_find_property(ptr, arg_name) == NULL) break;
100                         arg_name= NULL;
101                 }
102
103                 PyErr_Format( PyExc_AttributeError, "argument \"%s\" unrecognized", arg_name ? arg_name : "<UNKNOWN>");
104                 error_val = -1;
105         }
106
107         return error_val;
108 }
109
110 static PyObject *pyop_base_dir(PyObject *self);
111 static struct PyMethodDef pyop_base_methods[] = {
112         {"__dir__", (PyCFunction)pyop_base_dir, METH_NOARGS, ""},
113         {"add", (PyCFunction)PYOP_wrap_add, METH_VARARGS, ""},
114         {"remove", (PyCFunction)PYOP_wrap_remove, METH_VARARGS, ""},
115         {NULL, NULL, 0, NULL}
116 };
117
118 /* 'self' stores the operator string */
119 static PyObject *pyop_base_call( PyObject * self, PyObject * args,  PyObject * kw)
120 {
121         wmOperatorType *ot;
122         int error_val = 0;
123         PointerRNA ptr;
124         
125         // XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it...
126         bContext *C = (bContext *)PyCObject_AsVoidPtr(PyDict_GetItemString(PyEval_GetGlobals(), "__bpy_context__"));
127         
128         char *opname = _PyUnicode_AsString(self);
129         char *report_str= NULL;
130
131         if (PyTuple_Size(args)) {
132                 PyErr_SetString( PyExc_AttributeError, "All operator args must be keywords");
133                 return NULL;
134         }
135
136         ot= WM_operatortype_find(opname);
137         if (ot == NULL) {
138                 PyErr_Format( PyExc_SystemError, "Operator \"%s\"could not be found", opname);
139                 return NULL;
140         }
141         
142         if(ot->poll && (ot->poll(C) == 0)) {
143                 PyErr_SetString( PyExc_SystemError, "Operator poll() function failed, context is incorrect");
144                 return NULL;
145         }
146         
147         WM_operator_properties_create(&ptr, opname);
148         
149         error_val= PYOP_props_from_dict(&ptr, kw);
150         
151         if (error_val==0) {
152                 ReportList reports;
153
154                 BKE_reports_init(&reports, RPT_STORE);
155
156                 WM_operator_call_py(C, ot, &ptr, &reports);
157
158                 report_str= BKE_reports_string(&reports, RPT_ERROR);
159
160                 if (report_str) {
161                         PyErr_SetString(PyExc_SystemError, report_str);
162                         MEM_freeN(report_str);
163                         error_val = -1;
164                 }
165
166                 if (reports.list.first)
167                         BKE_reports_clear(&reports);
168         }
169
170         WM_operator_properties_free(&ptr);
171
172 #if 0
173         /* if there is some way to know an operator takes args we should use this */
174         {
175                 /* no props */
176                 if (kw != NULL) {
177                         PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname);
178                         return NULL;
179                 }
180
181                 WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL);
182         }
183 #endif
184
185         if (error_val==-1) {
186                 return NULL;
187         }
188
189         Py_RETURN_NONE;
190 }
191
192 static PyMethodDef pyop_base_call_meth[] = {
193         {"__op_call__", pyop_base_call, METH_VARARGS|METH_KEYWORDS, "generic operator calling function"}
194 };
195
196
197 //---------------getattr--------------------------------------------
198 static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname )
199 {
200         char *name = _PyUnicode_AsString(pyname);
201         PyObject *ret;
202         
203         if ((WM_operatortype_find(name))) {
204                 ret = PyCFunction_New( pyop_base_call_meth, pyname); /* set the name string as self, PyCFunction_New incref's self */
205         }
206         else if ((ret = PyObject_GenericGetAttr((PyObject *)self, pyname))) {
207                 /* do nothing, this accounts for methoddef's add and remove */
208         }
209         else {
210                 PyErr_Format( PyExc_AttributeError, "Operator \"%s\" not found", name);
211                 ret= NULL;
212         }
213
214         return ret;
215 }
216
217 static PyObject *pyop_base_dir(PyObject *self)
218 {
219         PyObject *list = PyList_New(0), *name;
220         wmOperatorType *ot;
221         PyMethodDef *meth;
222         
223         for(ot= WM_operatortype_first(); ot; ot= ot->next) {
224                 name = PyUnicode_FromString(ot->idname);
225                 PyList_Append(list, name);
226                 Py_DECREF(name);
227         }
228
229         for(meth=pyop_base_methods; meth->ml_name; meth++) {
230                 name = PyUnicode_FromString(meth->ml_name);
231                 PyList_Append(list, name);
232                 Py_DECREF(name);
233         }
234         
235         return list;
236 }
237
238 PyTypeObject pyop_base_Type = {NULL};
239
240 PyObject *BPY_operator_module( bContext *C )
241 {
242         pyop_base_Type.tp_name = "OperatorBase";
243         pyop_base_Type.tp_basicsize = sizeof( BPy_OperatorBase );
244         pyop_base_Type.tp_getattro = ( getattrofunc )pyop_base_getattro;
245         pyop_base_Type.tp_flags = Py_TPFLAGS_DEFAULT;
246         pyop_base_Type.tp_methods = pyop_base_methods;
247         
248         if( PyType_Ready( &pyop_base_Type ) < 0 )
249                 return NULL;
250
251         //submodule = Py_InitModule3( "operator", M_rna_methods, "rna module" );
252         return (PyObject *)PyObject_NEW( BPy_OperatorBase, &pyop_base_Type );
253 }
254
255
256