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