moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kig / objects / object_factory.cc
blob8cdd653aee86f47c798f75e6f4dbe1b1476fe370
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_factory.h"
20 #include "bogus_imp.h"
21 #include "curve_imp.h"
22 #include "intersection_types.h"
23 #include "line_imp.h"
24 #include "object_drawer.h"
25 #include "object_holder.h"
26 #include "other_type.h"
27 #include "point_imp.h"
28 #include "point_type.h"
29 #include "text_type.h"
31 #include "../kig/kig_document.h"
32 #include "../kig/kig_view.h"
33 #include "../misc/calcpaths.h"
34 #include "../misc/coordinate.h"
35 #include "../misc/object_hierarchy.h"
37 #include <algorithm>
38 #include <functional>
40 ObjectHolder* ObjectFactory::fixedPoint( const Coordinate& c ) const
42 ObjectHolder* o = new ObjectHolder( fixedPointCalcer( c ) );
43 return o;
46 ObjectTypeCalcer* ObjectFactory::fixedPointCalcer( const Coordinate& c ) const
48 std::vector<ObjectCalcer*> args;
49 args.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
50 args.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
51 ObjectTypeCalcer* oc = new ObjectTypeCalcer( FixedPointType::instance(), args );
52 return oc;
55 ObjectTypeCalcer* ObjectFactory::cursorPointCalcer( const Coordinate& c ) const
57 std::vector<ObjectCalcer*> args;
58 args.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
59 args.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
60 ObjectTypeCalcer* oc = new ObjectTypeCalcer( CursorPointType::instance(), args );
61 return oc;
64 const ObjectFactory* ObjectFactory::instance()
66 static ObjectFactory f;
67 return &f;
70 ObjectTypeCalcer* ObjectFactory::sensiblePointCalcer(
71 const Coordinate& c, const KigDocument& d, const KigWidget& w ) const
73 std::vector<ObjectHolder*> os = d.whatAmIOn( c, w );
74 if ( os.size() == 2 )
76 // we can calc intersection point *olny* between two objects...
77 std::vector<ObjectCalcer*> args;
78 args.push_back( os[0]->calcer() );
79 args.push_back( os[1]->calcer() );
80 // the simpliest case: two lines...
81 if ( ( os[0]->imp()->inherits( AbstractLineImp::stype() ) ) &&
82 ( os[1]->imp()->inherits( AbstractLineImp::stype() ) ) )
83 return new ObjectTypeCalcer( LineLineIntersectionType::instance(), args );
84 // other cases will follow...
86 for ( std::vector<ObjectHolder*>::iterator i = os.begin(); i != os.end(); ++i )
87 if ( (*i)->imp()->inherits( CurveImp::stype() ) )
88 return constrainedPointCalcer( (*i)->calcer(), c, d );
89 return fixedPointCalcer( c );
92 ObjectHolder* ObjectFactory::sensiblePoint(
93 const Coordinate& c, const KigDocument& d, const KigWidget& w ) const
95 return new ObjectHolder( sensiblePointCalcer( c, d, w ) );
98 ObjectTypeCalcer* ObjectFactory::relativePointCalcer(
99 ObjectCalcer* o, const Coordinate& loc ) const
101 Coordinate reference =
102 static_cast<const ObjectImp*>( o->imp() )->attachPoint();
103 assert( reference.valid() );
105 double x = 0.0;
106 double y = 0.0;
107 if ( loc.valid() )
109 x = loc.x - reference.x;
110 y = loc.y - reference.y;
112 std::vector<ObjectCalcer*> parents;
113 parents.push_back( new ObjectConstCalcer( new DoubleImp( x ) ) );
114 parents.push_back( new ObjectConstCalcer( new DoubleImp( y ) ) );
115 parents.push_back( o );
116 return new ObjectTypeCalcer( RelativePointType::instance(), parents );
119 ObjectTypeCalcer* ObjectFactory::constrainedPointCalcer(
120 ObjectCalcer* curve, double param ) const
122 assert( curve->imp()->inherits( CurveImp::stype() ) );
123 std::vector<ObjectCalcer*> parents;
124 parents.push_back( new ObjectConstCalcer( new DoubleImp( param ) ) );
125 parents.push_back( curve );
126 return new ObjectTypeCalcer( ConstrainedPointType::instance(), parents );
129 ObjectHolder* ObjectFactory::constrainedPoint(
130 ObjectCalcer* curve, double param ) const
132 return new ObjectHolder( constrainedPointCalcer( curve, param ) );
135 ObjectTypeCalcer* ObjectFactory::constrainedPointCalcer(
136 ObjectCalcer* curve, const Coordinate& c, const KigDocument& d ) const
138 assert( curve->imp()->inherits( CurveImp::stype() ) );
139 double param = static_cast<const CurveImp*>( curve->imp() )->getParam( c, d );
140 return constrainedPointCalcer( curve, param );
143 ObjectHolder* ObjectFactory::constrainedPoint(
144 ObjectCalcer* curve, const Coordinate& c, const KigDocument& d ) const
146 return new ObjectHolder( constrainedPointCalcer( curve, c, d ) );
149 ObjectTypeCalcer* ObjectFactory::locusCalcer(
150 ObjectCalcer* a, ObjectCalcer* b ) const
152 assert( dynamic_cast<const ObjectTypeCalcer*>( a ) );
153 ObjectTypeCalcer* constrained = static_cast<ObjectTypeCalcer*>( a );
154 assert( constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) );
155 assert( constrained->parents().size() == 2 );
156 ObjectCalcer* curve = a->parents().back();
158 const ObjectCalcer* moving = b;
160 std::vector<ObjectCalcer*> hierparents;
161 hierparents.push_back( constrained );
162 std::vector<ObjectCalcer*> sideOfTree = sideOfTreePath( hierparents, moving );
163 std::copy( sideOfTree.begin(), sideOfTree.end(), std::back_inserter( hierparents ) );
165 ObjectHierarchy hier( hierparents, moving );
167 std::vector<ObjectCalcer*> realparents( 2 + sideOfTree.size(), 0 );
168 realparents[0] = new ObjectConstCalcer( new HierarchyImp( hier ) );
169 realparents[1] = curve;
170 copy( sideOfTree.begin(), sideOfTree.end(), realparents.begin() + 2 );
172 return new ObjectTypeCalcer( LocusType::instance(), realparents );
175 ObjectHolder* ObjectFactory::locus( ObjectCalcer* a, ObjectCalcer* b ) const
177 return new ObjectHolder( locusCalcer( a, b ) );
180 ObjectHolder* ObjectFactory::label(
181 const QString& s, const Coordinate& loc,
182 bool needframe, const std::vector<ObjectCalcer*>& parents,
183 const KigDocument& doc ) const
185 return new ObjectHolder( labelCalcer( s, loc, needframe, parents, doc ) );
188 ObjectTypeCalcer* ObjectFactory::labelCalcer(
189 const QString& s, const Coordinate& loc,
190 bool needframe, const std::vector<ObjectCalcer*>& parents,
191 const KigDocument& doc ) const
193 return attachedLabelCalcer( s, 0, loc, needframe, parents, doc );
196 ObjectTypeCalcer* ObjectFactory::attachedLabelCalcer(
197 const QString& s, ObjectCalcer* p,
198 const Coordinate& loc, bool needframe,
199 const std::vector<ObjectCalcer*>& nparents,
200 const KigDocument& doc ) const
202 std::vector<ObjectCalcer*> parents;
203 parents.reserve( nparents.size() + 3 );
204 parents.push_back( new ObjectConstCalcer( new IntImp( needframe ? 1 : 0 ) ) );
207 * mp: (changes to add relative-attachment). Now an object is tested
208 * as follows:
209 * - if attachPoint() returns a valid coordinate, then we use the new method
210 * - if it is a point: 'old-style' treatment (we can change this shortly)
211 * - if it is a curve: 'old-style' treatment (we could use the new approach,
212 * which can be better/worse depending on personal taste, I think)
214 * the first condition that matches determines the behaviour.
215 * the new method works similarly to the curve case, but we generate a new
216 * RelativePointType instead of a ConstrainedPointType; this will in turn make use
217 * of the new attachPoint() method for objects.
219 * changed the preference order 2005/01/21 (now attachPoint has preference over points)
221 * NOTE: changes in the tests performed should be matched also in
222 * modes/popup.cc (addNameLabel) and in label.cc (TextLabelModeBase::mouseMoved)
225 if ( p && p->imp()->attachPoint().valid() )
227 ObjectCalcer* o = relativePointCalcer( p, loc );
228 o->calc( doc );
229 parents.push_back( o );
231 else if ( p && p->imp()->inherits( PointImp::stype() ) )
233 parents.push_back( p );
235 else if ( p && p->imp()->inherits( CurveImp::stype() ) )
237 double param = 0.5;
238 if ( loc.valid() )
239 param = static_cast<const CurveImp*>( p->imp() )->getParam( loc, doc );
241 ObjectCalcer* o = constrainedPointCalcer( p, param );
242 o->calc( doc );
243 parents.push_back( o );
245 else
247 if ( loc.valid() )
248 parents.push_back( new ObjectConstCalcer( new PointImp( loc ) ) );
249 else
250 parents.push_back( new ObjectConstCalcer( new PointImp( Coordinate( 0, 0 ) ) ) );
253 parents.push_back( new ObjectConstCalcer( new StringImp( s ) ) );
254 std::copy( nparents.begin(), nparents.end(), std::back_inserter( parents ) );
255 ObjectTypeCalcer* ret = new ObjectTypeCalcer( TextType::instance(), parents );
256 ret->calc( doc );
257 return ret;
260 ObjectHolder* ObjectFactory::attachedLabel(
261 const QString& s, ObjectCalcer* locationparent,
262 const Coordinate& loc, bool needframe,
263 const std::vector<ObjectCalcer*>& parents,
264 const KigDocument& doc ) const
266 return new ObjectHolder( attachedLabelCalcer( s, locationparent, loc, needframe, parents, doc ) );
269 ObjectPropertyCalcer* ObjectFactory::propertyObjectCalcer(
270 ObjectCalcer* o, const char* p ) const
272 int wp = o->imp()->propertiesInternalNames().findIndex( p );
273 if ( wp == -1 ) return 0;
274 return new ObjectPropertyCalcer( o, wp );
277 ObjectHolder* ObjectFactory::propertyObject(
278 ObjectCalcer* o, const char* p ) const
280 return new ObjectHolder( propertyObjectCalcer( o, p ) );
283 void ObjectFactory::redefinePoint(
284 ObjectTypeCalcer* point, const Coordinate& c,
285 KigDocument& doc, const KigWidget& w ) const
287 std::vector<ObjectHolder*> hos = doc.whatAmIOn( c, w );
288 std::vector<ObjectCalcer*> os;
289 ObjectCalcer* (ObjectHolder::*calcmeth)() = &ObjectHolder::calcer;
290 std::transform( hos.begin(), hos.end(), std::back_inserter( os ),
291 std::mem_fun( calcmeth ) );
292 ObjectCalcer* v = 0;
294 // we don't want one of our children as a parent...
295 std::set<ObjectCalcer*> children = getAllChildren( point );
296 for ( std::vector<ObjectCalcer*>::iterator i = os.begin();
297 i != os.end(); ++i )
298 if ( (*i)->imp()->inherits( CurveImp::stype() ) &&
299 children.find( *i ) == children.end() )
301 v = *i;
302 break;
305 if ( v )
307 // we want a constrained point...
308 const CurveImp* curveimp = static_cast<const CurveImp*>( v->imp() );
309 double newparam = curveimp->getParam( c, doc );
311 if ( point->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
313 // point already was constrained -> simply update the param
314 // DataObject and make sure point is on the right curve...
315 ObjectCalcer* dataobj = 0;
316 std::vector<ObjectCalcer*> parents = point->parents();
317 assert( parents.size() == 2 );
318 assert ( parents[0]->imp()->inherits( DoubleImp::stype() ) );
319 dataobj = parents[0];
321 parents.clear();
322 parents.push_back( dataobj );
323 parents.push_back( v );
324 point->setParents( parents );
326 assert( dynamic_cast<ObjectConstCalcer*>( dataobj ) );
327 static_cast<ObjectConstCalcer*>( dataobj )->setImp(
328 new DoubleImp( newparam ) );
330 else
332 // point used to be fixed -> add a new DataObject etc.
333 std::vector<ObjectCalcer*> args;
334 args.push_back( new ObjectConstCalcer( new DoubleImp( newparam ) ) );
335 args.push_back( v );
336 point->setType( ConstrainedPointType::instance() );
337 point->setParents( args );
340 else
342 // a fixed point...
343 if ( point->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
345 // point used to be constrained..
346 std::vector<ObjectCalcer*> a;
347 a.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
348 a.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
350 point->setType( FixedPointType::instance() );
351 point->setParents( a );
353 else
355 // point used to be fixed -> simply update the DataObject's
356 // we can use the point's move function for that..
357 point->move( c, doc );