source: trunk/src/objects/RpNumber.cc @ 1560

Last change on this file since 1560 was 1560, checked in by dkearney, 15 years ago

updates to the object system, fixed up tree and xml parser objects, added some basic tests for them and adopted number object to accept xml text and configure itself from the parsed xml. added fermi3.cc example program which contains suggested interface from apps meeting.

File size: 11.7 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture 2.0 Number Object Source
4 *
5 * ======================================================================
6 *  AUTHOR:  Derrick Kearney, Purdue University
7 *  Copyright (c) 2005-2009  Purdue Research Foundation
8 *
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 */
13
14#include "RpNumber.h"
15#include "RpUnits.h"
16#include "RpSimpleBuffer.h"
17#include "RpUnitsCInterface.h"
18#include "RpParserXML.h"
19#include "RpPath.h"
20
21using namespace Rappture;
22
23Number::Number()
24   : Object (),
25     _minSet (0),
26     _maxSet (0),
27     _presets (NULL)
28{
29    // FIXME: empty names should be autoname'd
30    this->name("");
31    this->path("");
32    this->label("");
33    this->desc("");
34    this->def(0.0);
35    this->cur(0.0);
36    this->min(0.0);
37    this->max(0.0);
38    // FIXME: empty units should be set to the None unit
39    // this->units(units);
40}
41
42Number::Number(const char *name, const char *units, double val)
43   : Object (),
44     _minSet (0),
45     _maxSet (0),
46     _presets (NULL)
47{
48    const RpUnits *u = NULL;
49
50    this->name(name);
51    this->path("");
52    this->label("");
53    this->desc("");
54    this->def(val);
55    this->cur(val);
56    this->min(0.0);
57    this->max(0.0);
58
59    u = RpUnits::find(std::string(units));
60    if (!u) {
61        u = RpUnits::define(units,NULL);
62    }
63    this->units(units);
64}
65
66Number::Number(const char *name, const char *units, double val,
67               double min, double max, const char *label,
68               const char *desc)
69    : Object (),
70      _minSet (0),
71      _maxSet (0),
72      _presets (NULL)
73{
74    const RpUnits *u = NULL;
75
76    this->name(name);
77    this->path("");
78    this->label(label);
79    this->desc(desc);
80    this->def(val);
81    this->cur(val);
82    this->min(min);
83    this->max(max);
84
85    u = RpUnits::find(std::string(units));
86    if (! u) {
87        u = RpUnits::define(units,NULL);
88    }
89    this->units(units);
90
91    if ((min == 0) && (max == 0)) {
92        _minSet = 0;
93        _maxSet = 0;
94    }
95    else {
96
97        _minSet = 1;
98        if (min > val) {
99            this->min(val);
100        }
101
102        _maxSet = 1;
103        if (max < val) {
104            this->max(val);
105        }
106    }
107}
108
109// copy constructor
110Number::Number ( const Number& o )
111    : Object (o),
112      _minSet (o._minSet),
113      _maxSet (o._maxSet)
114{
115    this->def(o.def());
116    this->cur(o.cur());
117    this->min(o.min());
118    this->max(o.max());
119    this->units(o.units());
120
121    // FIXME: need to copy _presets
122}
123
124// default destructor
125Number::~Number ()
126{
127    // clean up dynamic memory
128}
129
130const char *
131Number::units(void) const
132{
133    return propstr("units");
134}
135
136void
137Number::units(const char *p)
138{
139    propstr("units",p);
140}
141
142/**********************************************************************/
143// METHOD: convert()
144/// Convert the number object to another unit from string
145/**
146 * Store the result as the currentValue.
147 */
148
149int
150Number::convert(const char *to)
151{
152    const RpUnits* toUnit = NULL;
153    const RpUnits* fromUnit = NULL;
154    double convertedVal = cur();
155    int err = 0;
156
157    // make sure all units functions accept char*'s
158    toUnit = RpUnits::find(std::string(to));
159    if (!toUnit) {
160        // should raise error!
161        // conversion not defined because unit does not exist
162        return convertedVal;
163    }
164
165    fromUnit = RpUnits::find(std::string(units()));
166    if (!fromUnit) {
167        // should raise error!
168        // conversion not defined because unit does not exist
169        return convertedVal;
170    }
171
172    // perform the conversion
173    convertedVal = fromUnit->convert(toUnit,def(), &err);
174    if (!err) {
175        def(convertedVal);
176    }
177
178    convertedVal = fromUnit->convert(toUnit,cur(), &err);
179    if (!err) {
180        cur(convertedVal);
181    }
182
183    return err;
184}
185
186/**********************************************************************/
187// METHOD: value()
188/// Get the value of this object converted to specified units
189/**
190 * does not change the value of the object
191 * error code is returned
192 */
193
194int
195Number::value(const char *to, double *value) const
196{
197    return 1;
198}
199
200/**********************************************************************/
201// METHOD: addPreset()
202/// Add a preset / suggessted value to the object
203/**
204 * Add a preset value to the object. Currently all
205 * labels must be unique.
206 */
207
208Number&
209Number::addPreset(const char *label, const char *desc, double val,
210                  const char *units)
211{
212    preset *p = NULL;
213
214    p = new preset;
215    if (!p) {
216        // raise error and exit
217    }
218
219    p->label(label);
220    p->desc(desc);
221    p->val(val);
222    p->units(units);
223
224    if (_presets == NULL) {
225        _presets = Rp_ChainCreate();
226        if (_presets == NULL) {
227            // raise error and exit
228        }
229    }
230
231    Rp_ChainAppend(_presets,p);
232
233    return *this;
234}
235
236Number&
237Number::addPreset(const char *label, const char *desc, const char *val)
238{
239    double valval = 0.0;
240    const char *valunits = "";
241    char *endptr = NULL;
242    int result = 0;
243
244    std::string vstr = RpUnits::convert(val,"",RPUNITS_UNITS_OFF,&result);
245    if (result) {
246        // probably shouldnt trust this result
247        fprintf(stderr,"error in RpUnits::convert in addPreset\n");
248    }
249    size_t len = vstr.length();
250    valunits = val+len;
251
252    valval = strtod(val,&endptr);
253    if ( (endptr == val) || (endptr != valunits) ) {
254        // error? strtod was not able to find the same
255        // units location as RpUnits::convert
256        fprintf(stderr,"error while parsing units in addPreset\n");
257    }
258
259    return addPreset(label,desc,valval,valunits);
260}
261
262/**********************************************************************/
263// METHOD: delPreset()
264/// Delete a preset / suggessted value from the object
265/**
266 * Delete a preset value from the object.
267 */
268
269Number&
270Number::delPreset(const char *label)
271{
272    if (label == NULL) {
273        return *this;
274    }
275
276    if (_presets == NULL) {
277        return *this;
278    }
279
280    preset *p = NULL;
281    const char *plabel = NULL;
282    Rp_ChainLink *l = NULL;
283
284    // traverse the list looking for the matching preset
285    l = Rp_ChainFirstLink(_presets);
286    while (l != NULL) {
287        p = (preset *) Rp_ChainGetValue(l);
288        plabel = p->label();
289        if ((*label == *plabel) && (strcmp(plabel,label) == 0)) {
290            // we found matching entry, remove it
291            if (p) {
292                delete p;
293                Rp_ChainDeleteLink(_presets,l);
294            }
295            break;
296        }
297    }
298
299
300    return *this;
301}
302
303/**********************************************************************/
304// METHOD: xml()
305/// view this object's xml
306/**
307 * View this object as an xml element returned as text.
308 */
309
310const char *
311Number::xml(size_t indent, size_t tabstop)
312{
313    size_t l1width = indent + (1*tabstop);
314    size_t l2width = indent + (2*tabstop);
315    const char *sp = "";
316
317    Path p(path());
318    _tmpBuf.clear();
319
320    _tmpBuf.appendf(
321"%8$*5$s<number id='%1$s'>\n\
322%8$*6$s<about>\n\
323%8$*7$s<label>%2$s</label>\n\
324%8$*7$s<description>%3$s</description>\n\
325%8$*6$s</about>\n\
326%8$*6$s<units>%4$s</units>\n",
327       p.id(),label(),desc(),units(),indent,l1width,l2width,sp);
328
329    if (_minSet) {
330        _tmpBuf.appendf("%4$*3$s<min>%1$g%2$s</min>\n", min(),units(),l1width,sp);
331    }
332    if (_maxSet) {
333        _tmpBuf.appendf("%4$*3$s<max>%1$g%2$s</max>\n", max(),units(),l1width,sp);
334    }
335
336    _tmpBuf.appendf(
337"%6$*5$s<default>%1$g%3$s</default>\n\
338%6$*5$s<current>%2$g%3$s</current>\n\
339%6$*4$s</number>",
340       def(),cur(),units(),indent,l1width,sp);
341
342    return _tmpBuf.bytes();
343}
344
345/**********************************************************************/
346// METHOD: xml(const char *xmltext)
347/// configure the object based on Rappture1.1 xmltext
348/**
349 * Configure the object based on the provided xml
350 */
351
352void
353Number::xml(const char *xmltext)
354{
355    Rp_ParserXml *p = NULL;
356
357    p = Rp_ParserXmlCreate();
358
359    Rp_ParserXmlParse(p, xmltext);
360
361    Rp_TreeNode node = Rp_ParserXmlElement(p,NULL);
362    name(Rp_ParserXmlNodeId(p,node));
363    label(Rp_ParserXmlGet(p,"about.label"));
364    desc(Rp_ParserXmlGet(p,"about.description"));
365    units(Rp_ParserXmlGet(p,"units"));
366    minFromStr(Rp_ParserXmlGet(p,"min"));
367    maxFromStr(Rp_ParserXmlGet(p,"max"));
368    defFromStr(Rp_ParserXmlGet(p,"default"));
369    curFromStr(Rp_ParserXmlGet(p,"current"));
370
371    // collect info about the preset values
372    Rp_Chain *childChain = Rp_ChainCreate();
373    Rp_ParserXmlChildren(p,NULL,"preset",childChain);
374    Rp_ChainLink *l = Rp_ChainFirstLink(childChain);
375    while (l != NULL) {
376        Rp_TreeNode presetNode = (Rp_TreeNode) Rp_ChainGetValue(l);
377        Rp_ParserXmlBaseNode(p,presetNode);
378
379        const char *presetlabel = Rp_ParserXmlGet(p,"label");
380        const char *presetdesc = Rp_ParserXmlGet(p,"description");
381        const char *presetvalue = Rp_ParserXmlGet(p,"value");
382        addPreset(presetlabel,presetdesc,presetvalue);
383
384
385        l = Rp_ChainNextLink(l);
386    }
387
388    Rp_ChainDestroy(childChain);
389
390    // return the base node to the tree root
391    Rp_ParserXmlBaseNode(p,NULL);
392}
393
394/**********************************************************************/
395// METHOD: tree()
396/// return the object as a tree
397/**
398 * Represent the object as a tree.
399 * An Rp_TreeNode is returned.
400 */
401
402/*
403Rp_TreeNode
404tree()
405{
406    return NULL;
407}
408*/
409
410/**********************************************************************/
411// METHOD: tree(Rp_TreeNode root)
412/// construct a number object from the provided tree
413/**
414 * construct a number object from the provided tree
415 */
416
417/*
418void
419tree(
420    Rp_TreeNode root)
421{
422    if (root == NULL) {
423        // FIXME: setup error
424    }
425}
426*/
427
428/**********************************************************************/
429// METHOD: is()
430/// what kind of object is this
431/**
432 * return hex value telling what kind of object this is.
433 */
434
435const int
436Number::is() const
437{
438    // return "numb" in hex
439    return 0x6E756D62;
440}
441
442
443/**********************************************************************/
444// METHOD: minFromStr()
445/// xml helper function to receive min value as a string
446/**
447 * convert string to value and units and store as min
448 */
449
450void
451Number::minFromStr(
452    const char *val)
453{
454    double numericVal = 0;
455    int err = 0;
456
457    numericVal = rpConvertDbl(val,units(),&err);
458
459    if (!err) {
460        min(numericVal);
461    } else {
462        // FIXME: add error code
463    }
464}
465
466/**********************************************************************/
467// METHOD: maxFromStr()
468/// xml helper function to receive max value as a string
469/**
470 * convert string to value and units and store as max
471 */
472
473void
474Number::maxFromStr(
475    const char *val)
476{
477    double numericVal = 0;
478    int err = 0;
479
480    numericVal = rpConvertDbl(val,units(),&err);
481
482    if (!err) {
483        max(numericVal);
484    } else {
485        // FIXME: add error code
486    }
487}
488
489/**********************************************************************/
490// METHOD: defFromStr()
491/// xml helper function to receive default value as a string
492/**
493 * convert string to value and units and store as default
494 */
495
496void
497Number::defFromStr(
498    const char *val)
499{
500    double numericVal = 0;
501    int err = 0;
502
503    numericVal = rpConvertDbl(val,units(),&err);
504
505    if (!err) {
506        def(numericVal);
507    } else {
508        // FIXME: add error code
509    }
510}
511
512/**********************************************************************/
513// METHOD: currFromStr()
514/// xml helper function to receive current value as a string
515/**
516 * convert string to value and units and store as current
517 */
518
519void
520Number::curFromStr(
521    const char *val)
522{
523    double numericVal = 0;
524    int err = 0;
525
526    numericVal = rpConvertDbl(val,units(),&err);
527
528    if (!err) {
529        cur(numericVal);
530    } else {
531        // FIXME: add error code
532    }
533}
534
535
536
537// -------------------------------------------------------------------- //
538
Note: See TracBrowser for help on using the repository browser.