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
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"
26 #include "locus_imp.h"
27 #include "other_imp.h"
28 #include "point_imp.h"
31 #include "../misc/coordinate.h"
37 const ObjectImpFactory
* ObjectImpFactory::instance()
39 static const ObjectImpFactory t
;
43 ObjectImpFactory::ObjectImpFactory()
47 ObjectImpFactory::~ObjectImpFactory()
51 static void addXYElements( const Coordinate
& c
, QDomElement
& parent
, QDomDocument
& doc
)
53 QDomElement xe
= doc
.createElement( "x" );
56 QString::number( c
.x
) ) );
57 parent
.appendChild( xe
);
58 QDomElement ye
= doc
.createElement( "y" );
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
);
79 QString
ObjectImpFactory::serialize( const ObjectImp
& d
, QDomElement
& parent
,
80 QDomDocument
& doc
) const
82 if( d
.inherits( IntImp::stype() ) )
86 QString::number( static_cast<const IntImp
&>( d
).data() ) ) );
87 return QString::fromLatin1( "int" );
89 else if ( d
.inherits( DoubleImp::stype() ) )
93 QString::number( static_cast<const DoubleImp
&>( d
).data() ) ) );
94 return QString::fromLatin1( "double" );
96 else if( d
.inherits( StringImp::stype() ) )
100 static_cast<const StringImp
&>( d
).data() ) );
101 return QString::fromLatin1( "string" );
103 else if ( d
.inherits( TestResultImp::stype() ) )
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(),
155 return QString::fromLatin1( "point" );
157 else if( d
.inherits( TextImp::stype() ) )
159 QString text
= static_cast<const TextImp
&>( d
).text();
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" );
236 return QString::null
;
239 static Coordinate
readXYElements( const QDomElement
& e
, bool& ok
)
243 QDomElement xe
= e
.firstChild().toElement();
244 if ( xe
.isNull() || xe
.tagName() != "x" )
249 else x
= xe
.text().toDouble( &ok
);
251 QDomElement ye
= xe
.nextSibling().toElement();
252 if ( ye
.isNull() || ye
.tagName() != "y" )
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
)
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
)
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__ ); \
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" )
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
;
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";
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
;
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
;
386 double radius
= readDoubleElement( n
, ok
, "radius" );
387 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
389 double startangle
= readDoubleElement( n
, ok
, "startangle" );
390 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
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
;
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
;
435 double pdimen
= readDoubleElement( n
, ok
, "pdimen" );
436 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
439 double ecostheta0
= readDoubleElement( n
, ok
, "ecostheta0" );
440 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
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
;
460 double a001
= readDoubleElement( n
, ok
, "a001" );
461 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
464 double a002
= readDoubleElement( n
, ok
, "a002" );
465 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
468 double a011
= readDoubleElement( n
, ok
, "a011" );
469 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
472 double a012
= readDoubleElement( n
, ok
, "a012" );
473 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
476 double a022
= readDoubleElement( n
, ok
, "a022" );
477 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
480 double a111
= readDoubleElement( n
, ok
, "a111" );
481 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
484 double a112
= readDoubleElement( n
, ok
, "a112" );
485 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
488 double a122
= readDoubleElement( n
, ok
, "a112" );
489 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
492 double a222
= readDoubleElement( n
, ok
, "a222" );
493 if ( ! ok
) KIG_GENERIC_PARSE_ERROR
;
495 return new CubicImp( CubicCartesianData( a000
, a001
, a002
,
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
);