00001 /* 00002 libwt - Vassilis Virvilis Toolkit - a widget library 00003 Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the 00017 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, SA. 00019 */ 00020 00021 #ifndef WT_WVAR_H 00022 #define WT_WVAR_H 00023 00024 #include <boost/lexical_cast.hpp> 00025 00026 #include <wt/wsignal.h> 00027 00028 namespace Wt { 00029 00030 /// Watched variable avoids the need for get/set methods 00031 /*! 00032 A WVar watched variable is a templated attempt to 00033 vanquish the get set methods that accompanies object oriented 00034 programming. 00035 00036 \note The WVar class is good only for arithmetic (builtin) 00037 types and not generic classes due to c++'s C ish background. Maybe 00038 later we will build a WClass class. The problem is that WVar has 00039 a value of VARTYPE instead of inheriting from VARTYPE. This has 00040 the ugly effect that VARTYPE's members cannot be accessed through 00041 WVar without ugly casts, and of course in C++ is not possible to 00042 inherit from builtin types (int, bool) etc. 00043 00044 A WVar variable can be read through the cast operator and 00045 be written through the assign operator. The WVar variable 00046 emits a signal when it is about to change, after it 00047 has been changed, and when it is accessed for read. 00048 00049 if a slot from the ones that are called during aboutToChange 00050 returns true then the change is aborted. 00051 00052 A WVar variable can be publically read/write or protected. The 00053 default is to be publically read/write. If you do not wish for 00054 your variable to be publically readable just make your damn 00055 variable protected/private. 00056 00057 WVar<int> a is a read/write int variable. 00058 WVar<int, C> a is a publically readable and read/write for class C. 00059 00060 Example: 00061 see test/vars.c 00062 */ 00063 00064 template<typename VARTYPE> 00065 class WVarBase : public sigc::trackable { 00066 protected: 00067 /// Marshaler 00068 class Blocker { 00069 public: 00070 typedef bool result_type; 00071 template<typename T_iterator> 00072 result_type operator()(T_iterator first, T_iterator last) const { 00073 for (; first != last; ++first) 00074 if (*first) 00075 return true; 00076 return false; 00077 } 00078 }; 00079 00080 class OverideValue { 00081 public: 00082 OverideValue(bool valid_ = false, const VARTYPE& value_ = VARTYPE()) 00083 : valid_(valid_), 00084 value_(value_) {} 00085 00086 OverideValue& operator=(VARTYPE v) { 00087 valid_ = true; 00088 value_ = v; 00089 return *this; 00090 } 00091 00092 bool isValid() const { 00093 return valid_; 00094 } 00095 00096 VARTYPE value() const { 00097 return value_; 00098 } 00099 00100 private: 00101 bool valid_; 00102 VARTYPE value_; 00103 }; 00104 00105 typedef std::pair<bool, VARTYPE> ValidValue; 00106 /// Marshaler to override all values but the last 00107 class Overrider { 00108 public: 00109 typedef OverideValue result_type; 00110 template<typename T_iterator> 00111 result_type operator()(T_iterator first, T_iterator last) const { 00112 OverideValue result(false, VARTYPE()); 00113 for (; first != last; ++first) { 00114 result = (*first); 00115 } 00116 return result; 00117 } 00118 }; 00119 00120 /// avoids emitting read signal 00121 const VARTYPE& getValue() const { 00122 return value_; 00123 } 00124 00125 /// avoids emitting aboutToChange, changed signal 00126 void setValue(const VARTYPE & value) { 00127 value_ = value; 00128 } 00129 00130 WVarBase& operator=(VARTYPE value) { 00131 if (!aboutToChange.emit(value, value_)) { 00132 VARTYPE old(value_); 00133 setValue(value); 00134 changed.emit(value, old); 00135 } 00136 return *this; 00137 } 00138 00139 WVarBase& operator=(const WVarBase& value) { 00140 *this = static_cast<VARTYPE>(value); 00141 return *this; 00142 } 00143 00144 private: 00145 VARTYPE value_; 00146 00147 public: 00148 class RW { 00149 public: 00150 }; 00151 00152 WVarBase(VARTYPE value = 0) { 00153 value_ = value; 00154 } 00155 00156 Signal012M<bool, VARTYPE, VARTYPE, Blocker> aboutToChange; 00157 Signal012<void, VARTYPE, VARTYPE> changed; 00158 mutable Signal01<void, VARTYPE> read; 00159 mutable sigc::signal1<VARTYPE, VARTYPE, Overrider> override; 00160 00161 VARTYPE readValue() const { 00162 read.emit(value_); 00163 const OverideValue v = override.emit(value_); 00164 return (v.isValid()) ? v.value() : value_; 00165 } 00166 00167 ///\todo get, set and other they should really 00168 ///use const& where possible 00169 00170 /// usefull for overrides and variables connection 00171 VARTYPE get 00172 (VARTYPE ) const { 00173 return readValue(); 00174 } 00175 00176 void set 00177 (VARTYPE value) { 00178 *this = value; 00179 } 00180 00181 /// connect as a proxy to another WVar 00182 void connect(WVarBase& var) { 00183 // set the real variable to the proxy value 00184 var = getValue(); 00185 00186 changed.connect( 00187 sigc::slot1<void, VARTYPE>( 00188 sigc::mem_fun(var, &WVarBase::set 00189 ))); 00190 00191 override.connect(sigc::mem_fun(var, &WVarBase::get 00192 )); 00193 } 00194 00195 operator VARTYPE() const { 00196 return readValue(); 00197 } 00198 00199 operator const std::string() const { 00200 return boost::lexical_cast<std::string>(readValue()); 00201 } 00202 00203 WVarBase& operator+=(const VARTYPE& value) { 00204 if (value) { 00205 *this = getValue() + value; 00206 } 00207 return *this; 00208 } 00209 00210 WVarBase& operator-=(const VARTYPE & value) { 00211 if (value) { 00212 *this = getValue() - value; 00213 } 00214 return *this; 00215 } 00216 00217 /// prefix operator 00218 WVarBase& operator++() { 00219 VARTYPE other(*this); 00220 ++other; 00221 *this = other; 00222 return *this; 00223 } 00224 00225 WVarBase& operator--() { 00226 VARTYPE other(*this); 00227 --other; 00228 *this = other; 00229 return *this; 00230 } 00231 00232 /// postfix operator 00233 WVarBase& operator++(int) { 00234 VARTYPE other(*this); 00235 other++; 00236 *this = other; 00237 return *this; 00238 } 00239 00240 WVarBase& operator--(int) { 00241 VARTYPE other(*this); 00242 other--; 00243 *this = other; 00244 return *this; 00245 } 00246 }; 00247 00248 #define OPERATORS \ 00249 WVar& operator=(const VARTYPE & value) {\ 00250 return static_cast<WVar &>(WVarBase<VARTYPE>::operator=(value));\ 00251 }\ 00252 \ 00253 WVar& operator=(const WVarBase<VARTYPE>& value) {\ 00254 return static_cast<WVar &>(WVarBase<VARTYPE>::operator=(value));\ 00255 }\ 00256 \ 00257 WVar& operator+=(const VARTYPE & value) {\ 00258 return static_cast<WVar &>(WVarBase<VARTYPE>::operator+=(value));\ 00259 }\ 00260 \ 00261 WVar& operator-=(const VARTYPE & value) {\ 00262 return static_cast<WVar &>(WVarBase<VARTYPE>::operator-=(value));\ 00263 }\ 00264 \ 00265 WVar& operator++() {\ 00266 return static_cast<WVar &>(WVarBase<VARTYPE>::operator++());\ 00267 }\ 00268 \ 00269 WVar& operator--() {\ 00270 return static_cast<WVar &>(WVarBase<VARTYPE>::operator--());\ 00271 }\ 00272 \ 00273 WVar& operator++(int) {\ 00274 return static_cast<WVar &>(WVarBase<VARTYPE>::operator++(0));\ 00275 }\ 00276 \ 00277 WVar& operator--(int) {\ 00278 return static_cast<WVar &>(WVarBase<VARTYPE>::operator--(0));\ 00279 } 00280 00281 /// read only 00282 template<typename VARTYPE, typename PARENT = WVarBase<int>::RW> 00283 class WVar : public WVarBase<VARTYPE> { 00284 public: 00285 WVar(VARTYPE value = 0) 00286 : WVarBase<VARTYPE>(value) {} 00287 00288 protected: 00289 OPERATORS 00290 00291 // this wrapper bullshit here is required because g++ does 00292 // not compile the following simple statement 00293 // friend class PARENT; 00294 #if 1 00295 class WrappedParent { 00296 public: 00297 typedef PARENT Parent; 00298 }; 00299 00300 friend class WrappedParent::Parent; 00301 #else 00302 00303 friend class PARENT; 00304 #endif 00305 00306 }; 00307 00308 /// read write specialization 00309 template<> 00310 template<typename VARTYPE> 00311 class WVar<VARTYPE, WVarBase<int>::RW> : public WVarBase<VARTYPE> { 00312 00313 public: 00314 WVar(VARTYPE value = 0) 00315 : WVarBase<VARTYPE>(value) {} 00316 00317 OPERATORS 00318 }; 00319 00320 } // namespace 00321 00322 #endif // WT_WVAR_H
This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.