/** * $Id$ * * ***** 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. * * Contributor(s): Campbell Barton * * ***** END GPL LICENSE BLOCK ***** */ /* Note, this module is not to be used directly by the user. * its accessed from blender with bpy.__ops__ * */ #include "bpy_operator.h" #include "bpy_operator_wrap.h" #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */ #include "bpy_util.h" #include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" #include "MEM_guardedalloc.h" #include "BKE_report.h" static PyObject *pyop_poll( PyObject * self, PyObject * args) { wmOperatorType *ot; char *opname; PyObject *context_dict= NULL; /* optional args */ PyObject *context_dict_back; PyObject *ret; // 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... bContext *C = BPy_GetContext(); if (!PyArg_ParseTuple(args, "s|O:_bpy.ops.poll", &opname, &context_dict)) return NULL; ot= WM_operatortype_find(opname, TRUE); if (ot == NULL) { PyErr_Format(PyExc_SystemError, "Polling operator \"bpy.ops.%s\" error, could not be found", opname); return NULL; } if(!PyDict_Check(context_dict)) context_dict= NULL; context_dict_back= CTX_py_dict_get(C); CTX_py_dict_set(C, (void *)context_dict); Py_XINCREF(context_dict); /* so we done loose it */ /* main purpose of thsi function */ ret= WM_operator_poll((bContext*)C, ot) ? Py_True : Py_False; /* restore with original context dict, probably NULL but need this for nested operator calls */ Py_XDECREF(context_dict); CTX_py_dict_set(C, (void *)context_dict_back); Py_INCREF(ret); return ret; } static PyObject *pyop_call( PyObject * self, PyObject * args) { wmOperatorType *ot; int error_val = 0; PointerRNA ptr; int operator_ret= OPERATOR_CANCELLED; char *opname; char *context_str= NULL; PyObject *kw= NULL; /* optional args */ PyObject *context_dict= NULL; /* optional args */ PyObject *context_dict_back; /* note that context is an int, python does the conversion in this case */ int context= WM_OP_EXEC_DEFAULT; // 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... bContext *C = BPy_GetContext(); if (!PyArg_ParseTuple(args, "sO|O!s:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str)) return NULL; ot= WM_operatortype_find(opname, TRUE); if (ot == NULL) { PyErr_Format(PyExc_SystemError, "Calling operator \"bpy.ops.%s\" error, could not be found", opname); return NULL; } if(context_str) { if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) { char *enum_str= BPy_enum_as_string(operator_context_items); PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, expected a string enum in (%.200s)", opname, enum_str); MEM_freeN(enum_str); return NULL; } } if(!PyDict_Check(context_dict)) context_dict= NULL; context_dict_back= CTX_py_dict_get(C); CTX_py_dict_set(C, (void *)context_dict); Py_XINCREF(context_dict); /* so we done loose it */ if(WM_operator_poll((bContext*)C, ot) == FALSE) { const char *msg= CTX_wm_operator_poll_msg_get(C); PyErr_Format( PyExc_SystemError, "Operator bpy.ops.%.200s.poll() %s", opname, msg ? msg : "failed, context is incorrect"); CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */ error_val= -1; } else { WM_operator_properties_create_ptr(&ptr, ot); if(kw && PyDict_Size(kw)) error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); if (error_val==0) { ReportList *reports; reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); BKE_reports_init(reports, RPT_STORE); operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports); if(BPy_reports_to_error(reports)) error_val = -1; /* operator output is nice to have in the terminal/console too */ if(reports->list.first) { char *report_str= BKE_reports_string(reports, 0); /* all reports */ if(report_str) { PySys_WriteStdout("%s\n", report_str); MEM_freeN(report_str); } } BKE_reports_clear(reports); if ((reports->flag & RPT_FREE) == 0) { MEM_freeN(reports); } } WM_operator_properties_free(&ptr); #if 0 /* if there is some way to know an operator takes args we should use this */ { /* no props */ if (kw != NULL) { PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname); return NULL; } WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL); } #endif } /* restore with original context dict, probably NULL but need this for nested operator calls */ Py_XDECREF(context_dict); CTX_py_dict_set(C, (void *)context_dict_back); if (error_val==-1) { return NULL; } /* return operator_ret as a bpy enum */ return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret); } static PyObject *pyop_as_string( PyObject * self, PyObject * args) { wmOperatorType *ot; PointerRNA ptr; char *opname; PyObject *kw= NULL; /* optional args */ int all_args = 1; int error_val= 0; char *buf = NULL; PyObject *pybuf; bContext *C = BPy_GetContext(); if (!PyArg_ParseTuple(args, "s|O!i:_bpy.ops.as_string", &opname, &PyDict_Type, &kw, &all_args)) return NULL; ot= WM_operatortype_find(opname, TRUE); if (ot == NULL) { PyErr_Format( PyExc_SystemError, "_bpy.ops.as_string: operator \"%s\"could not be found", opname); return NULL; } /* WM_operator_properties_create(&ptr, opname); */ /* Save another lookup */ RNA_pointer_create(NULL, ot->srna, NULL, &ptr); if(kw && PyDict_Size(kw)) error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); if (error_val==0) buf= WM_operator_pystring(C, ot, &ptr, all_args); WM_operator_properties_free(&ptr); if (error_val==-1) { return NULL; } if(buf) { pybuf= PyUnicode_FromString(buf); MEM_freeN(buf); } else { pybuf= PyUnicode_FromString(""); } return pybuf; } static PyObject *pyop_dir(PyObject *self) { PyObject *list = PyList_New(0), *name; wmOperatorType *ot; for(ot= WM_operatortype_first(); ot; ot= ot->next) { name = PyUnicode_FromString(ot->idname); PyList_Append(list, name); Py_DECREF(name); } return list; } static PyObject *pyop_getrna(PyObject *self, PyObject *value) { wmOperatorType *ot; PointerRNA ptr; char *opname= _PyUnicode_AsString(value); BPy_StructRNA *pyrna= NULL; if(opname==NULL) { PyErr_SetString(PyExc_TypeError, "_bpy.ops.get_rna() expects a string argument"); return NULL; } ot= WM_operatortype_find(opname, TRUE); if(ot==NULL) { PyErr_Format(PyExc_KeyError, "_bpy.ops.get_rna(\"%s\") not found", opname); return NULL; } /* type */ //RNA_pointer_create(NULL, &RNA_Struct, ot->srna, &ptr); /* XXX - should call WM_operator_properties_free */ WM_operator_properties_create_ptr(&ptr, ot); pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); pyrna->freeptr= TRUE; return (PyObject *)pyrna; } static struct PyMethodDef bpy_ops_methods[] = { {"poll", (PyCFunction) pyop_poll, METH_VARARGS, NULL}, {"call", (PyCFunction) pyop_call, METH_VARARGS, NULL}, {"as_string", (PyCFunction) pyop_as_string, METH_VARARGS, NULL}, {"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL}, {"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL}, {"macro_define", (PyCFunction) PYOP_wrap_macro_define, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef bpy_ops_module = { PyModuleDef_HEAD_INIT, "_bpy.ops", NULL, -1,/* multiple "initialization" just copies the module dict. */ bpy_ops_methods, NULL, NULL, NULL, NULL }; PyObject *BPY_operator_module(void) { PyObject *submodule; submodule= PyModule_Create(&bpy_ops_module); PyDict_SetItemString(PyImport_GetModuleDict(), bpy_ops_module.m_name, submodule); /* INCREF since its its assumed that all these functions return the * module with a new ref like PyDict_New, since they are passed to * PyModule_AddObject which steals a ref */ Py_INCREF(submodule); return submodule; }