-
Notifications
You must be signed in to change notification settings - Fork 8
/
ufobject.h
497 lines (473 loc) · 22.6 KB
/
ufobject.h
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
/*
* UFRaw - Unidentified Flying Raw converter for digital camera images
*
* ufobject.h - UFObject definitions.
* Copyright 2004-2016 by Udi Fuchs
*
* 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.
*/
#ifndef _UFOBJECT_H
#define _UFOBJECT_H
/***********************************\
* UFObject C/C++ common interface *
\***********************************/
/// Type definition for the name of a UFObject.
typedef const char *UFName;
/// UFObject is base class for both the C and C++ interfaces.
typedef struct UFObject UFObject;
/// Events that can be triggered and should be handled by the event handler.
typedef enum {
uf_value_changed, ///< Value changed.
uf_default_changed, ///< Default value changed.
uf_element_added, ///< An UFObject was added to a UFGroup or a UFArray.
uf_user_data_set, ///< User data was set.
uf_destroyed ///< UFObject is being destroyed.
} UFEventType;
/// Function prototype for handling events.
typedef void (UFEventHandle)(UFObject *, UFEventType);
/**************************\
* UFObject C++ interface *
\**************************/
#ifdef __cplusplus
#include <string>
#include <list>
#include <stdexcept> // for std::runtime_error
/**
* UFObjects are smart data containers, which are suppose to know everything
* that is needed to handle and manipulated their content.
*
* UFObject is an abstract class. There are four UFObject implementations:
* - UFNumber - holds a number with a defined range and accuracy.
* - UFNumberArray - holds a fixed length array of numbers.
* - UFString - holds a string and possibly a list of tokens for this string.
* - UFGroup - holds a group of UFObjects.
* - UFIndex - holds an indexed group of UFObjects.
*
* There are downcasting definitions from all these implementations down
* to UFObject. These are needed because each UFObject type has different
* methods. Downcasting eases the access to these methods. An
* std::bad_cast exception will be thrown if invalid downcasting is attempted.
*
* Each UFObject has a UFName. This name identifies the object and should be
* unique. It is also used to access UFGroup members.
*
* The C++ interface of UFObject throws an exception is case of failure.
* Therefore, there is no error indication in the return-value of any of
* the methods. Most exceptions indicated programming errors and can be avoided.
* Only in the case of UFObject::Set(const char *string), a UFException could
* result from a user input error.
*
* \anchor C-interface
* The C interface of UFObject is shielded from all exception. Failure will
* be indicated in the return-value of the calling function and result in a
* call to UFObject::Message() that sends an error to the console by default.
* In the case of ufobject_set_string(), UFObject::Message() is not called,
* since it is assumes that the exception resulted from user input error.
*
* \exception UFException is the common exception thrown in case of errors.
* \exception std::bad_cast is thrown when the downcasting operators fail.
*/
class UFObject
{
public:
/// Trigger a #uf_destroyed event and destroy the object. An object that
/// has a Parent() should never be destroyed directly. It will be
/// destroyed when its parent is destroyed.
virtual ~UFObject();
UFName Name() const; ///< Retrieve the name of the UFObject.
/// Set pointer to general user data.
/// A #uf_user_data_set event is triggered.
void SetUserData(void *userData);
void *UserData(); ///< Retrieve pointer to general user data.
/// Downcast UFObject to UFNumber.
operator class UFNumber&();
/// Downcast const UFObject to const UFNumber.
operator const class UFNumber&() const;
/// Downcast UFObject to UFNumberArray.
operator class UFNumberArray&();
/// Downcast const UFObject to const UFNumberArray.
operator const class UFNumberArray&() const;
/// Downcast UFObject to UFString.
operator class UFString&();
/// Downcast const UFObject to const UFString.
operator const class UFString&() const;
/// Downcast UFObject to UFGroup.
operator class UFGroup&();
/// Downcast const UFObject to const UFGroup.
operator const class UFGroup&() const;
/// Downcast UFObject to UFArray.
operator class UFArray&();
/// Downcast const UFObject to const UFArray.
operator const class UFArray&() const;
bool HasParent() const; ///< Return true if object belongs to a UFGroup.
/// Return the UFGroup the object belongs too.
/// A std::logic_error will be thrown if the objects belongs to no group.
/// \exception UFException is thrown if the object has no parent.
/// This exception can be avoided with the use of HasParent().
UFGroup &Parent() const;
/// Translate object to a string. UFObject takes care of the memory
/// allocation and freeing of the string.
virtual const char *StringValue() const;
/// Create an XML block for the object.
/// If the object value is its default, create and empty XML block.
/// \param indent - Controls the XML block indentations.
virtual std::string XML(const char *indent = "") const;
/// Send an informational message in case of an error or warning.
/// This method is used internally in the implementation of UFObject.
/// Override this method to implement your own message handling.
/// The default handling is to send the message to the parent object.
/// If no patent exists, send the message to stderr.
/// \param format - a printf-like string format.
virtual void Message(const char *format, ...) const;
/// Throw a UFException. Use this method to throw exceptions from
/// within customized Event() methods.
/// \param format - a printf-like string format.
void Throw(const char *format, ...) const;
/// Set the value of the object to the value of the object parameter.
/// Objects must be of same type and must have the same name. If the
/// value changes, a #uf_value_changed event is triggered.
/// \exception UFException is thrown if the two objects do not
/// have the same Name(). This is probably a programming error.
virtual void Set(const UFObject &object) = 0;
/// Set the value of the object from the string value. This is the
/// reverse of the StringValue() method. If the value changes, an
/// #uf_value_changed event is triggered.
/// \exception UFException is thrown if the the string can not be
/// converted to the object type. This could result from a user input
/// error.
virtual void Set(const char *string) = 0;
/// Return true if object has its default value. For numerical objects,
/// the values has to the same up to the prescribed accuracy.
virtual bool IsDefault() const = 0;
/// Set the current object value to its default value.
/// A #uf_default_changed event is triggered.
virtual void SetDefault() = 0;
/// Reset the object value to its default value. If the value changes,
/// a #uf_value_changed event is triggered.
virtual void Reset() = 0;
/// Set a C-style event handler.
/// C++ events can be set by overriding the Event() virtual member.
void SetEventHandle(UFEventHandle *handle);
/// Handle any #UFEventType event. Override this method to implement your
/// own event handling. The default handling is to call the event handle
/// set by SetEventHandle() and in the case of #uf_value_changed, to call
/// also the parent's Event(). If you override this method, you probably
/// want to call UFObject::Event() from your own implementation of Event().
virtual void Event(UFEventType type);
/// Handle a #uf_value_changed event for the object that originated the
/// change. This method should be overridden if one wants to change
/// the values of other objects when the original object value has
/// changed. It is needed to prevent infinite loops where several
/// objects keep changing each other. The default method does not
/// do anything.
virtual void OriginalValueChangedEvent();
protected:
/// UFObject 's internal implementation is hidden here.
class _UFObject *const ufobject;
/// UFObject is an abstract class, therefore it cannot be constructed
/// directly.
explicit UFObject(_UFObject *object);
private:
UFObject(const UFObject &); // Disable the copy constructor.
UFObject &operator=(const UFObject &); // Disable the assignment operator.
};
/**
* UFNumber is a UFObject that holds a number which has an allowed range of
* values, a specified accuracy and default value.
*/
class UFNumber : public UFObject
{
public:
/// Construct a UFNumber whose initial value is set to its default value.
/// The number of accuracy digits effects the format of the StringValue()
/// of the number. The IsEqual() test is also controlled by
/// @a accuracyDigits. @a step and @a jump have no direct effect on the
/// object. They are useful for constructing a GtkAdjustment as in
/// ufnumber_hscale_new() and ufnumber_spin_button_new().
///
/// @a accuracyDigits, @a step and @a jump are
/// optional arguments, if they are not given they will be automatically
/// generated. @a accuracyDigits will be calculated from @a minimum,
/// @a maximum to given between 3 and 4 significant digits. @a step will
/// be set to 10 times the accuracy and @a jump to 10 times @a step.
UFNumber(UFName name, double minimum, double maximum, double defaultValue,
int accuracyDigits = -1, double step = 0.0, double jump = 0.0);
const char *StringValue() const;
/// Return the numerical value of the object. This @a double value can
/// have better accuracy than @a accuracyDigits. So, for example, after
/// an <tt>object.Set(1.0/3.0)</tt> command, the result of the condition
/// <tt>(obj.DoubleValue() == 1.0/3.0)</tt> should be true (but it is never
/// safe to rely on such behavior for floating-point numbers).
double DoubleValue() const;
void Set(const UFObject &object);
void Set(const char *string);
/// Set the value of the object to the given number. If the number is
/// outside of the allowed range, the number will be truncated and the
/// Message() method will be called to report this incident.
void Set(double number);
bool IsDefault() const;
void SetDefault();
void Reset();
/// Return true if object value is equal to @a number up to the prescribed
/// accuracy.
bool IsEqual(double number) const;
double Minimum() const;
double Maximum() const;
int AccuracyDigits() const;
double Step() const;
double Jump() const;
};
/**
* UFNumberArray is a UFObject that holds an fixed sized array of numbers.
*/
class UFNumberArray : public UFObject
{
public:
/// Construct a UFNumberArray with the given @a size. The initial value of
/// the array elements is set to its default value.
/// The number of accuracy digits effects the format of the StringValue()
/// of the number. The IsEqual() test is also controlled by
/// @a accuracyDigits. @a step and @a jump have no direct effect on the
/// object. They are useful for constructing a GtkAdjustment as in
/// ufnumber_array_hscale_new() and ufnumber_array_spin_button_new().
///
/// The object is create with one default value for all elements. Once
/// SetDefault() is called, each element can have a different default.
/// \sa @a accuracyDigits, @a step and @a jump are optional arguments,
/// their default values are discussed in UFNumber::UFNumber().
UFNumberArray(UFName name, int size, double minimum, double maximum,
double defaultValue, int accuracyDigits = 0xff, double step = 0.0,
double jump = 0.0);
const char *StringValue() const;
/// Return the numerical value of the @a index element of the object.
/// This @a double value can have better accuracy than @a accuracyDigits.
/// \sa UFNumber::StringValue() for more information.
/// \exception UFException is thrown if the index is negative or larger
/// than (Size()-1). This is probably a programming error.
double DoubleValue(int index) const;
void Set(const UFObject &object);
void Set(const char *string);
/// Set the value of the @a index element to the given number. If the
/// number is outside of the allowed range, the number will be truncated
/// and the Message() method will be called to report this incident.
/// \exception UFException is thrown if the index is negative or larger
/// than (Size()-1). This is probably a programming error.
void Set(int index, double number);
/// Set the values of all the array elements at once. This is useful if
/// one wants the #uf_value_changed event to be triggered only once.
/// @a array[] is assumed to be of the right Size().
void Set(const double array[]);
bool IsDefault() const;
void SetDefault();
void Reset();
/// Return true if the @a index element value is equal to @a number
/// up to the prescribed accuracy.
/// \exception UFException is thrown if the index is negative or larger
/// than (Size()-1). This is probably a programming error.
bool IsEqual(int index, double number) const;
int Size() const;
double Minimum() const;
double Maximum() const;
int AccuracyDigits() const;
double Step() const;
double Jump() const;
};
/**
* UFString is a UFObject that holds a character string.
*/
class UFString : public UFObject
{
public:
/// Construct a UFString whose initial value is set to its default value.
explicit UFString(UFName name, const char *defaultValue = "");
void Set(const UFObject &object);
void Set(const char *string);
bool IsDefault() const;
void SetDefault();
/// Set @a string as a default value.
/// A #uf_default_changed event is triggered.
void SetDefault(const char *string);
void Reset();
/// Return true if object value is equal to @a string.
bool IsEqual(const char *string) const;
};
/// A list of UFObjects returned by UFGroup or UFArray.
typedef std::list<UFObject *> UFGroupList;
/**
* UFGroup is a UFObject that contain a group of UFObject elements. This
* object is considered the Patent() of these elements.
*/
class UFGroup : public UFObject
{
public:
/// Construct an empty UFGroup, containing no objects.
/// The @a label is used to index the UFGroup inside a UFArray.
explicit UFGroup(UFName name, const char *label = "");
/// Destroy a UFGroup after destroying all the objects it contains.
~UFGroup();
std::string XML(const char *indent = "") const;
void Set(const UFObject &object);
void Set(const char *string);
bool IsDefault() const;
void SetDefault();
void Reset();
/// Return true if the UFGroup contains an object called @a name.
bool Has(UFName name) const;
/// Access a UFObject element in a UFGroup.
/// \exception UFException is thrown if an element with the given name
/// does not exist. This can be avoided with the use of the Has() method.
UFObject &operator[](UFName name);
/// Access a constant UFObject element in a constant UFGroup.
/// \exception UFException is thrown if an element with the given name
/// does not exist. This can be avoided with the use of the Has() method.
const UFObject &operator[](UFName name) const;
/// Return a list of all UFObjects in the group.
const UFGroupList List() const;
/// Add (append) a UFObject to a UFGroup. If the object belonged to
/// another group before, it will be detached from the original group.
/// \exception UFException is thrown if UFGroup already contains
/// an object with the same name. This can be avoided with the use of the
/// Has() method.
virtual UFGroup &operator<<(UFObject *object);
/// Drop an object from the group. The dropped object is returned.
/// If it is not needed any more it should be deleted to free its memory.
/// \exception UFException is thrown if an element with the given name
/// does not exist. This can be avoided with the use of the Has() method.
/// For UFArray, the index does not get updated.
UFObject &Drop(UFName name);
/// Remove all elements from the group.
/// The removed elements are deleted from memory.
/// For UFArray, the index does not get updated.
void Clear();
};
/**
* UFArray is a UFObject that contain an indexed group of UFObject elements.
* The array's elements are indexed by their StringValue(). In the current
* implementation, the StringValue() should not be changed after the
* UFObject was added to the UFArray.
*/
class UFArray : public UFGroup
{
public:
/// Construct an empty UFArray, containing no objects.
explicit UFArray(UFName name, const char *defaultIndex = "");
std::string XML(const char *indent = "") const;
void Set(const UFObject &object);
void Set(const char *string);
const char *StringValue() const;
bool IsDefault() const;
void SetDefault();
/// Set @a string as a default string value for the UFArray. As opposed
/// to the SetDefault() method with no arguments, this method does not
/// changes the default of the array's elements.
/// A #uf_default_changed event is triggered.
void SetDefault(const char *string);
void Reset();
/// Set the current index position in the array.
/// Return false if @a index is out of range.
bool SetIndex(int index);
/// Retriew the current index location in the array. -1 is returned
/// if the string index value corresponds to no element's label.
int Index() const;
/// Return true if the string index value is equal to @a string.
bool IsEqual(const char *string) const;
/// Add (append) a UFObject to a UFArray. If the object belonged to
/// another array before, it will be detached from the original array.
/// \exception UFException is thrown if UFArray already contains
/// an object with the same StringValue. This can be avoided with the
/// use of the Has() method.
UFArray &operator<<(UFObject *object);
};
/// This is the common exception thrown by the UFObject implementation.
/// Usually, it represents a programming error. But in the case of
/// UFObject::Set(const char *string), a UFException could result from
/// a user input error.
class UFException : public std::runtime_error
{
public:
explicit UFException(std::string &Message);
};
#endif // __cplusplus
/*************************\
* UFObject C interface *
\*************************/
typedef int UFBoolean;
#define UF_FALSE (0)
#define UF_TRUE (!UF_FALSE)
#ifdef __cplusplus
extern "C" {
#endif
/// Delete a UFObject and free its resources. Never use free() on UFObject s.
UFObject *ufobject_delete(UFObject *object);
/// Retrieve the name of the UFObject.
UFName ufobject_name(UFObject *object);
UFObject *ufobject_parent(UFObject *object);
/// Translate object to a string. See UFObject::StringValue() for details.
const char *ufobject_string_value(UFObject *object);
/// Set the value of the object from the string value.
/// Returns false on failure.
/// See \ref C-interface and UFObject::Set(const char *string) for details.
UFBoolean ufobject_set_string(UFObject *object, const char *string);
/// Copy the value of the source object to the destination object.
/// Returns false on failure.
/// See \ref C-interface and UFObject::Set(const UFObject &object) for details.
UFBoolean ufobject_copy(UFObject *destination, UFObject *source);
/// Create an XML block for the object. The returned buffer should be
/// free()'d by the caller. See UFObject::XML() for details.
char *ufobject_xml(UFObject *object, const char *indent);
void *ufobject_user_data(UFObject *object);
void ufobject_set_user_data(UFObject *object, void *user_data);
void ufobject_set_changed_event_handle(UFObject *object,
UFEventHandle *handle);
/// Return TRUE if object is set to its default value.
UFBoolean ufobject_is_default(UFObject *object);
/// Set the current object value to its default value.
void ufobject_set_default(UFObject *object);
/// Return the numerical value of the object. Returns NaN if object is not a
/// UFNumber. See \ref C-interface and UFNumber::DoubleValue() for more details.
double ufnumber_value(UFObject *object);
/// Set the value of the object to the given number. Returns false if @a object
/// is not a UFNumber. See \ref C-interface and UFNumber::Set(double number)
/// for more details.
UFBoolean ufnumber_set(UFObject *object, double number);
/// Return the numerical value of the @a index element of the object.
/// Returns NaN if @a object is not a UFNumberArray or @a index is out of range.
/// See \ref C-interface and UFNumberArray::DoubleValue() for more details.
double ufnumber_array_value(UFObject *object, int index);
/// Set the value of all the array elements at once.
/// Returns false if @a object is not a UFNumberArray. See \ref C-interface
/// and UFNumberArray::Set(const double array[]) for more details.
UFBoolean ufnumber_array_set(UFObject *object, const double array[]);
/// Return true if string value is equal to @a string.
/// Return false if it is not equal or if object is not a UFString.
/// See \ref C-interface for more details.
UFBoolean ufstring_is_equal(UFObject *object, const char *string);
/// Return true if the UFGroup @a object contains an object called name.
/// Return false if it does not, or if object is not a UFGroup.
/// See \ref C-interface for more details.
UFBoolean ufgroup_has(UFObject *object, UFName name);
/// Return a UFObject element in a UFGroup. Return NULL if element is not found
/// or if @a object is not a UFGroup. See \ref C-interface for more details.
UFObject *ufgroup_element(UFObject *object, UFName name);
/// Add a UFObject to a UFGroup. Return false if UFGroup already contains
/// an object with the same name. See \ref C-interface for more details.
UFBoolean ufgroup_add(UFObject *group, UFObject *object);
/// Drop an object from the group. The dropped object is returned.
/// If it is not needed any more it should be deleted to free its memory.
UFObject *ufgroup_drop(UFObject *group, UFName name);
/// Set the current index position in the array.
UFBoolean ufarray_set_index(UFObject *object, int index);
/// Retriew the current index location in the array. -1 is returned
/// if the string index value corresponds to no element's label.
int ufarray_index(UFObject *object);
/// Return true if array's string value is equal to @a string.
/// Return false if it is not equal or if object is not a UFArray.
/// See \ref C-interface for more details.
UFBoolean ufarray_is_equal(UFObject *object, const char *string);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /*_UFOBJECT_H*/