PDA

View Full Version : Qt Guru Required for MetaObject system problem.



hickscorp
4th August 2011, 19:21
Hello,

i have several questions about the Qt MetaObject system, related to issues i have with an application i'm working on.

1) Namespace Enums.
i have a very wide namespace named "RE". To allow declaration of enums and types inside that namespace while still being covered by the Qt MetaObject processing system, i use such trick:
#ifdef Q_MOC_RUN
class RELibOpt RE {
Q_GADGET
Q_ENUMS (AnEnum, AnotherEnum)
public:
#else
namespace RE {
#endif
// My whole fake class / namespace comes here,
// including all my enums declarations... Is there another way to make an enum "global" but still part of the parsed meta-object system?...
}

Q_DECLARE_METATYPE(RE::AnEnum);
Q_DECLARE_METATYPE(RE::AnotherEnum);
Is that right to do that? What would be the other solution to have a namespace containing enums and registered typedefs? i would like to be able to have my enums part of my "RE" namespace exactly as the Qt enums are part of the "Qt" namespace... What is Qt in this case? A class? A namespace? How is it processed by MOC?

2) Properties and Enums.
Still in my "RE" namespace, i have classes. In those classes, i use the Q_PROPERTY macro. However, if in a class RE::A i use a Q_PROPERTY using RE::AnEnum as it's base type, i'm unable to enumerate it's content with QMetaEnum: the QMetaProperty exists but says it's not an enum type! What is the solution to do that?

Thanks a lot,
Pierre.

wysota
4th August 2011, 19:59
There is a special code path in moc for processing the "Qt" namespace (yes, it is a namespace). It is impossible to use that path with user code unless something changed since the last time I analyzed the code (which was a couple of minor versions back). As for the second case I can only tell you to remember Qt meta-type system is based on a character-by-character string comparison. Can you access the enums defined in RE manually by processing its meta object?

hickscorp
5th August 2011, 15:32
There is a special code path in moc for processing the "Qt" namespace (yes, it is a namespace). It is impossible to use that path with user code unless something changed since the last time I analyzed the code (which was a couple of minor versions back).
Ok, thanks for the precision. As of the special way to process the Qt namespace, that's exactly what i'm doing with that preprocessor trick (Which emulates a class at MOC'ing time to allow the staticMetaObject to be generated).


As for the second case I can only tell you to remember Qt meta-type system is based on a character-by-character string comparison. Can you access the enums defined in RE manually by processing its meta object?
i sure can:

QMetaObject const &mo = RE::staticMetaObject;
int idx = mo.indexOfEnumerator("ReadingDirection");
QMetaEnum me = mo.enumerator(idx);
RE::ReadingDirection key = RE::ReadingDirectionRightToLeft;
qDebug() << key << "to string:" << me.valueToKey(key);
QString sz = "RE::ReadingDirectionRightToLeft";
qDebug() << sz << "to value:" << me.keyToValue(sz.toLatin1());
Output (Which is right):
2 to string: ReadingDirectionRightToLeft
"RE::ReadingDirectionRightToLeft" to value: 2

But still, i can't seem to access any enums on my QMetaProperties from my other classes:

QMetaObject const &mo = RE::MyClass::staticMetaObject;
int mpIdx = mo.indexOfProperty("readingDirection");
QMetaProperty const &mp = mo.property(mpIdx);
qDebug() << "Index:" << mpIdx << "isEnum" << mp.isEnumType();
Output (Which is obviously wrong, the isEnum should be true!):
Index: 5 isEnum false
For this example, i have tried all kinds of Q_PROPERTY declarations on my MyClass class... Ones with the RE:: specified on the base type, ones without, mixed, or not... It won't change the fact that the property is not seen as an enum:

Q_PROPERTY(ReadingDirection readingDirection READ readingDirection WRITE setReadingDirection)
Q_PROPERTY(RE::ReadingDirection readingDirection READ readingDirection WRITE setReadingDirection)
// none of them works.


Any clue please?

Added after 15 minutes:

This is so weird. i'm actually looking at qabstractscrollarea.h. In it, i can see:
class Q_GUI_EXPORT QAbstractScrollArea : public QFrame {
Q_OBJECT
Q_PROPERTY(Qt::ScrollBarPolicy verticalScrollBarPolicy READ verticalScrollBarPolicy WRITE setVerticalScrollBarPolicy)
// Rest of the declaration.
}This is in essence strictly identical to my stuff. Even the namespacing, since the QT_NAMESPACE could expand to something different than global namespace:
namespace RE {
class RELibOpt MyClass : public QObject {
Q_OBJECT
Q_PROPERTY(RE::ReadingDirection readingDirection READ readingDirection WRITE setReadingDirection)
// Rest of the declaration.
}

However, this snippet:
{
QMetaObject const &mo = RE::MyClass::staticMetaObject;
int mpIdx = mo.indexOfProperty("readingDirection");
QMetaProperty const &mp = mo.property(mpIdx);
qDebug() << "Index:" << mpIdx << "isEnum" << mp.isEnumType();
} {
QMetaObject const &mo = QAbstractScrollArea::staticMetaObject;
int mpIdx = mo.indexOfProperty("verticalScrollBarPolicy");
QMetaProperty const &mp = mo.property(mpIdx);
qDebug() << "Index:" << mpIdx << "isEnum" << mp.isEnumType();
} gives the following output:
Index: 5 isEnum false
Index: 64 isEnum true

This is odd... i'm not doing anything different, but i'm getting really different results. What could be the clue?

Added after 26 minutes:

One mode addition i discovered. If i add this to the MyClass class:
Q_PROPERTY(Qt::ScrollBarPolicy scrollPolicy READ scrollPolicy WRITE setScrollPolicy)
Then the QMetaProperty marks it's an enum, as opposed to my RE::* enums... Which is even more odd. So the problem definitely comes from the way my RE:: namespace enums gets MOC'ed... Can anyone help please?

Added after 4 minutes:

Half a dozen refactorings later, and as many tests later too... i have a very simple question.
- Let's say we make a class A inheriting publically from QObject, and having the Q_OBJECT macro for good.
- A also declares an enum AnEnum, and registers it via Q_ENUM.
- Now lets say there is another class B, with a Q_PROPERTY using A::AnEnum as it's base type.
1) Would it work?
2) Now picture the exact same scenario, but both A and B would be part of a namespace named NS. Would this still work?

i'm unable to make it work with very basic Qt code. Can someone please try and give feedback, and if it works post a snippet?
Thanks a lot for your time!
Pierre.