Trolltech Home | QSA-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

QSA-interest Archive, October 2005
automatic casting of variables to its superclass-type


Message 1 in thread

Hi trolls
This could be a feature-request for the next QSA ( but hopefully it is already 
possible with 1.2.0).
After working with QSA for some time now I thought about the possibility of 
wrapping whole C++-libraries to be able to use them with QScripts. Together 
with the Qt-Plugin-System it would be possible to give an application new 
functions of external libraries by simply adding a new wrapper-plugin.
I have already wrote a source-code-generator to be able to simply choose 
the include-files of the library to create wrapper-classes for each 
library-class. But now I´m really stuck.

The problem is, that a slot like "void setMyClass(MySuperClass*)" cannot be 
used in a script with objects from classes which inherit MySuperClass.
(which is possible in C++)
With the class-definitions from the end of this email, I would like to run a 
script like this:
	var C     = new MyClass();
	var useC = new MyUseClass();
	useC.setMyClass( C );

What I did:
I wrapped all classes of the external library and registerd these 
wrapper-classes in MyQSObjectFactory. 
The constructor of MyQSObjectFactory includes   
  qRegisterMetaType<MySuperClass>("MySuperClass");
  qRegisterMetaType<MyClass>("MySuperClass");
  qRegisterMetaType<MyClass>("MyUseClass");
,too.

The wrapper-classes are useable in QScripts as long as I call them with 
objects of desired class-Type.
This would work:
	var superC = new MySuperClass();
	var useC    = new MyUseClass();
	useC.setMyClass(superC);
But this does not work:
	var C      = new MySuperClass();
	var useC  = new MyUseClass();
	useC.setMyClass(C);

Qt´s metasystem should be able to figure out if the desired class is a 
superclass of the delivered one and could accept the variable.
I wonder why QVariant does not cast automatically.

What can I do ?

	Greetings
		Jens 

======================================
class MySuperClass
{
	public slots:
		virtual void wrapSuperFunc1();
		virtual void wrapSuperFunc2();
}
Q_DECLARE_METATYPE(MySuperClass)

class MyClass : public MySuperClass
{
	public slots:
		void wrapFunc1();
		void wrapFunc2();
}
Q_DECLARE_METATYPE(MyClass)
-----------------

class MyUseClass
{
	public slots:
		void setMyClass(MySuperClass* superClass);
}
Q_DECLARE_METATYPE(MyUseClass)


Message 2 in thread

Hi
Some kind of silent on this mailing list ;) , but I thought just to tell my 
workaround.
As it seems there is no possibility to make a QVariant automatically cast to a 
different type (it would be a great feature for Qt 4.x to extend QMetaType 
the way, that you can decide if autocasting is active or not when registering 
a new usertype ).
Because of that every class the user can create in QScript through my 
QSObjectFactories has a function to cast to its superclass like 
"MySuperClass* castTo_MySuperClass() { return this; }".

That way the user can use an object of MyUseClass as an argument in a function 
which requests a MySuperClass-object.
"var x = getBlaBla( objUseClass.castToMySuperClass() );" 

I still would like to see QScript/QVariant doing the casting automatically, 
because its not nice code using all this "castTo_..."-functions all over the 
place in a script.

Greetings
	Jens



Am Donnerstag, 6. Oktober 2005 00:52 schrieb Jens:
> Hi trolls
> This could be a feature-request for the next QSA ( but hopefully it is
> already possible with 1.2.0).
> After working with QSA for some time now I thought about the possibility of
> wrapping whole C++-libraries to be able to use them with QScripts. Together
> with the Qt-Plugin-System it would be possible to give an application new
> functions of external libraries by simply adding a new wrapper-plugin.
> I have already wrote a source-code-generator to be able to simply choose
> the include-files of the library to create wrapper-classes for each
> library-class. But now I´m really stuck.
>
> The problem is, that a slot like "void setMyClass(MySuperClass*)" cannot be
> used in a script with objects from classes which inherit MySuperClass.
> (which is possible in C++)
> With the class-definitions from the end of this email, I would like to run
> a script like this:
> 	var C     = new MyClass();
> 	var useC = new MyUseClass();
> 	useC.setMyClass( C );
>
> What I did:
> I wrapped all classes of the external library and registerd these
> wrapper-classes in MyQSObjectFactory.
> The constructor of MyQSObjectFactory includes
>   qRegisterMetaType<MySuperClass>("MySuperClass");
>   qRegisterMetaType<MyClass>("MySuperClass");
>   qRegisterMetaType<MyClass>("MyUseClass");
> ,too.
>
> The wrapper-classes are useable in QScripts as long as I call them with
> objects of desired class-Type.
> This would work:
> 	var superC = new MySuperClass();
> 	var useC    = new MyUseClass();
> 	useC.setMyClass(superC);
> But this does not work:
> 	var C      = new MySuperClass();
> 	var useC  = new MyUseClass();
> 	useC.setMyClass(C);
>
> Qt´s metasystem should be able to figure out if the desired class is a
> superclass of the delivered one and could accept the variable.
> I wonder why QVariant does not cast automatically.
>
> What can I do ?
>
> 	Greetings
> 		Jens
>
> ======================================
> class MySuperClass
> {
> 	public slots:
> 		virtual void wrapSuperFunc1();
> 		virtual void wrapSuperFunc2();
> }
> Q_DECLARE_METATYPE(MySuperClass)
>
> class MyClass : public MySuperClass
> {
> 	public slots:
> 		void wrapFunc1();
> 		void wrapFunc2();
> }
> Q_DECLARE_METATYPE(MyClass)
> -----------------
>
> class MyUseClass
> {
> 	public slots:
> 		void setMyClass(MySuperClass* superClass);
> }
> Q_DECLARE_METATYPE(MyUseClass)
>
> To unsubscribe - send "unsubscribe" in the body to
> qsa-interest-request@xxxxxxxxxxxxx


Message 3 in thread

Jens wrote:
> Hi trolls
> This could be a feature-request for the next QSA ( but hopefully it is already 
> possible with 1.2.0).
> After working with QSA for some time now I thought about the possibility of 
> wrapping whole C++-libraries to be able to use them with QScripts. Together 
> with the Qt-Plugin-System it would be possible to give an application new 
> functions of external libraries by simply adding a new wrapper-plugin.
> I have already wrote a source-code-generator to be able to simply choose 
> the include-files of the library to create wrapper-classes for each 
> library-class. But now I´m really stuck.
> 
> The problem is, that a slot like "void setMyClass(MySuperClass*)" cannot be 
> used in a script with objects from classes which inherit MySuperClass.
> (which is possible in C++)
> With the class-definitions from the end of this email, I would like to run a 
> script like this:
> 	var C     = new MyClass();
> 	var useC = new MyUseClass();
> 	useC.setMyClass( C );
> 
> What I did:
> I wrapped all classes of the external library and registerd these 
> wrapper-classes in MyQSObjectFactory. 
> The constructor of MyQSObjectFactory includes   
>   qRegisterMetaType<MySuperClass>("MySuperClass");
>   qRegisterMetaType<MyClass>("MySuperClass");
>   qRegisterMetaType<MyClass>("MyUseClass");
> ,too.

Hi Jens,

Granted that the types are QObjects and have the Q_OBJECT macro there 
should be no problem in passing a subclass to a base class. The example 
below works without problems. Its likely be that the registring of 
metatypes introduces conflicts, because then there also exists a 
QVariant conversion for the objects in addition to the QObject hiearachy.

Regards,
Gunnar

---

#include <qsinterpreter.h>
#include <qsobjectfactory.h>

#include <qapplication.h>

class BaseClass : public QObject { Q_OBJECT };
class SubClass : public BaseClass { Q_OBJECT };

class Object : public QObject
{
     Q_OBJECT
public:
     Object(QObject *parent = 0, const char *name = "context")
         : QObject(parent)
     {
         setObjectName(name);
     };
public slots:
     void takeBaseClass(BaseClass *bc) {
         printf("base class ok: %s\n", bc->metaObject()->className());
     }
};

class Factory : public QSObjectFactory
{
public:
     Factory()
     {
         registerClass("BaseClass", &BaseClass::staticMetaObject);
         registerClass("SubClass", &SubClass::staticMetaObject);
     }

     QObject *create(const QString &name, const QVariantList &args, 
QObject *context)
     {
         return name == "BaseClass" ? new BaseClass : new SubClass;
     }
};

int main(int argc, char **argv)
{
     QApplication app(argc, argv);
     QSInterpreter ip;

     Object obj;

     ip.addObjectFactory(new Factory);

     ip.evaluate("var subclass = new SubClass();\n"
                 "context.takeBaseClass(subclass);\n"
                 "var baseclass = new BaseClass();\n"
                 "context.takeBaseClass(baseclass)\n", &obj);
}

#include "pass_baseclass.moc"


Message 4 in thread

Am Freitag, 7. Oktober 2005 13:28 schrieb Gunnar Sletta:
> Jens wrote:
> > Hi trolls
> > This could be a feature-request for the next QSA ( but hopefully it is
> > already possible with 1.2.0).
> > After working with QSA for some time now I thought about the possibility
> > of wrapping whole C++-libraries to be able to use them with QScripts.
> > Together with the Qt-Plugin-System it would be possible to give an
> > application new functions of external libraries by simply adding a new
> > wrapper-plugin. I have already wrote a source-code-generator to be able
> > to simply choose the include-files of the library to create
> > wrapper-classes for each library-class. But now I´m really stuck.
> >
> > The problem is, that a slot like "void setMyClass(MySuperClass*)" cannot
> > be used in a script with objects from classes which inherit MySuperClass.
> > (which is possible in C++)
> > With the class-definitions from the end of this email, I would like to
> > run a script like this:
> > 	var C     = new MyClass();
> > 	var useC = new MyUseClass();
> > 	useC.setMyClass( C );
> >
> > What I did:
> > I wrapped all classes of the external library and registerd these
> > wrapper-classes in MyQSObjectFactory.
> > The constructor of MyQSObjectFactory includes
> >   qRegisterMetaType<MySuperClass>("MySuperClass");
> >   qRegisterMetaType<MyClass>("MySuperClass");
> >   qRegisterMetaType<MyClass>("MyUseClass");
> > ,too.
>
> Hi Jens,
>
> Granted that the types are QObjects and have the Q_OBJECT macro there
> should be no problem in passing a subclass to a base class. The example
> below works without problems. Its likely be that the registring of
> metatypes introduces conflicts, because then there also exists a
> QVariant conversion for the objects in addition to the QObject hiearachy.
>
Hi Gunnar
I actually thought it´s a good idea to register all classes as metatypes, but 
that introduces conflicts. After removing the QT_DECLARE_METATYPE lines I 
have no problems with passing a subclass to a base class anymore.
Thanks for your help.

Greetings
	Jens

> Regards,
> Gunnar
>
> ---
>
> #include <qsinterpreter.h>
> #include <qsobjectfactory.h>
>
> #include <qapplication.h>
>
> class BaseClass : public QObject { Q_OBJECT };
> class SubClass : public BaseClass { Q_OBJECT };
>
> class Object : public QObject
> {
>      Q_OBJECT
> public:
>      Object(QObject *parent = 0, const char *name = "context")
>
>          : QObject(parent)
>
>      {
>          setObjectName(name);
>      };
> public slots:
>      void takeBaseClass(BaseClass *bc) {
>          printf("base class ok: %s\n", bc->metaObject()->className());
>      }
> };
>
> class Factory : public QSObjectFactory
> {
> public:
>      Factory()
>      {
>          registerClass("BaseClass", &BaseClass::staticMetaObject);
>          registerClass("SubClass", &SubClass::staticMetaObject);
>      }
>
>      QObject *create(const QString &name, const QVariantList &args,
> QObject *context)
>      {
>          return name == "BaseClass" ? new BaseClass : new SubClass;
>      }
> };
>
> int main(int argc, char **argv)
> {
>      QApplication app(argc, argv);
>      QSInterpreter ip;
>
>      Object obj;
>
>      ip.addObjectFactory(new Factory);
>
>      ip.evaluate("var subclass = new SubClass();\n"
>                  "context.takeBaseClass(subclass);\n"
>                  "var baseclass = new BaseClass();\n"
>                  "context.takeBaseClass(baseclass)\n", &obj);
> }
>
> #include "pass_baseclass.moc"
>
> To unsubscribe - send "unsubscribe" in the body to
> qsa-interest-request@xxxxxxxxxxxxx


Message 5 in thread

Hi
I have already mentioned this on this mailing list a week ago and could solve 
my problems by removing the registration of the wrapper-class as a metatype.

But it seems that this solution only works with classes which have only one 
single superclass. Right now my wrapper-class is defined like:
class myWrapper : public QObject, public QVSWrapper { ... }

( Because myWrapper is part of a plugin (I´m using the QPluginLoader) the 
interface QVSWrapper must not inherit from QObject. .. But it has a function 
"virtual QObject* object() { return m_pBaseObj; }" with m_pBaseObj gets set 
in the constructor:
	myWrapper::myWrapper(...) : QObject(), QVSWrapper(this) { ... }
)

If I have a slot which needs a QVSWrapper, it is not possible to give it a 
myWrapper ... I get a segfault if I run a script like:
A)
var wrapper = new myWrapper();
Application.currentView.registerObject( wrapper );

Right now I have a slot "as_QVSObject()" like this:
QVSObject* as_QVSObject() { return this; }; to be able to write a script like:
B)
var wrapper = new myWrapper();
Application.currentView.registerObject( wrapper.as_QVSObject() );

The "normal" User will try to program a script like "A" and I would like to 
make it work like this. What can I do?

Greetings
	Jens 

P.S:
I have seen that QMetaObject::superClass() returns only one single 
QMetaObject. What happens if a class inherits from two superclasses?


Message 6 in thread

Hi
Here my result: 
QObject can only be once in the "inheriting-chain". That´s one reason why my 
QVSObject isn´t based on QObject. If my QVSObject isn´t based on QObject it 
has no QMetaObject and isn´t known as a superclass to Qt :(

Anyway, QSA shouldn´t segfault if the user calls a function which expects a 
QVSObject with a myWrapper.
( class myWrapper : public QObject, public QVSObject )

	Greetings
		Jens

Am Donnerstag, 13. Oktober 2005 13:31 schrieb Jens:
> Hi
> I have already mentioned this on this mailing list a week ago and could
> solve my problems by removing the registration of the wrapper-class as a
> metatype.
>
> But it seems that this solution only works with classes which have only one
> single superclass. Right now my wrapper-class is defined like:
> class myWrapper : public QObject, public QVSWrapper { ... }
>
> ( Because myWrapper is part of a plugin (I´m using the QPluginLoader) the
> interface QVSWrapper must not inherit from QObject. .. But it has a
> function "virtual QObject* object() { return m_pBaseObj; }" with m_pBaseObj
> gets set in the constructor:
> 	myWrapper::myWrapper(...) : QObject(), QVSWrapper(this) { ... }
> )
>
> If I have a slot which needs a QVSWrapper, it is not possible to give it a
> myWrapper ... I get a segfault if I run a script like:
> A)
> var wrapper = new myWrapper();
> Application.currentView.registerObject( wrapper );
>
> Right now I have a slot "as_QVSObject()" like this:
> QVSObject* as_QVSObject() { return this; }; to be able to write a script
> like: B)
> var wrapper = new myWrapper();
> Application.currentView.registerObject( wrapper.as_QVSObject() );
>
> The "normal" User will try to program a script like "A" and I would like to
> make it work like this. What can I do?
>
> Greetings
> 	Jens
>
> P.S:
> I have seen that QMetaObject::superClass() returns only one single
> QMetaObject. What happens if a class inherits from two superclasses?
>
> To unsubscribe - send "unsubscribe" in the body to
> qsa-interest-request@xxxxxxxxxxxxx