jump to navigation

QObject, multiple inheritance, and smart delegators October 29, 2012

Posted by Sandro Andrade in planetqt-sandroandrade.
8 comments

Hi there,

In last weeks I’ve been working on a Qt-based implementation of OMG’s UML/MOF specifications (more about that coming soon). The normative XMI files provide the full UML meta-model, featuring a number of multiple inheritances and dreaded diamonds. So, you can expect some hard times because of QObject disabilities for handling virtual inheritance and templates (no mix-ins ? no traits ?). Furthermore, a design and analysis tool for handling MOF-based models is also been developed and, as such, should be highly reflective in order to not be tied to any specific meta-model. Qt’s property system could easily do the trick, but keeping reading :).

Since a number of classes in UML meta-model are abstract, a possible solution to overcome QObject’s multiple inheritance issues would be to postpone QObject inheritance to lowest possible class in hierarchy. Also cross you fingers for not having a concrete class inheriting from two (or more) other concrete classes (actually, in UML this only occurs in ‘AssociationClass’). Current implementation is somehow akin to:

QElement is an “abstract” (protected constructor) class:

class Q_UML_EXPORT QElement
{
public:
    virtual ~QElement();
    const QSet<QElement *> *ownedElements() const;
    ...
protected:
    explicit QElement();
};

QNamedElement is also an “abstract” (protected constructor) class:

class Q_UML_EXPORT QNamedElement : public virtual QElement
{
public:
    virtual ~QNamedElement();
    QString name() const;
    void setName(QString name);
    QtUml::VisibilityKind visibility() const;
    void setVisibility(QtUml::VisibilityKind visibility);
    QString qualifiedName() const; // read-only
    QNamespace *namespace_() const;
    ...
protected:
    explicit QNamedElement();
};

QPackage is a concrete class:

class Q_UML_EXPORT QPackage : public QObject, public QNamespace, public QPackageableElement, public QTemplateableElement // dreaded diamonds here
{
    Q_OBJECT
    // From QElement
    Q_PROPERTY(const QSet<QElement *> * ownedElements READ ownedElements)
    // From QNamedElement
    Q_PROPERTY(QString name READ name WRITE setName)
    Q_PROPERTY(QString qualifiedName READ qualifiedName)
    Q_PROPERTY(QElement * namespace_ READ namespace_)

public:
    explicit QPackage(QObject *parent = 0);
    virtual ~QPackage();
};

That’s fine, even though generated documentation becomes somehow weird because of property accessors being implemented in base classes.

Issues arise, however, when implementing the analysis tool. It would be great if each property could be dynamically verified if it is a QNamedElement and its name would be exhibited in a property editor. Something like:

...
int propertyCount = currentElement->metaObject()->propertyCount();
for (int i = 0; i < propertyCount; ++i) {
    QMetaProperty property = element->metaObject()->property(i);
    QString typeName = property.typeName();
    if (typeName.endsWith('*') and !typeName.contains(QRegularExpression ("QSet|QList"))) {
        if (QtUml::QNamedElement *namedElement = property.read(element).value<QtUml::QElement *>()) {
                tableItem->setText(namedElement->name());
            }
}
...

The sad thing is: in Qt4, values can be extracted from QVariant’s only by using the same type used when constructing the QVariant. Qt5 introduces a nifty feature where you can safely extract a QObject * from any QVariant built from a QObjectDerived *. That would easily solve the issue above provided that QNamedElement would inherit from QObject :).

So, it seems the solution requires inheriting from QObject early in hierarchy (QElement) and get rid of multiple QObject inheritance by using delegation. In addition, accessing ‘sub-objects due to inheritance’ and ‘sub-objects due to delegation’ by using a common API would be a plus. That’s what I came up with:

class MyQObject : public QObject
{
    Q_OBJECT
public:
    explicit MyQObject(QObject *parent = 0);
    virtual ~MyQObject();

    template <class T> friend inline T myqobject_cast(MyQObject *object);

protected:
    QSet<MyQObject *> _subObjects;
};

template <class T>
inline T myqobject_cast(MyQObject *base)
{
    if (dynamic_cast<T>(base))
        return dynamic_cast<T>(base);
    foreach(MyQObject *myqobject, base->_subObjects) {
        T returnValue = myqobject_cast<T>(myqobject);
        if (returnValue != T())
            return returnValue;
    }
    return dynamic_cast<T>(base); // not found
}

A first MyQObject-derived class:

class Derived1 : public MyQObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName)
public:
    explicit Derived1(QObject *parent = 0);
    QString name() const;
    void setName(QString name);

private:
    QString _name;
};

A second MyQObject-derived class (Derived2) would be defined similarly.

A class “multiple inheriting” indirectly from MyQObject would be:

class Join : public MyQObject // no inheritance, no dreaded diamonds, 'smart delegation' instead
{
    Q_OBJECT
public:
    explicit Join(QObject *parent = 0);
    ~Join();

private:
    Derived2 *_derived2;
    Derived1 *_derived1;
};

 

Join::Join(QObject *parent) :
    MyQObject(parent), _derived2(new Derived2), _derived1(new Derived1)
{
    _subObjects.insert(_derived11);
    _subObjects.insert(_derived2);
}

Join::~Join()
{
    delete _derived2;
    delete _derived1;
}

That done, how a client would look like ?

Join *join = new Join;
if (myqobject_cast<MyQObject *>(join))
    qDebug() << "myqobject_cast<MyQObject *>(join) ok";
if (myqobject_cast<Derived1 *>(join))
    qDebug() << "myqobject_cast<Derived1 *>(join) ok";
if (myqobject_cast<Derived2 *>(join))
    qDebug() << "myqobject_cast<Derived2 *>(join) ok";
if (!myqobject_cast<Unrelated *>(join))
    qDebug() << "myqobject_cast<Unrelated *>(join) fail";

That would remove the burden of creating tons of stub methods (if aggregated object is deeply lower in hierarchy) and one more level of indirection (how to simulate virtual methods ?). Yes, sub-objects representing the tip of dreaded diamonds would be duplicated but myqobject_cast would return always the same sub-object.

I’m wondering how much of this could be automated by moc so that we could have something like:

class Join : public MyQObject, wraps Derived1, wraps Derived2
{
    Q_OBJECT
public:
    explicit Join(QObject *parent = 0);
    ~Join();
};

And that’s all, all hard work behind the scenes would be generated by moc 🙂 Only a little change in perspective when using such object would be needed (think always in terms of myqobject_cast’s).

So, too much engineering ? 🙂 Any alternative solution ? Comments ?

See you !

Advertisements

Help the Creativity of Children around the world October 16, 2012

Posted by tumaix in planetkde-tomazcanabrava.
add a comment

People, this is a very serious pledge campaign, I didn’t wrote but actually copied the text to put on planet-kde, thus, making it more spread around the globe.:

Original text from the pledge:

Some might remember a little campaign I started in February. Its time to do it again, bit why now? The answer is very simple LibreGraphicsMeeting will be next year a little bit nearly a month earlier. Additional to that some of the receiver of the campaign need a visa for going to Spain, where the next LibrGraphicsMeeting will be. They have to get the visa 6weeks before they enter the country so that would be end of February. And additional to that the have to show the tickets for the flights especially the back flight and the reservation of a hotel, pension or something similar. So we need the most of the money until that date or they can not go to the event.

This time there are three persons, I like to collecting for:

Gustavo Gonzalez, who is the author of Tupi – Open 2D Magic, a program for doing traditional 2D animations. If you take a look there are really not a lot of alternatives in this area in the FLOSS world, the only one would be SynfigStudio but that is to complicated. Tupi is easier to handle and to learn. In the last months Tupi made also a lot of progress, we tried to package it but it was totally wrong build dependencies like ffmpeg made it not possible to include it into Fedora. So Gustavo removed all that dependencies and structured it new, so that you can use it without ffmpeg and export the animations as ogv. But ffmpeg support is still available as plugin. There was also some other major improvements like a storyboard. I am sure when it is packaged a lot of people will like Tupi, the Design Team cant wait for it.
Gustavo tried already this year to go to the LibreGraphicsMeeting in Vienna but it did not happen because he had no money for doing it. He like to present Tupi at that event and I am very sure that is useful for him and the development of Tupi. So lets help him.

Second person is Onyeibo Oku from Nigeria. Onyeibo is since a long time member of the Fedora Design team, but he is also active as Ambassador in Africa. Onyeibo sketches really good and he is good with Blender. For him is important to meet some other people from the design team and he wishes also to give a talk at LibreGraphicsMeeting.

Last candidate I might know, its Tatica again. She was, thanks to a lot of donations, at the last LibreGraphicsMeeting and learned a lot there and like to go again.

So what will it cost? There are the flights for Tatica around 1200€/1550 US$, for Gustav around 1000€/1290US$ and for Onyeibo around 800€/1030US$. For Tatica last time we calculated 70€/90US$ for hotel. But we didn’t need so much because Tatica slept in an apartment which became much cheaper. I did some research and want to rent an apartment for them again, that will cost another 900€/1160US$. So the whole makes 3870€/5030US$

Because Pledgie and Paypal get each 3% of the sum, the sum would be 4080€/5300US$. Additional to that Paypal gets a small sum for each transfer, but that is hard to calculate. I calculated 80€/100US$ for that.

So what will happen if we get not the whole sum? When we reach the sum for the flight for Gustav, he will get it first, after that Onyeibo and last Tatica as she was already at LibreGraphicsMeeting. But we need the sum for the flights in February otherwise we get no visa for Gustav and Onyeibo. But hopefully we get the sum but that’s up on you.

Lgm2013_2
Pledge link for donations: http://pledgie.com/campaigns/18338

All KDE-Edu Apps with KActivities on 4.10 October 16, 2012

Posted by tumaix in planetkde-tomazcanabrava.
4 comments

Ronaldo Fernandes, a Student from faculdades ruy barbosa that is doing it’s first internship for KDE is doing an awesome work porting all KDE-Edu apps to KActivities for inclusion on KDE 4.10, he’s having a lot of help from me, and I’m having a lot of help from Ivan about the KActivities system.

Apps that are already KActivity enabled ( in our branch, I’m reviewing everything before sending to reviewboard the diffs ) are Kig, KAlgebra, Cantor, KTouch, KHangMan and KTurtle. 🙂

 

KDE-Edu and KDE-Utils fully Activity-Enabled for 4.10? October 1, 2012

Posted by tumaix in planetkde-tomazcanabrava, uncategorized.
2 comments

the ‘Intern me on KDE’ program is starting to give it’s fruits.

two of my the students are now porting evey-app (where applicable ) of kde-edu and  kde-utils to use the KActivities plugin, if installed.

Kudos to them.