add has_method to work around firefox bug

This commit is contained in:
David Rose 2009-07-09 06:58:54 +00:00
parent 9f56a959c2
commit ce23653ac2
7 changed files with 99 additions and 4 deletions

View File

@ -70,6 +70,11 @@ object_set_property(P3D_object *object, const char *property,
return ((P3DObject *)object)->set_property(property, value);
}
static bool
object_has_method(const P3D_object *object, const char *method_name) {
return ((const P3DObject *)object)->has_method(method_name);
}
static P3D_object *
object_call(const P3D_object *object, const char *method_name,
P3D_object *params[], int num_params) {
@ -95,6 +100,7 @@ P3D_class_definition P3DObject::_object_class = {
&object_get_repr,
&object_get_property,
&object_set_property,
&object_has_method,
&object_call,
&object_eval,
};
@ -163,6 +169,11 @@ generic_set_property(P3D_object *object, const char *property,
return false;
}
static bool
generic_has_method(const P3D_object *object, const char *method_name) {
return ((const P3DObject *)object)->has_method(method_name);
}
static P3D_object *
generic_call(const P3D_object *object, const char *method_name,
P3D_object *params[], int num_params) {
@ -188,6 +199,7 @@ P3D_class_definition P3DObject::_generic_class = {
&generic_get_repr,
&generic_get_property,
&generic_set_property,
&generic_has_method,
&generic_call,
&generic_eval,
};
@ -297,6 +309,17 @@ set_property(const string &property, P3D_object *value) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: P3DObject::has_method
// Access: Public, Virtual
// Description: Returns true if the named method exists on this
// object, false otherwise.
////////////////////////////////////////////////////////////////////
bool P3DObject::
has_method(const string &method_name) const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: P3DObject::call
// Access: Public, Virtual

View File

@ -46,6 +46,7 @@ public:
virtual P3D_object *get_property(const string &property) const;
virtual bool set_property(const string &property, P3D_object *value);
virtual bool has_method(const string &method_name) const;
virtual P3D_object *call(const string &method_name,
P3D_object *params[], int num_params) const;
virtual P3D_object *eval(const string &expression) const;

View File

@ -173,6 +173,29 @@ set_property(const string &property, P3D_object *value) {
return bresult;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonObject::has_method
// Access: Public, Virtual
// Description: Returns true if the named method exists on this
// object, false otherwise.
////////////////////////////////////////////////////////////////////
bool P3DPythonObject::
has_method(const string &method_name) const {
bool bresult = false;
P3D_object *params[1];
params[0] = new P3DStringObject(method_name);
P3D_object *result = call("__has_method__", params, 1);
if (result != NULL) {
bresult = P3D_OBJECT_GET_BOOL(result);
P3D_OBJECT_FINISH(result);
}
return bresult;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonObject::call
// Access: Public, Virtual

View File

@ -44,6 +44,7 @@ public:
virtual P3D_object *get_property(const string &property) const;
virtual bool set_property(const string &property, P3D_object *value);
virtual bool has_method(const string &method_name) const;
virtual P3D_object *call(const string &method_name,
P3D_object *params[], int num_params) const;

View File

@ -395,6 +395,28 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
}
}
} else if (strcmp(method_name, "__has_method__") == 0) {
char *property_name;
result = Py_False;
if (PyArg_ParseTuple(params, "s", &property_name)) {
if (*property_name) {
// Check for a callable method
if (PyObject_HasAttrString(obj, property_name)) {
PyObject *prop = PyObject_GetAttrString(obj, property_name);
if (PyCallable_Check(prop)) {
result = Py_True;
}
Py_DECREF(prop);
}
} else {
// Check for the default method
if (PyCallable_Check(obj)) {
result = Py_True;
}
}
}
Py_INCREF(result);
} else {
// Not a special-case name. Call the named method.
PyObject *method = PyObject_GetAttrString(obj, (char *)method_name);

View File

@ -377,6 +377,14 @@ typedef bool
P3D_object_set_property_method(P3D_object *object, const char *property,
P3D_object *value);
/* Returns true if the indicated method name exists on the object,
false otherwise. In the Python case, this actually returns true if
the object has the indicated property, and that property represents
a callable object. If method_name is empty or NULL, returns true
if the object itself is callable. */
typedef bool
P3D_object_has_method_method(const P3D_object *object, const char *method_name);
/* Invokes a named method on the object. If method_name is empty or
NULL, invokes the object itself as a function. You must pass an
array of P3D_objects as the list of parameters. The ownership of
@ -416,6 +424,7 @@ typedef struct _P3D_class_definition {
P3D_object_get_property_method *_get_property;
P3D_object_set_property_method *_set_property;
P3D_object_has_method_method *_has_method;
P3D_object_call_method *_call;
P3D_object_eval_method *_eval;
@ -444,6 +453,7 @@ struct _P3D_object {
#define P3D_OBJECT_GET_PROPERTY(object, property) ((object)->_class->_get_property((object), (property)))
#define P3D_OBJECT_SET_PROPERTY(object, property, value) ((object)->_class->_set_property((object), (property), (value)))
#define P3D_OBJECT_HAS_METHOD(object, property) ((object)->_class->_has_method((object), (property)))
#define P3D_OBJECT_CALL(object, method_name, params, num_params) ((object)->_class->_call((object), (method_name), (params), (num_params)))
#define P3D_OBJECT_EVAL(object, expression) ((object)->_class->_eval((object), (expression)))

View File

@ -101,11 +101,26 @@ invalidate() {
////////////////////////////////////////////////////////////////////
bool PPPandaObject::
has_method(NPIdentifier name) {
string property_name = identifier_to_string(name);
logfile << "has_method: " << this << ", " << property_name << "\n" << flush;
string method_name = identifier_to_string(name);
logfile << "has_method: " << this << ", " << method_name << "\n" << flush;
if (_p3d_object == NULL) {
// Not powered up yet.
return false;
}
// As below, we always return true. Why not?
return true;
// Unlike has_property(), below, it turns out that we really do need
// to honestly answer whether there is a method by this name,
// because if there is, then Firefox won't query the property in a
// meaningful fashion.
// Of course, in Python the distinction between property and method
// is a little looser than Firefox seems to want to make it, and
// sometimes you have an object which is both. This could become
// problematic in obscure situations. Too bad, say I. Mozilla's
// bug, not mine.
bool result = P3D_OBJECT_HAS_METHOD(_p3d_object, method_name.c_str());
return result;
}
////////////////////////////////////////////////////////////////////