#include "metareader.h" #include #include "config/config.h" #include "node.h" NodeMetaReader::NodeMetaReader(const QString &xml_meta_filename) : xml_filename_(xml_meta_filename), iterations_(1), iteration_input_(nullptr) { QFile metadata_file(xml_filename_); if (metadata_file.open(QFile::ReadOnly)) { QXmlStreamReader reader(&metadata_file); while (!reader.atEnd()) { reader.readNext(); if (reader.isStartElement() && reader.name() == "effect") { XMLReadEffect(&reader); } } metadata_file.close(); } else { qWarning() << "Failed to load node metadata file" << xml_filename_; } } QString NodeMetaReader::Name() const { return GetStringForCurrentLanguage(&names_); } const QString &NodeMetaReader::id() const { return id_; } QString NodeMetaReader::Category() const { return GetStringForCurrentLanguage(&categories_); } QString NodeMetaReader::Description() const { return GetStringForCurrentLanguage(&descriptions_); } const QString &NodeMetaReader::filename() const { return xml_filename_; } const QString &NodeMetaReader::frag_code() const { return frag_code_; } const QString &NodeMetaReader::vert_code() const { return vert_code_; } const int &NodeMetaReader::iterations() const { return iterations_; } NodeInput *NodeMetaReader::iteration_input() const { return iteration_input_; } const QList &NodeMetaReader::inputs() const { return inputs_; } void NodeMetaReader::Retranslate() { QMap >::const_iterator iterator; // Iterate through parameter language tables that we have for (iterator=param_names_.begin();iterator!=param_names_.end();iterator++) { NodeInput* this_input = GetInputWithID(iterator.key()); this_input->set_name(GetStringForCurrentLanguage(&iterator.value())); } } void NodeMetaReader::XMLReadLanguageString(QXmlStreamReader* reader, QMap* map) { QString lang; // Traverse through name attributes for its language QXmlStreamAttributes attrs = reader->attributes(); foreach (const QXmlStreamAttribute& attr, attrs) { if (attr.name() == "lang") { lang = attr.value().toString(); // We don't recognize any other "name" attributes at this time break; } } // Insert name with language into map map->insert(lang, reader->readElementText().trimmed()); } void NodeMetaReader::XMLReadEffect(QXmlStreamReader* reader) { // Traverse through effect attributes for an ID QXmlStreamAttributes attrs = reader->attributes(); foreach (const QXmlStreamAttribute& attr, attrs) { if (attr.name() == "id") { id_ = attr.value().toString(); // We don't recognize any other "effect" attributes at this time break; } } if (id_.isEmpty()) { qWarning() << "Effect metadata" << xml_filename_ << "has no ID"; return; } // Continue reading for other metadata while (!reader->atEnd() && !(reader->isEndElement() && reader->name() == "effect")) { reader->readNext(); if (reader->isStartElement()) { if (reader->name() == "name") { // Pick up name XMLReadLanguageString(reader, &names_); } else if (reader->name() == "category") { // Pick up category XMLReadLanguageString(reader, &categories_); } else if (reader->name() == "description") { // Pick up description XMLReadLanguageString(reader, &descriptions_); } else if (reader->name() == "iterations") { // Pick up iterations XMLReadIterations(reader); } else if (reader->name() == "fragment") { // Pick up fragment shader code XMLReadShader(reader, frag_code_); } else if (reader->name() == "vertex") { // Pick up vertex shader code XMLReadShader(reader, vert_code_); } else if (reader->name() == "param") { // Pick up a parameter XMLReadParam(reader); } } } } void NodeMetaReader::XMLReadIterations(QXmlStreamReader* reader) { int iteration_pickup = reader->readElementText().toInt(); if (iterations_ > 0) { iterations_ = iteration_pickup; } else { // If the iteration value is invalid, don't set it, print an error insteead qWarning() << "Invalid iteration number in" << xml_filename_ << "- setting to default (1)"; } } void NodeMetaReader::XMLReadParam(QXmlStreamReader *reader) { QString param_id; NodeParam::DataType param_type = NodeParam::kAny; bool is_iterative = false; // Traverse through parameter attributes for an ID QXmlStreamAttributes attrs = reader->attributes(); foreach (const QXmlStreamAttribute& attr, attrs) { if (attr.name() == "id") { param_id = attr.value().toString(); } else if (attr.name() == "type") { param_type = NodeParam::StringToDataType(attr.value().toString()); } else if (attr.name() == "iterative_input") { is_iterative = true; } } if (param_id.isEmpty()) { qWarning() << "Effect metadata" << xml_filename_ << "contains a parameter with no ID - parameter was not added"; return; } QVariant default_val; QHash properties; // Traverse through param contents for more data while (!reader->atEnd() && !(reader->isEndElement() && reader->name() == "param")) { reader->readNext(); if (reader->isStartElement()) { // NOTE: readElementText() returns a string, but for number types (which min and max apply to), QVariant will // convert them automatically if (reader->name() == "name") { // See if we've already made a table for this param before if (!param_names_.contains(param_id)) { param_names_.insert(param_id, QMap()); } // Insert language into table XMLReadLanguageString(reader, ¶m_names_[param_id]); } else if (reader->name() == "default") { default_val = reader->readElementText(); } else { properties.insert(reader->name().toString(), reader->readElementText()); } } } NodeInput* input = new NodeInput(param_id, param_type, default_val); QHash::const_iterator iterator; for (iterator=properties.begin();iterator!=properties.end();iterator++) { input->set_property(iterator.key(), iterator.value()); } if (is_iterative) { iteration_input_ = input; } inputs_.append(input); } void NodeMetaReader::XMLReadShader(QXmlStreamReader *reader, QString &destination) { QString code_url; // Traverse through parameter attributes for an ID QXmlStreamAttributes attrs = reader->attributes(); foreach (const QXmlStreamAttribute& attr, attrs) { if (attr.name() == "url") { code_url = attr.value().toString(); // We don't recognize any other "shader" attributes at this time break; } } // Add code in file from URL if (!code_url.isEmpty()) { destination.append(Node::ReadFileAsString(code_url)); } // Add any code that's inline in the XML QString element_text = reader->readElementText().trimmed(); if (!element_text.isEmpty()) { destination.append(element_text); } } QString NodeMetaReader::GetStringForCurrentLanguage(const QMap *language_map) { if (language_map->isEmpty()) { // There are no entries for this map, this must be an empty string return QString(); } // Get current language config QString language = Config::Current()["Language"].toString(); // See if our map has an exact language match QString str_for_lang = language_map->value(language); if (!str_for_lang.isEmpty()) { return str_for_lang; } // If not, try to find a match with the same language but not the same derivation QString base_lang = language.split('_').first(); QList available_languages = language_map->keys(); foreach (const QString& l, available_languages) { if (l.startsWith(base_lang)) { // This is the same language, so we can return this return language_map->value(l); } } // We couldn't find an exact or close match, just return the first in the list // (assume a string in the wrong language is better than no string at all) return language_map->first(); } NodeInput *NodeMetaReader::GetInputWithID(const QString &id) const { foreach (NodeInput* input, inputs_) { if (input->id() == id) { return input; } } return nullptr; }