Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Implementing a DBus interface exposing an object tree to clients



  • I want to implement a DBus API where the client is able to get a hierarchy of devices and their properties as follows:

    Device 0
        Some Category
            Property 1
            Property 2
    Device 1
        Some Other Category
            Subcategory
                Property 1
    

    is there a way to access the objects as a tree in the client without manually parsing the relationships from the object paths?


  • Lifetime Qt Champion

    Hi,

    I am not sure I am following you on this. How would you like to access the data of your data tree ?



  • I'd basically like to get the object located at /DBusInterface/devices and use its subtrees for presentation, something like:

    Device d = getRootDeviceFromDbus();
    constructItemModel(d); // Construct item model from root device recursively
    

  • Lifetime Qt Champion

    So you are missing the construct model method ?



  • I'm trying to find out if there's a way to get the object tree without manually parsing all the object paths


  • Lifetime Qt Champion

    If the structure is fixed. You can create a model on top of these objects.



  • The structure isn't fixed, which is the entire reason for needing this


  • Lifetime Qt Champion

    Ok, but what would you get from your DBus endpoint ?



  • Ended up writing the following code that parses a list of paths into a tree

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        auto central = new QWidget;
        auto lo = new QVBoxLayout;
    
        auto view = new QTreeView;
        auto model = new QStandardItemModel;
    
        auto root = model->invisibleRootItem();
    
        QStringList pathList;
    
        pathList << "/dev" << "/dev/gpu" << "/dev/gpu2" << "/dev/gpu/fans/0" << "/dev/gpu2/powerlim";
    
        struct Node {
            QString name;
            QVector <Node*> children;
        };
    
    
        auto lowestAncestor = [=](QStringList tokens, Node *root, int *tokenIndex) {
            int i = 0;
            bool flag = false;
            Node *node_it = root;
            while (node_it && i < tokens.length()) {
                for (auto node : node_it->children) {
                    if (node->name.compare(tokens[i]) == 0) {
                        i++;
                        flag = true;
                        node_it = node;
                        break;
                    }
                }
                if (!flag) {
                    break;
                }
                flag = false;
            }
            *tokenIndex = i;
            return node_it;
        };
    
        std::function<void (QString, QStringList, Node*)> addNode;
        addNode = [=, &addNode](QString path, QStringList tokens, Node *node) {
            // Call this function until lowestAncestor.name == tokens.last()
            int i;
            auto n = lowestAncestor(tokens, node, &i);
            if (tokens.last().compare(n->name) != 0) {
                auto new_ = new Node;
                new_->name = tokens[i];
    
                n->children.append(new_);
                addNode(path, tokens, node);
            }
        };
    
        Node *rootNode = new Node;
    
        for (auto &path : pathList) {
            addNode(path, path.split(QRegExp("/+"), QString::SkipEmptyParts), rootNode);
        }
    
        std::function <void(QStandardItem*, Node*)> traverse;
        traverse = [=, &traverse](QStandardItem *item, Node *node) {
            auto newItem = new QStandardItem;
            newItem->setData(node->name, Qt::DisplayRole);
    
            item->appendRow(newItem);
            for (auto node : node->children) {
                traverse(newItem, node);
            }
        };
    
        for (auto n : rootNode->children) {
            traverse(root, n);
        }
    
        view->setModel(model);
    
        lo->addWidget(view);
    
        central->setLayout(lo);
        setCentralWidget(central);
    }
    

Log in to reply