PIValueTree improvements: methods with path (recursive), forEachRecursive()

PIValueTreeConvertions::fromTextFile now can include other files and handle ${} substitutions
This commit is contained in:
2024-07-09 21:44:30 +03:00
parent 903b320629
commit 0bafd3fa98
3 changed files with 92 additions and 14 deletions

View File

@@ -127,9 +127,10 @@ PIValueTree prepareFromText(const PIValueTree & root) {
PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) { PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) {
PIValueTree ret; PIValueTree ret;
PIMap<PIString, PIString> substitutions;
if (!device) return ret; if (!device) return ret;
PIString base_path; PIString base_path;
if (device->isTypeOf<PIFile>()) base_path = PIFile::FileInfo(device->path()).dir(); if (device->isTypeOf<PIFile>()) base_path = PIFile::FileInfo(device->path()).dir().replaceAll('\\', '/');
PIIOTextStream ts(device); PIIOTextStream ts(device);
PIString line, comm; PIString line, comm;
PIVariant value; PIVariant value;
@@ -165,6 +166,7 @@ PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) {
if (ind > 0) if (ind > 0)
if (line[ind - 1] == '\\') continue; if (line[ind - 1] == '\\') continue;
cind = ind; cind = ind;
break;
} }
if (cind >= 0) { if (cind >= 0) {
comm = line.takeMid(cind + 1); comm = line.takeMid(cind + 1);
@@ -198,26 +200,32 @@ PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) {
path << line.takeLeft(ind).split('.').trim(); path << line.takeLeft(ind).split('.').trim();
line.cutLeft(1).trim(); line.cutLeft(1).trim();
if (path.front() == "include") { if (path.front() == "include") {
/*name = line.mid(ind + 1).trimmed(); PIString include = line.trimmed();
PIConfig * iconf = new PIConfig(name, incdirs); if (!PIFile::FileInfo(include).isAbsolute()) {
//piCout << "include" << name << iconf->dev; include = base_path + "/" + include.replaceAll('\\', '/');
if (!iconf->dev) { include.replaceAll("//", '/');
delete iconf;
} else {
inc_devs << iconf;
includes << iconf << iconf->includes;
updateIncludes();
} }
other.back() = src;*/ PIValueTree inc_vt = PIValueTreeConversions::fromTextFile(include);
inc_vt.forEachRecursive(
[&substitutions](const PIValueTree & v, const PIString & fn) { substitutions[fn] = v.value().toString(); });
path.clear();
} }
} else { } else {
line.clear(); line.clear();
continue; continue;
} }
// piCout << path << line << comm; // piCout << path << line << comm;
if (path.isEmpty()) {
line.clear();
continue;
}
PIValueTree & leaf(ret[path]); PIValueTree & leaf(ret[path]);
leaf.setComment(comm); leaf.setComment(comm);
leaf.setValue(unmask(line)); line = unmask(line);
for (const auto & s: substitutions)
line.replaceAll("${" + s.first + "}", s.second);
leaf.setValue(line);
substitutions[path.join('.')] = leaf.value().toString();
if (!path.contains(_attribute_)) if (!path.contains(_attribute_))
if (!leaf.contains({_attribute_, "type"})) leaf[_attribute_].addChild({"type", type}); if (!leaf.contains({_attribute_, "type"})) leaf[_attribute_].addChild({"type", type});
line.clear(); line.clear();

View File

@@ -125,12 +125,24 @@ void PIValueTree::applyValues(const PIValueTree & root, bool recursive) {
PIVariant PIValueTree::childValue(const PIString & child_name, const PIVariant & default_value, bool * exists) const { PIVariant PIValueTree::childValue(const PIString & child_name, const PIVariant & default_value, bool * exists) const {
if (!contains(child_name)) { const PIValueTree & node = child(child_name);
if (node.isNull()) {
if (exists) *exists = false; if (exists) *exists = false;
return default_value; return default_value;
} }
return child(child_name).value();
if (exists) *exists = true; if (exists) *exists = true;
return node.value();
}
PIVariant PIValueTree::childValue(const PIStringList & child_path, const PIVariant & default_value, bool * exists) const {
const PIValueTree & node = child(child_path);
if (node.isNull()) {
if (exists) *exists = false;
return default_value;
}
if (exists) *exists = true;
return node.value();
} }
@@ -167,6 +179,15 @@ const PIValueTree & PIValueTree::child(const PIString & name) const {
} }
const PIValueTree & PIValueTree::child(const PIStringList & path) const {
if (_is_null || path.isEmpty()) return *this;
const PIValueTree * ret = &child(path[0]);
for (int i = 1; i < path.size_s(); ++i)
ret = &child(path[i]);
return *ret;
}
PIValueTree & PIValueTree::child(const PIString & name) { PIValueTree & PIValueTree::child(const PIString & name) {
if (_is_null) return *this; if (_is_null) return *this;
for (auto & c: _children) for (auto & c: _children)
@@ -175,6 +196,15 @@ PIValueTree & PIValueTree::child(const PIString & name) {
} }
PIValueTree & PIValueTree::child(const PIStringList & path) {
if (_is_null || path.isEmpty()) return *this;
PIValueTree * ret = &child(path[0]);
for (int i = 1; i < path.size_s(); ++i)
ret = &child(path[i]);
return *ret;
}
PIValueTree & PIValueTree::insertChild(int index, const PIValueTree & n) { PIValueTree & PIValueTree::insertChild(int index, const PIValueTree & n) {
if (_is_null) return *this; if (_is_null) return *this;
for (auto & c: _children) for (auto & c: _children)
@@ -214,6 +244,11 @@ PIValueTree & PIValueTree::remove(const PIString & name) {
} }
void PIValueTree::forEachRecursive(std::function<void(const PIValueTree &, const PIString &)> func) {
forEachRecursiveInternal(func);
}
const PIStringList & PIValueTree::standardAttributes() { const PIStringList & PIValueTree::standardAttributes() {
static PIStringList ret = { static PIStringList ret = {
// clang-format off // clang-format off
@@ -293,3 +328,11 @@ PIValueTree & PIValueTree::nullValue() {
ret._is_null = true; ret._is_null = true;
return ret; return ret;
} }
void PIValueTree::forEachRecursiveInternal(std::function<void(const PIValueTree &, const PIString &)> func, PIString prefix) {
for (auto & c: _children) {
func(c, prefix + c.name());
c.forEachRecursiveInternal(func, c.name() + ".");
}
}

View File

@@ -191,6 +191,17 @@ public:
//! \param exists Если не равно нулю, будет установлено в true, если дочерний узел существует, false в противном случае. //! \param exists Если не равно нулю, будет установлено в true, если дочерний узел существует, false в противном случае.
PIVariant childValue(const PIString & child_name, const PIVariant & default_value = PIVariant(), bool * exists = nullptr) const; PIVariant childValue(const PIString & child_name, const PIVariant & default_value = PIVariant(), bool * exists = nullptr) const;
//! \~\brief
//! \~english Returns the value of a child node with a given path.
//! \param child_path The path of the child node.
//! \param default_value The default value to be returned if the child node is not found.
//! \param exists If not null, set to true if the child node exists, false otherwise.
//! \~russian Возвращает значение дочернего элемента с заданным путем.
//! \param child_path Путь дочернего узла.
//! \param default_value Значение по умолчанию, которое будет возвращено, если дочерний узел не найден.
//! \param exists Если не равно нулю, будет установлено в true, если дочерний узел существует, false в противном случае.
PIVariant childValue(const PIStringList & child_path, const PIVariant & default_value = PIVariant(), bool * exists = nullptr) const;
//! \~\brief //! \~\brief
//! \~english Reads the value of a child node with a given name into "read_to". Returns a reference to the current %PIValueTree object. //! \~english Reads the value of a child node with a given name into "read_to". Returns a reference to the current %PIValueTree object.
//! \~russian Читает значение дочернего элемента с заданным именем в "read_to". Возвращает ссылку на текущий объект %PIValueTree. //! \~russian Читает значение дочернего элемента с заданным именем в "read_to". Возвращает ссылку на текущий объект %PIValueTree.
@@ -220,11 +231,21 @@ public:
//! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет. //! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет.
const PIValueTree & child(const PIString & name) const; const PIValueTree & child(const PIString & name) const;
//! \~\brief
//! \~english Returns a const reference to the child node with a given path, or null node if it doesn`t exists.
//! \~russian Возвращает константную ссылку на дочерний узел с заданным путем или пустой узел, если его нет.
const PIValueTree & child(const PIStringList & path) const;
//! \~\brief //! \~\brief
//! \~english Returns a reference to the child node with a given name, or null node if it doesn`t exists. //! \~english Returns a reference to the child node with a given name, or null node if it doesn`t exists.
//! \~russian Возвращает ссылку на дочерний узел с заданным именем или пустой узел, если его нет. //! \~russian Возвращает ссылку на дочерний узел с заданным именем или пустой узел, если его нет.
PIValueTree & child(const PIString & name); PIValueTree & child(const PIString & name);
//! \~\brief
//! \~english Returns a reference to the child node with a given path, or null node if it doesn`t exists.
//! \~russian Возвращает ссылку на дочерний узел с заданным путем или пустой узел, если его нет.
PIValueTree & child(const PIStringList & path);
//! \~\brief //! \~\brief
//! \~english Inserts a node at a given index. Returns a reference to the current %PIValueTree object. //! \~english Inserts a node at a given index. Returns a reference to the current %PIValueTree object.
//! \~russian Вставляет узел в заданном индексе. Возвращает ссылку на текущий объект %PIValueTree. //! \~russian Вставляет узел в заданном индексе. Возвращает ссылку на текущий объект %PIValueTree.
@@ -260,6 +281,11 @@ public:
//! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет. //! \~russian Возвращает константную ссылку на дочерний узел с заданным именем или пустой узел, если его нет.
const PIValueTree & operator[](const PIString & name) const { return child(name); } const PIValueTree & operator[](const PIString & name) const { return child(name); }
//! \~\brief
//! \~english Recursive call "func" for every child. "full_name" is a name with path, joined with ".".
//! \~russian Рекурсивно выполняет "func" для каждого узла. "full_name" - это имя с путём, соединены ".".
void forEachRecursive(std::function<void(const PIValueTree & item, const PIString & full_name)> func);
//! \~\brief //! \~\brief
//! \~english Returns a list of standard attribute names. //! \~english Returns a list of standard attribute names.
//! \~russian Возвращает список стандартных имен атрибутов. //! \~russian Возвращает список стандартных имен атрибутов.
@@ -268,6 +294,7 @@ public:
private: private:
static void print(PIString & s, const PIValueTree & v, PIString tab); static void print(PIString & s, const PIValueTree & v, PIString tab);
static PIValueTree & nullValue(); static PIValueTree & nullValue();
void forEachRecursiveInternal(std::function<void(const PIValueTree &, const PIString &)> func, PIString prefix = {});
PIString _name; PIString _name;
PIString _comment; PIString _comment;