QString OsmAnd::ResolvedMapStyle_P::dumpRuleNodeOutputValues( const std::shared_ptr<const RuleNode>& ruleNode, const QString& prefix, const bool allowOverride) const { QString dump; const auto builtinValueDefs = MapStyleBuiltinValueDefinitions::get(); for (const auto& ruleValueEntry : rangeOf(constOf(ruleNode->values))) { const auto valueDefId = ruleValueEntry.key(); const auto& valueDef = getValueDefinitionById(valueDefId); // Skip all non-Output values if (valueDef->valueClass != MapStyleValueDefinition::Class::Output) continue; const auto& resolvedRuleValue = ruleValueEntry.value(); dump += prefix + QString(QLatin1String("%1 %2 = %3;\n")) .arg(allowOverride ? QLatin1String("setOrOverride") : QLatin1String("setIfNotSet")) .arg(valueDef->name) .arg(dumpResolvedValue(resolvedRuleValue, valueDef->dataType)); } return dump; }
std::shared_ptr<OsmAnd::ResolvedMapStyle_P::RuleNode> OsmAnd::ResolvedMapStyle_P::resolveRuleNode( const std::shared_ptr<const UnresolvedMapStyle::RuleNode>& unresolvedRuleNode) { const std::shared_ptr<RuleNode> resolvedRuleNode(new RuleNode( unresolvedRuleNode->isSwitch)); // Resolve values for (const auto& itUnresolvedValueEntry : rangeOf(constOf(unresolvedRuleNode->values))) { const auto& name = itUnresolvedValueEntry.key(); const auto& value = itUnresolvedValueEntry.value(); // Find value definition id and object const auto valueDefId = getValueDefinitionIdByName(name); const auto& valueDef = getValueDefinitionById(valueDefId); if (valueDefId < 0 || !valueDef) { LogPrintf(LogSeverityLevel::Warning, "Ignoring unknown value '%s' = '%s'", qPrintable(name), qPrintable(value)); continue; } // Try to resolve value ResolvedValue resolvedValue; if (!resolveValue(value, valueDef->dataType, valueDef->isComplex, resolvedValue)) { LogPrintf(LogSeverityLevel::Warning, "Ignoring value for '%s' since '%s' can not be resolved", qPrintable(name), qPrintable(value)); continue; } resolvedRuleNode->values[valueDefId] = resolvedValue; } // <switch>/<case> subnodes for (const auto& unresolvedChild : constOf(unresolvedRuleNode->oneOfConditionalSubnodes)) { const auto resolvedChild = resolveRuleNode(unresolvedChild); if (!resolvedChild) return nullptr; resolvedRuleNode->oneOfConditionalSubnodes.push_back(resolvedChild); } // <apply> subnodes for (const auto& unresolvedChild : constOf(unresolvedRuleNode->applySubnodes)) { const auto resolvedChild = resolveRuleNode(unresolvedChild); if (!resolvedChild) return nullptr; resolvedRuleNode->applySubnodes.push_back(resolvedChild); } return resolvedRuleNode; }
bool OsmAndTools::Styler::evaluate(EvaluatedMapObjects& outEvaluatedMapObjects, std::ostream& output) #endif { bool success = true; for (;;) { // Find style if (configuration.verbose) output << xT("Resolving style '") << QStringToStlString(configuration.styleName) << xT("'...") << std::endl; const auto mapStyle = configuration.stylesCollection->getResolvedStyleByName(configuration.styleName); if (!mapStyle) { if (configuration.verbose) { output << "Failed to resolve style '" << QStringToStlString(configuration.styleName) << "' from collection:" << std::endl; for (const auto& style : configuration.stylesCollection->getCollection()) { if (style->isMetadataLoaded()) { if (style->isStandalone()) output << "\t" << QStringToStlString(style->name) << std::endl; else { output << "\t" << QStringToStlString(style->name) << "::" << QStringToStlString(style->parentName) << std::endl; } } else output << "\t[missing metadata]" << std::endl; } } else { output << "Failed to resolve style '" << QStringToStlString(configuration.styleName) << "' from collection:" << std::endl; } success = false; break; } // Load all map objects const auto mapObjectsFilterById = [this] (const std::shared_ptr<const OsmAnd::ObfMapSectionInfo>& section, const uint64_t mapObjectId, const OsmAnd::AreaI& bbox, const OsmAnd::ZoomLevel firstZoomLevel, const OsmAnd::ZoomLevel lastZoomLevel, const OsmAnd::ZoomLevel requestedZoom) -> bool { return configuration.mapObjectsIds.contains(mapObjectId); }; if (configuration.verbose) { if (configuration.mapObjectsIds.isEmpty()) output << xT("Going to load all available map objects...") << std::endl; else output << xT("Going to load ") << configuration.mapObjectsIds.size() << xT(" map objects...") << std::endl; } const auto obfDataInterface = configuration.obfsCollection->obtainDataInterface(); QList< std::shared_ptr<const OsmAnd::BinaryMapObject> > mapObjects_; success = obfDataInterface->loadBinaryMapObjects( &mapObjects_, nullptr, configuration.zoom, nullptr, configuration.mapObjectsIds.isEmpty() ? OsmAnd::ObfMapSectionReader::FilterByIdFunction() : mapObjectsFilterById, nullptr, nullptr, nullptr, nullptr); const auto mapObjects = OsmAnd::copyAs< QList< std::shared_ptr<const OsmAnd::MapObject> > >(mapObjects_); if (!success) { if (configuration.verbose) output << xT("Failed to load map objects!") << std::endl; break; } if (configuration.verbose) output << xT("Loaded ") << mapObjects.size() << xT(" map objects") << std::endl; // Prepare all resources for map style evaluation if (configuration.verbose) { output << xT("Initializing map presentation environment with display density ") << configuration.displayDensityFactor << xT(", map scale ") << configuration.mapScale << xT(", symbols scale ") << configuration.symbolsScale << xT(" and locale '") << QStringToStlString(configuration.locale) << xT("'...") << std::endl; } const std::shared_ptr<OsmAnd::MapPresentationEnvironment> mapPresentationEnvironment(new OsmAnd::MapPresentationEnvironment( mapStyle, configuration.displayDensityFactor, configuration.mapScale, configuration.symbolsScale, configuration.locale)); if (configuration.verbose) output << xT("Applying extra style settings to map presentation environment...") << std::endl; mapPresentationEnvironment->setSettings(configuration.styleSettings); // Create primitiviser const std::shared_ptr<OsmAnd::MapPrimitiviser> primitiviser(new OsmAnd::MapPrimitiviser(mapPresentationEnvironment)); if (configuration.verbose) output << xT("Going to primitivise map objects...") << std::endl; OsmAnd::MapPrimitiviser_Metrics::Metric_primitiviseAllMapObjects metrics; const auto primitivisedData = primitiviser->primitiviseAllMapObjects( configuration.zoom, mapObjects, nullptr, nullptr, configuration.metrics ? &metrics : nullptr); if (configuration.verbose) { output << xT("Primitivised ") << primitivisedData->primitivesGroups.size() << xT(" groups from ") << mapObjects.size() << xT(" map objects") << std::endl; } // Obtain evaluated values for each group and print it for (const auto& primitivisedGroup : OsmAnd::constOf(primitivisedData->primitivesGroups)) { const auto& mapObject = primitivisedGroup->sourceObject; const auto binaryMapObject = std::dynamic_pointer_cast<const OsmAnd::BinaryMapObject>(mapObject); const auto& encDecRules = mapObject->encodingDecodingRules; // Skip objects that were not requested if (!configuration.mapObjectsIds.isEmpty() && binaryMapObject && !configuration.mapObjectsIds.contains(binaryMapObject->id)) { continue; } outEvaluatedMapObjects[mapObject] = primitivisedGroup; output << QStringToStlString(QString(80, QLatin1Char('-'))) << std::endl; output << QStringToStlString(mapObject->toString()) << std::endl; for (const auto& typeRuleId : OsmAnd::constOf(mapObject->typesRuleIds)) { const auto itTypeRule = encDecRules->decodingRules.constFind(typeRuleId); if (itTypeRule != encDecRules->decodingRules.cend()) { const auto& typeRule = *itTypeRule; output << xT("\tType: ") << QStringToStlString(typeRule.tag) << xT(" = ") << QStringToStlString(typeRule.value) << std::endl; } else { output << xT("\tType: #") << typeRuleId << xT(" (UNRESOLVED)") << std::endl; } } for (const auto& typeRuleId : OsmAnd::constOf(mapObject->additionalTypesRuleIds)) { const auto itTypeRule = encDecRules->decodingRules.constFind(typeRuleId); if (itTypeRule != encDecRules->decodingRules.cend()) { const auto& typeRule = *itTypeRule; output << xT("\tExtra type: ") << QStringToStlString(typeRule.tag) << xT(" = ") << QStringToStlString(typeRule.value) << std::endl; } else { output << xT("\tExtra type: #") << typeRuleId << xT(" (UNRESOLVED)") << std::endl; } } for (const auto& captionTagId : OsmAnd::constOf(mapObject->captionsOrder)) { const auto& captionValue = mapObject->captions[captionTagId]; if (encDecRules->name_encodingRuleId == captionTagId) output << xT("\tCaption: ") << QStringToStlString(captionValue) << std::endl; else if (encDecRules->ref_encodingRuleId == captionTagId) output << xT("\tRef: ") << QStringToStlString(captionValue) << std::endl; else { const auto itCaptionTagAsLocalizedName = encDecRules->localizedName_decodingRules.constFind(captionTagId); const auto itCaptionTagRule = encDecRules->decodingRules.constFind(captionTagId); QString captionTag(QLatin1String("UNRESOLVED")); if (itCaptionTagAsLocalizedName != encDecRules->localizedName_decodingRules.cend()) captionTag = *itCaptionTagAsLocalizedName; if (itCaptionTagRule != encDecRules->decodingRules.cend()) captionTag = itCaptionTagRule->tag; output << xT("\tCaption [") << QStringToStlString(captionTag) << xT("]: ") << QStringToStlString(captionValue) << std::endl; } } if (!primitivisedGroup->points.isEmpty()) { output << primitivisedGroup->points.size() << xT(" point(s):") << std::endl; unsigned int pointPrimitiveIndex = 0u; for (const auto& pointPrimitive : OsmAnd::constOf(primitivisedGroup->points)) { output << xT("\tPoint #") << pointPrimitiveIndex << std::endl; QString ruleTag; QString ruleValue; const auto typeRuleResolved = mapObject->obtainTagValueByTypeRuleIndex( pointPrimitive->typeRuleIdIndex, ruleTag, ruleValue); if (typeRuleResolved) { output << xT("\t\tTag/value: ") << QStringToStlString(ruleTag) << xT(" = ") << QStringToStlString(ruleValue) << std::endl; } else { output << xT("\t\tTag/value: ") << pointPrimitive->typeRuleIdIndex << xT(" (failed to resolve)") << std::endl; } output << xT("\t\tZ order: ") << pointPrimitive->zOrder << std::endl; output << xT("\t\tArea*2: ") << pointPrimitive->doubledArea << std::endl; const auto& values = pointPrimitive->evaluationResult.getValues(); for (const auto& evaluatedValueEntry : OsmAnd::rangeOf(values)) { const auto valueDefinitionId = evaluatedValueEntry.key(); const auto value = evaluatedValueEntry.value(); const auto valueDefinition = mapStyle->getValueDefinitionById(valueDefinitionId); output << xT("\t\t") << QStringToStlString(valueDefinition->name) << xT(" = "); if (valueDefinition->dataType == OsmAnd::MapStyleValueDataType::Color) output << QStringToStlString(OsmAnd::ColorARGB(value.toUInt()).toString()); else output << QStringToStlString(value.toString()); output << std::endl; } pointPrimitiveIndex++; } } if (!primitivisedGroup->polylines.isEmpty()) { output << primitivisedGroup->polylines.size() << xT(" polyline(s):") << std::endl; unsigned int polylinePrimitiveIndex = 0u; for (const auto& polylinePrimitive : OsmAnd::constOf(primitivisedGroup->polylines)) { output << xT("\tPolyline #") << polylinePrimitiveIndex << std::endl; QString ruleTag; QString ruleValue; const auto typeRuleResolved = mapObject->obtainTagValueByTypeRuleIndex( polylinePrimitive->typeRuleIdIndex, ruleTag, ruleValue); if (typeRuleResolved) { output << xT("\t\tTag/value: ") << QStringToStlString(ruleTag) << xT(" = ") << QStringToStlString(ruleValue) << std::endl; } else { output << xT("\t\tTag/value: ") << polylinePrimitive->typeRuleIdIndex << xT(" (failed to resolve)") << std::endl; } output << xT("\t\tZ order: ") << polylinePrimitive->zOrder << std::endl; output << xT("\t\tArea*2: ") << polylinePrimitive->doubledArea << std::endl; const auto& values = polylinePrimitive->evaluationResult.getValues(); for (const auto& evaluatedValueEntry : OsmAnd::rangeOf(values)) { const auto valueDefinitionId = evaluatedValueEntry.key(); const auto value = evaluatedValueEntry.value(); const auto valueDefinition = mapStyle->getValueDefinitionById(valueDefinitionId); output << xT("\t\t") << QStringToStlString(valueDefinition->name) << xT(" = "); if (valueDefinition->dataType == OsmAnd::MapStyleValueDataType::Color) output << QStringToStlString(OsmAnd::ColorARGB(value.toUInt()).toString()); else output << QStringToStlString(value.toString()); output << std::endl; } polylinePrimitiveIndex++; } } if (!primitivisedGroup->polygons.isEmpty()) { output << primitivisedGroup->polygons.size() << xT(" polygon(s):") << std::endl; unsigned int polygonPrimitiveIndex = 0u; for (const auto& polygonPrimitive : OsmAnd::constOf(primitivisedGroup->polygons)) { output << xT("\tPolygon #") << polygonPrimitiveIndex << std::endl; QString ruleTag; QString ruleValue; const auto typeRuleResolved = mapObject->obtainTagValueByTypeRuleIndex( polygonPrimitive->typeRuleIdIndex, ruleTag, ruleValue); if (typeRuleResolved) { output << xT("\t\tTag/value: ") << QStringToStlString(ruleTag) << xT(" = ") << QStringToStlString(ruleValue) << std::endl; } else { output << xT("\t\tTag/value: ") << polygonPrimitive->typeRuleIdIndex << xT(" (failed to resolve)") << std::endl; } output << xT("\t\tZ order: ") << polygonPrimitive->zOrder << std::endl; output << xT("\t\tArea*2: ") << polygonPrimitive->doubledArea << std::endl; const auto& values = polygonPrimitive->evaluationResult.getValues(); for (const auto& evaluatedValueEntry : OsmAnd::rangeOf(values)) { const auto valueDefinitionId = evaluatedValueEntry.key(); const auto value = evaluatedValueEntry.value(); const auto valueDefinition = mapStyle->getValueDefinitionById(valueDefinitionId); output << xT("\t\t") << QStringToStlString(valueDefinition->name) << xT(" = "); if (valueDefinition->dataType == OsmAnd::MapStyleValueDataType::Color) output << QStringToStlString(OsmAnd::ColorARGB(value.toUInt()).toString()); else output << QStringToStlString(value.toString()); output << std::endl; } polygonPrimitiveIndex++; } } const auto itSymbolsGroup = primitivisedData->symbolsGroups.constFind(mapObject); if (itSymbolsGroup != primitivisedData->symbolsGroups.cend()) { const auto& symbolsGroup = *itSymbolsGroup; output << symbolsGroup->symbols.size() << xT(" symbol(s):") << std::endl; unsigned int symbolIndex = 0u; for (const auto& symbol : OsmAnd::constOf(symbolsGroup->symbols)) { const auto textSymbol = std::dynamic_pointer_cast<const OsmAnd::MapPrimitiviser::TextSymbol>(symbol); const auto iconSymbol = std::dynamic_pointer_cast<const OsmAnd::MapPrimitiviser::IconSymbol>(symbol); output << xT("\tSymbol #") << symbolIndex; if (textSymbol) output << xT(" (text)"); else if (iconSymbol) output << xT(" (icon)"); output << std::endl; auto primitiveIndex = -1; if (primitiveIndex == -1) { primitiveIndex = primitivisedGroup->points.indexOf(symbol->primitive); if (primitiveIndex >= 0) output << xT("\t\tPrimitive: Point #") << primitiveIndex << std::endl; } if (primitiveIndex == -1) { primitiveIndex = primitivisedGroup->polylines.indexOf(symbol->primitive); if (primitiveIndex >= 0) output << xT("\t\tPrimitive: Polyline #") << primitiveIndex << std::endl; } if (primitiveIndex == -1) { primitiveIndex = primitivisedGroup->polygons.indexOf(symbol->primitive); if (primitiveIndex >= 0) output << xT("\t\tPrimitive: Polygon #") << primitiveIndex << std::endl; } output << xT("\t\tPosition31: ") << symbol->location31.x << xT("x") << symbol->location31.y << std::endl; output << xT("\t\tOrder: ") << symbol->order << std::endl; output << xT("\t\tDraw along path: ") << (symbol->drawAlongPath ? xT("yes") : xT("no")) << std::endl; output << xT("\t\tIntersects with: ") << QStringToStlString(QStringList(symbol->intersectsWith.toList()).join(QLatin1String(", "))) << std::endl; output << xT("\t\tMinDistance: ") << symbol->minDistance << std::endl; if (textSymbol) { output << xT("\t\tText: ") << QStringToStlString(textSymbol->value) << std::endl; output << xT("\t\tLanguage: "); switch (textSymbol->languageId) { case OsmAnd::LanguageId::Invariant: output << xT("invariant"); break; case OsmAnd::LanguageId::Native: output << xT("native"); break; case OsmAnd::LanguageId::Localized: output << xT("localized"); break; } output << std::endl; output << xT("\t\tDraw text on path: ") << (textSymbol->drawOnPath ? xT("yes") : xT("no")) << std::endl; output << xT("\t\tText vertical offset: ") << textSymbol->verticalOffset << std::endl; output << xT("\t\tText color: ") << QStringToStlString(textSymbol->color.toString()) << std::endl; output << xT("\t\tText size: ") << textSymbol->size << std::endl; output << xT("\t\tText shadow radius: ") << textSymbol->shadowRadius << std::endl; output << xT("\t\tText shadow color: ") << QStringToStlString(textSymbol->shadowColor.toString()) << std::endl; output << xT("\t\tText wrap width: ") << textSymbol->wrapWidth << std::endl; output << xT("\t\tText is bold: ") << (textSymbol->isBold ? xT("yes") : xT("no")) << std::endl; output << xT("\t\tText is italic: ") << (textSymbol->isItalic ? xT("yes") : xT("no")) << std::endl; output << xT("\t\tShield resource name: ") << QStringToStlString(textSymbol->shieldResourceName) << std::endl; } else if (iconSymbol) { output << xT("\t\tIcon resource name: ") << QStringToStlString(iconSymbol->resourceName) << std::endl; for (const auto& overlayResoucreName : iconSymbol->overlayResourceNames) output << xT("\t\tOverlay resource name: ") << QStringToStlString(overlayResoucreName) << std::endl; output << xT("\t\tShield resource name: ") << QStringToStlString(iconSymbol->shieldResourceName) << std::endl; output << xT("\t\tIntersection size: ") << iconSymbol->intersectionSize << std::endl; } symbolIndex++; } } } if (configuration.metrics) { output << xT("Metrics:\n") << QStringToStlString(metrics.toString(false, QLatin1String("\t"))) << std::endl; } break; } return success; }
QString OsmAnd::ResolvedMapStyle_P::dumpRuleNode( const std::shared_ptr<const RuleNode>& ruleNode, const bool rejectSupported, const QString& prefix) const { QString dump; const auto builtinValueDefs = MapStyleBuiltinValueDefinitions::get(); bool hasInputValueTests = false; bool hasDisable = false; for (const auto& ruleValueEntry : rangeOf(constOf(ruleNode->values))) { const auto valueDefId = ruleValueEntry.key(); const auto& valueDef = getValueDefinitionById(valueDefId); if (valueDef->valueClass == MapStyleValueDefinition::Class::Input) hasInputValueTests = true; else if (valueDef->valueClass == MapStyleValueDefinition::Class::Output && valueDef->name == QLatin1String("disable")) hasDisable = true; if (hasInputValueTests && hasDisable) break; } if (hasInputValueTests) { dump += prefix + QLatin1String("local testPassed = true;\n"); for (const auto& ruleValueEntry : rangeOf(constOf(ruleNode->values))) { const auto valueDefId = ruleValueEntry.key(); const auto& valueDef = getValueDefinitionById(valueDefId); // Test only input values if (valueDef->valueClass != MapStyleValueDefinition::Class::Input) continue; const auto& resolvedRuleValue = ruleValueEntry.value(); //bool evaluationResult = false; if (valueDefId == builtinValueDefs->id_INPUT_MINZOOM) { dump += prefix + QString(QLatin1String("if (testPassed) testPassed = (%1 <= %2);\n")) .arg(dumpResolvedValue(resolvedRuleValue, MapStyleValueDataType::Integer)) .arg(valueDef->name); } else if (valueDefId == builtinValueDefs->id_INPUT_MAXZOOM) { dump += prefix + QString(QLatin1String("if (testPassed) testPassed = (%1 >= %2);\n")) .arg(dumpResolvedValue(resolvedRuleValue, MapStyleValueDataType::Integer)) .arg(valueDef->name); } else if (valueDefId == builtinValueDefs->id_INPUT_ADDITIONAL) { dump += prefix + QString(QLatin1String("if (testPassed and inputMapObject) testPassed = (inputMapObject contains %1);\n")) .arg(dumpResolvedValue(resolvedRuleValue, MapStyleValueDataType::String)); } else if (valueDefId == builtinValueDefs->id_INPUT_TEST) { dump += prefix + QString(QLatin1String("if (testPassed) testPassed = (%1 == 1);\n")) .arg(valueDef->name); } else if (valueDef->dataType == MapStyleValueDataType::Float) { dump += prefix + QString(QLatin1String("if (testPassed) testPassed = (%1 == %2);\n")) .arg(dumpResolvedValue(resolvedRuleValue, MapStyleValueDataType::Float)) .arg(valueDef->name); } else if (valueDef->dataType == MapStyleValueDataType::Integer) { dump += prefix + QString(QLatin1String("if (testPassed) testPassed = (%1 == %2);\n")) .arg(dumpResolvedValue(resolvedRuleValue, MapStyleValueDataType::Integer)) .arg(valueDef->name); } else if (valueDef->dataType == MapStyleValueDataType::Boolean) { dump += prefix + QString(QLatin1String("if (testPassed) testPassed = (%1 == %2);\n")) .arg(dumpResolvedValue(resolvedRuleValue, MapStyleValueDataType::Boolean)) .arg(valueDef->name); } else if (valueDef->dataType == MapStyleValueDataType::String) { dump += prefix + QString(QLatin1String("if (testPassed) testPassed = (%1 == %2);\n")) .arg(dumpResolvedValue(resolvedRuleValue, MapStyleValueDataType::String)) .arg(valueDef->name); } else { dump += prefix + QString(QLatin1String("// Unknown condition with '%1'\n")) .arg(valueDef->name); } } if (rejectSupported) dump += prefix + QLatin1String("if (not testPassed) reject;\n"); else dump += prefix + QLatin1String("if (not testPassed) exit;\n"); dump += prefix + QLatin1String("\n"); } if (hasDisable) { if (rejectSupported) dump += prefix + QLatin1String("if (disable) reject;\n"); else dump += prefix + QLatin1String("if (disable) exit;\n"); dump += prefix + QLatin1String("\n"); } if (!ruleNode->isSwitch) dump += dumpRuleNodeOutputValues(ruleNode, prefix, true); if (!ruleNode->oneOfConditionalSubnodes.isEmpty()) { dump += prefix + QLatin1String("local atLeastOneConditionalMatched = false;\n"); for (const auto& oneOfConditionalSubnode : constOf(ruleNode->oneOfConditionalSubnodes)) { dump += prefix + QLatin1String("if (not atLeastOneConditionalMatched):\n"); dump += dumpRuleNode(oneOfConditionalSubnode, false, prefix + QLatin1String("\t")); dump += prefix + QLatin1String("\tatLeastOneConditionalMatched = true;\n"); } if (ruleNode->isSwitch) { if (rejectSupported) dump += prefix + QLatin1String("if (not atLeastOneConditionalMatched) reject;\n"); else dump += prefix + QLatin1String("if (not atLeastOneConditionalMatched) exit;\n"); } dump += prefix + QLatin1String("\n"); } if (ruleNode->isSwitch) dump += dumpRuleNodeOutputValues(ruleNode, prefix, false); if (!ruleNode->applySubnodes.isEmpty()) { for (const auto& applySubnode : constOf(ruleNode->applySubnodes)) { dump += prefix + QLatin1String("apply:\n"); dump += dumpRuleNode(applySubnode, false, prefix + QLatin1String("\t")); } dump += prefix + QLatin1String("\n"); } return dump; }