5

I'm using QVariant to manage the project settings of our In-House application.

For this I'm using a nested QVariantMap recursively containing QVariantMaps and leaves holding the actual values.

Now, I found it quite cumbersome to set and remove nodes from this tree like structure. Especially, if the nesting reaches a certain depth.

Part of the problem is, that value<T> returns a copy instead of a reference. (I'm wondering, why Qt is lacking this feature??)

#include <QVariantMap>
#include <QDebug>

int main(int argc, char** args) {
    QVariantMap map = { {"A", QVariantMap{ {"B",5.} }} };
    {
        // Change value
        auto nested = map["A"].value<QVariantMap>();
        nested["B"] = 6;
        map["A"] = nested;
        qDebug() << map;
        // What it should be
        // map["A"]["B"] = 5;
    }
    {
        // Remove value
        auto nested = map["A"].value<QVariantMap>();
        nested.remove("B");
        map["A"] = nested;
        qDebug() << map;
        // What it should be
        // map["A"].remove("B");
    }
}

What might be the easiest way to directly set and remove values and to make my function a one-liner? Performance is not critical, but ease of usability is definitely an issue for me.

Aleph0
  • 5,816
  • 4
  • 29
  • 80
  • 1
    I always use `QVariant` as the function argument(pass the data) and use `QAbstractItemModel` as a container for storing or modifing data. – JustWe Dec 12 '18 at 09:55
  • @Jiu: This could be a workable approach. With this solution it might be even possible to use `QStandardItemModel` instead of `QVariant` anyway. – Aleph0 Dec 12 '18 at 09:57

1 Answers1

0

After some thought I came up to the idea to use a path to my desired value. This path should be unique.

The following code recursively finds the value and removes it. Changing a value should be quite similar. I'm not sure, if there might an easier approach.

bool remove(QVariantMap& map, const QString& path, QString sep = ".") {
    auto elems = path.split(sep);
    if (elems.size() > 1) {
        if (!map.contains(elems.first())) return false;
        auto tmp = elems;
        tmp.pop_front();
        auto childMap = map[elems.first()].value<QVariantMap>();
        bool ret = remove(childMap, tmp.join("."));
        if (!ret) return false;
        map[elems.first()] = childMap;
        return true;
    }
    else if (elems.size() == 1) {
        return map.remove(elems[0]) >= 1;
    }
    else {
        return false;
    }
}

Remark

This solution should not be used, if there is a lot of data, as there is quite a lot of copying of maps.

Aleph0
  • 5,816
  • 4
  • 29
  • 80