p3dPythonObject.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // Filename: p3dPythonObject.cxx
  2. // Created by: drose (03Jul09)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) Carnegie Mellon University. All rights reserved.
  8. //
  9. // All use of this software is subject to the terms of the revised BSD
  10. // license. You should have received a copy of this license along
  11. // with this source code in a file named "LICENSE."
  12. //
  13. ////////////////////////////////////////////////////////////////////
  14. #include "p3dPythonObject.h"
  15. ////////////////////////////////////////////////////////////////////
  16. // Function: P3DPythonObject::Constructor
  17. // Access: Public
  18. // Description:
  19. ////////////////////////////////////////////////////////////////////
  20. P3DPythonObject::
  21. P3DPythonObject(P3DSession *session, int object_id) :
  22. _session(session),
  23. _object_id(object_id)
  24. {
  25. _session->ref();
  26. }
  27. ////////////////////////////////////////////////////////////////////
  28. // Function: P3DPythonObject::Destructor
  29. // Access: Public, Virtual
  30. // Description:
  31. ////////////////////////////////////////////////////////////////////
  32. P3DPythonObject::
  33. ~P3DPythonObject() {
  34. // When the P3DPythonObject wrapper goes away, we have to inform the
  35. // child process that we no longer need the corresponding PyObject
  36. // to be kept around.
  37. _session->drop_pyobj(_object_id);
  38. p3d_unref_delete(_session);
  39. }
  40. ////////////////////////////////////////////////////////////////////
  41. // Function: P3DPythonObject::get_type
  42. // Access: Public, Virtual
  43. // Description: Returns the fundamental type of this kind of object.
  44. ////////////////////////////////////////////////////////////////////
  45. P3D_object_type P3DPythonObject::
  46. get_type() {
  47. return P3D_OT_object;
  48. }
  49. ////////////////////////////////////////////////////////////////////
  50. // Function: P3DPythonObject::get_bool
  51. // Access: Public, Virtual
  52. // Description: Returns the object value coerced to a boolean, if
  53. // possible.
  54. ////////////////////////////////////////////////////////////////////
  55. bool P3DPythonObject::
  56. get_bool() {
  57. bool bresult = 0;
  58. P3D_object *result = call("__bool__", true, NULL, 0);
  59. if (result != NULL) {
  60. bresult = P3D_OBJECT_GET_BOOL(result);
  61. P3D_OBJECT_DECREF(result);
  62. }
  63. return bresult;
  64. }
  65. ////////////////////////////////////////////////////////////////////
  66. // Function: P3DPythonObject::get_int
  67. // Access: Public, Virtual
  68. // Description: Returns the object value coerced to an integer, if
  69. // possible.
  70. ////////////////////////////////////////////////////////////////////
  71. int P3DPythonObject::
  72. get_int() {
  73. int iresult = 0;
  74. P3D_object *result = call("__int__", true, NULL, 0);
  75. if (result != NULL) {
  76. iresult = P3D_OBJECT_GET_INT(result);
  77. P3D_OBJECT_DECREF(result);
  78. }
  79. return iresult;
  80. }
  81. ////////////////////////////////////////////////////////////////////
  82. // Function: P3DPythonObject::get_float
  83. // Access: Public, Virtual
  84. // Description: Returns the object value coerced to a floating-point
  85. // value, if possible.
  86. ////////////////////////////////////////////////////////////////////
  87. double P3DPythonObject::
  88. get_float() {
  89. double fresult = 0.0;
  90. P3D_object *result = call("__float__", true, NULL, 0);
  91. if (result != NULL) {
  92. fresult = P3D_OBJECT_GET_FLOAT(result);
  93. P3D_OBJECT_DECREF(result);
  94. }
  95. return fresult;
  96. }
  97. ////////////////////////////////////////////////////////////////////
  98. // Function: P3DPythonObject::make_string
  99. // Access: Public, Virtual
  100. // Description: Fills the indicated C++ string object with the value
  101. // of this object coerced to a string.
  102. ////////////////////////////////////////////////////////////////////
  103. void P3DPythonObject::
  104. make_string(string &value) {
  105. P3D_object *result = call("__str__", true, NULL, 0);
  106. if (result != NULL) {
  107. int size = P3D_OBJECT_GET_STRING(result, NULL, 0);
  108. char *buffer = new char[size];
  109. P3D_OBJECT_GET_STRING(result, buffer, size);
  110. value = string(buffer, size);
  111. delete[] buffer;
  112. P3D_OBJECT_DECREF(result);
  113. }
  114. }
  115. ////////////////////////////////////////////////////////////////////
  116. // Function: P3DPythonObject::get_property
  117. // Access: Public, Virtual
  118. // Description: Returns the named property element in the object. The
  119. // return value is a new-reference P3D_object, or NULL
  120. // on error.
  121. ////////////////////////////////////////////////////////////////////
  122. P3D_object *P3DPythonObject::
  123. get_property(const string &property) {
  124. P3D_object *params[1];
  125. params[0] = new P3DStringObject(property);
  126. P3D_object *result = call("__get_property__", true, params, 1);
  127. P3D_OBJECT_DECREF(params[0]);
  128. return result;
  129. }
  130. ////////////////////////////////////////////////////////////////////
  131. // Function: P3DPythonObject::set_property
  132. // Access: Public, Virtual
  133. // Description: Modifies (or deletes, if value is NULL) the named
  134. // property element in the object. Returns true on
  135. // success, false on failure.
  136. ////////////////////////////////////////////////////////////////////
  137. bool P3DPythonObject::
  138. set_property(const string &property, bool needs_response, P3D_object *value) {
  139. if (!_session->get_matches_script_origin()) {
  140. // If you can't be scripting us, you can't be setting properties either.
  141. return false;
  142. }
  143. return set_property_insecure(property, needs_response, value);
  144. }
  145. ////////////////////////////////////////////////////////////////////
  146. // Function: P3DPythonObject::set_property_insecure
  147. // Access: Public
  148. // Description: Works as set_property(), but does not check the
  149. // matches_script_origin flag. Intended to be called
  150. // internally only, never to be called from Javascript.
  151. ////////////////////////////////////////////////////////////////////
  152. bool P3DPythonObject::
  153. set_property_insecure(const string &property, bool needs_response,
  154. P3D_object *value) {
  155. bool bresult = !needs_response;
  156. P3D_object *params[2];
  157. params[0] = new P3DStringObject(property);
  158. P3D_object *result = NULL;
  159. if (value == NULL) {
  160. // Delete an attribute.
  161. result = call_insecure("__del_property__", needs_response, params, 1);
  162. } else {
  163. // Set a new attribute.
  164. params[1] = value;
  165. result = call_insecure("__set_property__", needs_response, params, 2);
  166. }
  167. P3D_OBJECT_DECREF(params[0]);
  168. if (result != NULL) {
  169. bresult = P3D_OBJECT_GET_BOOL(result);
  170. P3D_OBJECT_DECREF(result);
  171. }
  172. return bresult;
  173. }
  174. ////////////////////////////////////////////////////////////////////
  175. // Function: P3DPythonObject::has_method
  176. // Access: Public, Virtual
  177. // Description: Returns true if the named method exists on this
  178. // object, false otherwise.
  179. ////////////////////////////////////////////////////////////////////
  180. bool P3DPythonObject::
  181. has_method(const string &method_name) {
  182. // First, check the cache.
  183. pair<HasMethod::iterator, bool> cresult = _has_method.insert(HasMethod::value_type(method_name, false));
  184. HasMethod::iterator hi = cresult.first;
  185. if (!cresult.second) {
  186. // Already cached.
  187. return (*hi).second;
  188. }
  189. bool bresult = false;
  190. P3D_object *params[1];
  191. params[0] = new P3DStringObject(method_name);
  192. P3D_object *result = call("__has_method__", true, params, 1);
  193. P3D_OBJECT_DECREF(params[0]);
  194. if (result != NULL) {
  195. bresult = P3D_OBJECT_GET_BOOL(result);
  196. P3D_OBJECT_DECREF(result);
  197. }
  198. // Save the cached result, so we don't have to keep asking this
  199. // question. We assume that the set of methods on an object don't
  200. // change substantially, so we can get away with keeping this cache.
  201. (*hi).second = bresult;
  202. return bresult;
  203. }
  204. ////////////////////////////////////////////////////////////////////
  205. // Function: P3DPythonObject::call
  206. // Access: Public, Virtual
  207. // Description: Invokes the named method on the object, passing the
  208. // indicated parameters. If the method name is empty,
  209. // invokes the object itself.
  210. //
  211. // If needs_response is true, the return value is a
  212. // new-reference P3D_object on success, or NULL on
  213. // failure. If needs_response is false, the return
  214. // value is always NULL, and there is no way to
  215. // determine success or failure.
  216. ////////////////////////////////////////////////////////////////////
  217. P3D_object *P3DPythonObject::
  218. call(const string &method_name, bool needs_response,
  219. P3D_object *params[], int num_params) {
  220. if (!_session->get_matches_script_origin()) {
  221. // If you can't be scripting us, you can't be calling methods.
  222. return NULL;
  223. }
  224. return call_insecure(method_name, needs_response, params, num_params);
  225. }
  226. ////////////////////////////////////////////////////////////////////
  227. // Function: P3DPythonObject::call_insecure
  228. // Access: Public
  229. // Description: Works as call(), but does not check the
  230. // matches_script_origin flag. Intended to be called
  231. // internally only, never to be called from Javascript.
  232. ////////////////////////////////////////////////////////////////////
  233. P3D_object *P3DPythonObject::
  234. call_insecure(const string &method_name, bool needs_response,
  235. P3D_object *params[], int num_params) {
  236. TiXmlDocument *doc = new TiXmlDocument;
  237. TiXmlElement *xcommand = new TiXmlElement("command");
  238. xcommand->SetAttribute("cmd", "pyobj");
  239. xcommand->SetAttribute("op", "call");
  240. if (!method_name.empty()) {
  241. xcommand->SetAttribute("method_name", method_name);
  242. }
  243. TiXmlElement *xobject = _session->p3dobj_to_xml(this);
  244. xobject->SetValue("object");
  245. xcommand->LinkEndChild(xobject);
  246. for (int i = 0; i < num_params; ++i) {
  247. TiXmlElement *xparams = _session->p3dobj_to_xml(params[i]);
  248. xcommand->LinkEndChild(xparams);
  249. }
  250. doc->LinkEndChild(xcommand);
  251. // If no response is requested, send the command out in a vacuum,
  252. // and return NULL.
  253. if (!needs_response) {
  254. _session->send_command(doc);
  255. return NULL;
  256. }
  257. // If a response is requested, we have to send the command and wait
  258. // for it.
  259. TiXmlDocument *response = _session->command_and_response(doc);
  260. P3D_object *result = NULL;
  261. if (response != NULL) {
  262. TiXmlElement *xresponse = response->FirstChildElement("response");
  263. if (xresponse != NULL) {
  264. TiXmlElement *xvalue = xresponse->FirstChildElement("value");
  265. if (xvalue != NULL) {
  266. result = _session->xml_to_p3dobj(xvalue);
  267. }
  268. }
  269. delete response;
  270. }
  271. return result;
  272. }
  273. ////////////////////////////////////////////////////////////////////
  274. // Function: P3DPythonObject::output
  275. // Access: Public, Virtual
  276. // Description: Writes a formatted representation of the value to the
  277. // indicated string. This is intended for developer
  278. // assistance.
  279. ////////////////////////////////////////////////////////////////////
  280. void P3DPythonObject::
  281. output(ostream &out) {
  282. P3D_object *result = call("__repr__", true, NULL, 0);
  283. out << "Python " << _object_id;
  284. if (result != NULL) {
  285. out << ": " << *result;
  286. P3D_OBJECT_DECREF(result);
  287. }
  288. }
  289. ////////////////////////////////////////////////////////////////////
  290. // Function: P3DPythonObject::fill_xml
  291. // Access: Public, Virtual
  292. // Description: If this object has a valid XML representation for the
  293. // indicated session (that hasn't already been
  294. // implemented by the generic code in P3DSession), this
  295. // method will apply it to the indicated "value" element
  296. // and return true. Otherwise, this method will leave
  297. // the element unchanged and return false.
  298. ////////////////////////////////////////////////////////////////////
  299. bool P3DPythonObject::
  300. fill_xml(TiXmlElement *xvalue, P3DSession *session) {
  301. if (session == _session) {
  302. // If it's a P3DPythonObject from the same session, just send
  303. // the object_id down, since the actual implementation of this
  304. // object exists (as a Python object) in the sub-process space.
  305. xvalue->SetAttribute("type", "python");
  306. xvalue->SetAttribute("object_id", _object_id);
  307. return true;
  308. }
  309. // Otherwise, we have to send it as a browser object.
  310. return false;
  311. }
  312. ////////////////////////////////////////////////////////////////////
  313. // Function: P3DPythonObject::as_python_object
  314. // Access: Public, Virtual
  315. // Description: Returns this object, downcast to a P3DPythonObject,
  316. // if it is in fact an object of that type; or NULL if
  317. // it is not.
  318. ////////////////////////////////////////////////////////////////////
  319. P3DPythonObject *P3DPythonObject::
  320. as_python_object() {
  321. return this;
  322. }
  323. ////////////////////////////////////////////////////////////////////
  324. // Function: P3DPythonObject::get_session
  325. // Access: Public
  326. // Description: Returns the session that this object is identified
  327. // with.
  328. ////////////////////////////////////////////////////////////////////
  329. P3DSession *P3DPythonObject::
  330. get_session() {
  331. return _session;
  332. }
  333. ////////////////////////////////////////////////////////////////////
  334. // Function: P3DPythonObject::get_object_id
  335. // Access: Public
  336. // Description: Returns the object_id number that is used to uniquely
  337. // identify this object in the XML stream.
  338. ////////////////////////////////////////////////////////////////////
  339. int P3DPythonObject::
  340. get_object_id() {
  341. return _object_id;
  342. }