SmokeObject * SmokeObject::fromPtr(void *ptr, const Class *klass, bool allocated, bool copy) { if (!klass) error("Attempt to create SmokeObject with NULL class"); if (!ptr) error("Attempt to create SmokeObject with NULL pointer"); SmokeObject *so = instances[ptr]; if (!so) { so = new SmokeObject(ptr, klass, allocated); #ifdef MEM_DEBUG qDebug("%p: created for %p (%s)", so, ptr, klass->name()); #endif // record this ASAP, resolveClassId() needs it for virtual callbacks if (allocated) // do not record unallocated; not informed when deleted instances[so->ptr()] = so; #ifdef MEM_DEBUG else qDebug("%p: unallocated, not registering pointer", so); #endif so->cast(Class::fromSmokeId(so->smoke(), so->module()->resolveClassId(so))); /* it seems that all multiple inheritance in Qt goes through QObject or QEvent, so we can catch offset pointers at run-time */ // FIXME: what happens with other libraries? take QtRuby approach? #ifdef MEM_DEBUG if (allocated && so->klass() != klass) qDebug("%p: class switch %s::%s -> %s::%s", so, klass->smokeBase()->smoke()->moduleName(), klass->name(), so->klass()->smokeBase()->smoke()->moduleName(), so->klass()->name()); #endif if (so->ptr() != ptr) { // must be multiple inheritance, recache SmokeObject *tmp_so = instances[so->ptr()]; #ifdef MEM_DEBUG qDebug("%p: multiple inheritance detected, switch to %p", so, so->ptr()); #endif if (tmp_so) { #ifdef MEM_DEBUG qDebug("%p: replaced with existing %p", so, tmp_so); #endif delete so; so = tmp_so; copy = false; // don't think we every want to copy here } else instances[so->ptr()] = so; instances.remove(ptr); } if (copy) { // copy the data void *tmp_ptr = so->ptr(); so->_ptr = so->clonePtr(); instances[so->ptr()] = so; // update the instances hash after cloning instances.remove(tmp_ptr); #ifdef MEM_DEBUG qDebug("%p: copied to %p", so, so->ptr()); #endif so->_allocated = true; } } return so; }
Method* MocClass::findMethod(const MethodCall& call) const { Method *method = _delegate->findMethod(call); if (method) return(method); SmokeObject *o = call.target(); /* only QObjects have meta methods */ if (o && o->ptr() && o->instanceOf("QObject") && o->klass() == this) { /* unwrap the call */ QObject * qobject = reinterpret_cast<QObject *>(o->castPtr("QObject")); const QMetaObject * meta = qobject->metaObject(); /* get the method id */ int id = findMethodId(o->smoke(), meta, call.method()->name(), call.args()); if (id >= 0) method = new MocMethod(o->smoke(), meta, id); } return method; }
QVariant qvariant_from_sexp(SEXP rvalue, int index) { QVariant variant; if (index == -1) { /* If a particular element is not selected, then non-lists of length one are considered scalars. Otherwise, collections. Except for raw vectors, which are naturally QByteArrays. */ if (TYPEOF(rvalue) == RAWSXP) return QVariant(from_sexp<QByteArray>(rvalue)); else if (TYPEOF(rvalue) == VECSXP || length(rvalue) > 1) { SEXP rlist = coerceVector(rvalue, VECSXP); if (getAttrib(rvalue, R_NamesSymbol) != R_NilValue) variant = asQVariantOfType(rlist, QMetaType::QVariantMap); else variant = asQVariantOfType(rlist, QMetaType::QVariantList); return variant; } index = 0; } switch(TYPEOF(rvalue)) { case RAWSXP: variant = qVariantFromValue(RAW(rvalue)[index]); break; case LGLSXP: // Rprintf("Logical\n"); // FIXME: by converting to 'bool' all NA become TRUE variant = QVariant((bool)LOGICAL(rvalue)[index]); break; case REALSXP: // Rprintf("Real\n"); variant = QVariant(REAL(rvalue)[index]); break; case INTSXP: // Rprintf("Integer\n"); { SEXP levels; if ((levels = getAttrib(rvalue, R_LevelsSymbol)) != R_NilValue) { int level = INTEGER(rvalue)[index]; SEXP level_str = NA_STRING; /*Rprintf("getting level: %d\n", level);*/ if (level != NA_INTEGER) level_str = STRING_ELT(levels, level - 1); variant = QVariant(sexp2qstring(level_str)); } else variant = QVariant(INTEGER(rvalue)[index]); break; } case STRSXP: // Rprintf("String\n"); variant = QVariant(sexp2qstring(STRING_ELT(rvalue, index))); break; case EXTPTRSXP: // Rprintf("External pointer\n"); variant = qVariantFromValue(unwrapPointer(rvalue, void)); break; case VECSXP: variant = from_sexp<QVariant>(VECTOR_ELT(rvalue, index)); break; case ENVSXP: { SmokeObject *so = SmokeObject::fromSexp(rvalue); if (so->instanceOf("QWidget")) variant = qVariantFromValue(reinterpret_cast<QWidget *>(so->castPtr("QWidget"))); else if (so->instanceOf("QObject")) variant = qVariantFromValue(reinterpret_cast<QObject *>(so->castPtr("QObject"))); else { QMetaType::Type type = (QMetaType::Type) QMetaType::type(so->className()); if (type) variant = asQVariantOfType(rvalue, type, false); else variant = qVariantFromValue(so->ptr()); } } break; case NILSXP: // invalid QVariant break; default: error("Converting to QVariant: unhandled R type"); } return variant; }