// Copyright (C) 2002 Dominique Devriese // 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 2 // 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, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. #include "object_imp_factory.h" #include "object_imp.h" #include "bogus_imp.h" #include "circle_imp.h" #include "conic_imp.h" #include "cubic_imp.h" #include "line_imp.h" #include "locus_imp.h" #include "other_imp.h" #include "point_imp.h" #include "text_imp.h" #include "../misc/coordinate.h" #include #include const ObjectImpFactory* ObjectImpFactory::instance() { static const ObjectImpFactory t; return &t; } ObjectImpFactory::ObjectImpFactory() { } ObjectImpFactory::~ObjectImpFactory() { } static void addXYElements( const Coordinate& c, TQDomElement& parent, TQDomDocument& doc ) { TQDomElement xe = doc.createElement( "x" ); xe.appendChild( doc.createTextNode( TQString::number( c.x ) ) ); parent.appendChild( xe ); TQDomElement ye = doc.createElement( "y" ); ye.appendChild( doc.createTextNode( TQString::number( c.y ) ) ); parent.appendChild( ye ); } static void addDoubleElement( const char* name, double d, TQDomElement& parent, TQDomDocument& doc ) { TQDomElement e = doc.createElement( name ); e.appendChild( doc.createTextNode( TQString::number( d ) ) ); parent.appendChild( e ); } static void addCoordinateElement( const char* name, const Coordinate& d, TQDomElement& p, TQDomDocument& doc ) { TQDomElement e = doc.createElement( name ); addXYElements( d, e, doc ); p.appendChild( e ); } TQString ObjectImpFactory::serialize( const ObjectImp& d, TQDomElement& parent, TQDomDocument& doc ) const { if( d.inherits( IntImp::stype() ) ) { parent.appendChild( doc.createTextNode( TQString::number( static_cast( d ).data() ) ) ); return TQString::fromLatin1( "int" ); } else if ( d.inherits( DoubleImp::stype() ) ) { parent.appendChild( doc.createTextNode( TQString::number( static_cast( d ).data() ) ) ); return TQString::fromLatin1( "double" ); } else if( d.inherits( StringImp::stype() ) ) { parent.appendChild( doc.createTextNode( static_cast( d ).data() ) ); return TQString::fromLatin1( "string" ); } else if ( d.inherits( TestResultImp::stype() ) ) { parent.appendChild( doc.createTextNode( static_cast( d ).data() ) ); return TQString::fromLatin1( "testresult" ); } else if( d.inherits( HierarchyImp::stype() ) ) { static_cast( d ).data().serialize( parent, doc ); return TQString::fromLatin1( "hierarchy" ); } else if ( d.inherits( TransformationImp::stype() ) ) { const Transformation& trans = static_cast( d ).data(); TQDomElement matrixe = doc.createElement( "matrix" ); for ( int i = 0; i < 3; ++i ) { for ( int j = 0; j < 3; ++j ) { TQDomElement elel = doc.createElement( "element" ); elel.setAttribute( "row", TQString::number( i ) ); elel.setAttribute( "column", TQString::number( j ) ); elel.appendChild( doc.createTextNode( TQString::number( trans.data( i, j ) ) ) ); matrixe.appendChild( elel ); }; } parent.appendChild( matrixe ); TQDomElement homothetye = doc.createElement( "homothetic" ); const char* ishomothety = trans.isHomothetic() ? "true" : "false"; homothetye.appendChild( doc.createTextNode( ishomothety ) ); parent.appendChild( homothetye ); return TQString::fromLatin1( "transformation" ); } else if( d.inherits( AbstractLineImp::stype() ) ) { LineData l = static_cast( d ).data(); addCoordinateElement( "a", l.a, parent, doc ); addCoordinateElement( "b", l.b, parent, doc ); if( d.inherits( SegmentImp::stype() ) ) return TQString::fromLatin1( "segment" ); else if( d.inherits( RayImp::stype() ) ) return TQString::fromLatin1( "ray" ); else return TQString::fromLatin1( "line" ); } else if( d.inherits( PointImp::stype() ) ) { addXYElements( static_cast( d ).coordinate(), parent, doc ); return TQString::fromLatin1( "point" ); } else if( d.inherits( TextImp::stype() ) ) { TQString text = static_cast( d ).text(); parent.appendChild( doc.createTextNode( text ) ); return TQString::fromLatin1( "text" ); } else if( d.inherits( AngleImp::stype() ) ) { addDoubleElement( "size", static_cast( d ).size(), parent, doc ); return TQString::fromLatin1( "angle" ); } else if ( d.inherits( ArcImp::stype() ) ) { const ArcImp& a = static_cast( d ); addCoordinateElement( "center", a.center(), parent, doc ); addDoubleElement( "radius", a.radius(), parent, doc ); addDoubleElement( "startangle", a.startAngle(), parent, doc ); addDoubleElement( "angle", a.angle(), parent, doc ); return TQString::fromLatin1( "arc" ); } else if( d.inherits( VectorImp::stype() ) ) { Coordinate dir = static_cast( d ).dir(); addXYElements( dir, parent, doc ); return TQString::fromLatin1( "vector" ); } else if( d.inherits( LocusImp::stype() ) ) { const LocusImp& locus = static_cast( d ); // serialize the curve.. TQDomElement curve = doc.createElement( "curve" ); const CurveImp& curveimp = *locus.curve(); TQString type = serialize( curveimp, curve, doc ); curve.setAttribute( "type", type ); parent.appendChild( curve ); // serialize the hierarchy.. TQDomElement hier = doc.createElement( "calculation" ); locus.hierarchy().serialize( hier, doc ); parent.appendChild( hier ); return TQString::fromLatin1( "locus" ); } else if( d.inherits( CircleImp::stype() ) ) { const CircleImp& c = static_cast( d ); addCoordinateElement( "center", c.center(), parent, doc ); addDoubleElement( "radius", c.radius(), parent, doc ); return TQString::fromLatin1( "circle" ); } else if( d.inherits( ConicImp::stype() ) ) { const ConicPolarData data = static_cast( d ).polarData(); addCoordinateElement( "focus1", data.focus1, parent, doc ); addDoubleElement( "pdimen", data.pdimen, parent, doc ); addDoubleElement( "ecostheta0", data.ecostheta0, parent, doc ); addDoubleElement( "esintheta0", data.esintheta0, parent, doc ); return TQString::fromLatin1( "conic" ); } else if( d.inherits( CubicImp::stype() ) ) { const CubicCartesianData data = static_cast( d ).data(); TQDomElement coeffs = doc.createElement( "coefficients" ); addDoubleElement( "a000", data.coeffs[0], coeffs, doc ); addDoubleElement( "a001", data.coeffs[1], coeffs, doc ); addDoubleElement( "a002", data.coeffs[2], coeffs, doc ); addDoubleElement( "a011", data.coeffs[3], coeffs, doc ); addDoubleElement( "a012", data.coeffs[4], coeffs, doc ); addDoubleElement( "a022", data.coeffs[5], coeffs, doc ); addDoubleElement( "a111", data.coeffs[6], coeffs, doc ); addDoubleElement( "a112", data.coeffs[7], coeffs, doc ); addDoubleElement( "a122", data.coeffs[8], coeffs, doc ); addDoubleElement( "a222", data.coeffs[9], coeffs, doc ); parent.appendChild( coeffs ); return TQString::fromLatin1( "cubic" ); } assert( false ); return TQString(); } static Coordinate readXYElements( const TQDomElement& e, bool& ok ) { double x, y; ok = true; TQDomElement xe = e.firstChild().toElement(); if ( xe.isNull() || xe.tagName() != "x" ) { ok = false; return Coordinate(); } else x = xe.text().toDouble( &ok ); TQDomElement ye = xe.nextSibling().toElement(); if ( ye.isNull() || ye.tagName() != "y" ) { ok = false; return Coordinate(); } else y = ye.text().toDouble( &ok ); return Coordinate( x, y ); } static Coordinate readCoordinateElement( TQDomNode n, bool& ok, const char* tagname ) { TQDomElement e = n.toElement(); if ( e.isNull() || e.tagName() != tagname ) { ok = false; Coordinate ret; return ret; } return readXYElements( e, ok ); } static double readDoubleElement( TQDomNode n, bool& ok, const char* tagname ) { TQDomElement e = n.toElement(); if ( e.isNull() || e.tagName() != tagname ) { ok = false; return 0.; }; return e.text().toDouble( &ok ); } ObjectImp* ObjectImpFactory::deserialize( const TQString& type, const TQDomElement& parent, TQString& error ) const { #define KIG_GENERIC_PARSE_ERROR \ { \ error = i18n( "An error was encountered at line %1 in file %2." ) \ .tqarg( __LINE__ ).tqarg( __FILE__ ); \ return 0; \ } bool ok = true; if ( type == "int" ) { int ret = parent.text().toInt( &ok ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new IntImp( ret ); } else if ( type == "double" ) { double ret = parent.text().toDouble( &ok ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new DoubleImp( ret ); } else if ( type == "string" ) { return new StringImp( parent.text() ); } else if ( type == "testresult" ) { return new TestResultImp( parent.text() ); } else if ( type == "hierarchy" ) { ObjectHierarchy* hier = ObjectHierarchy::buildSafeObjectHierarchy( parent, error ); if ( ! hier ) return 0; HierarchyImp* imp = new HierarchyImp( *hier ); delete hier; return imp; } else if ( type == "transformation" ) { double data[3][3]; bool homothetic = false; for ( TQDomElement childe = parent.firstChild().toElement(); ! childe.isNull(); childe = childe.nextSibling().toElement() ) { if ( childe.tagName() == "matrix" ) { for ( TQDomElement elel = childe.firstChild().toElement(); ! elel.isNull(); elel = elel.nextSibling().toElement() ) { if ( elel.tagName() != "element" ) KIG_GENERIC_PARSE_ERROR; bool ok = true; int row = elel.attribute( "row" ).toInt( &ok ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; int column = elel.attribute( "column" ).toInt( &ok ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; data[row][column] = elel.text().toDouble( &ok ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; }; } else if ( childe.tagName() == "homothetic" ) { homothetic = childe.text() == "true"; } else continue; }; Transformation trans( data, homothetic ); return new TransformationImp( trans ); } else if ( type == "point" ) { Coordinate ret = readXYElements( parent, ok ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new PointImp( ret ); } else if ( type == "line" || type == "segment" || type == "ray" ) { TQDomNode n = parent.firstChild(); Coordinate a = readCoordinateElement( n, ok, "a" ); if ( !ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); Coordinate b = readCoordinateElement( n, ok, "b" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; if ( type == "line" ) return new LineImp( a, b ); else if ( type == "segment" ) return new SegmentImp( a, b ); else return new RayImp( a, b ); } else if( type == "angle" ) { double size = readDoubleElement( parent.firstChild(), ok, "size" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new AngleImp( Coordinate(), 0, size ); } else if ( type == "arc" ) { TQDomNode n = parent.firstChild(); Coordinate center = readCoordinateElement( n, ok, "center" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double radius = readDoubleElement( n, ok, "radius" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double startangle = readDoubleElement( n, ok, "startangle" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double angle = readDoubleElement( n, ok, "angle" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new ArcImp( center, radius, startangle, angle ); } else if( type == "vector" ) { Coordinate dir = readXYElements( parent, ok ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new VectorImp( Coordinate(), dir ); } else if( type == "locus" ) { TQDomElement curvee = parent.firstChild().toElement(); if ( curvee.isNull() || curvee.tagName() != "curve" ) KIG_GENERIC_PARSE_ERROR; TQString type = curvee.attribute( "type" ); ObjectImp* oi = deserialize( type, curvee, error ); if ( ! oi || ! oi->inherits( CurveImp::stype() ) ) KIG_GENERIC_PARSE_ERROR; //CurveImp* curvei = static_cast( oi ); TQDomElement hiere = curvee.nextSibling().toElement(); if ( hiere.isNull() || hiere.tagName() != "calculation" ) KIG_GENERIC_PARSE_ERROR; assert( false ); // TODO // return new LocusImp( curvei, hier ); } else if( type == "circle" ) { TQDomNode n = parent.firstChild(); Coordinate center = readCoordinateElement( n, ok, "center" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double radius = readDoubleElement( n, ok, "radius" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new CircleImp( center, radius ); } else if( type == "conic" ) { TQDomNode n = parent.firstChild(); Coordinate focus1 = readCoordinateElement( n, ok, "focus1" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double pdimen = readDoubleElement( n, ok, "pdimen" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double ecostheta0 = readDoubleElement( n, ok, "ecostheta0" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double esintheta0 = readDoubleElement( n, ok, "esintheta0" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new ConicImpPolar( ConicPolarData( focus1, pdimen, ecostheta0, esintheta0 ) ); } else if( type == "cubic" ) { TQDomElement coeffse = parent.firstChild().toElement(); if ( coeffse.isNull() || coeffse.tagName() != "coefficients" ) KIG_GENERIC_PARSE_ERROR; TQDomNode n = coeffse.firstChild(); double a000 = readDoubleElement( n, ok, "a000" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a001 = readDoubleElement( n, ok, "a001" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a002 = readDoubleElement( n, ok, "a002" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a011 = readDoubleElement( n, ok, "a011" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a012 = readDoubleElement( n, ok, "a012" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a022 = readDoubleElement( n, ok, "a022" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a111 = readDoubleElement( n, ok, "a111" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a112 = readDoubleElement( n, ok, "a112" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a122 = readDoubleElement( n, ok, "a112" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; n = n.nextSibling(); double a222 = readDoubleElement( n, ok, "a222" ); if ( ! ok ) KIG_GENERIC_PARSE_ERROR; return new CubicImp( CubicCartesianData( a000, a001, a002, a011, a012, a022, a111, a112, a122, a222 ) ); } error = i18n( "This Kig file uses an object of type \"%1\", " "which this Kig version does not support." "Perhaps you have compiled Kig without support " "for this object type," "or perhaps you are using an older Kig version." ).tqarg( type ); return 0; }