diff --git a/src/gpgui/CMakeLists.txt b/src/gpgui/CMakeLists.txt index ef77097b..b278ff74 100644 --- a/src/gpgui/CMakeLists.txt +++ b/src/gpgui/CMakeLists.txt @@ -33,7 +33,11 @@ add_executable(gpgui gui/MainWindow.cpp gui/browse_widget.cpp gui/pol_editor.cpp - gui/xml_editor.cpp + + gui/xml/xml_editor.cpp + gui/xml/xml_attribute.cpp + gui/xml/xml_edit.cpp + gui/xml/xml_string_edit.cpp ) if(SYSTEM_NAME STREQUAL "FreeBSD") @@ -57,6 +61,7 @@ target_include_directories(gpgui ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libgptbackend/preg ${CMAKE_CURRENT_SOURCE_DIR}/gui/ + ${CMAKE_CURRENT_SOURCE_DIR}/gui/xml ) install(TARGETS gpgui) diff --git a/src/gpgui/gui/xml/xml_attribute.cpp b/src/gpgui/gui/xml/xml_attribute.cpp new file mode 100644 index 00000000..3af9afd9 --- /dev/null +++ b/src/gpgui/gui/xml/xml_attribute.cpp @@ -0,0 +1,125 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xml_attribute.h" + +XmlAttribute::XmlAttribute(const QDomNode &node) { + // NOTE: there are two "attributes", attributes of the object and xml attributes + const QDomNamedNodeMap attributes = node.attributes(); + + const QDomNode attribute_name = attributes.namedItem("name"); + m_name = attribute_name.nodeValue(); + + const QDomNode attribute_type = attributes.namedItem("type"); + m_type = string_to_attribute_type(attribute_type.nodeValue()); + + const QDomNode attribute_use = attributes.namedItem("use"); + m_required = (attribute_use.nodeValue() == "required"); + + // Recurse through all ancestors of node and check if any of them have an attribute "name" set to "Properties" + // TODO: might actually not be useful? Delete if not + auto get_is_property = + [node]() -> bool { + QDomNode current = node.parentNode(); + + while (!current.isNull()) { + const QDomNamedNodeMap current_attributes = current.attributes(); + const QDomNode name_node = current_attributes.namedItem("name"); + if (!name_node.isNull()) { + const QString this_name = name_node.nodeValue(); + + if (this_name == "Properties") { + return true; + } + } + + const QDomNode new_current = current.parentNode(); + + if (new_current == current) { + // Reached top node + return false; + } else { + current = new_current; + } + } + + return false; + }; + m_is_property = get_is_property(); +} + +void XmlAttribute::print() const { + printf("attribute\n"); + printf(" name=%s\n", qPrintable(m_name)); + printf(" type=%s\n", qPrintable(attribute_type_to_string(m_type))); + printf(" required=%d\n", m_required); + printf(" properties=%d\n", m_is_property); +} + + +QString XmlAttribute::name() const { + return m_name; +} + +XmlAttributeType XmlAttribute::type() const { + return m_type; +} + +bool XmlAttribute::required() const { + return m_required; +} + +bool XmlAttribute::is_property() const { + return m_is_property; +} + +const QHash attribute_type_to_string_map = { + {XmlAttributeType_String, "string"}, + {XmlAttributeType_Boolean, "boolean"}, + {XmlAttributeType_UnsignedByte, "unsignedByte"} +}; + +QString attribute_type_to_string(const XmlAttributeType type) { + const QString string = attribute_type_to_string_map.value(type, "UNKNOWN_ATTRIBUTE_TYPE"); + return string; +} + +XmlAttributeType string_to_attribute_type(const QString string_raw) { + auto generate_string_to_attribute_type_map = + []() -> QHash { + QHash result; + + for (auto type : attribute_type_to_string_map.keys()) { + const QString string = attribute_type_to_string_map[type]; + result.insert(string, type); + } + + return result; + }; + static QHash string_to_attribute_type_map = generate_string_to_attribute_type_map(); + + QString string = string_raw; + if (string.contains("xs:")) { + string.remove("xs:"); + } + + const XmlAttributeType type = string_to_attribute_type_map.value(string, XmlAttributeType_None); + + return type; +} diff --git a/src/gpgui/gui/xml/xml_attribute.h b/src/gpgui/gui/xml/xml_attribute.h new file mode 100644 index 00000000..fc72eea6 --- /dev/null +++ b/src/gpgui/gui/xml/xml_attribute.h @@ -0,0 +1,56 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XML_ATTRIBUTE_H +#define XML_ATTRIBUTE_H + +#include +#include +#include +#include + +enum XmlAttributeType { + XmlAttributeType_String, + XmlAttributeType_Boolean, + XmlAttributeType_UnsignedByte, + XmlAttributeType_None +}; + +class XmlAttribute { +public: + XmlAttribute(const QDomNode &node); + + void print() const; + + QString name() const; + XmlAttributeType type() const; + bool required() const; + bool is_property() const; + +private: + QString m_name; + XmlAttributeType m_type; + bool m_required; + bool m_is_property; +}; + +QString attribute_type_to_string(const XmlAttributeType type); +XmlAttributeType string_to_attribute_type(const QString string_raw); + +#endif /* XML_ATTRIBUTE_H */ diff --git a/src/gpgui/gui/xml/xml_edit.cpp b/src/gpgui/gui/xml/xml_edit.cpp new file mode 100644 index 00000000..84c772e7 --- /dev/null +++ b/src/gpgui/gui/xml/xml_edit.cpp @@ -0,0 +1,55 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xml_edit.h" + +#include + +// Look for attribute's node in the document by iterating +// through all nodes and looking for and attribute with same name +QDomNode find_attribute_node(const QDomDocument &doc, const QString &attribute_name) { + QStack elements_to_explore; + const QDomElement top_element = doc.documentElement(); + elements_to_explore.push(top_element); + + while (!elements_to_explore.isEmpty()) { + const QDomElement element = elements_to_explore.pop(); + + QDomNode child = element.firstChild(); + while (!child.isNull()) { + QDomElement child_as_element = child.toElement(); + const bool is_element = !child_as_element.isNull(); + + if (is_element) { + elements_to_explore.push(child_as_element); + } + + // Check node's attributes + const QDomNamedNodeMap attributes = child.attributes(); + const QDomNode attribute_node = attributes.namedItem(attribute_name); + if (!attribute_node.isNull()) { + return attribute_node; + } + + child = child.nextSibling(); + } + } + + return QDomNode(); +} diff --git a/src/gpgui/gui/xml/xml_edit.h b/src/gpgui/gui/xml/xml_edit.h new file mode 100644 index 00000000..5295f455 --- /dev/null +++ b/src/gpgui/gui/xml/xml_edit.h @@ -0,0 +1,51 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XML_EDIT_H +#define XML_EDIT_H + +#include +#include + +class QGridLayout; +class QWidget; + +class XmlEdit : public QObject { +Q_OBJECT +public: + virtual void add_to_layout(QGridLayout *layout) = 0; + virtual void load(const QDomDocument &doc) = 0; + virtual bool changed() const = 0; + virtual bool verify_input(QWidget *parent) = 0; + virtual bool apply(QDomDocument *doc) = 0; + +signals: + void edited(); +}; + +#define DECL_XML_EDIT_VIRTUALS()\ +void add_to_layout(QGridLayout *layout);\ +void load(const QDomDocument &doc);\ +bool changed() const;\ +bool verify_input(QWidget *parent);\ +bool apply(QDomDocument *doc); + +QDomNode find_attribute_node(const QDomDocument &doc, const QString &attribute_name); + +#endif /* XML_EDIT_H */ diff --git a/src/gpgui/gui/xml/xml_editor.cpp b/src/gpgui/gui/xml/xml_editor.cpp new file mode 100644 index 00000000..092e60cf --- /dev/null +++ b/src/gpgui/gui/xml/xml_editor.cpp @@ -0,0 +1,154 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xml_editor.h" +#include "xml_edit.h" +#include "xml_string_edit.h" +#include "xml_attribute.h" + +#include +#include +#include +#include +#include +#include +#include + +QList XmlEditor::schema_attributes; +QHash XmlEditor::schema_attributes_by_name; + +QList edits; + +void XmlEditor::load_schema() { + static bool loaded = false; + if (loaded) { + return; + } else { + loaded = true; + } + + QFile file("../shortcuts_xml_schema.xml"); + const bool open_success = file.open(QIODevice::ReadOnly | QIODevice::Text); + if (!open_success) { + printf("Failed to open xml file\n"); + return; + } + + QDomDocument doc("schema"); + doc.setContent(&file); + + file.close(); + + const QDomNodeList attributes = doc.elementsByTagName("xs:attribute"); + for (int i = 0; i < attributes.size(); i++) { + const QDomNode node = attributes.at(i); + const XmlAttribute attribute(node); + + schema_attributes.append(attribute); + schema_attributes_by_name.insert(attribute.name(), attribute); + } +} + +XmlEditor::XmlEditor(const QString &path_arg) +: QDialog() +{ + path = path_arg; + + load_schema(); + + setAttribute(Qt::WA_DeleteOnClose); + resize(300, 600); + + const QString title_label_text = tr("Editing xml file:") + path; + auto title_label = new QLabel(title_label_text); + + auto button_box = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Ok); + + connect( + button_box, &QDialogButtonBox::accepted, + this, &QDialog::accept); + connect( + button_box, &QDialogButtonBox::rejected, + this, &QDialog::reject); + + QFile file(path); + const bool open_success = file.open(QIODevice::ReadOnly | QIODevice::Text); + if (!open_success) { + printf("Failed to open xml file\n"); + return; + } + + QDomDocument doc("file"); + doc.setContent(&file); + + file.close(); + + auto edits_layout = new QGridLayout(); + + for (auto attribute : schema_attributes) { + auto edit = new XmlStringEdit(attribute); + edit->add_to_layout(edits_layout); + edit->load(doc); + + edits.append(edit); + } + + const auto top_layout = new QVBoxLayout(); + setLayout(top_layout); + top_layout->addWidget(title_label); + top_layout->addLayout(edits_layout); + top_layout->addWidget(button_box); + + connect( + button_box->button(QDialogButtonBox::Ok), &QPushButton::clicked, + this, &XmlEditor::on_ok); +} + +void XmlEditor::on_ok() { + QFile read_file(path); + const bool opened_read_file = read_file.open(QIODevice::ReadOnly | QIODevice::Text); + if (!opened_read_file) { + printf("Failed to open xml file for reading\n"); + return; + } + QDomDocument doc("read_file"); + doc.setContent(&read_file); + + read_file.close(); + + for (auto edit : edits) { + edit->apply(&doc); + } + + printf("changed doc=%s\n", qPrintable(doc.toString())); + + // Save changes to file + QFile write_file(path); + const bool opened_write_file = write_file.open(QIODevice::QIODevice::WriteOnly | QIODevice::Truncate); + if (!opened_write_file) { + printf("Failed to open xml file for writing\n"); + return; + } + + const QByteArray doc_bytes = doc.toByteArray(4); + const char *doc_cstr = doc_bytes.constData(); + write_file.write(doc_cstr); + + write_file.close(); +} diff --git a/src/gpgui/gui/xml_editor.h b/src/gpgui/gui/xml/xml_editor.h similarity index 73% rename from src/gpgui/gui/xml_editor.h rename to src/gpgui/gui/xml/xml_editor.h index 3f9146ba..041aeeb2 100644 --- a/src/gpgui/gui/xml_editor.h +++ b/src/gpgui/gui/xml/xml_editor.h @@ -20,34 +20,30 @@ #ifndef XML_EDITOR_H #define XML_EDITOR_H +#include "xml_attribute.h" + #include #include #include - -enum AttributeType { - AttributeType_String, - AttributeType_Boolean, - AttributeType_UnsignedByte, - AttributeType_None -}; - -class GpoXmlAttribute { -public: - QString name; - AttributeType type; - bool required; - bool properties; -}; +#include +#include class XmlEditor final : public QDialog { Q_OBJECT public: - static QList schema_attributes; + static QList schema_attributes; + static QHash schema_attributes_by_name; - XmlEditor(const QString &path); + XmlEditor(const QString &path_arg); static void load_schema(); + +private slots: + void on_ok(); + +private: + QString path; }; #endif /* XML_EDITOR_H */ diff --git a/src/gpgui/gui/xml/xml_string_edit.cpp b/src/gpgui/gui/xml/xml_string_edit.cpp new file mode 100644 index 00000000..b2ac156b --- /dev/null +++ b/src/gpgui/gui/xml/xml_string_edit.cpp @@ -0,0 +1,84 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xml_string_edit.h" + +#include +#include +#include +#include + +XmlStringEdit::XmlStringEdit(const XmlAttribute &attribute_arg) +: attribute(attribute_arg) { + edit = new QLineEdit(); + + QObject::connect( + edit, &QLineEdit::textChanged, + [this]() { + emit edited(); + }); +} + +void XmlStringEdit::load(const QDomDocument &doc) { + const QDomNode attribute_node = find_attribute_node(doc, attribute.name()); + + original_value = attribute_node.nodeValue(); + + edit->blockSignals(true); + edit->setText(original_value); + edit->blockSignals(false); + + emit edited(); +} + +void XmlStringEdit::add_to_layout(QGridLayout *layout) { + const QString label_text = attribute.name() + ":"; + const auto label = new QLabel(label_text); + + // TODO: connect_changed_marker(this, label); + + // TODO: shared usage via append_to_grid_layout_with_label(layout, label, edit); + const int row = layout->rowCount(); + layout->addWidget(label, row, 0); + layout->addWidget(edit, row, 1); +} + +bool XmlStringEdit::verify_input(QWidget *parent) { + return true; +} + +bool XmlStringEdit::changed() const { + const QString new_value = edit->text(); + return (new_value != original_value); +} + +bool XmlStringEdit::apply(QDomDocument *doc) { + printf("apply %s\n", qPrintable(attribute.name())); + if (!changed()) { + printf(" not applying\n"); + return true; + } + printf("!!!!!!!applying\n"); + + QDomNode attribute_node = find_attribute_node(*doc, attribute.name()); + const QString new_value = edit->text(); + attribute_node.setNodeValue(new_value); + + return true; +} diff --git a/src/gpgui/gui/xml/xml_string_edit.h b/src/gpgui/gui/xml/xml_string_edit.h new file mode 100644 index 00000000..e7e3f6c8 --- /dev/null +++ b/src/gpgui/gui/xml/xml_string_edit.h @@ -0,0 +1,43 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XML_STRING_EDIT_H +#define XML_STRING_EDIT_H + +#include "xml_edit.h" +#include "xml_attribute.h" + +#include + +class QLineEdit; + +class XmlStringEdit final : public XmlEdit { +Q_OBJECT +public: + QLineEdit *edit; + + XmlStringEdit(const XmlAttribute &attribute_arg); + DECL_XML_EDIT_VIRTUALS(); + +private: + XmlAttribute attribute; + QString original_value; +}; + +#endif /* XML_STRING_EDIT_H */ diff --git a/src/gpgui/gui/xml_editor.cpp b/src/gpgui/gui/xml_editor.cpp deleted file mode 100644 index 449f4a12..00000000 --- a/src/gpgui/gui/xml_editor.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * ADMC - AD Management Center - * - * Copyright (C) 2020 BaseALT Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "xml_editor.h" - -#include -#include -#include -#include -#include -#include - -const QHash attribute_type_to_string = { - {AttributeType_String, "string"}, - {AttributeType_Boolean, "boolean"}, - {AttributeType_UnsignedByte, "unsignedByte"} -}; - -QList XmlEditor::schema_attributes; - -AttributeType string_to_attribute_type(const QString string_raw) { - auto generate_string_to_attribute_type_map = - []() -> QHash { - QHash result; - - for (auto type : attribute_type_to_string.keys()) { - const QString string = attribute_type_to_string[type]; - result.insert(string, type); - } - - return result; - }; - static QHash string_to_attribute_type_map = generate_string_to_attribute_type_map(); - - QString string = string_raw; - if (string.contains("xs:")) { - string.remove("xs:"); - } - - const AttributeType type = string_to_attribute_type_map.value(string, AttributeType_None); - - return type; -} - -void XmlEditor::load_schema() { - static bool loaded = false; - if (loaded) { - return; - } else { - loaded = true; - } - - QFile file("../shortcuts_xml_schema.xml"); - const bool open_success = file.open(QIODevice::ReadOnly | QIODevice::Text); - if (!open_success) { - printf("Failed to open xml file\n"); - return; - } - - QDomDocument doc("schema"); - doc.setContent(&file); - - file.close(); - - QDomNode root = doc.namedItem("Properties"); - QDomNodeList node_list = root.childNodes(); - for (int i = 0; i < node_list.size(); i++) { - printf("=%s\n", qPrintable(node_list.at(i).nodeValue())); - } - - // NOTE: there are two things that are called "attributes" in this context, the nodes which are named "xs:attribute" and the attributes of those nodes - QDomNodeList attributes = doc.elementsByTagName("xs:attribute"); - for (int i = 0; i < attributes.size(); i++) { - const QDomNode node = attributes.at(i); - - GpoXmlAttribute gpo_attribute; - - // Recurse through all ancestors of node and check if any of them have an attribute "name" set to "Properties" - auto is_child_of_properties = - [node]() -> bool { - QDomNode current = node.parentNode(); - - while (!current.isNull()) { - const QDomNamedNodeMap node_attributes = current.attributes(); - const QDomNode name_node = node_attributes.namedItem("name"); - if (!name_node.isNull()) { - const QString this_name = name_node.nodeValue(); - - if (this_name == "Properties") { - return true; - } - } - - const QDomNode new_current = current.parentNode(); - - if (new_current == current) { - // Reached top node - return false; - } else { - current = new_current; - } - } - - return false; - }; - - gpo_attribute.properties = is_child_of_properties(); - - const QDomNamedNodeMap xml_attribs = node.attributes(); - - const QDomNode xml_name = xml_attribs.namedItem("name"); - gpo_attribute.name = xml_name.nodeValue(); - - const QDomNode xml_use = xml_attribs.namedItem("use"); - gpo_attribute.required = (xml_use.nodeValue() == "required"); - - QDomNode xml_type = xml_attribs.namedItem("type"); - gpo_attribute.type = string_to_attribute_type(xml_type.nodeValue()); - - printf("attribute\n"); - printf(" name=%s\n", qPrintable(gpo_attribute.name)); - printf(" type=%s\n", qPrintable(attribute_type_to_string[gpo_attribute.type])); - printf(" required=%d\n", gpo_attribute.required); - printf(" properties=%d\n", gpo_attribute.properties); - - schema_attributes.append(gpo_attribute); - } -} - -XmlEditor::XmlEditor(const QString &path) -: QDialog() -{ - load_schema(); - - setAttribute(Qt::WA_DeleteOnClose); - resize(300, 600); - - const QString title_label_text = tr("Editing xml file:") + path; - auto title_label = new QLabel(title_label_text); - - auto button_box = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Ok); - - const auto top_layout = new QVBoxLayout(); - setLayout(top_layout); - top_layout->addWidget(title_label); - top_layout->addWidget(button_box); - - connect( - button_box, &QDialogButtonBox::accepted, - this, &QDialog::accept); - connect( - button_box, &QDialogButtonBox::rejected, - this, &QDialog::reject); - - { - QFile file(path); - const bool open_success = file.open(QIODevice::ReadOnly | QIODevice::Text); - if (!open_success) { - printf("Failed to open xml file\n"); - return; - } - - const QByteArray file_byte_array = file.readAll(); - const QString file_string(file_byte_array); - - QXmlStreamReader xml(file_string); - - while (!xml.atEnd()) { - const QXmlStreamReader::TokenType token_type = xml.readNext(); - - switch (token_type) { - case QXmlStreamReader::StartElement: { - if (xml.name() == "Properties") { - const QXmlStreamAttributes attributes = xml.attributes(); - - for (const QXmlStreamAttribute attribute : attributes) { - printf("%s=%s\n", qPrintable(attribute.name().toString()), qPrintable(attribute.value().toString())); - } - } - - break; - } - default: { - break; - } - } - } - } -}