/* XmlUtil.cpp * * Copyright (C) 2013-2016 Jaye Evins * * This file is part of gLabels-qt. * * gLabels-qt 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. * * gLabels-qt 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 gLabels-qt. If not, see . */ #include "XmlUtil.h" #include #include #include namespace glabels { namespace model { // // Static data // XmlUtil* XmlUtil::mInstance = nullptr; XmlUtil::XmlUtil() { mUnits = Units(Units::PT); } void XmlUtil::init() { if ( mInstance == nullptr ) { mInstance = new XmlUtil(); } } Units XmlUtil::units() { init(); return mInstance->mUnits; } void XmlUtil::setUnits( const Units& units ) { init(); mInstance->mUnits = units; } QString XmlUtil::getStringAttr( const QDomElement& node, const QString& name, const QString& default_value ) { init(); return node.attribute( name, default_value ); } double XmlUtil::getDoubleAttr( const QDomElement& node, const QString& name, double default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { bool ok; double value = valueString.toDouble( &ok ); if ( !ok ) { qWarning() << "Error: bad double value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } return value; } return default_value; } bool XmlUtil::getBoolAttr( const QDomElement& node, const QString& name, bool default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { bool ok; int intValue = valueString.toInt( &ok ); if ( (valueString == "True") || (valueString == "TRUE") || (valueString == "true") || (ok && (intValue == 1) ) ) { return true; } if ( (valueString == "False") || (valueString == "FALSE") || (valueString == "false") || (ok && (intValue == 0) ) ) { return false; } qWarning() << "Error: bad boolean value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } return default_value; } int XmlUtil::getIntAttr( const QDomElement& node, const QString& name, int default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { bool ok; int value = valueString.toInt( &ok ); if ( !ok ) { qWarning() << "Error: bad integer value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } return value; } return default_value; } uint32_t XmlUtil::getUIntAttr( const QDomElement& node, const QString& name, uint32_t default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { bool ok; uint32_t value = valueString.toUInt( &ok, 0 ); if ( !ok ) { qWarning() << "Error: bad unsigned integer value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } return value; } return default_value; } QString XmlUtil::getI18nAttr( const QDomElement& node, const QString& name, const QString& default_value ) { init(); QString i18nString = node.attribute( QString("_").append(name), "" ); if ( i18nString == "" ) { return node.attribute( name, default_value ); } return QCoreApplication::translate( "XmlStrings", i18nString.toUtf8().constData() ); } Distance XmlUtil::getLengthAttr( const QDomElement& node, const QString& name, const Distance& default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { double value; QString unitsString; QTextStream valueStream( &valueString, QIODevice::ReadOnly ); valueStream >> value >> unitsString; if ( !unitsString.isEmpty() && !Units::isIdValid( unitsString ) ) { qWarning() << "Error: bad length value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } return Distance( value, unitsString ); } return default_value; } QFont::Weight XmlUtil::getWeightAttr( const QDomElement& node, const QString& name, QFont::Weight default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { if ( valueString == "bold" ) { return QFont::Bold; } else if ( valueString == "normal" ) { return QFont::Normal; } else { qWarning() << "Error: bad weight value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } } return default_value; } Qt::Alignment XmlUtil::getAlignmentAttr( const QDomElement& node, const QString& name, Qt::Alignment default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { if ( valueString == "right" ) { return Qt::AlignRight; } else if ( valueString == "hcenter" ) { return Qt::AlignHCenter; } else if ( valueString == "left" ) { return Qt::AlignLeft; } else if ( valueString == "bottom" ) { return Qt::AlignBottom; } else if ( valueString == "vcenter" ) { return Qt::AlignVCenter; } else if ( valueString == "top" ) { return Qt::AlignTop; } else { qWarning() << "Error: bad alignment value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } } return default_value; } QTextOption::WrapMode XmlUtil::getWrapModeAttr( const QDomElement& node, const QString& name, QTextOption::WrapMode default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { if ( valueString == "word" ) { return QTextOption::WordWrap; } else if ( valueString == "anywhere" ) { return QTextOption::WrapAnywhere; } else if ( valueString == "none" ) { return QTextOption::NoWrap; } else { qWarning() << "Error: bad wrap mode value in attribute " << node.tagName() << ":" << name << "=" << valueString; return default_value; } } return default_value; } Units XmlUtil::getUnitsAttr( const QDomElement& node, const QString& name, const Units& default_value ) { init(); QString valueString = node.attribute( name, "" ); if ( valueString != "" ) { return Units( valueString ); } return default_value; } QPainterPath XmlUtil::getPathDataAttr( const QDomElement& node, const QString& name, const Units& units ) { init(); QPainterPath d; // // Simple path data parser // QStringList tokens = node.attribute( name, "" ).split( " ", QString::SkipEmptyParts ); enum { CMD, MX, MY, MDX, MDY, LX, LY, LDX, LDY, HX, HDX, VY, VDY } state = CMD; Distance x = 0; Distance y = 0; Distance dx = 0; Distance dy = 0; QPointF c; for ( int i = 0; i < tokens.size(); i++ ) { switch (state) { case CMD: switch (tokens[i][0].unicode()) { case 'M': state = MX; break; case 'm': state = MDX; break; case 'L': state = LX; break; case 'l': state = LDX; break; case 'H': state = HX; break; case 'h': state = HDX; break; case 'V': state = VY; break; case 'v': state = VDY; break; case 'Z': case 'z': d.closeSubpath(); state = CMD; break; } break; case MX: x = Distance( tokens[i].toDouble(), units ); state = MY; break; case MY: y = Distance( tokens[i].toDouble(), units ); d.moveTo( x.pt(), y.pt() ); state = CMD; break; case MDX: dx = Distance( tokens[i].toDouble(), units ); state = MDY; break; case MDY: dy = Distance( tokens[i].toDouble(), units ); c = d.currentPosition(); d.moveTo( c.x()+x.pt(), c.y()+y.pt() ); state = CMD; break; case LX: x = Distance( tokens[i].toDouble(), units ); state = LY; break; case LY: y = Distance( tokens[i].toDouble(), units ); d.lineTo( x.pt(), y.pt() ); state = CMD; break; case LDX: dx = Distance( tokens[i].toDouble(), units ); state = LDY; break; case LDY: dy = Distance( tokens[i].toDouble(), units ); c = d.currentPosition(); d.lineTo( c.x()+dx.pt(), c.y()+dy.pt() ); state = CMD; break; case HX: x = Distance( tokens[i].toDouble(), units ); c = d.currentPosition(); d.lineTo( x.pt(), c.y() ); state = CMD; break; case HDX: dx = Distance( tokens[i].toDouble(), units ); c = d.currentPosition(); d.lineTo( c.x()+dx.pt(), c.y() ); state = CMD; break; case VY: y = Distance( tokens[i].toDouble(), units ); c = d.currentPosition(); d.lineTo( c.x(), y.pt() ); state = CMD; break; case VDY: dy = Distance( tokens[i].toDouble(), units ); c = d.currentPosition(); d.lineTo( c.x(), c.y()+dy.pt() ); state = CMD; break; } } return d; } void XmlUtil::setStringAttr( QDomElement& node, const QString& name, const QString& value ) { init(); node.setAttribute( name, value ); } void XmlUtil::setDoubleAttr( QDomElement& node, const QString& name, double value ) { init(); node.setAttribute( name, QString::number(value) ); } void XmlUtil::setBoolAttr( QDomElement& node, const QString& name, bool value ) { init(); node.setAttribute( name, value ? "true" : "false" ); } void XmlUtil::setIntAttr( QDomElement& node, const QString& name, int value ) { init(); node.setAttribute( name, QString::number(value) ); } void XmlUtil::setUIntAttr( QDomElement& node, const QString& name, uint32_t value ) { init(); node.setAttribute( name, "0x" + QString::number(value, 16) ); } void XmlUtil::setLengthAttr( QDomElement& node, const QString& name, const Distance& value ) { init(); Units units = mInstance->mUnits; node.setAttribute( name, QString::number(value.inUnits(units)) + units.toIdString() ); } void XmlUtil::setWeightAttr( QDomElement& node, const QString& name, QFont::Weight value ) { switch (value) { case QFont::Bold: node.setAttribute( name, "bold" ); break; default: node.setAttribute( name, "normal" ); break; } } void XmlUtil::setAlignmentAttr( QDomElement& node, const QString& name, Qt::Alignment value ) { switch (value) { case Qt::AlignRight: node.setAttribute( name, "right" ); break; case Qt::AlignHCenter: node.setAttribute( name, "hcenter" ); break; case Qt::AlignLeft: node.setAttribute( name, "left" ); break; case Qt::AlignBottom: node.setAttribute( name, "bottom" ); break; case Qt::AlignVCenter: node.setAttribute( name, "vcenter" ); break; case Qt::AlignTop: node.setAttribute( name, "top" ); break; default: node.setAttribute( name, "left" ); break; } } void XmlUtil::setWrapModeAttr( QDomElement& node, const QString& name, QTextOption::WrapMode value ) { switch (value) { case QTextOption::WordWrap: node.setAttribute( name, "word" ); break; case QTextOption::WrapAnywhere: node.setAttribute( name, "anywhere" ); break; case QTextOption::NoWrap: case QTextOption::ManualWrap: node.setAttribute( name, "none" ); break; default: node.setAttribute( name, "word" ); break; } } void XmlUtil::setUnitsAttr( QDomElement& node, const QString& name, const Units& value ) { node.setAttribute( name, value.toIdString() ); } void XmlUtil::setPathDataAttr( QDomElement& node, const QString& name, const QPainterPath& path, const Units& units ) { QString pathString; for ( int i = 0; i < path.elementCount(); i++ ) { auto element = path.elementAt( i ); // QPainterPath is natively in pts Distance x = Distance::pt( element.x ); Distance y = Distance::pt( element.y ); // Translate desired units for path data double xValue = x.inUnits( units ); double yValue = y.inUnits( units ); if ( element.isMoveTo() ) { pathString.append( QString( "M %1 %2" ).arg( xValue ).arg( yValue ) ); } else if ( element.isLineTo() ) { pathString.append( QString( "L %1 %2" ).arg( xValue ).arg( yValue ) ); } if ( i < (path.elementCount() - 1) ) { pathString.append( " " ); } } node.setAttribute( name, pathString ); } } }