PDA

View Full Version : QItemEditorFactory for QList.



hickscorp
15th October 2010, 16:54
Hello everyone,

i'm facing a problem for which i'm not finding any solution... i've tried pretty much everything, but i believe i may not understand something in the required logic here.
My project has reached a certain complexity point "code" speaking, and it's hard to provide all the relevant source code since everything depends on a lot of other stuff.

Basically, i have defined custom types:
// File is being Moc'ed.

namespace REA {
class IntList : public QList<qint32> {};
class UIntList : public QList<quint32> {};
class RgbList : public QList<QRgb> {};
class StringList : public QStringList {};
class CharList : public QList<QChar> {};
class RgbToUIntHash : public QHash<QRgb,quint32> {};
class StringToStringHash : public QHash<QString,QString> {};
class StringToImageHash : public QHash<QString,QImage> {};
// And a lot more types...

// ------------------------------------- Rectangles ------------------------------------- //
// Rectangle.
class Rect : public QRect {
public:
// Members.
bool isRelative;
// Constructors.
Rect (QPoint const &p=QPoint(0,0), QSize const &s=QSize(0,0), bool r=false)
: QRect(p, s), isRelative(r) {};
// QDataStream friend serialization stuff.
friend QDataStream& operator<< (QDataStream& s, Rect const &r) { return s << *(QRect*)&r << r.isRelative; };
friend QDataStream& operator>> (QDataStream& s, Rect &r) { return s >> *(QRect*)&r >> r.isRelative; };
};
// Float rectangle.
class RectF : public QRectF {
public:
// Members.
bool isRelative;
// Constructors.
RectF (QPointF const &p=QPointF(0,0), QSizeF const &s=QSizeF(0,0), bool r=false)
: QRectF(p, s), isRelative(r) {};
// QDataStream friend serialization stuff.
friend QDataStream& operator<< (QDataStream& s, RectF const &r) { return s << *(QRectF*)&r << r.isRelative; };
friend QDataStream& operator>> (QDataStream& s, RectF &r) { return s >> *(QRectF*)&r >> r.isRelative; };
};
// And a lot more custom types...
};
Q_DECLARE_METATYPE(REA::IntList);
Q_DECLARE_METATYPE(REA::UIntList);
Q_DECLARE_METATYPE(REA::RgbList);
Q_DECLARE_METATYPE(REA::StringList);
Q_DECLARE_METATYPE(REA::CharList);
Q_DECLARE_METATYPE(REA::RgbToUIntHash);
Q_DECLARE_METATYPE(REA::StringToStringHash);
Q_DECLARE_METATYPE(REA::StringToImageHash);
Q_DECLARE_METATYPE(REA::Rect);
Q_DECLARE_METATYPE(REA::RectF);
// And the same for any other type...

Then at runtime, i register everything:
#define RegisterStreamOperators(name) qRegisterMetaTypeStreamOperators<name>(#name)
// Register lists / maps / hashes meta-types for streaming.
RegisterStreamOperators(REA::IntList);
RegisterStreamOperators(REA::UIntList);
RegisterStreamOperators(REA::RgbList);
RegisterStreamOperators(REA::StringList);
RegisterStreamOperators(REA::CharList);
RegisterStreamOperators(REA::RgbToUIntHash);
RegisterStreamOperators(REA::StringToStringHash);
RegisterStreamOperators(REA::StringToImageHash);
RegisterStreamOperators(REA::Rect);
RegisterStreamOperators(REA::RectF);
#undef RegisterStreamOperators

Then, i have this very special class called "Variable", which acts a very similar way as QVariant does (It actually uses a QVariant internally). The Variable class allows me to define an i/o direction for a value, a name, and defines streaming operators to save / load lists of variables.

Then on my GUI project, i have subclassed QItemEditorFactory to allow me to dynamically instantiate editors based on the type of variable being edited:
#include "CustomItemEditorFactory.h"
// Editor classes.
#include "REATypes.h"
// Basic types.
#include <QLineEdit>
// Custom types.
#include "WgtBoolEditor.h"
#include "WgtPointEditor.h"
#include "WgtPointFEditor.h"
#include "WgtSizeEditor.h"
#include "WgtSizeFEditor.h"
#include "WgtRectEditor.h"
#include "WgtRectFEditor.h"
#include "WgtWFNodeUidEditor.h"
#include "WgtMemberPicker.h"

using namespace REA;

CustomItemEditorFactory::CustomItemEditorFactory (const QItemEditorFactory* standardFactory)
: QItemEditorFactory(), _standardFactory(standardFactory) {
}

QWidget* CustomItemEditorFactory::createEditor (QVariant::Type type, QWidget* parent) const {
switch (type) {
case QVariant::String: return new QLineEdit(parent);
case QVariant::Bool: return new WgtBoolEditor(parent);
case QVariant::Point: return new WgtPointEditor(parent);
case QVariant::PointF: return new WgtPointFEditor(parent);
case QVariant::Size: return new WgtSizeEditor(parent);
case QVariant::SizeF: return new WgtSizeEditor(parent);
default:
if (type==qMetaTypeId<REA::Rect>()) return new WgtRectEditor(parent);
else if (type==qMetaTypeId<REA::RectF>()) return new WgtRectFEditor(parent);
else if (type==qMetaTypeId<REA::UniqueIdentifier>()) return new WgtWFNodeUidEditor(parent);
else if (type==qMetaTypeId<REA::MemberPath>()) return new WgtMemberPicker(parent);
else return _standardFactory->createEditor(type, parent);
};
}

QByteArray CustomItemEditorFactory::valuePropertyName (QVariant::Type type) const {
// Any custom type...
if ( type==QVariant::Bool ||
type==QVariant::Point || type==QVariant::PointF ||
type==QVariant::Size || type==QVariant::SizeF ||
type>=QVariant::UserType)
return "value";
else
return _standardFactory->valuePropertyName(type);
}

void CustomItemEditorFactory::installAsStandardFactory () {
QItemEditorFactory::setDefaultFactory(new CustomItemEditorFactory(QItemEditorFactory::defaul tFactory()));
}

All this works flawlessly, i have no problem doing something like:
WgtVariableEditor *wgt = new WgtVariableEditor(this, var); The Variable editor widget important part looks like that:
WgtVariableEditor::WgtVariableEditor (QWidget *parent, Variable const &var)
: QWidget(parent, 0), _widget(0), _variable(var) {
// Create and set layout for this widget.
QHBoxLayout *lyt = new QHBoxLayout(this);
lyt->setSpacing(0);
lyt->setMargin(0);
setLayout(lyt);

// Retrieve editor widget object.
QItemEditorFactory const *f = QItemEditorFactory::defaultFactory();

// Create the widget and store it's metaobject.
_widget = f->createEditor((QVariant::Type)_variable.value.userT ype(), this);
lyt->addWidget(_widget);

// Retrieve metaobject.
QMetaObject const *mo = _widget->metaObject();
// Retrieve value property name.
QByteArray vpName = f->valuePropertyName((QVariant::Type)_variable.value. userType());
// Set widget value.
_widget->setProperty(vpName, _variable.value);
// Get property index.
int pIndex = mo->indexOfProperty(vpName);
// Retrieve metamethod for notification signal.
QMetaMethod signal = mo->property(pIndex).notifySignal();
// Finally generate signal name.
QString sName = QString("2%1").arg(signal.signature());
connect(_widget, sName.toLatin1(), this, SLOT(onValueEdition()));
}

Now, my problem is when it comes to editing lists and my QList-based custom types (REA::UIntList, REA::StringList, etc). i have no idea how to proceed. i first have created a template class (WgtListEditor), but Qt doesn't allow to subclass QObject (Nor QWidget, logic) in a template class...

i have tried then many and many other solutions... None of them works, and i got lost in the Qt editor logic.

Can someone please provide me with serious advices, and if possible with a diagram or some pseudo-code based on how my objects are made?

Thank you very much for your time, i appreciate any kind of help you could provide.
Pierre.

i notived my code was complettely messed up with the tabulations and everything... i recomend you switch to "plain" view of code, and copy paste into your favorite editor for a better anc clear view ;)

hickscorp
29th October 2010, 12:32
Bump... Anyone?