moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kig / objects / object_imp_factory.cc
blob50d83b62ac55c929a15bdf700e604af5fe7d4da0
1 // Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16 // 02111-1307, USA.
18 #include "object_imp_factory.h"
20 #include "object_imp.h"
21 #include "bogus_imp.h"
22 #include "circle_imp.h"
23 #include "conic_imp.h"
24 #include "cubic_imp.h"
25 #include "line_imp.h"
26 #include "locus_imp.h"
27 #include "other_imp.h"
28 #include "point_imp.h"
29 #include "text_imp.h"
31 #include "../misc/coordinate.h"
33 #include <qdom.h>
35 #include <klocale.h>
37 const ObjectImpFactory* ObjectImpFactory::instance()
39 static const ObjectImpFactory t;
40 return &t;
43 ObjectImpFactory::ObjectImpFactory()
47 ObjectImpFactory::~ObjectImpFactory()
51 static void addXYElements( const Coordinate& c, QDomElement& parent, QDomDocument& doc )
53 QDomElement xe = doc.createElement( "x" );
54 xe.appendChild(
55 doc.createTextNode(
56 QString::number( c.x ) ) );
57 parent.appendChild( xe );
58 QDomElement ye = doc.createElement( "y" );
59 ye.appendChild(
60 doc.createTextNode(
61 QString::number( c.y ) ) );
62 parent.appendChild( ye );
65 static void addDoubleElement( const char* name, double d, QDomElement& parent, QDomDocument& doc )
67 QDomElement e = doc.createElement( name );
68 e.appendChild( doc.createTextNode( QString::number( d ) ) );
69 parent.appendChild( e );
72 static void addCoordinateElement( const char* name, const Coordinate& d, QDomElement& p, QDomDocument& doc )
74 QDomElement e = doc.createElement( name );
75 addXYElements( d, e, doc );
76 p.appendChild( e );
79 QString ObjectImpFactory::serialize( const ObjectImp& d, QDomElement& parent,
80 QDomDocument& doc ) const
82 if( d.inherits( IntImp::stype() ) )
84 parent.appendChild(
85 doc.createTextNode(
86 QString::number( static_cast<const IntImp&>( d ).data() ) ) );
87 return QString::fromLatin1( "int" );
89 else if ( d.inherits( DoubleImp::stype() ) )
91 parent.appendChild(
92 doc.createTextNode(
93 QString::number( static_cast<const DoubleImp&>( d ).data() ) ) );
94 return QString::fromLatin1( "double" );
96 else if( d.inherits( StringImp::stype() ) )
98 parent.appendChild(
99 doc.createTextNode(
100 static_cast<const StringImp&>( d ).data() ) );
101 return QString::fromLatin1( "string" );
103 else if ( d.inherits( TestResultImp::stype() ) )
105 parent.appendChild(
106 doc.createTextNode(
107 static_cast<const TestResultImp&>( d ).data() ) );
108 return QString::fromLatin1( "testresult" );
110 else if( d.inherits( HierarchyImp::stype() ) )
112 static_cast<const HierarchyImp&>( d ).data().serialize( parent, doc );
113 return QString::fromLatin1( "hierarchy" );
115 else if ( d.inherits( TransformationImp::stype() ) )
117 const Transformation& trans = static_cast<const TransformationImp&>( d ).data();
119 QDomElement matrixe = doc.createElement( "matrix" );
120 for ( int i = 0; i < 3; ++i )
122 for ( int j = 0; j < 3; ++j )
124 QDomElement elel = doc.createElement( "element" );
125 elel.setAttribute( "row", QString::number( i ) );
126 elel.setAttribute( "column", QString::number( j ) );
127 elel.appendChild( doc.createTextNode( QString::number( trans.data( i, j ) ) ) );
128 matrixe.appendChild( elel );
131 parent.appendChild( matrixe );
133 QDomElement homothetye = doc.createElement( "homothetic" );
134 const char* ishomothety = trans.isHomothetic() ? "true" : "false";
135 homothetye.appendChild( doc.createTextNode( ishomothety ) );
136 parent.appendChild( homothetye );
138 return QString::fromLatin1( "transformation" );
140 else if( d.inherits( AbstractLineImp::stype() ) )
142 LineData l = static_cast<const AbstractLineImp&>( d ).data();
143 addCoordinateElement( "a", l.a, parent, doc );
144 addCoordinateElement( "b", l.b, parent, doc );
145 if( d.inherits( SegmentImp::stype() ) )
146 return QString::fromLatin1( "segment" );
147 else if( d.inherits( RayImp::stype() ) )
148 return QString::fromLatin1( "ray" );
149 else return QString::fromLatin1( "line" );
151 else if( d.inherits( PointImp::stype() ) )
153 addXYElements( static_cast<const PointImp&>( d ).coordinate(),
154 parent, doc );
155 return QString::fromLatin1( "point" );
157 else if( d.inherits( TextImp::stype() ) )
159 QString text = static_cast<const TextImp&>( d ).text();
160 parent.appendChild(
161 doc.createTextNode( text ) );
162 return QString::fromLatin1( "text" );
164 else if( d.inherits( AngleImp::stype() ) )
166 addDoubleElement( "size", static_cast<const AngleImp&>( d ).size(), parent, doc );
167 return QString::fromLatin1( "angle" );
169 else if ( d.inherits( ArcImp::stype() ) )
171 const ArcImp& a = static_cast<const ArcImp&>( d );
172 addCoordinateElement( "center", a.center(), parent, doc );
173 addDoubleElement( "radius", a.radius(), parent, doc );
174 addDoubleElement( "startangle", a.startAngle(), parent, doc );
175 addDoubleElement( "angle", a.angle(), parent, doc );
176 return QString::fromLatin1( "arc" );
178 else if( d.inherits( VectorImp::stype() ) )
180 Coordinate dir = static_cast<const VectorImp&>( d ).dir();
181 addXYElements( dir, parent, doc );
182 return QString::fromLatin1( "vector" );
184 else if( d.inherits( LocusImp::stype() ) )
186 const LocusImp& locus = static_cast<const LocusImp&>( d );
188 // serialize the curve..
189 QDomElement curve = doc.createElement( "curve" );
190 const CurveImp& curveimp = *locus.curve();
191 QString type = serialize( curveimp, curve, doc );
192 curve.setAttribute( "type", type );
193 parent.appendChild( curve );
195 // serialize the hierarchy..
196 QDomElement hier = doc.createElement( "calculation" );
197 locus.hierarchy().serialize( hier, doc );
198 parent.appendChild( hier );
200 return QString::fromLatin1( "locus" );
202 else if( d.inherits( CircleImp::stype() ) )
204 const CircleImp& c = static_cast<const CircleImp&>( d );
205 addCoordinateElement( "center", c.center(), parent, doc );
206 addDoubleElement( "radius", c.radius(), parent, doc );
207 return QString::fromLatin1( "circle" );
209 else if( d.inherits( ConicImp::stype() ) )
211 const ConicPolarData data = static_cast<const ConicImp&>( d ).polarData();
212 addCoordinateElement( "focus1", data.focus1, parent, doc );
213 addDoubleElement( "pdimen", data.pdimen, parent, doc );
214 addDoubleElement( "ecostheta0", data.ecostheta0, parent, doc );
215 addDoubleElement( "esintheta0", data.esintheta0, parent, doc );
216 return QString::fromLatin1( "conic" );
218 else if( d.inherits( CubicImp::stype() ) )
220 const CubicCartesianData data = static_cast<const CubicImp&>( d ).data();
221 QDomElement coeffs = doc.createElement( "coefficients" );
222 addDoubleElement( "a000", data.coeffs[0], coeffs, doc );
223 addDoubleElement( "a001", data.coeffs[1], coeffs, doc );
224 addDoubleElement( "a002", data.coeffs[2], coeffs, doc );
225 addDoubleElement( "a011", data.coeffs[3], coeffs, doc );
226 addDoubleElement( "a012", data.coeffs[4], coeffs, doc );
227 addDoubleElement( "a022", data.coeffs[5], coeffs, doc );
228 addDoubleElement( "a111", data.coeffs[6], coeffs, doc );
229 addDoubleElement( "a112", data.coeffs[7], coeffs, doc );
230 addDoubleElement( "a122", data.coeffs[8], coeffs, doc );
231 addDoubleElement( "a222", data.coeffs[9], coeffs, doc );
232 parent.appendChild( coeffs );
233 return QString::fromLatin1( "cubic" );
235 assert( false );
236 return QString::null;
239 static Coordinate readXYElements( const QDomElement& e, bool& ok )
241 double x, y;
242 ok = true;
243 QDomElement xe = e.firstChild().toElement();
244 if ( xe.isNull() || xe.tagName() != "x" )
246 ok = false;
247 return Coordinate();
249 else x = xe.text().toDouble( &ok );
251 QDomElement ye = xe.nextSibling().toElement();
252 if ( ye.isNull() || ye.tagName() != "y" )
254 ok = false;
255 return Coordinate();
257 else y = ye.text().toDouble( &ok );
259 return Coordinate( x, y );
262 static Coordinate readCoordinateElement( QDomNode n, bool& ok,
263 const char* tagname )
265 QDomElement e = n.toElement();
266 if ( e.isNull() || e.tagName() != tagname )
268 ok = false;
269 Coordinate ret;
270 return ret;
272 return readXYElements( e, ok );
275 static double readDoubleElement( QDomNode n, bool& ok,
276 const char* tagname )
278 QDomElement e = n.toElement();
279 if ( e.isNull() || e.tagName() != tagname )
281 ok = false;
282 return 0.;
284 return e.text().toDouble( &ok );
287 ObjectImp* ObjectImpFactory::deserialize( const QString& type,
288 const QDomElement& parent,
289 QString& error ) const
291 #define KIG_GENERIC_PARSE_ERROR \
293 error = i18n( "An error was encountered at line %1 in file %2." ) \
294 .arg( __LINE__ ).arg( __FILE__ ); \
295 return 0; \
298 bool ok = true;
299 if ( type == "int" )
301 int ret = parent.text().toInt( &ok );
302 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
303 return new IntImp( ret );
305 else if ( type == "double" )
307 double ret = parent.text().toDouble( &ok );
308 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
309 return new DoubleImp( ret );
311 else if ( type == "string" )
313 return new StringImp( parent.text() );
315 else if ( type == "testresult" )
317 return new TestResultImp( parent.text() );
319 else if ( type == "hierarchy" )
321 ObjectHierarchy* hier = ObjectHierarchy::buildSafeObjectHierarchy( parent, error );
322 if ( ! hier ) return 0;
323 return new HierarchyImp( *hier );
325 else if ( type == "transformation" )
327 double data[3][3];
328 bool homothetic = false;
329 for ( QDomElement childe = parent.firstChild().toElement();
330 ! childe.isNull(); childe = childe.nextSibling().toElement() )
332 if ( childe.tagName() == "matrix" )
334 for ( QDomElement elel = childe.firstChild().toElement();
335 ! elel.isNull(); elel = elel.nextSibling().toElement() )
337 if ( elel.tagName() != "element" ) KIG_GENERIC_PARSE_ERROR;
338 bool ok = true;
339 int row = elel.attribute( "row" ).toInt( &ok );
340 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
341 int column = elel.attribute( "column" ).toInt( &ok );
342 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
343 data[row][column] = elel.text().toDouble( &ok );
344 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
347 else if ( childe.tagName() == "homothetic" )
349 homothetic = childe.text() == "true";
351 else continue;
353 Transformation trans( data, homothetic );
354 return new TransformationImp( trans );
356 else if ( type == "point" )
358 Coordinate ret = readXYElements( parent, ok );
359 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
360 return new PointImp( ret );
362 else if ( type == "line" || type == "segment" || type == "ray" )
364 QDomNode n = parent.firstChild();
365 Coordinate a = readCoordinateElement( n, ok, "a" );
366 if ( !ok ) KIG_GENERIC_PARSE_ERROR;
367 n = n.nextSibling();
368 Coordinate b = readCoordinateElement( n, ok, "b" );
369 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
370 if ( type == "line" ) return new LineImp( a, b );
371 else if ( type == "segment" ) return new SegmentImp( a, b );
372 else return new RayImp( a, b );
374 else if( type == "angle" )
376 double size = readDoubleElement( parent.firstChild(), ok, "size" );
377 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
378 return new AngleImp( Coordinate(), 0, size );
380 else if ( type == "arc" )
382 QDomNode n = parent.firstChild();
383 Coordinate center = readCoordinateElement( n, ok, "center" );
384 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
385 n = n.nextSibling();
386 double radius = readDoubleElement( n, ok, "radius" );
387 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
388 n = n.nextSibling();
389 double startangle = readDoubleElement( n, ok, "startangle" );
390 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
391 n = n.nextSibling();
392 double angle = readDoubleElement( n, ok, "angle" );
393 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
394 return new ArcImp( center, radius, startangle, angle );
396 else if( type == "vector" )
398 Coordinate dir = readXYElements( parent, ok );
399 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
400 return new VectorImp( Coordinate(), dir );
402 else if( type == "locus" )
404 QDomElement curvee = parent.firstChild().toElement();
405 if ( curvee.isNull() || curvee.tagName() != "curve" ) KIG_GENERIC_PARSE_ERROR;
406 QString type = curvee.attribute( "type" );
407 ObjectImp* oi = deserialize( type, curvee, error );
408 if ( ! oi || ! oi->inherits( CurveImp::stype() ) ) KIG_GENERIC_PARSE_ERROR;
409 //CurveImp* curvei = static_cast<CurveImp*>( oi );
411 QDomElement hiere = curvee.nextSibling().toElement();
412 if ( hiere.isNull() || hiere.tagName() != "calculation" ) KIG_GENERIC_PARSE_ERROR;
413 assert( false ); // TODO
414 // return new LocusImp( curvei, hier );
416 else if( type == "circle" )
418 QDomNode n = parent.firstChild();
419 Coordinate center = readCoordinateElement( n, ok, "center" );
420 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
422 n = n.nextSibling();
423 double radius = readDoubleElement( n, ok, "radius" );
424 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
426 return new CircleImp( center, radius );
428 else if( type == "conic" )
430 QDomNode n = parent.firstChild();
431 Coordinate focus1 = readCoordinateElement( n, ok, "focus1" );
432 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
434 n = n.nextSibling();
435 double pdimen = readDoubleElement( n, ok, "pdimen" );
436 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
438 n = n.nextSibling();
439 double ecostheta0 = readDoubleElement( n, ok, "ecostheta0" );
440 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
442 n = n.nextSibling();
443 double esintheta0 = readDoubleElement( n, ok, "esintheta0" );
444 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
446 return new ConicImpPolar(
447 ConicPolarData( focus1, pdimen, ecostheta0, esintheta0 ) );
449 else if( type == "cubic" )
451 QDomElement coeffse = parent.firstChild().toElement();
452 if ( coeffse.isNull() || coeffse.tagName() != "coefficients" )
453 KIG_GENERIC_PARSE_ERROR;
455 QDomNode n = coeffse.firstChild();
456 double a000 = readDoubleElement( n, ok, "a000" );
457 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
459 n = n.nextSibling();
460 double a001 = readDoubleElement( n, ok, "a001" );
461 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
463 n = n.nextSibling();
464 double a002 = readDoubleElement( n, ok, "a002" );
465 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
467 n = n.nextSibling();
468 double a011 = readDoubleElement( n, ok, "a011" );
469 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
471 n = n.nextSibling();
472 double a012 = readDoubleElement( n, ok, "a012" );
473 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
475 n = n.nextSibling();
476 double a022 = readDoubleElement( n, ok, "a022" );
477 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
479 n = n.nextSibling();
480 double a111 = readDoubleElement( n, ok, "a111" );
481 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
483 n = n.nextSibling();
484 double a112 = readDoubleElement( n, ok, "a112" );
485 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
487 n = n.nextSibling();
488 double a122 = readDoubleElement( n, ok, "a112" );
489 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
491 n = n.nextSibling();
492 double a222 = readDoubleElement( n, ok, "a222" );
493 if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
495 return new CubicImp( CubicCartesianData( a000, a001, a002,
496 a011, a012, a022,
497 a111, a112, a122,
498 a222 ) );
501 error = i18n( "This Kig file uses an object of type \"%1\", "
502 "which this Kig version does not support."
503 "Perhaps you have compiled Kig without support "
504 "for this object type,"
505 "or perhaps you are using an older Kig version." ).arg( type );
506 return 0;