1 /*
2     Copyright (C) 2021 by Pawel Soja <kernel32.pl@gmail.com>
3 
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Lesser General Public
6     License as published by the Free Software Foundation; either
7     version 2.1 of the License, or (at your option) any later version.
8 
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Lesser General Public License for more details.
13 
14     You should have received a copy of the GNU Lesser General Public
15     License along with this library; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18 
19 #pragma once
20 
21 #include "indiapi.h"
22 #include "indidevapi.h"
23 #include "indiwidgettraits.h"
24 
25 #include "indidriver.h" // IUSaveConfigXXX (indicom.c)
26 
27 #include "indiwidgetview.h"
28 
29 #include <string>
30 #include <cstring>
31 #include <cstdarg>
32 #include <cstdlib>
33 #include <type_traits>
34 
35 namespace INDI
36 {
37 
38 template <typename> struct WidgetView;
39 template <typename> struct PropertyView;
40 
41 #define PROPERTYVIEW_BASE_ACCESS public
42 // don't use direct access to low-level property
43 //#define PROPERTYVIEW_BASE_ACCESS protected // future
44 
45 /**
46  * \class INDI::PropertyView and INDI::WidgetView
47  * \brief Provides decorator for Low-Level IXXXVectorProperty/IXXX
48  *
49  * INDI::PropertyView
50  *
51  * A class that will allow a easy transition to the new widget handling interface (future).
52  * - Use PropertyView<IText>   instead of ITextVectorProperty
53  * - Use PropertyView<INumber> instead of INumberVectorProperty
54  * - Use PropertyView<ISwitch> instead of ISwitchVectorProperty
55  * - Use PropertyView<ILight>  instead of ILightVectorProperty
56  * - Use PropertyView<IBLOB>   instead of IBLOBVectorProperty
57  *
58  * The PropertyView<IXXX> class is compatible with low-level IXXXVectorProperty structures.
59  *
60  * INDI::WidgetView
61  *
62  * A class that will allow a easy transition to the new widget handling interface (future).
63  * - Use WidgetView<IText>   instead of IText
64  * - Use WidgetView<INumber> instead of INumber
65  * - Use WidgetView<ISwitch> instead of ISwitch
66  * - Use WidgetView<ILight>  instead of ILight
67  * - Use WidgetView<IBLOB>   instead of IBLOB
68  *
69  * The WidgetView<IXXX> class is compatible with low-level IXXX structures.
70  */
71 
72 template <typename T>
73 struct PropertyView: PROPERTYVIEW_BASE_ACCESS WidgetTraits<T>::PropertyType
74 {
75     using Type = T;
76     using PropertyType = typename WidgetTraits<T>::PropertyType;
77     using WidgetType = WidgetView<T>;
78 
79     friend class Property;
80     friend class PropertyPrivate;
81     friend class BaseDevice;
82     friend class DefaultDevice;
83     template <typename>
84     friend struct WidgetView;
85 
86     template <typename X, typename Needed>
87     using enable_if_is_same_t = typename std::enable_if<std::is_same<X, Needed>::value, bool>::type;
88 public:
89     PropertyView();
90 
91     // #PS: do not delete items, they may be on the stack.
92     //~PropertyView()                                        { for(auto &p: *this) {p.clear();} free(widget()); }
93 
94 public:
95     void setDeviceName(const char *name);                  /* outside implementation */
96     void setDeviceName(const std::string &name);           /* outside implementation */
97 
98     void setName(const char *name);                        /* outside implementation */
99     void setName(const std::string &name);                 /* outside implementation */
100 
101     void setLabel(const char *label);                      /* outside implementation */
102     void setLabel(const std::string &label);               /* outside implementation */
103 
104     void setGroupName(const char *name);                   /* outside implementation */
105     void setGroupName(const std::string &name);            /* outside implementation */
106 
107     void setPermission(IPerm permission);                  /* outside implementation */
108     void setTimeout(double timeout);                       /* outside implementation */
109     void setState(IPState state);
110 
111     void setTimestamp(const char *timestamp);              /* outside implementation */
112     void setTimestamp(const std::string &timestamp);       /* outside implementation */
113 
114     void setAux(void *user);                               /* outside implementation */
115     void setWidgets(WidgetType *w, size_t count);          /* outside implementation */
116 
117     template <size_t N>
118     void setWidgets(WidgetType (&w)[N]);                   /* outside implementation */
119 
120 public: // only for ISwitch
121     void setRule(ISRule rule);                             /* outside implementation */
122     bool setRule(const std::string &rule);                 /* outside implementation */
123 
124     template <typename X = T, enable_if_is_same_t<X, ISwitch> = true>
resetPropertyView125     void reset()                                           { IUResetSwitch(this); }
126 
127     template <typename X = T, enable_if_is_same_t<X, ISwitch> = true>
findOnSwitchPropertyView128     WidgetType *findOnSwitch() const                       { return static_cast<WidgetType *>(IUFindOnSwitch(this)); }
129 
130     template <typename X = T, enable_if_is_same_t<X, ISwitch> = true>
findOnSwitchIndexPropertyView131     int findOnSwitchIndex() const                          { return IUFindOnSwitchIndex(this); }
132 
133 public: // only for INumber
134     template <typename X = T, enable_if_is_same_t<X, INumber> = true>
135     void updateMinMax();                                   /* outside implementation - only driver side, see indipropertyview_driver.cpp */
136 
137 public: //getters
getDeviceNamePropertyView138     const char *getDeviceName() const                      { return this->device; }
getNamePropertyView139     const char *getName()       const                      { return this->name; }
getLabelPropertyView140     const char *getLabel()      const                      { return this->label; }
getGroupNamePropertyView141     const char *getGroupName()  const                      { return this->group; }
142 
143     IPerm getPermission()       const;                     /* outside implementation */
getPermissionAsStringPropertyView144     const char *getPermissionAsString() const              { return permStr(getPermission()); }
145 
146     ISRule getRule()            const;                     /* outside implementation */
getRuleAsStringPropertyView147     const char * getRuleAsString() const                   { return ruleStr(getRule()); }
148 
149     double getTimeout()         const;                     /* outside implementation */
getStatePropertyView150     IPState getState()          const                      { return this->s; }
getStateAsStringPropertyView151     const char *getStateAsString() const                   { return pstateStr(getState()); }
152 
getTimestampPropertyView153     const char *getTimestamp()  const                      { return this->timestamp; }
getAuxPropertyView154     void *getAux()              const                      { return this->aux; }
155 
156     int count() const;                                     /* outside implementation */
157     WidgetType *widget() const;                            /* outside implementation */
158 
159     WidgetType *findWidgetByName(const char *name) const;  /* outside implementation */
160 
161 public: //tests
isEmptyPropertyView162     bool isEmpty() const                                   { return widget() == nullptr || count() == 0; }
163 
isNameMatchPropertyView164     bool isNameMatch(const char *otherName) const          { return !strcmp(getName(), otherName); }
isNameMatchPropertyView165     bool isNameMatch(const std::string &otherName) const   { return getName() == otherName; }
166 
isLabelMatchPropertyView167     bool isLabelMatch(const char *otherLabel) const        { return !strcmp(getLabel(), otherLabel); }
isLabelMatchPropertyView168     bool isLabelMatch(const std::string &otherLabel) const { return getLabel() == otherLabel; }
169 
170 public: // only driver side
171     void save(FILE *f) const;                              /* outside implementation */
172 
173     void vapply(const char *format, va_list args) const;   /* outside implementation - only driver side, see indipropertyview_driver.cpp */
174     void vdefine(const char *format, va_list args) const;  /* outside implementation - only driver side, see indipropertyview_driver.cpp */
175 
176     void apply(const char *format, ...) const ATTRIBUTE_FORMAT_PRINTF(2, 3);  /* outside implementation - only driver side, see indipropertyview_driver.cpp */
177     void define(const char *format, ...) const ATTRIBUTE_FORMAT_PRINTF(2, 3); /* outside implementation - only driver side, see indipropertyview_driver.cpp */
178 
applyPropertyView179     void apply() const                                     { apply(nullptr);  }
definePropertyView180     void define() const                                    { define(nullptr); }
181 
182 public:
183     template <typename X = T, enable_if_is_same_t<X, IText> = true>
184     void fill(
185         const char *device, const char *name, const char *label, const char *group,
186         IPerm permission, double timeout, IPState state
187     ); /* outside implementation - only driver side, see indipropertyview_driver.cpp */
188 
189     template <typename X = T, enable_if_is_same_t<X, INumber> = true>
190     void fill(
191         const char *device, const char *name, const char *label, const char *group,
192         IPerm permission, double timeout, IPState state
193     ); /* outside implementation - only driver side, see indipropertyview_driver.cpp */
194 
195     template <typename X = T, enable_if_is_same_t<X, ISwitch> = true>
196     void fill(
197         const char *device, const char *name, const char *label, const char *group,
198         IPerm permission, ISRule rule, double timeout, IPState state
199     ); /* outside implementation - only driver side, see indipropertyview_driver.cpp */
200 
201     template <typename X = T, enable_if_is_same_t<X, ILight> = true>
202     void fill(
203         const char *device, const char *name, const char *label, const char *group,
204         IPState state
205     ); /* outside implementation - only driver side, see indipropertyview_driver.cpp */
206 
207     template <typename X = T, enable_if_is_same_t<X, IBLOB> = true>
208     void fill(
209         const char *device, const char *name, const char *label, const char *group,
210         IPerm permission, double timeout, IPState state
211     ); /* outside implementation - only driver side, see indipropertyview_driver.cpp */
212 
213 public:
214     template <typename X = T, enable_if_is_same_t<X, IText> = true>
215     bool update(const char * const texts[], const char * const names[], int n);
216     /* outside implementation - only driver side, see indipropertyview_driver.cpp */
217 
218     template <typename X = T, enable_if_is_same_t<X, INumber> = true>
219     bool update(const double values[], const char * const names[], int n);
220     /* outside implementation - only driver side, see indipropertyview_driver.cpp */
221 
222     template <typename X = T, enable_if_is_same_t<X, ISwitch> = true>
223     bool update(const ISState states[], const char * const names[], int n);
224     /* outside implementation - only driver side, see indipropertyview_driver.cpp */
225 
226     /*
227     template <typename X = T, enable_if_is_same_t<X, ILight> = true>
228     bool update(..., const char * const names[], int n);
229     */
230 
231     template <typename X = T, enable_if_is_same_t<X, IBLOB> = true>
232     bool update(
233         const int sizes[], const int blobsizes[], const char * const blobs[], const char * const formats[],
234         const char * const names[], int n
235     ); /* outside implementation - only driver side, see indipropertyview_driver.cpp */
236 
237 
238 public:
beginPropertyView239     WidgetType *begin() const                              { return widget();           }
endPropertyView240     WidgetType *end()   const                              { return widget() + count(); }
241 
atPropertyView242     WidgetType *at(size_t index) const                     { return widget() + index;   }
243 public:
clearPropertyView244     void clear()
245     {
246         for(auto &p: *this) { p.clear(); }
247         //free(widget()); // #PS: do not delete items, they may be on the stack.
248         memset(this, 0, sizeof(*this));
249     }
250 };
251 
252 template <typename>
253 struct WidgetView;
254 
255 template <>
256 struct WidgetView<IText>: PROPERTYVIEW_BASE_ACCESS IText
257 {
258     using Type = IText;
259     template <typename> friend struct PropertyView;
260 
261 public:
262     WidgetView()                                           { memset(this, 0, sizeof(*this)); }
263     WidgetView(const WidgetView &other): Type(other)       { this->text = nullptr; setText(other.text); }
264     WidgetView(WidgetView &&other): Type(other)            { memset(static_cast<Type*>(&other), 0, sizeof(other)); }
265     WidgetView &operator=(const WidgetView &other)         { return *this = WidgetView(other); }
266     WidgetView &operator=(WidgetView &&other)              { std::swap(static_cast<Type&>(other), static_cast<Type&>(*this)); return *this; }
267     ~WidgetView()                                          { free(this->text); }
268     void clear()                                           { free(this->text); memset(this, 0, sizeof(*this)); }
269     // bool isNull() const                                    { return reinterpret_cast<const void*>(this) == nullptr; }
270 
271 public: // setters
272     void setParent(ITextVectorProperty *parent)            { this->tvp = parent; }
273     void setParent(PropertyView<Type> *parent)             { this->tvp = static_cast<ITextVectorProperty*>(parent); }
274 
275     void setName(const char *name)                         { strncpy(this->name, name, MAXINDINAME); }
276     void setName(const std::string &name)                  { setName(name.data()); }
277 
278     void setLabel(const char *label)                       { strncpy(this->label, label, MAXINDILABEL); }
279     void setLabel(const std::string &label)                { setLabel(label.data()); }
280 
281     //void setText(const char *text)                         { free(this->text); this->text = strndup(text, strlen(text)); }
282     void setText(const char *text, size_t size)            { this->text = strncpy(static_cast<char*>(realloc(this->text, size + 1)), text, size); this->text[size] = '\0'; }
283     void setText(const char *text)                         { setText(text, strlen(text)); }
284     void setText(const std::string &text)                  { setText(text.data(), text.size()); }
285 
286     void setAux(void *user)                                { this->aux0 = user; }
287     // don't use any other aux!
288 
289 public: //getters
290     const char *getName()  const                           { return this->name; }
291     const char *getLabel() const                           { return this->label; }
292     const char *getText()  const                           { return this->text; }
293 
294     void *getAux() const                                   { return this->aux0; }
295 
296 public: //tests
297     bool isNameMatch(const char *otherName) const          { return !strcmp(getName(), otherName); }
298     bool isNameMatch(const std::string &otherName) const   { return getName() == otherName; }
299 
300     bool isLabelMatch(const char *otherLabel) const        { return !strcmp(getLabel(), otherLabel); }
301     bool isLabelMatch(const std::string &otherLabel) const { return getLabel() == otherLabel; }
302 
303 public:
304     void fill(const char *name, const char *label, const char *initialText)
305     ; /* outside implementation - only driver side, see indipropertyview_driver.cpp */
306 
307     void fill(const std::string &name, const std::string &label, const std::string &initialText)
308     { fill(name.c_str(), label.c_str(), initialText.c_str()); }
309 };
310 
311 template <>
312 struct WidgetView<INumber>: PROPERTYVIEW_BASE_ACCESS INumber
313 {
314     using Type = INumber;
315     template <typename> friend struct PropertyView;
316 
317 public:
318     WidgetView()                                           { memset(this, 0, sizeof(*this)); }
319     WidgetView(const WidgetView &other): Type(other)       { }
320     WidgetView(WidgetView &&other): Type(other)            { memset(static_cast<Type*>(&other), 0, sizeof(other)); }
321     WidgetView &operator=(const WidgetView &other)         { return *this = WidgetView(other); }
322     WidgetView &operator=(WidgetView &&other)              { std::swap(static_cast<Type&>(other), static_cast<Type&>(*this)); return *this; }
323     ~WidgetView()                                          { }
324     void clear()                                           { memset(this, 0, sizeof(*this)); }
325     // bool isNull() const                                    { return reinterpret_cast<const void*>(this) == nullptr; }
326 
327 public: // setters
328     void setParent(INumberVectorProperty *parent)          { this->nvp = parent; }
329     void setParent(PropertyView<Type> *parent)             { this->nvp = static_cast<INumberVectorProperty*>(parent); }
330 
331     void setName(const char *name)                         { strncpy(this->name, name, MAXINDINAME); }
332     void setName(const std::string &name)                  { setName(name.data()); }
333 
334     void setLabel(const char *label)                       { strncpy(this->label, label, MAXINDILABEL); }
335     void setLabel(const std::string &label)                { setLabel(label.data()); }
336 
337     void setFormat(const char *format)                     { strncpy(this->format, format, MAXINDIFORMAT); }
338     void setFormat(const std::string &format)              { setLabel(format.data()); }
339 
340     void setMin(double min)                                { this->min = min; }
341     void setMax(double max)                                { this->max = max; }
342     void setMinMax(double min, double max)                 { setMin(min); setMax(max); }
343     void setStep(double step)                              { this->step = step; }
344     void setValue(double value)                            { this->value = value; }
345 
346     void setAux(void *user)                                { this->aux0 = user; }
347     // don't use any other aux!
348 
349 public: //getters
350     const char *getName()   const                          { return this->name; }
351     const char *getLabel()  const                          { return this->label; }
352     const char *getFormat() const                          { return this->format; }
353 
354     double getMin()   const                                { return this->min; }
355     double getMax()   const                                { return this->max; }
356     double getStep()  const                                { return this->step; }
357     double getValue() const                                { return this->value; }
358 
359     void *getAux() const                                   { return this->aux0; }
360 
361 public: //tests
362     bool isNameMatch(const char *otherName) const          { return !strcmp(getName(), otherName); }
363     bool isNameMatch(const std::string &otherName) const   { return getName() == otherName; }
364 
365     bool isLabelMatch(const char *otherLabel) const        { return !strcmp(getLabel(), otherLabel); }
366     bool isLabelMatch(const std::string &otherLabel) const { return getLabel() == otherLabel; }
367 
368 public:
369     void fill(const char *name, const char *label, const char *format,
370               double min, double max, double step, double value)
371     ; /* outside implementation - only driver side, see indipropertyview_driver.cpp */
372 
373     void fill(const std::string &name, const std::string &label, const std::string &format,
374               double min, double max, double step, double value)
375     { fill(name.c_str(), label.c_str(), format.c_str(), min, max, step, value); }
376 };
377 
378 template <>
379 struct WidgetView<ISwitch>: PROPERTYVIEW_BASE_ACCESS ISwitch
380 {
381     using Type = ISwitch;
382     template <typename> friend struct PropertyView;
383 
384 public:
385     WidgetView()                                           { memset(this, 0, sizeof(*this)); }
386     WidgetView(const WidgetView &other): Type(other)       { }
387     WidgetView(WidgetView &&other): Type(other)            { memset(static_cast<Type*>(&other), 0, sizeof(other)); }
388     WidgetView &operator=(const WidgetView &other)         { return *this = WidgetView(other); }
389     WidgetView &operator=(WidgetView &&other)              { std::swap(static_cast<Type&>(other), static_cast<Type&>(*this)); return *this; }
390     ~WidgetView()                                          { }
391     void clear()                                           { memset(this, 0, sizeof(*this)); }
392     // bool isNull() const                                    { return reinterpret_cast<const void*>(this) == nullptr; }
393 
394 public: // setters
395     void setParent(ISwitchVectorProperty *parent)          { this->svp = parent; }
396     void setParent(PropertyView<Type> *parent)             { this->svp = static_cast<ISwitchVectorProperty*>(parent); }
397 
398     void setName(const char *name)                         { strncpy(this->name, name, MAXINDINAME); }
399     void setName(const std::string &name)                  { setName(name.data()); }
400 
401     void setLabel(const char *label)                       { strncpy(this->label, label, MAXINDILABEL); }
402     void setLabel(const std::string &label)                { setLabel(label.data()); }
403 
404     void setState(const ISState &state)                    { this->s = state; }
405     bool setState(const std::string &state)                { return crackISState(state.data(), &this->s) == 0; }
406 
407     void setAux(void *user)                                { this->aux = user; }
408     // don't use any other aux!
409 
410 public: //getters
411     const char *getName()   const                          { return this->name; }
412     const char *getLabel()  const                          { return this->label; }
413 
414     ISState getState() const                               { return this->s; }
415     const char *getStateAsString() const                   { return sstateStr(getState()); }
416 
417     void *getAux() const                                   { return this->aux; }
418 
419 
420 public: //tests
421     bool isNameMatch(const char *otherName) const          { return !strcmp(getName(), otherName); }
422     bool isNameMatch(const std::string &otherName) const   { return getName() == otherName; }
423 
424     bool isLabelMatch(const char *otherLabel) const        { return !strcmp(getLabel(), otherLabel); }
425     bool isLabelMatch(const std::string &otherLabel) const { return getLabel() == otherLabel; }
426 
427 public:
428     void fill(const char *name, const char *label, ISState state = ISS_OFF)
429     ; /* outside implementation - only driver side, see indipropertyview_driver.cpp */
430 
431     void fill(const std::string &name, const std::string &label, ISState state = ISS_OFF)
432     { fill(name.c_str(), label.c_str(), state); }
433 };
434 
435 template <>
436 struct WidgetView<ILight>: PROPERTYVIEW_BASE_ACCESS ILight
437 {
438     using Type = ILight;
439     template <typename> friend struct PropertyView;
440 
441 public:
442     WidgetView()                                           { memset(this, 0, sizeof(*this)); }
443     WidgetView(const WidgetView &other): Type(other)       { }
444     WidgetView(WidgetView &&other): Type(other)            { memset(static_cast<Type*>(&other), 0, sizeof(other)); }
445     WidgetView &operator=(const WidgetView &other)         { return *this = WidgetView(other); }
446     WidgetView &operator=(WidgetView &&other)              { std::swap(static_cast<Type&>(other), static_cast<Type&>(*this)); return *this; }
447     ~WidgetView()                                          { }
448     void clear()                                           { memset(this, 0, sizeof(*this)); }
449     // bool isNull() const                                    { return reinterpret_cast<const void*>(this) == nullptr; }
450 
451 public: // setters
452     void setParent(ILightVectorProperty *parent)           { this->lvp = parent; }
453     void setParent(PropertyView<Type> *parent)             { this->lvp = static_cast<ILightVectorProperty*>(parent); }
454 
455     void setName(const char *name)                         { strncpy(this->name, name, MAXINDINAME); }
456     void setName(const std::string &name)                  { setName(name.data()); }
457 
458     void setLabel(const char *label)                       { strncpy(this->label, label, MAXINDILABEL); }
459     void setLabel(const std::string &label)                { setLabel(label.data()); }
460 
461     void setState(const IPState &state)                    { this->s = state; }
462     bool setState(const std::string &state)                { return crackIPState(state.data(), &this->s) == 0; }
463 
464     void setAux(void *user)                                { this->aux = user; }
465     // don't use any other aux!
466 
467 public: //getters
468     const char *getName()   const                          { return this->name; }
469     const char *getLabel()  const                          { return this->label; }
470 
471     IPState getState() const                               { return this->s; }
472     const char *getStateAsString() const                   { return pstateStr(getState()); }
473 
474     void *getAux() const                                   { return this->aux; }
475 
476 
477 public: //tests
478     bool isNameMatch(const char *otherName) const          { return !strcmp(getName(), otherName); }
479     bool isNameMatch(const std::string &otherName) const   { return getName() == otherName; }
480 
481     bool isLabelMatch(const char *otherLabel) const        { return !strcmp(getLabel(), otherLabel); }
482     bool isLabelMatch(const std::string &otherLabel) const { return getLabel() == otherLabel; }
483 
484 public:
485     void fill(const char *name, const char *label, IPState state = IPS_OK)
486     ; /* outside implementation - only driver side, see indipropertyview_driver.cpp */
487 
488     void fill(const std::string &name, const std::string &&label, IPState state = IPS_OK)
489     { fill(name.c_str(), label.c_str(), state); }
490 };
491 
492 template <>
493 struct WidgetView<IBLOB>: PROPERTYVIEW_BASE_ACCESS IBLOB
494 {
495     using Type = IBLOB;
496     template <typename> friend struct PropertyView;
497 
498 public:
499     WidgetView()                                           { memset(this, 0, sizeof(*this)); }
500     WidgetView(const WidgetView &other): Type(other)       { }
501     WidgetView(WidgetView &&other): Type(other)            { memset(static_cast<Type*>(&other), 0, sizeof(other)); }
502     WidgetView &operator=(const WidgetView &other)         { return *this = WidgetView(other); }
503     WidgetView &operator=(WidgetView &&other)              { std::swap(static_cast<Type&>(other), static_cast<Type&>(*this)); return *this; }
504     ~WidgetView()                                          { /* free(this->blob); */ }
505     void clear()                                           { /* free(this->blob); */ memset(this, 0, sizeof(*this)); }
506     // bool isNull() const                                    { return reinterpret_cast<const void*>(this) == nullptr; }
507 
508 public: // setters
509     void setParent(IBLOBVectorProperty *parent)            { this->bvp = parent; }
510     void setParent(PropertyView<Type> *parent)             { this->bvp = static_cast<IBLOBVectorProperty*>(parent); }
511 
512     void setName(const char *name)                         { strncpy(this->name, name, MAXINDINAME); }
513     void setName(const std::string &name)                  { setName(name.data()); }
514 
515     void setLabel(const char *label)                       { strncpy(this->label, label, MAXINDILABEL); }
516     void setLabel(const std::string &label)                { setLabel(label.data()); }
517 
518     void setFormat(const char *format)                     { strncpy(this->format, format, MAXINDIBLOBFMT); }
519     void setFormat(const std::string &format)              { setLabel(format.data()); }
520 
521     void setBlob(void *blob)                               { this->blob = blob; }
522     void setBlobLen(int size)                              { this->bloblen = size; }
523     void setSize(int size)                                 { this->size = size; }
524 
525     void setAux(void *user)                                { this->aux0 = user; }
526     // don't use any other aux!
527 
528 public: //getters
529     const char *getName()   const                          { return this->name; }
530     const char *getLabel()  const                          { return this->label; }
531     const char *getFormat() const                          { return this->format; }
532 
533     const void *getBlob()   const                          { return this->blob; }
534     int getBlobLen() const                                 { return this->bloblen; }
535     int getSize() const                                    { return this->size; }
536 
537     void *getAux() const                                   { return this->aux0; }
538 
539 public: //tests
540     bool isNameMatch(const char *otherName) const          { return !strcmp(getName(), otherName); }
541     bool isNameMatch(const std::string &otherName) const   { return getName() == otherName; }
542 
543     bool isLabelMatch(const char *otherLabel) const        { return !strcmp(getLabel(), otherLabel); }
544     bool isLabelMatch(const std::string &otherLabel) const { return getLabel() == otherLabel; }
545 
546 public:
547     void fill(const char *name, const char *label, const char *format)
548     ; /* outside implementation - only driver side, see indipropertyview_driver.cpp */
549 
550     void fill(const std::string &name, const std::string &label, const std::string &format)
551     { fill(name.c_str(), label.c_str(), format.c_str()); }
552 };
553 
554 
555 
556 
557 /* outside implementation */
558 template <typename T>
559 inline PropertyView<T>::PropertyView()
560 { memset(this, 0, sizeof(*this)); }
561 
562 template <typename T>
563 inline void PropertyView<T>::setDeviceName(const char *name)
564 { strncpy(this->device, name, MAXINDIDEVICE); }
565 
566 template <typename T>
567 inline void PropertyView<T>::setDeviceName(const std::string &name)
568 { setDeviceName(name.data()); }
569 
570 template <typename T>
571 inline void PropertyView<T>::setName(const char *name)
572 { strncpy(this->name, name, MAXINDINAME); }
573 
574 template <typename T>
575 inline void PropertyView<T>::setName(const std::string &name)
576 { setName(name.data()); }
577 
578 template <typename T>
579 inline void PropertyView<T>::setLabel(const char *label)
580 { strncpy(this->label, label, MAXINDILABEL); }
581 
582 template <typename T>
583 inline void PropertyView<T>::setLabel(const std::string &label)
584 { setLabel(label.data()); }
585 
586 template <typename T>
587 inline void PropertyView<T>::setGroupName(const char *name)
588 { strncpy(this->group, name, MAXINDIGROUP); }
589 
590 template <typename T>
591 inline void PropertyView<T>::setGroupName(const std::string &name)
592 { setGroupName(name.data()); }
593 
594 template <typename T>
595 inline void PropertyView<T>::setState(IPState state)
596 { this->s = state; }
597 
598 template <typename T>
599 inline void PropertyView<T>::setTimestamp(const char *timestamp)
600 { strncpy(this->timestamp, timestamp, MAXINDITSTAMP); }
601 
602 template <typename T>
603 inline void PropertyView<T>::setTimestamp(const std::string &timestamp)
604 { setTimestamp(timestamp.data()); }
605 
606 template <typename T>
607 template <size_t N>
608 inline void PropertyView<T>::setWidgets(WidgetType (&w)[N])
609 { setWidgets(static_cast<WidgetType*>(w), N); }
610 
611 template <typename T>
612 inline void PropertyView<T>::setAux(void *user)
613 { this->aux = user; }
614 
615 template <>
616 inline void PropertyView<IText>::save(FILE *f) const
617 { IUSaveConfigText(f, this); }
618 
619 template <>
620 inline void PropertyView<INumber>::save(FILE *f) const
621 { IUSaveConfigNumber(f, this); }
622 
623 template <>
624 inline void PropertyView<ISwitch>::save(FILE *f) const
625 { IUSaveConfigSwitch(f, this); }
626 
627 template <>
628 inline void PropertyView<ILight>::save(FILE *f) const
629 { (void)f; /* IUSaveConfigLight(f, this); */ }
630 
631 template <>
632 inline void PropertyView<IBLOB>::save(FILE *f) const
633 { IUSaveConfigBLOB(f, this); }
634 
635 template <typename T>
636 inline void PropertyView<T>::setTimeout(double timeout)
637 { this->timeout = timeout; }
638 
639 template <>
640 inline void PropertyView<ILight>::setTimeout(double)
641 { }
642 
643 template <typename T>
644 inline void PropertyView<T>::setPermission(IPerm permission)
645 { this->p = permission; }
646 
647 template <>
648 inline void PropertyView<ILight>::setPermission(IPerm)
649 { }
650 
651 template <typename T>
652 inline void PropertyView<T>::setRule(ISRule)
653 { }
654 
655 template <>
656 inline void PropertyView<ISwitch>::setRule(ISRule rule)
657 { this->r = rule; }
658 
659 template <typename T>
660 inline bool PropertyView<T>::setRule(const std::string &)
661 { return false; }
662 
663 template <>
664 inline bool PropertyView<ISwitch>::setRule(const std::string &rule)
665 { return crackISRule(rule.data(), &this->r) == 0; }
666 
667 template <typename T>
668 inline WidgetView<T> *PropertyView<T>::findWidgetByName(const char *) const
669 { return nullptr; }
670 
671 template <>
672 inline WidgetView<IText> *PropertyView<IText>::findWidgetByName(const char *name) const
673 { return static_cast<WidgetView<IText> *>(IUFindText(this, name)); }
674 
675 template <>
676 inline WidgetView<INumber> *PropertyView<INumber>::findWidgetByName(const char *name) const
677 { return static_cast<WidgetView<INumber> *>(IUFindNumber(this, name)); }
678 
679 template <>
680 inline WidgetView<ISwitch> *PropertyView<ISwitch>::findWidgetByName(const char *name) const
681 { return static_cast<WidgetView<ISwitch> *>(IUFindSwitch(this, name)); }
682 
683 template <>
684 inline WidgetView<ILight> *PropertyView<ILight>::findWidgetByName(const char *name) const
685 { return static_cast<WidgetView<ILight> *>(IUFindLight(this, name)); }
686 
687 template <>
688 inline WidgetView<IBLOB> *PropertyView<IBLOB>::findWidgetByName(const char *name) const
689 { return static_cast<WidgetView<IBLOB> *>(IUFindBLOB(this, name)); }
690 
691 template <typename T>
692 inline IPerm PropertyView<T>::getPermission() const
693 { return this->p; }
694 
695 template <>
696 inline IPerm PropertyView<ILight>::getPermission() const
697 { return IP_RO; }
698 
699 template <typename T>
700 inline ISRule PropertyView<T>::getRule() const
701 { return ISR_NOFMANY; }
702 
703 template <>
704 inline ISRule PropertyView<ISwitch>::getRule() const
705 { return this->r; }
706 
707 template <typename T>
708 inline double PropertyView<T>::getTimeout() const
709 { return this->timeout; }
710 
711 template <>
712 inline double PropertyView<ILight>::getTimeout() const
713 { return 0; }
714 
715 template <>
716 inline void PropertyView<IText>::setWidgets(WidgetType *w, size_t size)
717 { this->tp = w; this->ntp = size; }
718 
719 template <>
720 inline void PropertyView<INumber>::setWidgets(WidgetType *w, size_t size)
721 { this->np = w; this->nnp = size; }
722 
723 template <>
724 inline void PropertyView<ISwitch>::setWidgets(WidgetType *w, size_t size)
725 { this->sp = w; this->nsp = size; }
726 
727 template <>
728 inline void PropertyView<ILight>::setWidgets(WidgetType *w, size_t size)
729 { this->lp = w; this->nlp = size; }
730 
731 template <>
732 inline void PropertyView<IBLOB>::setWidgets(WidgetType *w, size_t size)
733 { this->bp = w; this->nbp = size; }
734 
735 template <>
736 inline int PropertyView<IText>::count() const
737 { return this->ntp; }
738 
739 template <>
740 inline int PropertyView<INumber>::count() const
741 { return this->nnp; }
742 
743 template <>
744 inline int PropertyView<ISwitch>::count() const
745 { return this->nsp; }
746 
747 template <>
748 inline int PropertyView<ILight>::count() const
749 { return this->nlp; }
750 
751 template <>
752 inline int PropertyView<IBLOB>::count() const
753 { return this->nbp; }
754 
755 template <>
756 inline PropertyView<IText>::WidgetType *PropertyView<IText>::widget() const
757 { return static_cast<WidgetType*>(this->tp); }
758 
759 template <>
760 inline PropertyView<INumber>::WidgetType *PropertyView<INumber>::widget() const
761 { return static_cast<WidgetType*>(this->np); }
762 
763 template <>
764 inline PropertyView<ISwitch>::WidgetType *PropertyView<ISwitch>::widget() const
765 { return static_cast<WidgetType*>(this->sp); }
766 
767 template <>
768 inline PropertyView<ILight>::WidgetType *PropertyView<ILight>::widget() const
769 { return static_cast<WidgetType*>(this->lp); }
770 
771 template <>
772 inline PropertyView<IBLOB>::WidgetType *PropertyView<IBLOB>::widget() const
773 { return static_cast<WidgetType*>(this->bp); }
774 
775 }
776