PDA

View Full Version : Improving qgraphicsitem_cast



Gopala Krishna
15th June 2007, 18:35
I am facing a problem in my app where i want the qgraphicsitem_cast to cast items properly anywhere along hierarchy. I can't use dynamic_cast since i am compiling without rtti support.
Example:
if Base inherits QGraphicsItem and Derived inherits Base and both the classes define(or declare) Type as well type() which point to different values, then the cast fails even though its legal as shown below.

Derived *d = new Derived();
QGraphicsItem *item = d;
Q_ASSERT (qgraphicsitem_cast<Derived*>(item)); Succeeds
Q_ASSERT (qgraphicsitem_cast<Base*>(item)); //This fails though legal :(

My current solution is custom cast function as shown


//stolen from source of qgraphicsitem_cast but modified to suit my needs
template <class T> inline T graphicsitem_cast(QGraphicsItem *item)
{
bool firstCond = int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type);
bool secondCond = !firstCond && item && ((int(static_cast<T>(0)->Type) & item->type()) == (int(static_cast<T>(0)->Type)));
bool result = firstCond | secondCond;
return result ? static_cast<T>(item) : 0;
}

Notice the bitwise AND used in secondCond. qgraphicsitem_cast on other hand uses "==" and hence it fails.
Now I define my hierarcy as follows(with woking eg)

#include <QtGui>

//stolen from source of qgraphicsitem_cast but modified to suit my needs
template <class T> inline T graphicsitem_cast(QGraphicsItem *item)
{
bool firstCond = int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type);
bool secondCond = !firstCond && item && ((int(static_cast<T>(0)->Type) & item->type()) == (int(static_cast<T>(0)->Type)));
bool result = firstCond | secondCond;
return result ? static_cast<T>(item) : 0;
}

const int startValue = 65536;

class Base : public QGraphicsLineItem
{
public:
enum { Type = startValue };
Base() : QGraphicsLineItem() {}
int type() const { return Type;}
};

class Derived1 : public Base
{
public:
enum { Type = (startValue << 1) | Base::Type };
Derived1() : Base() {}
int type() const { return Type;}
};

class Derived2 : public Derived1
{
public:
enum { Type = (startValue << 2) | Derived1::Type };
Derived2() : Derived1() {}
int type() const { return Type;}
};

int main()
{
Base *base = new Base();
Derived1 *d1 = new Derived1();
Derived2 *d2 = new Derived2();

QGraphicsItem *item = d2;
if(graphicsitem_cast<Base*>(item) != 0) {
//Check for crash
item->setFlags( QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsSelectable );
qDebug() << item->flags();
}
if(graphicsitem_cast<Derived1*>(item) != 0) {
//Check for crash
item->setFlags( QGraphicsItem::ItemIsFocusable );
qDebug() << item->flags();
}
if(graphicsitem_cast<Derived2*>(item) != 0) {
//Check for crash
item->setFlags( QGraphicsItem::ItemIsSelectable );
qDebug() << item->flags();
}
//All above succeeds
return 0;
}


The problem is I don't think this is elegant :(
Is there any elegant solution ? Can I use any template tricks in a better way ?

Gopala Krishna
17th June 2007, 17:07
No one has a better solution for this ? Any boost guys here to help me ? :confused: