[Kde-bindings] KDE/kdebindings/qtruby
Richard Dale
Richard_Dale at tipitina.demon.co.uk
Mon Dec 4 09:49:11 UTC 2006
SVN commit 610424 by rdale:
* Add a QMap<int,QVariant> marshaller
* When marhalling QMap types with QVariant values, if the Ruby value isn't
a Qt::Variant then one is created
* Qt::Variants can now be constructed with Hash's of String/Qt::Variant
pairs, and from Arrays of Qt::Variants
* Custom types know to the QMetaType system, such as some QtDBus types,
can be used to construct Qt::Variant via the QMetaType::constructor() call
* Fixed a bug in Qt::AbstractItemModel.createIndex() which meant it wouldn't
work on 64 bit machines
CCMAIL: kde-bindings at kde.org
M +12 -0 ChangeLog
M +129 -58 rubylib/qtruby/Qt.cpp
M +98 -11 rubylib/qtruby/handlers.cpp
M +4 -0 rubylib/qtruby/lib/Qt/qtruby4.rb
--- trunk/KDE/kdebindings/qtruby/ChangeLog #610423:610424
@@ -1,3 +1,15 @@
+2006-12-04 Richard Dale <rdale at foton.es>
+
+ * Add a QMap<int,QVariant> marshaller
+ * When marhalling QMap types with QVariant values, if the Ruby value isn't
+ a Qt::Variant then one is created
+ * Qt::Variants can now be constructed with Hash's of String/Qt::Variant
+ pairs, and from Arrays of Qt::Variants
+ * Custom types know to the QMetaType system, such as some QtDBus types,
+ can be used to construct Qt::Variant via the QMetaType::constructor() call
+ * Fixed a bug in Qt::AbstractItemModel.createIndex() which meant it wouldn't
+ work on 64 bit machines
+
2006-11-30 Richard Dale <rdale at foton.es>
* The Qt::KeySequence constructor wasn't working when passed a
--- trunk/KDE/kdebindings/qtruby/rubylib/qtruby/Qt.cpp #610423:610424
@@ -158,9 +158,9 @@
}
smokeruby_object *value_obj_info(VALUE ruby_value) { // ptr on success, null on fail
- if (TYPE(ruby_value) != T_DATA) {
- return 0;
- }
+ if (TYPE(ruby_value) != T_DATA) {
+ return 0;
+ }
smokeruby_object * o = 0;
Data_Get_Struct(ruby_value, smokeruby_object, o);
@@ -175,35 +175,40 @@
VALUE getPointerObject(void *ptr);
bool isQObject(Smoke *smoke, Smoke::Index classId) {
- if(strcmp(smoke->classes[classId].className, "QObject") == 0)
+ if (strcmp(smoke->classes[classId].className, "QObject") == 0) {
return true;
-
- for(Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents;
- *p;
- p++) {
- if(isQObject(smoke, *p))
- return true;
+ }
+
+ for (Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents; *p; p++) {
+ if (isQObject(smoke, *p)) {
+ return true;
+ }
}
+
return false;
}
bool isDerivedFrom(Smoke *smoke, Smoke::Index classId, Smoke::Index baseId) {
- if(classId == 0 && baseId == 0)
- return false;
- if(classId == baseId)
- return true;
- for(Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents;
- *p;
- p++) {
- if(isDerivedFrom(smoke, *p, baseId))
- return true;
+ if (classId == 0 && baseId == 0) {
+ return false;
+ }
+
+ if (classId == baseId) {
+ return true;
+ }
+
+ for(Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents; *p; p++) {
+ if (isDerivedFrom(smoke, *p, baseId)) {
+ return true;
+ }
}
return false;
}
bool isDerivedFromByName(Smoke *smoke, const char *className, const char *baseClassName) {
- if(!smoke || !className || !baseClassName)
- return false;
+ if (!smoke || !className || !baseClassName) {
+ return false;
+ }
Smoke::Index idClass = smoke->idClass(className);
Smoke::Index idBase = smoke->idClass(baseClassName);
return isDerivedFrom(smoke, idClass, idBase);
@@ -224,26 +229,25 @@
}
void unmapPointer(smokeruby_object *o, Smoke::Index classId, void *lastptr) {
- void *ptr = o->smoke->cast(o->ptr, o->classId, classId);
- if(ptr != lastptr) {
- lastptr = ptr;
- if (pointer_map.contains(ptr)) {
- VALUE * obj_ptr = pointer_map[ptr];
+ void *ptr = o->smoke->cast(o->ptr, o->classId, classId);
+ if (ptr != lastptr) {
+ lastptr = ptr;
+ if (pointer_map.contains(ptr)) {
+ VALUE * obj_ptr = pointer_map[ptr];
- if (do_debug & qtdb_gc) {
- const char *className = o->smoke->classes[o->classId].className;
- qWarning("unmapPointer (%s*)%p -> %p size: %d", className, ptr, obj_ptr, pointer_map.size() - 1);
+ if (do_debug & qtdb_gc) {
+ const char *className = o->smoke->classes[o->classId].className;
+ qWarning("unmapPointer (%s*)%p -> %p size: %d", className, ptr, obj_ptr, pointer_map.size() - 1);
+ }
+
+ pointer_map.remove(ptr);
+ xfree((void*) obj_ptr);
}
-
- pointer_map.remove(ptr);
- xfree((void*) obj_ptr);
+ }
+
+ for (Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents; *i; i++) {
+ unmapPointer(o, *i, lastptr);
}
- }
- for(Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents;
- *i;
- i++) {
- unmapPointer(o, *i, lastptr);
- }
}
// Store pointer in pointer_map hash : "pointer_to_Qt_object" => weak ref to associated Ruby object
@@ -265,11 +269,9 @@
pointer_map.insert(ptr, obj_ptr);
}
- for(Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents;
- *i;
- i++) {
- mapPointer(obj, o, *i, lastptr);
- }
+ for (Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents; *i; i++) {
+ mapPointer(obj, o, *i, lastptr);
+ }
return;
}
@@ -584,6 +586,8 @@
QVariant * variant = (QVariant*) o->ptr;
void * value_ptr = 0;
+ VALUE result = Qnil;
+ smokeruby_object * vo = 0;
if (strcmp(classname, "Qt::Pixmap") == 0) {
QPixmap v = qVariantValue<QPixmap>(*variant);
@@ -633,10 +637,8 @@
} else if (strcmp(classname, "Qt::TextFormat") == 0) {
QTextFormat v = qVariantValue<QTextFormat>(*variant);
value_ptr = (void *) new QTextFormat(v);
- } else if ( strcmp(classname, "Qt::DBusArgument") == 0
- && qstrcmp(variant->typeName(), "QDBusArgument") == 0 )
- {
- value_ptr = (void *) variant->constData();
+ } else if (variant->type() >= QVariant::UserType) {
+ value_ptr = QMetaType::construct(QMetaType::type(variant->typeName()), (void *) variant->constData());
} else {
// Assume the value of the Qt::Variant can be obtained
// with a call such as Qt::Variant.toPoint()
@@ -648,8 +650,7 @@
return rb_funcall(variant_value, rb_intern(toValueMethodName), 1, variant_value);
}
- VALUE result = Qnil;
- smokeruby_object * vo = alloc_smokeruby_object(true, o->smoke, *value_class_id, value_ptr);
+ vo = alloc_smokeruby_object(true, o->smoke, *value_class_id, value_ptr);
result = set_obj_info(classname, vo);
return result;
@@ -704,6 +705,8 @@
v = new QVariant(qVariantFromValue(*(QTextLength*) o->ptr));
} else if (strcmp(classname, "Qt::TextFormat") == 0) {
v = new QVariant(qVariantFromValue(*(QTextFormat*) o->ptr));
+ } else if (QVariant::nameToType(o->smoke->classes[o->classId].className) >= QVariant::UserType) {
+ v = new QVariant(QVariant::nameToType(o->smoke->classes[o->classId].className), o->ptr);
} else {
// Assume the Qt::Variant can be created with a
// Qt::Variant.new(obj) call
@@ -1373,13 +1376,35 @@
}
static VALUE
-qabstractitemmodel_createindex(int argc, VALUE * argv, VALUE /* self */)
+qabstractitemmodel_createindex(int argc, VALUE * argv, VALUE self)
{
- if (argc == 3 && TYPE(argv[2]) != T_FIXNUM && TYPE(argv[2]) != T_BIGNUM) {
- // Change the VALUE to a Ruby Integer, so it can be marshalled to a
- // C++ int. Then look for the QAbstractItemModel::createIndex(int, int, int)
- // variant
- argv[2] = INT2NUM(argv[2]);
+ if (argc == 3) {
+ smokeruby_object * o = value_obj_info(self);
+ Smoke::Index nameId = o->smoke->idMethodName("createIndex$$$");
+ Smoke::Index meth = o->smoke->findMethod(qt_Smoke->idClass("QAbstractItemModel"), nameId);
+ Smoke::Index i = o->smoke->methodMaps[meth].method;
+ i = -i; // turn into ambiguousMethodList index
+ while (o->smoke->ambiguousMethodList[i] != 0) {
+ if ( strcmp( o->smoke->types[o->smoke->argumentList[o->smoke->methods[o->smoke->ambiguousMethodList[i]].args + 2]].name,
+ "void*" ) == 0 )
+ {
+ Smoke::Method &m = o->smoke->methods[o->smoke->ambiguousMethodList[i]];
+ Smoke::ClassFn fn = o->smoke->classes[m.classId].classFn;
+ Smoke::StackItem stack[4];
+ stack[1].s_int = NUM2INT(argv[0]);
+ stack[2].s_int = NUM2INT(argv[1]);
+ stack[3].s_voidp = (void*) argv[2];
+ (*fn)(m.method, o->ptr, stack);
+ smokeruby_object * result = alloc_smokeruby_object( true,
+ o->smoke,
+ o->smoke->idClass("QModelIndex"),
+ new QModelIndex(*((QModelIndex*) stack[0].s_voidp)) );
+
+ return set_obj_info("Qt::ModelIndex", result);
+ }
+
+ i++;
+ }
}
return rb_call_super(argc, argv);
@@ -1462,6 +1487,51 @@
return obj;
}
+static VALUE
+new_qvariant(int argc, VALUE * argv, VALUE self)
+{
+static Smoke::Index new_qvariant_qlist = 0;
+static Smoke::Index new_qvariant_qmap = 0;
+
+ if (new_qvariant_qlist == 0) {
+ Smoke::Index nameId = qt_Smoke->idMethodName("QVariant?");
+ Smoke::Index meth = qt_Smoke->findMethod(qt_Smoke->idClass("QVariant"), nameId);
+ Smoke::Index i = qt_Smoke->methodMaps[meth].method;
+ i = -i; // turn into ambiguousMethodList index
+ while (qt_Smoke->ambiguousMethodList[i] != 0) {
+ const char * argType = qt_Smoke->types[qt_Smoke->argumentList[qt_Smoke->methods[qt_Smoke->ambiguousMethodList[i]].args]].name;
+
+ if (strcmp(argType, "const QList<QVariant>&" ) == 0) {
+ new_qvariant_qlist = qt_Smoke->ambiguousMethodList[i];
+ } else if (strcmp(argType, "const QMap<QString,QVariant>&" ) == 0) {
+ new_qvariant_qmap = qt_Smoke->ambiguousMethodList[i];
+ }
+
+ i++;
+ }
+ }
+
+ if (argc == 1 && TYPE(argv[0]) == T_HASH) {
+ _current_method = new_qvariant_qmap;
+ MethodCall c(qt_Smoke, _current_method, self, argv, argc-1);
+ c.next();
+ return *(c.var());
+ } else if ( argc == 1
+ && TYPE(argv[0]) == T_ARRAY
+ && RARRAY(argv[0])->len > 0 )
+ {
+ smokeruby_object * o = value_obj_info(rb_ary_entry(argv[0], 0));
+ if (o != 0 && strcmp(o->smoke->classes[o->classId].className, "QVariant") == 0) {
+ _current_method = new_qvariant_qlist;
+ MethodCall c(qt_Smoke, _current_method, self, argv, argc-1);
+ c.next();
+ return *(c.var());
+ }
+ }
+
+ return rb_call_super(argc, argv);
+}
+
static QByteArray *
find_cached_selector(int argc, VALUE * argv, VALUE klass, char * methodName)
{
@@ -1715,7 +1785,7 @@
if (TYPE(self) == T_DATA) {
// If a ruby block was passed then run that now
if (rb_block_given_p()) {
- rb_funcall(qt_internal_module, rb_intern("run_initializer_block"), 2, self, rb_block_proc());
+ rb_funcall(qt_internal_module, rb_intern("run_initializer_block"), 2, self, rb_block_proc());
}
return self;
@@ -1736,8 +1806,6 @@
}
{
- // Put this in a C block so that the mcid will be de-allocated at the end of the block,
- // rather than on f'n exit, to avoid the longjmp problem described below
QByteArray * mcid = find_cached_selector(argc+4, temp_stack, klass, rb_class2name(klass));
if (_current_method == -1) {
@@ -2907,6 +2975,8 @@
qtextlayout_class = klass;
} else if (packageName == "Qt::Variant") {
qvariant_class = klass;
+ rb_define_singleton_method(qvariant_class, "fromValue", (VALUE (*) (...)) qvariant_from_value, 1);
+ rb_define_singleton_method(qvariant_class, "new", (VALUE (*) (...)) new_qvariant, -1);
} else if (packageName == "Qt::ByteArray") {
rb_define_method(klass, "+", (VALUE (*) (...)) qbytearray_append, 1);
} else if (packageName == "Qt::Char") {
@@ -3038,6 +3108,7 @@
rb_define_method(qt_base_class, "dispose", (VALUE (*) (...)) dispose, 0);
rb_define_method(qt_base_class, "isDisposed", (VALUE (*) (...)) is_disposed, 0);
rb_define_method(qt_base_class, "disposed?", (VALUE (*) (...)) is_disposed, 0);
+
rb_define_method(qt_base_class, "qVariantValue", (VALUE (*) (...)) qvariant_value, 2);
rb_define_method(qt_base_class, "qVariantFromValue", (VALUE (*) (...)) qvariant_from_value, 1);
--- trunk/KDE/kdebindings/qtruby/rubylib/qtruby/handlers.cpp #610423:610424
@@ -74,6 +74,7 @@
extern "C" {
extern VALUE set_obj_info(const char * className, smokeruby_object * o);
extern VALUE qt_internal_module;
+extern VALUE qvariant_class;
extern bool application_terminated;
};
@@ -1455,13 +1456,13 @@
}
void marshall_QMapQStringQVariant(Marshall *m) {
- switch(m->action()) {
- case Marshall::FromVALUE:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
{
- VALUE hash = *(m->var());
- if (TYPE(hash) != T_HASH) {
- m->item().s_voidp = 0;
- break;
+ VALUE hash = *(m->var());
+ if (TYPE(hash) != T_HASH) {
+ m->item().s_voidp = 0;
+ break;
}
QMap<QString,QVariant> * map = new QMap<QString,QVariant>;
@@ -1474,12 +1475,17 @@
VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);
smokeruby_object *o = value_obj_info(value);
- if( !o || !o->ptr)
- continue;
- void * ptr = o->ptr;
- ptr = o->smoke->cast(ptr, o->classId, o->smoke->idClass("QVariant"));
+ if (!o || !o->ptr || o->classId != o->smoke->idClass("QVariant")) {
+ // If the value isn't a Qt::Variant, then try and construct
+ // a Qt::Variant from it
+ value = rb_funcall(qvariant_class, rb_intern("fromValue"), 1, value);
+ if (value == Qnil) {
+ continue;
+ }
+ o = value_obj_info(value);
+ }
- (*map)[QString(StringValuePtr(key))] = (QVariant)*(QVariant*)ptr;
+ (*map)[QString(StringValuePtr(key))] = (QVariant)*(QVariant*)o->ptr;
}
m->item().s_voidp = map;
@@ -1528,6 +1534,85 @@
}
}
+void marshall_QMapIntQVariant(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE hash = *(m->var());
+ if (TYPE(hash) != T_HASH) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ QMap<int,QVariant> * map = new QMap<int,QVariant>;
+
+ // Convert the ruby hash to an array of key/value arrays
+ VALUE temp = rb_funcall(hash, rb_intern("to_a"), 0);
+
+ for (long i = 0; i < RARRAY(temp)->len; i++) {
+ VALUE key = rb_ary_entry(rb_ary_entry(temp, i), 0);
+ VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);
+
+ smokeruby_object *o = value_obj_info(value);
+ if (!o || !o->ptr || o->classId != o->smoke->idClass("QVariant")) {
+ // If the value isn't a Qt::Variant, then try and construct
+ // a Qt::Variant from it
+ value = rb_funcall(qvariant_class, rb_intern("fromValue"), 1, value);
+ if (value == Qnil) {
+ continue;
+ }
+ o = value_obj_info(value);
+ }
+
+ (*map)[NUM2INT(key)] = (QVariant)*(QVariant*)o->ptr;
+ }
+
+ m->item().s_voidp = map;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QMap<int,QVariant> *map = (QMap<int,QVariant>*)m->item().s_voidp;
+ if (!map) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE hv = rb_hash_new();
+
+ QMap<int,QVariant>::Iterator it;
+ for (it = map->begin(); it != map->end(); ++it) {
+ void *p = new QVariant(it.value());
+ VALUE obj = getPointerObject(p);
+
+ if (obj == Qnil) {
+ smokeruby_object * o = alloc_smokeruby_object( true,
+ m->smoke(),
+ m->smoke()->idClass("QVariant"),
+ p );
+ obj = set_obj_info("Qt::Variant", o);
+ }
+
+ rb_hash_aset(hv, INT2NUM(it.key()), obj);
+ }
+
+ *(m->var()) = hv;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
void marshall_QMapintQVariant(Marshall *m) {
switch(m->action()) {
case Marshall::FromVALUE:
@@ -2072,6 +2157,8 @@
{ "QMap<QString,QString>", marshall_QMapQStringQString },
{ "QMap<QString,QString>&", marshall_QMapQStringQString },
{ "QMap<QString,QVariant>", marshall_QMapQStringQVariant },
+ { "QMap<int,QVariant>&", marshall_QMapIntQVariant },
+ { "QMap<int,QVariant>", marshall_QMapIntQVariant },
{ "QMap<QString,QVariant>&", marshall_QMapQStringQVariant },
{ "QList<QTextFrame*>", marshall_QTextFrameList },
{ "QList<QAction*>", marshall_QActionList },
--- trunk/KDE/kdebindings/qtruby/rubylib/qtruby/lib/Qt/qtruby4.rb #610423:610424
@@ -1693,6 +1693,10 @@
end
end
+ def value
+ return to_ruby
+ end
+
def inspect
str = super
str.sub(/>$/, " typeName=%s>" % typeName)
More information about the Kde-bindings
mailing list