| 1 | // ************************************************************************** | 
|---|
| 2 | /** @class EventImp | 
|---|
| 3 |  | 
|---|
| 4 | @brief A general base-class describing events issues in a state machine | 
|---|
| 5 |  | 
|---|
| 6 | @section General purpose | 
|---|
| 7 |  | 
|---|
| 8 | The general purpose of this class is to describe an event which can | 
|---|
| 9 | occur in one of our StateMachines. It provides pointers to data | 
|---|
| 10 | associated with the event, a target state and stores the states in which | 
|---|
| 11 | issuing this event is allowed. The target state might be negative to | 
|---|
| 12 | describe that no transition of the state is requested. | 
|---|
| 13 |  | 
|---|
| 14 | Such an event canjust be a description of an event, but can also be | 
|---|
| 15 | an issued event which already contain data. | 
|---|
| 16 |  | 
|---|
| 17 | The format can, but need not, contain the format of the data area. | 
|---|
| 18 | As a rule, it should follow the format also used in the DIM network. | 
|---|
| 19 |  | 
|---|
| 20 |  | 
|---|
| 21 | @section Assigning functions to an event | 
|---|
| 22 |  | 
|---|
| 23 | To any event a function call can be assigned. Thanks to boost::bind there | 
|---|
| 24 | are various and different very powerful ways to do that. | 
|---|
| 25 |  | 
|---|
| 26 | The function assigned with AssignFunction must return int. When it is | 
|---|
| 27 | executed it is given a const reference of the current event as an argument, | 
|---|
| 28 | i.e. if you want to get such a reference in your function, you can reference | 
|---|
| 29 | it using the placeholder _1. (Remark: it is allowe to omit the _1 placeholder | 
|---|
| 30 | if no reference to the EventImp object is needed) | 
|---|
| 31 |  | 
|---|
| 32 | A few examples: | 
|---|
| 33 |  | 
|---|
| 34 | \code | 
|---|
| 35 | int function(const EventImp &evt, int i, const char *txt) { return i; } | 
|---|
| 36 |  | 
|---|
| 37 | EventImp evt; | 
|---|
| 38 | evt.AssignFunction(boost::bind(function, _1, 7, "hallo")); | 
|---|
| 39 | cout << evt.Exec() << endl; | 
|---|
| 40 | // 7 | 
|---|
| 41 | \endcode | 
|---|
| 42 |  | 
|---|
| 43 | When the function is executed later via ExecFunc() in will get a reference | 
|---|
| 44 | to the executing EventImp as its first argument (indicated by '_1'), it will | 
|---|
| 45 | get 7 and "hallo" as second and third argument. | 
|---|
| 46 |  | 
|---|
| 47 | \code | 
|---|
| 48 | int function(int i, const char *txt, const EventImp &evt) { return i; } | 
|---|
| 49 |  | 
|---|
| 50 | EventImp evt; | 
|---|
| 51 | evt.AssignFunction(boost::bind(function, 7, "hallo", _1)); | 
|---|
| 52 | cout << evt.Exec() << endl; | 
|---|
| 53 | // 7 | 
|---|
| 54 | \endcode | 
|---|
| 55 |  | 
|---|
| 56 | Is the same example than the one above, but the arguments are in a different | 
|---|
| 57 | order. | 
|---|
| 58 |  | 
|---|
| 59 | \code | 
|---|
| 60 | class A | 
|---|
| 61 | { | 
|---|
| 62 | int function(const EventImp &evt, int i, const char *txt) | 
|---|
| 63 | { | 
|---|
| 64 | cout << this << endl; return i; | 
|---|
| 65 | } | 
|---|
| 66 | }; | 
|---|
| 67 |  | 
|---|
| 68 | A a; | 
|---|
| 69 |  | 
|---|
| 70 | EventImp evt; | 
|---|
| 71 | evt.AssignFunction(boost::bind(&A::function, &a, _1, 7, "hallo")); | 
|---|
| 72 | cout << evt.Exec() << endl; | 
|---|
| 73 | // &a | 
|---|
| 74 | // 7 | 
|---|
| 75 | \endcode | 
|---|
| 76 |  | 
|---|
| 77 | The advanatge of boost::bind is that it also works for member functions | 
|---|
| 78 | of classes. In this case the first argument after the function-pointer | 
|---|
| 79 | \b must be a pointer to a valid class-object. This can also be \em this | 
|---|
| 80 | if called from within a class object. | 
|---|
| 81 |  | 
|---|
| 82 | Also note that everything (as usual) which is not a reference is copied | 
|---|
| 83 | when the bind function is invoked. If you want to distribute a reference | 
|---|
| 84 | instead use ref(something), like | 
|---|
| 85 |  | 
|---|
| 86 | \code | 
|---|
| 87 | int function(int &i)  { return i; } | 
|---|
| 88 |  | 
|---|
| 89 | int j = 5; | 
|---|
| 90 | EventImp evt; | 
|---|
| 91 | evt.AssignFunction(bind(function, ref(j)); | 
|---|
| 92 | j = 7; | 
|---|
| 93 | cout << evt.Exec() << endl; | 
|---|
| 94 | // 7 | 
|---|
| 95 | \endcode | 
|---|
| 96 |  | 
|---|
| 97 | Note, that you are responsible for the validity, that means: Do not | 
|---|
| 98 | destroy your object (eg. reference to j) while bind might still be called | 
|---|
| 99 | later, or a pointer to \em this. | 
|---|
| 100 |  | 
|---|
| 101 | @section References | 
|---|
| 102 | - <A HREF="http://www.boost.org/doc/libs/1_45_0/libs/bind/bind.html">boost::bind (V1.45.0)</A> | 
|---|
| 103 |  | 
|---|
| 104 | @todo | 
|---|
| 105 | Add link to DIM format | 
|---|
| 106 |  | 
|---|
| 107 | */ | 
|---|
| 108 | // ************************************************************************** | 
|---|
| 109 | #include "EventImp.h" | 
|---|
| 110 |  | 
|---|
| 111 | #include <sstream> | 
|---|
| 112 |  | 
|---|
| 113 | #include "Time.h" | 
|---|
| 114 | #include "WindowLog.h" | 
|---|
| 115 | #include "Description.h" | 
|---|
| 116 |  | 
|---|
| 117 | using namespace std; | 
|---|
| 118 |  | 
|---|
| 119 | // -------------------------------------------------------------------------- | 
|---|
| 120 | // | 
|---|
| 121 | //! Copy the contents of an EventImp (fTargetState, fAllowedStates and | 
|---|
| 122 | //!  fFunction) | 
|---|
| 123 | // | 
|---|
| 124 | EventImp::EventImp(const EventImp &cmd) : | 
|---|
| 125 | fTargetState(cmd.fTargetState), fAllowedStates(cmd.fAllowedStates), | 
|---|
| 126 | fFunction(cmd.fFunction) | 
|---|
| 127 | { | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | // -------------------------------------------------------------------------- | 
|---|
| 131 | // | 
|---|
| 132 | //! If the state is 0 or positive add it to fAllowedStates | 
|---|
| 133 | //! | 
|---|
| 134 | //! @param state | 
|---|
| 135 | //!     The state which should be added | 
|---|
| 136 | // | 
|---|
| 137 | void EventImp::AddAllowedState(int state) | 
|---|
| 138 | { | 
|---|
| 139 | if (state>=0) | 
|---|
| 140 | fAllowedStates.push_back(state); | 
|---|
| 141 | } | 
|---|
| 142 |  | 
|---|
| 143 | // -------------------------------------------------------------------------- | 
|---|
| 144 | // | 
|---|
| 145 | //! Add all states in the string to fAllowedStates. | 
|---|
| 146 | //! | 
|---|
| 147 | //! @param states | 
|---|
| 148 | //!    A string containing the states. They can either be separated by | 
|---|
| 149 | //!    whitespaces or commas, e.g. "1 2 3 4" or "1, 7, 9, 10". Note that | 
|---|
| 150 | //!    no real consistency check is done. | 
|---|
| 151 | // | 
|---|
| 152 | void EventImp::AddAllowedStates(const char *states) | 
|---|
| 153 | { | 
|---|
| 154 | stringstream stream(states); | 
|---|
| 155 |  | 
|---|
| 156 | const bool sep = stream.str().find(',')==string::npos; | 
|---|
| 157 |  | 
|---|
| 158 | string buffer; | 
|---|
| 159 | while (getline(stream, buffer, sep ? ' ' : ',')) | 
|---|
| 160 | AddAllowedState(stoi(buffer)); | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | // -------------------------------------------------------------------------- | 
|---|
| 164 | // | 
|---|
| 165 | //! Return whether the given state is in the list of allowed states. | 
|---|
| 166 | //! | 
|---|
| 167 | //! @param state | 
|---|
| 168 | //!    The state to look for in fAllowedStates | 
|---|
| 169 | //! | 
|---|
| 170 | //! @returns | 
|---|
| 171 | //!    If the given state is negative returns false. If the list of allowed | 
|---|
| 172 | //!    states is empty return true. Otherwise return whether the state | 
|---|
| 173 | //!    is found in fAllowedList or not. | 
|---|
| 174 | // | 
|---|
| 175 | bool EventImp::IsStateAllowed(int state) const | 
|---|
| 176 | { | 
|---|
| 177 | // States with negative values are internal states and are | 
|---|
| 178 | // never allowed | 
|---|
| 179 | if (state<0) | 
|---|
| 180 | return false; | 
|---|
| 181 |  | 
|---|
| 182 | // In case no allowed state is explicitly set | 
|---|
| 183 | // all positive states are allowed | 
|---|
| 184 | if (fAllowedStates.size()==0) | 
|---|
| 185 | return true; | 
|---|
| 186 |  | 
|---|
| 187 | return find(fAllowedStates.begin(), fAllowedStates.end(), state)!=fAllowedStates.end(); | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | // -------------------------------------------------------------------------- | 
|---|
| 191 | // | 
|---|
| 192 | //! @returns the event data converted to a std::string. Trailing redundant | 
|---|
| 193 | //!          \0's are removed. | 
|---|
| 194 | //! | 
|---|
| 195 | string EventImp::GetString() const | 
|---|
| 196 | { | 
|---|
| 197 | size_t s = GetSize()-1; | 
|---|
| 198 | while (s>0 && GetText()[s]==0) | 
|---|
| 199 | s--; | 
|---|
| 200 |  | 
|---|
| 201 | return std::string(GetText(), s+1); | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | // -------------------------------------------------------------------------- | 
|---|
| 205 | // | 
|---|
| 206 | //! Print the contents of the event to the given stream. | 
|---|
| 207 | //! | 
|---|
| 208 | //! @param out | 
|---|
| 209 | //!    An ostream to which the output should be redirected. | 
|---|
| 210 | //! | 
|---|
| 211 | //! @param strip | 
|---|
| 212 | //!    defines whether a possible SERVER name in the event name | 
|---|
| 213 | //!    should be stripped or not. | 
|---|
| 214 | //! | 
|---|
| 215 | void EventImp::Print(ostream &out, bool strip) const | 
|---|
| 216 | { | 
|---|
| 217 | out << " \xc2\xb7 "; | 
|---|
| 218 |  | 
|---|
| 219 | const string str = GetName(); | 
|---|
| 220 | if (!str.empty()) | 
|---|
| 221 | out << kBold << str.substr(strip?str.find_first_of('/')+1:0); | 
|---|
| 222 |  | 
|---|
| 223 | const string fmt = GetFormat(); | 
|---|
| 224 | if (!fmt.empty()) | 
|---|
| 225 | out << kBold << "[" << fmt << "]"; | 
|---|
| 226 |  | 
|---|
| 227 | vector<Description> v = Description::SplitDescription(GetDescription()); | 
|---|
| 228 |  | 
|---|
| 229 | if (!GetDescription().empty()) | 
|---|
| 230 | { | 
|---|
| 231 | for (vector<Description>::const_iterator j=v.begin()+1; | 
|---|
| 232 | j!=v.end(); j++) | 
|---|
| 233 | out << " <" << j->name << ">"; | 
|---|
| 234 | } | 
|---|
| 235 |  | 
|---|
| 236 | out << kReset << ":"; | 
|---|
| 237 |  | 
|---|
| 238 | for (unsigned int i=0; i<fAllowedStates.size(); i++) | 
|---|
| 239 | out << " " << fAllowedStates[i]; | 
|---|
| 240 |  | 
|---|
| 241 | if (fTargetState<0) | 
|---|
| 242 | out << " [conf]"; | 
|---|
| 243 | else | 
|---|
| 244 | out << " [trans->" << fTargetState << "]"; | 
|---|
| 245 |  | 
|---|
| 246 | const Time tm = GetTime(); | 
|---|
| 247 |  | 
|---|
| 248 | const bool t = tm!=Time::None && tm!=Time(1970,1,1); | 
|---|
| 249 | const bool s = GetSize()>0; | 
|---|
| 250 |  | 
|---|
| 251 | if (s || t) | 
|---|
| 252 | out << "("; | 
|---|
| 253 | if (t) | 
|---|
| 254 | out << tm.GetAsStr("%H:%M:%S.%f"); | 
|---|
| 255 | if (s && t) | 
|---|
| 256 | out << "/"; | 
|---|
| 257 | if (s) | 
|---|
| 258 | out << "size=" << GetSize(); | 
|---|
| 259 | if (s || t) | 
|---|
| 260 | out << ")"; | 
|---|
| 261 | out << endl; | 
|---|
| 262 |  | 
|---|
| 263 | if (GetDescription().empty()) | 
|---|
| 264 | return; | 
|---|
| 265 |  | 
|---|
| 266 | out << "      " << v[0].comment << endl; | 
|---|
| 267 |  | 
|---|
| 268 | for (vector<Description>::const_iterator j=v.begin()+1; | 
|---|
| 269 | j!=v.end(); j++) | 
|---|
| 270 | { | 
|---|
| 271 | out << "      " << kGreen << j->name; | 
|---|
| 272 | if (!j->comment.empty()) | 
|---|
| 273 | out << kReset << ": " << kBlue << j->comment; | 
|---|
| 274 | if (!j->unit.empty()) | 
|---|
| 275 | out << kYellow << " [" << j->unit << "]"; | 
|---|
| 276 | out << endl; | 
|---|
| 277 | } | 
|---|
| 278 | } | 
|---|
| 279 |  | 
|---|
| 280 | // -------------------------------------------------------------------------- | 
|---|
| 281 | // | 
|---|
| 282 | //! Calls Print(std::cout) | 
|---|
| 283 | //! | 
|---|
| 284 | //! @param strip | 
|---|
| 285 | //!    defines whether a possible SERVER name in the event name | 
|---|
| 286 | //!    should be stripped or not. | 
|---|
| 287 | // | 
|---|
| 288 | void EventImp::Print(bool strip) const | 
|---|
| 289 | { | 
|---|
| 290 | Print(cout, strip); | 
|---|
| 291 | } | 
|---|