freesoftware, Kde, Planet, Qt

Qdbusxml2cpp and QDBusAbstractAdaptor Limitations

Issue #1:

Object implementing two different interfaces, both having a method named "Bar"

<interface name="org.drdanz.foo">
  <method name="Bar">
</interface>
<interface name="org.drdanz.boo">
  <method name="Bar">
</interface>

The adaptor code generated by qdbusxml2cpp is something like

[...]

QString fooAdaptor::Bar() const
{
    // handle method call home.drdanz.foo.Bar
    parent()->Bar();
}

[...]

QString booAdaptor::Bar() const
{
    // handle method call home.drdanz.boo.Bar
    parent()->Bar();
}

[...]

This means that the called method is the same, therefore it is not possible to have two different behaviours of the methods.

I don’t think that there is a way to know which of the methods called the parent()->Bar(); method and implement a simple switch (the QObject::sender() works only if called in a slot activated by a signal and I’m not aware of any other method to do that.

Solutions:

  1. Modify the auto-generated adaptor classes or to call a different method. (boring)
  2. Do not use qdbusxml2cpp and write the adaptor classes by hand, or don’t use adaptors at all (even more boring)

Issue #2

Objects implementing the same interface

class Base : public QObject {
  virtual <interface org.drdanz.foo> = 0
}
class Derived1 : public Base {
  <interface org.drdanz.foo>
  <interface org.drdanz.foo.bar1>
  <interface org.drdanz.foo.bar2>
}
class Derived2 : public Base {
  <interface org.drdanz.foo>
  <interface org.drdanz.foo.bar1>
  <interface org.drdanz.foo.bar3>
}
class Derived3 : public Base {
  <interface org.drdanz.foo>
  <interface org.drdanz.foo.bar2>
  <interface org.drdanz.foo.bar3>
}

Implementation of org.drdanz.foo.bar1 should available to all the classes that implement that interface.

Adaptors for interfaces org.drdanz.foo.barX cannot be created using Base as the parent class because Base should have virtual methods for every possible barX

(Just to demonstrate that a similar architecture make sense and is legal in D-Bus, an existing example is the Connection object in Telepathy, that must always implement the interface org.freedesktop.Telepathy.Connection, but can implement any number of additional org.freedesktop.Telepathy.Connection.Interface.XXXX interface.)

It is impossible to create a class Bar1 and declare

class Base : public virtual QObject {
  virtual <interface org.drdanz.foo> = 0
}
class Bar1 : public virtual QObject {
  <interface org.drdanz.foo.bar1>
}
class Derived1 : public Base, public Bar1;

because both Base and Bar1 needs to be QObject to be a parent for the adaptor and multiple inheritance is not supported for QObjects:

Warning: Class Derived1 inherits from two QObject subclasses Base and Bar1. This is not supported!

Solutions:

  1. Write/modify adaptors by hand (boring)
  2. Auto generate adaptors for every derived class and implement the methods multiple times (redundant and stupid)

A better possible solution to both issues:

Allow auto generated adaptors to use the methods on a QObject (adaptee) that is not the parent.

This is what qdbusxml2cpp produces in Qt 4.7:

qdbusxml2cpp produced adaptors in Qt 4.7
qdbusxml2cpp produced adaptors in Qt 4.7

The Object that "owns" the adaptor is the same that implements the real methods.

This is in my opinion what should be produced by qdbusxml2cpp:

What qdbusxml2cpp should produce
What qdbusxml2cpp should produce

The object that is registered on D-Bus exports all the adaptors, but the implementation of the interface can be in a different object

This requires just a few changes in the class QDBusAbstractAdaptor:

  1. Add a public (or protected) method to retrieve the adaptee QObject* adaptee() const;
  2. Add a method to set the adaptee void setAdaptee(QObject *adaptee);
  3. Add a constructor QBBusAbstractAdaptor(QObject *adaptee, QObject *parent).
    This doesn’t mean that adaptee must not be the parent, it just means that it can be a different object.
    Therefore to be backwards compatible the QBBusAbstractAdaptor(QObject *parent) must be modified to setAdaptee(parent)

Then a few changes are required in qdbusxml2cpp, to produce adaptors that use methods of the adaptee class instead methods of parent class.

An even easier implementation requires just to implement the adaptee logic in classes generated by qdbusxml2cpp

It could be enough to modify only qdbusxml2cpp
It could be enough to modify only qdbusxml2cpp