[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