libqi-api  release-2.5.3-2016-11-18
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
proxyproperty.hpp
Go to the documentation of this file.
1 #pragma once
2 /*
3 ** Copyright (C) 2013 Aldebaran Robotics
4 ** See COPYING for the license
5 */
6 
7 #ifndef _QI_TYPE_PROXYPROPERTY_HPP_
8 #define _QI_TYPE_PROXYPROPERTY_HPP_
9 
10 #include <qi/log.hpp>
11 #include <qi/property.hpp>
12 #include <qi/anyfunction.hpp>
13 
14 
15 namespace qi
16 {
21  template < typename T, template< class...> class PropertyType = Property >
22  class ProxyProperty: public PropertyType<T>
23  {
24  public:
28  /* The signal bounce code is completely duplicated from SignalProxy.
29  * Unfortunately factoring this is not trivial:
30  * onSubscribe needs to be passed to Signal constructor, and we want to keep
31  * it that way.
32  */
33  ProxyProperty(AnyObject object, const std::string& propertyName)
34  {
35  setup(object, propertyName);
36  }
37  void setup(AnyObject object, const std::string& propertyName);
39  void onSubscribe(bool enable, GenericObject* object, const std::string& propertyName, SignalLink link);
41  void triggerOverride(const GenericFunctionParameters& params, MetaCallType, GenericObject* object, const std::string& propertyName);
42  private:
43  T getter(GenericObject* object, const std::string& propertyName);
44  bool setter(T&, const T&, GenericObject* object, const std::string& propertyName);
45  };
46 
47  template<typename T, template< class...> class PropertyType>
48  void makeProxyProperty(PropertyType<T>& target, AnyObject object, const std::string& signalName)
49  {
50  ProxyProperty<T, PropertyType>& proxy = static_cast<ProxyProperty<T, PropertyType> &>(target);
51  proxy.setup(object, signalName);
52  }
53  template<typename T, template< class...> class PropertyType>
54  void makeProxyProperty(ProxyProperty<T, PropertyType>& target, AnyObject object, const std::string& signalName)
55  {
56  target.setup(object, signalName);
57  }
58 
59  template<typename T, template< class...> class PropertyType>
61  {
62  SignalType::disconnectAll();
63  }
64 
65  template<typename T, template< class...> class PropertyType>
66  void ProxyProperty<T, PropertyType>::setup(AnyObject object, const std::string& propertyName)
67  {
68  // signal part
69  SignalBase::setOnSubscribers(boost::bind(&ThisProxyType::onSubscribe, this, _1,
70  object.asGenericObject(), propertyName, SignalBase::invalidSignalLink));
71  SignalBase::setTriggerOverride(boost::bind(&ThisProxyType::triggerOverride, this, _1, _2,
72  object.asGenericObject(), propertyName));
73 
74  // property part
75  this->_getter = boost::bind(&ThisProxyType::getter, this, object.asGenericObject(), propertyName);
76  this->_setter = boost::bind(&ThisProxyType::setter, this, _1, _2, object.asGenericObject(), propertyName);
77  }
78 
79  template<typename T, template< class...> class PropertyType>
80  void ProxyProperty<T, PropertyType>::onSubscribe(bool enable, GenericObject* object, const std::string& propertyName, SignalLink link)
81  {
82  if (enable)
83  {
84  link = object->connect(propertyName,
86  AnyFunction::fromDynamicFunction(boost::bind(&ThisProxyType::bounceEvent, this, _1))
87  ));
88  }
89  else
90  {
91  bool ok = !object->disconnect(link).hasError();
92  if (!ok)
93  qiLogError("qitype.proxysignal") << "Failed to disconnect from parent signal";
95  }
96  // rebind onSubscribe since link changed
97  SignalBase::setOnSubscribers(boost::bind(&ThisProxyType::onSubscribe, this, _1,
98  object, propertyName, link));
99  }
100 
101  template<typename T, template< class...> class PropertyType>
103  {
104  // Receive notify from backend, trigger on our signal, bypassing our trigger overload
105  SignalType::callSubscribers(args);
106  return AnyReference(typeOf<void>());
107  }
108 
109  template<typename T, template< class...> class PropertyType>
111  GenericObject* object, const std::string& propertyName)
112  {
113  // Just forward to backend, which will notify us in bouceEvent(),
114  // and then we will notify our local Subscribers
115  object->metaPost(propertyName, params);
116  }
117  template<typename T, template< class...> class PropertyType>
118  T ProxyProperty<T, PropertyType>::getter(GenericObject* object, const std::string& propertyName)
119  {
120  return object->property<T>(propertyName);
121  }
122  template<typename T, template< class...> class PropertyType>
123  bool ProxyProperty<T, PropertyType>::setter(T& target, const T& v, GenericObject* object, const std::string& propertyName)
124  {
125  // no need to fill target it's never used since we have a getter
126  object->setProperty(propertyName, v).value(); // throw on remote error
127  // Prevent local subscribers from being called
128  return false;
129  }
130 }
131 #endif // _QITYPE_PROXYPROPERTY_HPP_
ProxyProperty(AnyObject object, const std::string &propertyName)
void onSubscribe(bool enable, GenericObject *object, const std::string &propertyName, SignalLink link)
static const SignalLink invalidSignalLink
Definition: signal.hpp:103
void setOnSubscribers(OnSubscribers onSubscribers)
AnyReference bounceEvent(const AnyReferenceVector args)
void setTriggerOverride(Trigger trigger)
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:112
void makeProxyProperty(PropertyType< T > &target, AnyObject object, const std::string &signalName)
void setup(AnyObject object, const std::string &propertyName)
std::vector< AnyReference > AnyReferenceVector
void triggerOverride(const GenericFunctionParameters &params, MetaCallType, GenericObject *object, const std::string &propertyName)
MetaCallType
Definition: typeobject.hpp:21
static AnyFunction fromDynamicFunction(DynamicFunction f)
Convenient log macro.
qi::uint64_t SignalLink
Definition: signal.hpp:35
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:327