summaryrefslogtreecommitdiffstats
path: root/kig/objects/object_calcer.h
blob: 6df94fe8d71ecdab932d54fddf672482bef1a786 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
// Copyright (C)  2003  Dominique Devriese <[email protected]>

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301, USA.

#ifndef KIG_OBJECTS_OBJECT_CALCER_H
#define KIG_OBJECTS_OBJECT_CALCER_H

#include "common.h"
#include "../misc/boost_intrusive_pointer.hpp"

class ObjectCalcer;

void intrusive_ptr_add_ref( ObjectCalcer* p );
void intrusive_ptr_release( ObjectCalcer* p );

/**
 * An ObjectCalcer is an object that represents an algorithm for
 * calculating an ObjectImp from other ObjectImp's.  It is also a node
 * in the dependency graph of a certain document. E.g. a LineImp can
 * be calculated from the two PointImp's it has to go through; every
 * time either of them moves, this calculation is redone.  In this
 * case, there would be an ObjectCalcer that keeps a reference to its
 * two parents ( the ObjectCalcer's representing the points ), and
 * that will calculate its ObjectImp value every time it is asked to
 * do so ( i.e. every time one of its parents moves.. ).
 *
 * Each ObjectHolder keeps its ObjectImp itself, and recalculates it
 * from its parents in its calc() method ( if necessary ).
 *
 * Because of the complex relations that ObjectCalcer's hold to other
 * ObjectCalcer's and to other classes, they have been made
 * reference-counted.  This means that they keep a count internally of
 * how much times a pointer to them is held.  If this count reaches 0,
 * this means that nobody needs them anymore, and they delete
 * themselves.  E.g. an ObjectCalcer always keeps a reference to its
 * parents, to ensure that those aren't deleted before it is deleted.
 *
 * At runtime, there will be an entire graph of ObjectCalcer that
 * depend on their parents..  At the bottom, there are Calcer's that
 * the user is aware of, and that are held by ObjectHolder's.  At the
 * top, there are Calcer's without parents that serve only to hold
 * some data.  Those are most likely ObjectConstCalcer's.  There are
 * some algorithms to work with the dependency graph in various ways
 * in ../misc/calcpath.h
 *
 * ObjectCalcer's also decide how an object should be allowed to
 * move.  If the user selects a point, and tries to move it, then its
 * ObjectCalcer will be asked whether it can move, and if so, will be
 * asked to move.  See below with the canMove(), move() and
 * moveReferencePoint() methods..
 */
class ObjectCalcer
{
protected:
  /**
   * ObjectCalcer's are reference counted..  They all take a reference
   * to their parents, and some other classes like ObjectHolder take a
   * reference to some ObjectCalcer's that they don't want to see
   * deleted..
   */
  friend void intrusive_ptr_add_ref( ObjectCalcer* p );
  friend void intrusive_ptr_release( ObjectCalcer* p );
  int refcount;
  void ref();
  void deref();

  // we keep track of our children, so algorithms can easily walk over
  // the dependency graph..

  std::vector<ObjectCalcer*> mchildren;

  ObjectCalcer();
public:
  /**
   * a calcer should call this to register itself as a child of this
   * calcer.  This automatically takes a reference.
   */
  void addChild( ObjectCalcer* c );
  /**
   * a calcer should call this in its destructor, to inform its parent
   * that it is no longer a child of this calcer.  This will release
   * the reference taken in addChild..
   */
  void delChild( ObjectCalcer* c );

  // use this pointer type to keep a reference to an ObjectCalcer...
  typedef myboost::intrusive_ptr<ObjectCalcer> shared_ptr;

  /**
   * Returns the child ObjectCalcer's of this ObjectCalcer.
   */
 std::vector<ObjectCalcer*> children() const;

  virtual ~ObjectCalcer();
  /**
   * Returns the parent ObjectCalcer's of this ObjectCalcer.
   */
  virtual std::vector<ObjectCalcer*> parents() const = 0;
  /**
   * Returns the ObjectImp of this ObjectCalcer.
   */
  virtual const ObjectImp* imp() const = 0;
  /**
   * Makes the ObjectCalcer recalculate its ObjectImp from its
   * parents.
   */
  virtual void calc( const KigDocument& ) = 0;

  /**
   * An ObjectCalcer expects its parents to have an ObjectImp of a
   * certain type.  This method returns the ObjectImpType that \p o
   * should have. \p os is a list of all the parents in order, and
   * \p o is part of it. This method will return the ObjectImpType
   * that the parent should *at least* be.  For example, a Translated
   * object can translate any sort of object, so it will return
   * ObjectImp::stype() here ( the topmost ObjectImpType, that all
   * other ObjectImpType's inherit ).
   */
  virtual const ObjectImpType* impRequirement(
    ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const = 0;

  /**
   * Returns whether this ObjectCalcer supports moving.
   */
  virtual bool canMove() const;
  /**
   * Returns whether this ObjectCalcer can be translated at any position
   * in the coordinate plane.  Note that a ConstrainedPointType can be
   * moved, but cannot be moved everywhere.
   */
  virtual bool isFreelyTranslatable() const;
  /**
   * Moving an object most of the time signifies invoking changes in
   * some of its parents.  This method returns the set of parents that
   * will be changed in the move() method.  The object itself should
   * not be included.
   */
  virtual std::vector<ObjectCalcer*> movableParents() const;
  /**
   * In order to support simultaneously moving objects that are in
   * different locations, we need for each object a location that it
   * is assumed to be at, at the moment the moving starts.  This
   * method returns such a point.
   */
  virtual Coordinate moveReferencePoint() const;
  /**
   * This is the method that does the real moving work.  It will be
   * invoked to tell the object to move to the new location to.  After
   * this, the calc() method will be calced, so you only need to do
   * the real changes in this method, updating the ObjectImp should be
   * done in the calc() method, not here.
   */
  virtual void move( const Coordinate& to, const KigDocument& doc );

  /**
   * If this ObjectCalcer represents a curve, return true if the given
   * point is by construction on this curve.  If this ObjectCalcer
   * represents a point, return true if this point is by construction
   * on the given curve.
   */
  virtual bool isDefinedOnOrThrough( const ObjectCalcer* o ) const = 0;
};

/**
 * This is an ObjectCalcer that uses one of the various ObjectType's
 * to calculate its ObjectImp.  It basically forwards all of its
 * functionality to the ObjectType that it holds a pointer to.
 */
class ObjectTypeCalcer
  : public ObjectCalcer
{
  std::vector<ObjectCalcer*> mparents;
  const ObjectType* mtype;
  ObjectImp* mimp;
public:
  typedef myboost::intrusive_ptr<ObjectTypeCalcer> shared_ptr;
  /**
   * Construct a new ObjectTypeCalcer with a given type and parents.
   */
//  ObjectTypeCalcer( const ObjectType* type, const std::vector<ObjectCalcer*>& parents );
  /**
   * the sort boolean tells whether the sortArgs method should be invoked or not;
   * if not present
   */
  ObjectTypeCalcer( const ObjectType* type, const std::vector<ObjectCalcer*>& parents, bool sort=true );
  ~ObjectTypeCalcer();

  const ObjectImp* imp() const;
  std::vector<ObjectCalcer*> parents() const;
  void calc( const KigDocument& doc );

  /**
   * Set the parents of this ObjectTypeCalcer to np.  This object will
   * release the reference it had to its old parents, and take a new
   * one on the new parents.
   */
  void setParents( const std::vector<ObjectCalcer*> np );
  void setType( const ObjectType* t );

  const ObjectType* type() const;

  const ObjectImpType* impRequirement(
    ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
  bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
  bool canMove() const;
  bool isFreelyTranslatable() const;
  std::vector<ObjectCalcer*> movableParents() const;
  Coordinate moveReferencePoint() const;
  void move( const Coordinate& to, const KigDocument& doc );
};

/**
 * This is an ObjectCalcer that keeps an ObjectImp, and never
 * calculates a new one.  It is a trivial, but very useful
 * ObjectCalcer.  It is used often in Kig, for holding data to be used
 * by other ObjectCalcer's.
 */
class ObjectConstCalcer
  : public ObjectCalcer
{
  ObjectImp* mimp;
public:
  typedef myboost::intrusive_ptr<ObjectConstCalcer> shared_ptr;

  /**
   * Construct a new ObjectConstCalcer with the given imp as the
   * stored ObjectImp.
   *
   * This class takes ownership of the imp you pass it, it should have
   * been constructed using new, and this class is responsible for
   * deleting it.
   */
  ObjectConstCalcer( ObjectImp* imp );
  ~ObjectConstCalcer();

  const ObjectImp* imp() const;
  void calc( const KigDocument& doc );
  std::vector<ObjectCalcer*> parents() const;

  /**
   * Set the ObjectImp of this ObjectConstCalcer to the given
   * newimp. The old one will be deleted.
   */
  void setImp( ObjectImp* newimp );
  /**
   * Set the ObjectImp of this ObjectConstCalcer to the given
   * newimp. The old one will not be deleted, but returned.
   */
  ObjectImp* switchImp( ObjectImp* newimp );

  const ObjectImpType* impRequirement(
    ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
  bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
};

/**
 * This is an ObjectCalcer that has a single parent, and gets a
 * certain property from it in its calc() method.
 *
 * \see ObjectImp::property
 */
class ObjectPropertyCalcer
  : public ObjectCalcer
{
  ObjectImp* mimp;
  ObjectCalcer* mparent;
  int mpropid;
public:
  /**
   * Construct a new ObjectPropertyCalcer, that will get the property
   * from parent with number propid.
   */
  ObjectPropertyCalcer( ObjectCalcer* parent, int propid );
  ~ObjectPropertyCalcer();

  const ObjectImp* imp() const;
  std::vector<ObjectCalcer*> parents() const;
  void calc( const KigDocument& doc );

  int propId() const;
  ObjectCalcer* parent() const;

  const ObjectImpType* impRequirement(
    ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
  bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
};

#endif