PDA

View Full Version : QVariant and Plugin interfaces



QPlace
4th August 2007, 20:06
I have interfaces obtained from plugins and these interface pointers are stuffed in a QList container. Then this container is shown in a combobox with smth. like:

MyInterface* ptrInterface; // pointer to interface
foreach(ptrInterface, m_container.List() )
ui.combobox->insertItem(0,ptrInterface->Description(), QVariant(ptrInterface));

Next, I am trying to retrieve the data associated with the combobox item:


MyInterface* ptrInterface= qvariant_cast<MyInterface*>(ui.cmbModels->itemData(0));

moc compiler complains that 'qt_metatype_id' : is not a member of 'QMetaTypeId<T>'.

Indeed there is no place to define metatype for interface since interface methods are abstract.

My question is: how to put interface into a combobox item data and then retrieve it? (I understand that currentIndex of combobox also points to a container, but I would rather retrieve the data from combobox item).

marcel
4th August 2007, 20:21
See Q_DECLARE_METATYPE (http://doc.trolltech.com/latest/q_declare_metatype.html) in the documentation.
qMetaTypeId() calls fail for a type that has not been declared with that macro.

EDIT: also, qRegisterMetaType could be of some help.

Regards

marcel
4th August 2007, 20:36
Otherwise, you could try adding QPointer containing the pointer to the interface as item data, and not directly the interface pointer.

Regards

QPlace
4th August 2007, 22:57
Marcel, thank you for this and also previous replies. Your help is greatly appreciated. In this particular case the problem seems to be that abstract classes cannot be used with Q_DECLARE_METATYPE. The same thing is QPointer encapsulation of a pointer to an abstract class.

If you have any code snipped that does it, can you please post it here ?

Thanks.

marcel
4th August 2007, 23:02
I don't have code for this, but I think the reason for that is your interfaces do not inherit QObject.
So, a possible solution is this.

Anyway, could you say what errors do you get?

Regards

QPlace
5th August 2007, 02:13
Here is how the interface class looks like with Q_DECLARE_METATYPE:

class ModelInterface : public QObject
{
public:
virtual ~ModelInterface() { }
virtual QString Description () = 0;
virtual int ID() = 0;
virtual bool setImplementation(QString fname) = 0;
};
Q_DECLARE_INTERFACE(ModelInterface,
"xxxx/1.0")
Q_DECLARE_METATYPE(ModelInterface)

It is defined in a header file (.h). Upon compiling I am getting following errors:

>xxxx\ModelInterface.h(14) : error C2259: 'ModelInterface' : cannot instantiate abstract class
2> due to following members:
2> 'QString ModelInterface::Description(void)' : is abstract
2> xxxx\ModelInterface.h(7) : see declaration of 'ModelInterface::Description'
2> 'int ModelInterface::ID(void)' : is abstract
....

When I take out Q_DECLARE_METATYPE everything compiles OK

(Adding Q_OBJECT to the class declaration does not change anything)

marcel
5th August 2007, 17:31
I think you can do this:


typedef struct InterfaceMask {
MyInterface *interfacePtr;
InterfaceMask() {
interfacePtr = NULL;
}
InterfaceMask(MyInterface* ptr) {
interfacePtr = ptr;
}
} InterfaceMask;

Q_DECLARE_METATYPE(InterfaceMask);


Next, when adding the interfaces to the combo:



MyInterface* ptrInterface; // pointer to interface
foreach(ptrInterface, m_container.List() )
{
InterfaceMask *mask = new InterfaceMask(ptrInterface);
ui.combobox->insertItem(0,ptrInterface->Description(), QVariant(mask));
}



Finally, you can retrieve it with:


InterfaceMask *mask = qvariant_cast<InterfaceMask*>(ui.cmbModels->itemData(0));
MyInterface* ptrInterface= mask->interfacePtr;


BTW, I didn't test this, but should work.

Regards

marcel
5th August 2007, 22:28
Ok. I think I have done it.


#include <QtCore/QCoreApplication>
#include "test.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

QVariant v = QVariant::fromValue(new holder(new impl()));
holder *h = qvariant_cast<holder*>(v);


return a.exec();
}


#ifndef TEST_H
#define TEST_H

#include <QtCore>

class intf
{
public:
virtual void xxx() = 0;
};

class impl : public intf
{
int x;
public:
impl()
{
x = 5;
}

void xxx()
{
}
};

typedef struct holder
{
intf* ptr;
char* xx;
holder()
{
ptr = NULL;
xx = new char[10];
strcpy(xx, "lksjd");
}

holder(intf* p)
{
ptr = p;
xx = new char[10];
strcpy(xx, "lksjd");
}
};

Q_DECLARE_METATYPE(holder)
Q_DECLARE_METATYPE(holder*)

#endif
After performing the cast in main, I get the same structure, which is good :).
Those class members are there just to assure I'm getting the same thing back from the qvariant.

Please note:


Q_DECLARE_METATYPE(holder)
Q_DECLARE_METATYPE(holder*)
Also holder*( has to be registered, otherwise it won't work. I forgot to mention this earlier.

I thing you too can use this.(sorry for the messy code).
Instead of an "impl" instance you can pass the pointer to your interface when building the qvariant.


Regards

QPlace
6th August 2007, 00:48
I was actually typing the response when I got the reply from you. Your help is extremely valuable, especially for QT novice like myself. Your first option did not work, as you already know, so I would not bore you with the details :).

Thank you again for your efforts and time spend helping us all here on this forum. I am taking your latest submission for incorporation in the code. I am sure it will work.

marcel
6th August 2007, 01:04
No problem, I am in a kind of vacation :).
Yes, it should work since I tested it before.
However you should use only the idea because the code I posted is a crap ( but it will compile and work anyway :)). It was meant only as a 5 minute proof to the idea.

Anyway, the code in the previous post is basically the same as the last one and it would have worked if you registered the pointer to holder type. (e.g. Q_REGISTER_METATYPE(holder*)).

Regards