1 // SPDX-FileCopyrightText: 2002 Dominique Devriese <devriese@kde.org> 2 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 #ifndef KIG_OBJECTS_OBJECT_IMP_H 6 #define KIG_OBJECTS_OBJECT_IMP_H 7 8 #include "common.h" 9 10 class IntImp; 11 class DoubleImp; 12 class StringImp; 13 class InvalidImp; 14 class HierarchyImp; 15 class TransformationImp; 16 class TestResultImp; 17 class LineImp; 18 class PointImp; 19 class TextImp; 20 class AngleImp; 21 class VectorImp; 22 class LocusImp; 23 class CircleImp; 24 class ConicImp; 25 class CubicImp; 26 class SegmentImp; 27 class RayImp; 28 class ArcImp; 29 class FilledPolygonImp; 30 class ClosedPolygonalImp; 31 class OpenPolygonalImp; 32 class BezierImp; 33 class RationalBezierImp; 34 35 /** 36 * \internal This is some OO magic commonly referred to as "double 37 * dispatch". If you need to do some action on an ObjectImp, and you 38 * need to do something different dependent on the type of o, then 39 * make a Visitor class that inherits this interface, and implements 40 * the appropriate functions properly, and call "o->visit( my_visitor 41 * );". 42 */ 43 class ObjectImpVisitor 44 { 45 public: 46 virtual ~ObjectImpVisitor(); 47 void visit( const ObjectImp* imp ); 48 virtual void visit( const IntImp* imp ); 49 virtual void visit( const DoubleImp* imp ); 50 virtual void visit( const StringImp* imp ); 51 virtual void visit( const InvalidImp* imp ); 52 virtual void visit( const HierarchyImp* imp ); 53 virtual void visit( const TransformationImp* imp ); 54 virtual void visit( const TestResultImp* imp ); 55 virtual void visit( const LineImp* imp ); 56 virtual void visit( const PointImp* imp ); 57 virtual void visit( const TextImp* imp ); 58 virtual void visit( const AngleImp* imp ); 59 virtual void visit( const VectorImp* imp ); 60 virtual void visit( const LocusImp* imp ); 61 virtual void visit( const CircleImp* imp ); 62 virtual void visit( const ConicImp* imp ); 63 virtual void visit( const CubicImp* imp ); 64 virtual void visit( const SegmentImp* imp ); 65 virtual void visit( const RayImp* imp ); 66 virtual void visit( const ArcImp* imp ); 67 virtual void visit( const FilledPolygonImp* imp ); 68 virtual void visit( const ClosedPolygonalImp* imp ); 69 virtual void visit( const OpenPolygonalImp* imp ); 70 virtual void visit( const BezierImp* imp ); 71 virtual void visit( const RationalBezierImp* imp ); 72 }; 73 74 typedef unsigned int uint; 75 76 /** 77 * Instances of this class represent a certain ObjectImp type. Every 78 * ObjectImp type has a static ObjectImpType member, that it returns a 79 * reference to in its type() function. Think of it as a nice enum, 80 * that you can also get some data from. 81 */ 82 class ObjectImpType 83 { 84 const ObjectImpType* mparent; 85 const char* minternalname; 86 const char* mtranslatedname; 87 const char* mselectstatement; 88 const char* mselectnamestatement; 89 const char* mremoveastatement; 90 const char* maddastatement; 91 const char* mmoveastatement; 92 const char* mattachtothisstatement; 93 const char* mshowastatement; 94 const char* mhideastatement; 95 class StaticPrivate; 96 static StaticPrivate* sd(); 97 public: 98 /** 99 * Returns the type with name n. 100 * 101 * \internal Do *not* call this from functions that can be called at 102 * static initializer time ! It depends on information that is only 103 * available after that stage and will crash if used too early. 104 */ 105 static const ObjectImpType* typeFromInternalName( const char* n ); 106 107 /** 108 * \internal Construct an ObjectImpType, with a lot of data about 109 * your ObjectImp type. 110 * 111 * @param parent is the ObjectImpType of 112 * your parent ObjectImp type. Never give 0 as parent, except for 113 * the top ObjectImp ObjectImpType. 114 * @param internalname is an internal name 115 * @param translatedname is a translatable string like "segment" 116 * @param selectstatement is a translatable string like "Select this segment" 117 * @param selectnamestatement is a translatable string like "Select segment %1" 118 * @param removeastatement is a translatable string like "Remove a Segment" 119 * @param addastatement is a translatable string like "Add a Segment" 120 * @param moveastatement is a translatable string like "Move a Segment" 121 * @param attachtothisstatement is a translatable string like "Attach to 122 * this segment" 123 * @param showastatement is a translatable string like "Show a Segment" 124 * @param hideastatement is a translatable string like "Hide a Segment" 125 * 126 * All translatable strings should have 127 * I18N_NOOP around them! 128 */ 129 explicit ObjectImpType( 130 const ObjectImpType* parent, const char* internalname, 131 const char* translatedname, 132 const char* selectstatement, 133 const char* selectnamestatement, 134 const char* removeastatement, 135 const char* addastatement, 136 const char* moveastatement, 137 const char* attachtothisstatement, 138 const char* showastatement, 139 const char* hideastatement ); 140 virtual ~ObjectImpType(); 141 142 /** 143 * Does the ObjectImp type represented by this instance inherit the 144 * ObjectImp type represented by t ? 145 */ 146 bool inherits( const ObjectImpType* t ) const; 147 virtual bool match( const ObjectImpType* t ) const; 148 149 /** 150 * Returns an internal name for this ObjectImp type. This name is 151 * guaranteed unique, and mostly corresponds with the class name of 152 * the corresponding ObjectImp. 153 */ 154 const char* internalName() const; 155 /** 156 * The name of this type, translated to the currently used language. 157 */ 158 QString translatedName() const; 159 /** 160 * Returns a translatable string of the form "Select this %1". 161 * E.g. "Select this segment". Note that users of this function 162 * should use i18n on the returned string before using it. 163 */ 164 const char* selectStatement() const; 165 166 /** 167 * Returns a translatable string of the form "Select point %1". %1 168 * will be filled in by whomever calls this function with the name 169 * of the object in question. This function should be used as 170 * follows: i18n( x->selectNameStatement() ).arg( xname ). 171 */ 172 const char* selectNameStatement() const; 173 174 /** 175 * Returns a translated string of the form "Remove a xxx". 176 * E.g. "Remove a Segment". 177 */ 178 QString removeAStatement() const; 179 /** 180 * Returns a translated string of the form "Add a xxx". 181 * E.g. "Add a Segment". 182 */ 183 QString addAStatement() const; 184 /** 185 * Returns a translated string of the form "Move a xxx". 186 * E.g. "Move a Segment". 187 */ 188 QString moveAStatement() const; 189 /** 190 * Returns a translated string of the form "Attach to this xxx". 191 * E.g. "Attach to this segment". 192 * \internal This is used by the text label construction mode 193 */ 194 QString attachToThisStatement() const; 195 196 /** 197 * Returns a translated string of the form "Show a xxx". 198 * E.g. "Show a Segment". 199 */ 200 QString showAStatement() const; 201 202 /** 203 * Returns a translated string of the form "Hide a xxx". 204 * E.g. "Hide a Segment". 205 */ 206 QString hideAStatement() const; 207 }; 208 209 /** 210 * The ObjectImp class represents the behaviour of an object after it 211 * is calculated. This means how to draw() it, whether it claims to 212 * contain a certain point etc. It is also the class where the 213 * ObjectType's get their information from. 214 */ 215 class ObjectImp 216 { 217 protected: 218 ObjectImp(); 219 public: 220 /** 221 * The ObjectImpType representing the base ObjectImp class. All 222 * other ObjectImp's inherit from this type. 223 */ 224 static const ObjectImpType* stype(); 225 226 /** 227 * mp: The following three methods (getPropLid, getPropGid, getPropName) 228 * deal with the properties of ObjectImp(s). 229 * the properties architecture (vectors of properties associated to 230 * each Imp) didn't work at all in situation when a node in the object 231 * hierarchy of which a properties is used changes it's Imp dynamically. 232 * An example of this is a python script that constructs a "hyperbolic 233 * segment" in the half-plane model of hyperbolic geometry, that results 234 * in a circular arc or a segment depending on the relative position of 235 * the two end-points. 236 * A workaround for this problem is to maintain two numberings for a 237 * property: the "local" id (Lid) is the index in the property vector 238 * associated to an ObjectImp, it makes only sense relatively to a 239 * specific ObjectImp; the "global" id (Gid) is a global numbering 240 * generated runtime and distinguishing properties only based on their 241 * internal name. 242 * A property node must only use the global numbering, so that when the 243 * parent changes it's Imp, the correct property (if it exists) of the 244 * new Imp will be used. 245 * the association of Gid to properties is constructed runtime whenever 246 * a new property is first used by populating a static vector 247 * (see object_imp.cc). 248 * The conversion Gid->Lid requires a vector search, so that a caching 249 * mechanism has been set up in the ObjectPropertyCalcer that stores the 250 * Lid and recalculates it when the typeid of the ObjectImp of the parent 251 * changes. 252 * 253 * getPropLid: returns the local numbering corresponding to a Gid 254 * getPropGid: returns the Gid of a property given its internal name 255 * getPropName: returns the internal name of a property given its Gid 256 * 257 * Note: in object_hierarchy.cc the class "FetchPropertyNode" is quite 258 * similar to "ObjectPropertyCalcer", and thus is similarly restructured. 259 * However the caching mechanism has not been setup in this case. 260 * It seems that "FetchPropertyNode" is only used for the "drawprelim" 261 * in constructions that involve a macro that in turn involves a property, 262 * so perhaps the caching is not that important. 263 */ 264 int getPropLid( int propgid ) const; 265 int getPropGid( const char *pname ) const; 266 const char* getPropName( int propgid ) const; 267 268 virtual ~ObjectImp(); 269 270 /** 271 * Returns true if this ObjectImp inherits the ObjectImp type 272 * represented by t. 273 * E.g. you can check whether an ObjectImp is a LineImp by doing: 274 * \if creating-python-scripting-doc 275 * \code 276 * if object.inherits( LineImp.stype() ): 277 * \endcode 278 * \else 279 * \code 280 * if( object.inherits( LineImp::stype() ) 281 * \endcode 282 * \endif 283 */ 284 bool inherits( const ObjectImpType* t ) const; 285 286 /** 287 * Returns a reference point where to attach labels; when this 288 * returns an invalidCoord then the attachment is either not 289 * done at all, or done in a specific way (like for curves, 290 * or for points) The treatment of points could also take 291 * advantage of this attachment mechanism. 292 * 293 * If this method returns a valid Coordinate, then this is 294 * interpreted as a pivot point for the label, which can still 295 * be moved relative to that point, but follows the object when 296 * the object changes. 297 * In practice a new RelativePointType is created (position of 298 * the string), this type in turn depends on the object (to get 299 * its attachPoint) and two DoubleImp that are interpreted as 300 * relative displacement (x and y) 301 */ 302 virtual Coordinate attachPoint( ) const = 0; 303 304 /** 305 * Return this ObjectImp, transformed by the transformation t. 306 */ 307 virtual ObjectImp* transform( const Transformation& t ) const = 0; 308 309 virtual void draw( KigPainter& p ) const = 0; 310 virtual bool contains( const Coordinate& p, int width, 311 const KigWidget& si ) const = 0; 312 virtual bool inRect( const Rect& r, int width, 313 const KigWidget& si ) const = 0; 314 virtual Rect surroundingRect() const = 0; 315 316 /** 317 * Returns true if this is a valid ObjectImp. 318 * If you want to return an invalid ObjectImp, you should return an 319 * InvalidImp instance. 320 */ 321 bool valid() const; 322 323 virtual int numberOfProperties() const; 324 // the names of the properties as perceived by the user.. put 325 // I18N_NOOP's around them here.. 326 virtual const QByteArrayList properties() const; 327 // the names of the properties as known only by kig internally. No 328 // need for I18N_NOOP. Preferably choose some lowercase name with 329 // only letters and dashes, no spaces.. 330 virtual const QByteArrayList propertiesInternalNames() const; 331 virtual ObjectImp* property( int which, const KigDocument& d ) const; 332 // Sometimes we need to know which type an imp needs to be at least 333 // in order to have the imp with number which. Macro's need it 334 // foremost. This function answers that question.. 335 virtual const ObjectImpType* impRequirementForProperty( int which ) const; 336 // Return whether the property with number which is by construction 337 // always a point on this curve ( if this is a curve ), or always a 338 // curve through this point ( if this is a curve ). 339 virtual bool isPropertyDefinedOnOrThroughThisImp( int which ) const; 340 // What icon should be shown when talking about this property ? 341 virtual const char* iconForProperty( int which ) const; 342 343 /** 344 * Returns the lowermost ObjectImpType that this object is an 345 * instantiation of. 346 * E.g. if you want to get a string containing the internal name of 347 * the type of an object, you can do: 348 * \if creating-python-scripting-doc 349 * \code 350 * tn = object.type().internalName() 351 * \endcode 352 * \else 353 * \code 354 * std::string typename = object.type()->internalName(); 355 * \endcode 356 * \endif 357 */ 358 virtual const ObjectImpType* type() const = 0; 359 virtual void visit( ObjectImpVisitor* vtor ) const = 0; 360 361 /** 362 * Returns a copy of this ObjectImp. 363 * The copy is an exact copy. Changes to the copy don't affect the 364 * original. 365 */ 366 virtual ObjectImp* copy() const = 0; 367 368 // s is a string with at least one escape ( "%N" where N is a 369 // number ) somewhere. This function replaces the first escape it 370 // sees with the "value" of this imp ( using the QString::arg 371 // functions ). This is e.g. used by TextType to turn its variable 372 // args into strings.. 373 // if you implement this, then you should return true in 374 // canFillInEscape() ( standard implementation returns false ), and 375 // override fillInNextEscape() ( standard implementation does an 376 // assert( false ) ).. 377 virtual bool canFillInNextEscape() const; 378 virtual void fillInNextEscape( QString& s, const KigDocument& ) const; 379 380 /** 381 * Returns true if this ObjectImp is equal to rhs. 382 * This function checks whether rhs is of the same ObjectImp type, 383 * and whether it contains the same data as this ObjectImp. 384 * \internal It is used e.g. by the KigCommand stuff to see what the 385 * user has changed during a move. 386 */ 387 virtual bool equals( const ObjectImp& rhs ) const = 0; 388 389 /** 390 * \internal Return true if this imp is just a cache imp. This 391 * means that it will never be considered to be stored in a file or 392 * in an ObjectHierarchy. This is useful for objects which cannot 393 * (easily and usefully) be (de)serialized, like e.g. 394 * PythonCompiledScriptImp. For normal objects, the default 395 * implementation returns false, which is fine. 396 */ 397 virtual bool isCache() const; 398 }; 399 #endif 400