]> Creatis software - crea.git/blob - src/creaMessageManager.h
Message manager can now be observed (to get messages) with a boost::signal/slot mecha...
[crea.git] / src / creaMessageManager.h
1
2 /*! \file
3  
4   \brief Class creaMessageManager and Macros for outputing messages in crea
5
6   There are 4 kinds of messages :
7   - Messages (normal messages)
8   - Debug messages (not compiled in release)
9   - Warnings 
10   - Errors
11   There are also "types" of messages which are strings which identify the nature of the message 
12   (for example : "Kernel" messages are generated by the core classes of the library, there can be a type of 
13   message for each type of Node, and so on...)
14   A type of message must be declared by registering it into the MessageManager. This is done by a line like :
15   crea::MessageManager::RegisterMessageType("Kernel","Messages generated by the core classes of the library",5);
16   where : 
17   -The first string is the type of the message (the category which will be used to generate a message of this type)
18   -The second string is help string
19   -The integer is the initial level for the messages of this type (see below).
20   
21   To generate a message of a known type then use one of the macros :
22   creaMessage, creaDebugMessage, creaWarning, creaError or their variants.
23
24   example :
25
26   creaMessage("Kernel",4,"problem with "<<GetName()<<creaendl);
27
28   will push the 3rd argument in std::cout if the message level of "Kernel" messages is greater or equal to 4.
29   which means that it generates a message of level 4 (0 : very important/always displayed ... 9 : deep debug message).
30
31   At run time, one is able to change the level of the messages displayed by using a command like :
32   
33   crea::MessageManager::SetMessageLevel("Kernel",5); 
34   
35   which tells the manager to display all Kernel messages of level up to 5.
36
37   Variants :
38
39   crea*Cont : continues a previous creaMessage on the same line (without rewriting the type and level)
40   crea*Inc / Dec : displays the message and then increments/decrement the messages tabulation 
41
42 */
43   //===========================================================
44   /**
45      \class crea::MessageManager
46      \brief Manages the messages displayed by crea
47   */
48
49
50 #ifndef __creaMessageManager_h__
51 #define __creaMessageManager_h__
52
53 // The do { } while(0) statement in macros is made to "swallow the semicolon" 
54 // see http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html#Swallowing-the-Semicolon
55
56 #include "creaSystem.h"
57 #include "creaRTTI.h" // for CREA_GET_CURRENT_OBJECT_NAME
58
59 #include <string>
60 #include <map>
61 #include <iostream>
62 #include <sstream>
63
64 // Comment out these symbols to prevent compilation 
65 //#define CREA_COMPILE_MESSAGES
66 //#define CREA_COMPILE_DEBUG_MESSAGES
67 //#define CREA_COMPILE_WARNING_MESSAGES
68 //#define CREA_COMPILE_ERROR_MESSAGES
69
70
71 #define creaOnMessageLevel(key,value)                   \
72   int __creaOnMessageLevelVariable =                    \
73     crea::MessageManager::GetMessageLevel(key);         \
74   if ( __creaOnMessageLevelVariable<0)                  \
75     {                                                   \
76       creaWarning("message type '"<<key<<"' unknown");  \
77     }                                                   \
78   else if (value<= __creaOnMessageLevelVariable) 
79
80 #ifdef CREA_PREPEND_MESSAGE_WITH_CODE
81 #define creaMessageCode                         \
82   key[0] << key[1] << key[2] << value << " "
83 #else 
84 #define creaMessageCode ""
85 #endif 
86
87 #ifdef CREA_PREPEND_MESSAGE_WITH_TAB
88 #define creaMessageTab                          \
89   crea::MessageManager::GetTab()
90 #else 
91 #define creaMessageTab ""
92 #endif
93
94 //#define CREA_PREPEND_MESSAGE_WITH_SPACE
95 #ifdef CREA_PREPEND_MESSAGE_WITH_SPACE
96 #define creaMessageSpace(value)                 \
97   crea::MessageManager::GetSpace(value)
98 #else 
99 #define creaMessageSpace(value) ""
100 #endif
101  
102
103 //===========================================================
104 #ifdef CREA_COMPILE_MESSAGES
105
106 // Macro for messages
107 #define creaMessage(key,value,MESSAGE)                  \
108   do {                                                  \
109     creaOnMessageLevel(key,value)                       \
110       {                                                 \
111         std::ostringstream s;                           \
112         s << creaMessageCode                            \
113           << creaMessageTab                             \
114           << creaMessageSpace(value)                    \
115           << MESSAGE;                                   \
116         crea::MessageManager::SendMessage(key,s.str()); \
117       }                                                 \
118   }                                                     \
119   while (0)
120
121 // Macro for continuing a message (when one wants to split the macro
122 // call into multiple lines)
123 #define creaMessageCont(key,value,MESSAGE)              \
124   do                                                    \
125     {                                                   \
126       creaOnMessageLevel(key,value)                     \
127         {                                               \
128         std::ostringstream s;                           \
129         s << MESSAGE;                                   \
130         crea::MessageManager::SendMessage(key,s.str()); \
131         }                                               \
132     }                                                   \
133   while (0)
134
135 #define creaMessageInc(key,value,MESSAGE)               \
136   do                                                    \
137     {                                                   \
138         std::ostringstream s;                           \
139         s << creaMessageCode                            \
140           << creaMessageTab                             \
141           << creaMessageSpace(value)                    \
142           << MESSAGE;                                   \
143         crea::MessageManager::SendMessage(key,s.str()); \
144         crea::MessageManager::IncTab();                 \
145         }                                               \
146     }                                                   \
147   while (0)
148
149 #define creaMessageDec(key,value,MESSAGE)                       \
150   do                                                            \
151     {                                                           \
152       creaOnMessageLevel(key,value)                             \
153         {                                                       \
154           crea::MessageManager::DecTab();                       \
155           std::ostringstream s;                                 \
156           s << creaMessageCode                                  \
157             << creaMessageTab                                   \
158             << creaMessageSpace(value)                          \
159             << MESSAGE;                                         \
160           crea::MessageManager::SendMessage(key,s.str());       \
161         }                                                       \
162     }                                                           \
163   while (0)
164
165 #define creaDecTab(key,value)                   \
166   do                                            \
167     {                                           \
168       creaOnMessageLevel(key,value)             \
169         {                                       \
170           crea::MessageManager::DecTab();       \
171         }                                       \
172     }                                           \
173   while (0)
174
175 #define creaIncTab(key,value)                   \
176   do                                            \
177     {                                           \
178       creaOnMessageLevel(key,value)             \
179         {                                       \
180           crea::MessageManager::IncTab();       \
181         }                                       \
182     }                                           \
183   while (0)
184
185 #define creaResetTab()                          \
186   do                                            \
187     {                                           \
188       crea::MessageManager::ResetTab();         \
189     }                                           \
190   while (0)
191
192 #else
193 #define creaMessage(key,value,MESSAGE)
194 #define creaMessageInc(key,value,MESSAGE)
195 #define creaMessageDec(key,value,MESSAGE)
196 #define creaMessageCont(key,value,MESSAGE)
197 #define creaDecTab(key,value)
198 #define creaIncTab(key,value)
199 #define creaResetTab()
200 #endif
201 //===========================================================
202
203
204
205 //===========================================================
206 // Macros for debug messages
207 #ifdef CREA_COMPILE_DEBUG_MESSAGES
208 #define creaDebugMessage(key,value,MESSAGE) creaMessage(key,value,MESSAGE)
209 #define creaDebugMessageCont(key,value,MESSAGE) creaMessageCont(key,value,MESSAGE)
210 #define creaDebugMessageInc(key,value,MESSAGE) creaMessageInc(key,value,MESSAGE)  
211 #define creaDebugMessageDec(key,value,MESSAGE) creaMessageDec(key,value,MESSAGE)
212 #define creaDebugDecTab(key,value) creaDecTab(key,value)
213 #define creaDebugIncTab(key,value) creaIncTab(key,value)
214 #define creaDebugResetTab() creaResetTab()
215 #else
216 #define creaDebugMessage(key,value,MESSAGE) 
217 #define creaDebugMessageCont(key,value,MESSAGE) 
218 #define creaDebugMessageInc(key,value,MESSAGE)
219 #define creaDebugMessageDec(key,value,MESSAGE) 
220 #define creaDebugDecTab(key,value)
221 #define creaDebugIncTab(key,value)
222 #endif
223 //===========================================================
224
225 //===========================================================
226 #ifdef CREA_COMPILE_WARNING_MESSAGES
227 #define creaWarning(MESSAGE)                                            \
228   do                                                                    \
229     {                                                                   \
230       int lev = crea::MessageManager::GetMessageLevel("warning");       \
231       if (lev >0)                                                       \
232         {                                                               \
233           std::cerr << "!! WARNING !! " << MESSAGE << std::endl;        \
234           if (lev >1)                                                   \
235             {                                                           \
236               std::cerr << "!! WARNING !! In file '"<<__FILE__          \
237                         <<"' ; Line "<<__LINE__<<std::endl;             \
238             }                                                           \
239         }                                                               \
240     }                                                                   \
241   while (0) 
242
243 #else
244 #define creaWarning(MESSAGE) 
245 #endif
246 //===========================================================
247
248
249 //===========================================================
250 #ifdef CREA_COMPILE_ERROR_MESSAGES
251 //#include "creaWx.h"
252 #define creaError(MESSAGE)                              \
253   do                                                    \
254     {                                                   \
255       std::ostringstream s;                             \
256       s << MESSAGE;                                     \
257       std::ostringstream f;                             \
258       f << __FILE__ << " (l."<<__LINE__<<")";           \
259       crea::Exception e( CREA_GET_CURRENT_OBJECT_NAME,  \
260                         f.str(),                        \
261                         s.str());                       \
262       throw e;                                          \
263     }                                                   \
264   while (0) 
265
266 #define creaGlobalError(MESSAGE)                                \
267   do                                                    \
268     {                                                   \
269       std::ostringstream s;                             \
270       s << MESSAGE;                                     \
271       std::ostringstream f;                             \
272       f << __FILE__ << " (l."<<__LINE__<<")";           \
273       crea::Exception e( "global scope",                \
274                         f.str(),                        \
275                         s.str());                       \
276       throw e;                                          \
277     }                                                   \
278   while (0) 
279
280 #define CREA_INTERNAL_ERROR_MESSAGE \
281   "\n\n***********************************************\n**** THIS IS AN INTERNAL ERROR TO crea     ****\n**** Please send a full bug report to :    ****\n****  creatools@creatis.insa-lyon.fr ****\n***********************************************\n\n"
282
283 #define creaInternalError(MESSAGE)                      \
284   do                                                    \
285     {                                                   \
286       std::ostringstream s;                             \
287       s << MESSAGE << CREA_INTERNAL_ERROR_MESSAGE;      \
288       std::ostringstream f;                             \
289       f << __FILE__ << " (l."<<__LINE__<<")";           \
290       crea::Exception e( CREA_GET_CURRENT_OBJECT_NAME,  \
291                          f.str(),                       \
292                          s.str());                      \
293       throw e;                                          \
294     }                                                   \
295   while (0) 
296
297 #else
298 #define creaError(MESSAGE)
299 #define creaGlobalError(MESSAGE)
300 #define creaInternalError(MESSAGE)
301 #endif
302 //===========================================================
303
304 //===========================================================
305 #define creaendl std::endl
306 //===========================================================
307
308 // Signal/slot mechanism for message events
309 #include <boost/signal.hpp>
310 #include <boost/bind.hpp>
311
312 namespace crea 
313 {
314   
315   class CREA_EXPORT MessageManager
316   {
317   public:
318     //=============================================
319     typedef boost::signal<void (const std::string&)>  MessageSignalType;
320     typedef MessageSignalType::slot_function_type MessageCallbackType;
321     //=============================================
322     ///
323     MessageManager();
324     ///
325     ~MessageManager();
326     ///
327     static MessageManager* GetInstance();
328     ///
329     static void RegisterMessageType(const std::string& key, 
330                                     const std::string& help,
331                                     unsigned char default_level = 9);
332     ///
333     static void SetMessageLevel(const std::string& key, unsigned char level);
334     ///
335     static int GetMessageLevel(const std::string& key);
336     ///  
337     static void SendMessage(const std::string& key, const std::string& mess);
338     ///
339     static void AddMessageObserver(const std::string& key, MessageCallbackType callback );
340     ///
341     static void SendMessagesToCout(bool v = true);
342     ///
343     static std::string& GetTab() { static std::string s; return s; }
344     ///
345     static std::string GetSpace(int n) { 
346       std::string s; s.insert(0,"                ",n); return s; }
347     ///
348     static void IncTab() { GetTab() += std::string(" "); }
349     ///
350     static void DecTab() { GetTab() = GetTab().substr(0,GetTab().length()-1); }
351     ///
352     static void ResetTab() { GetTab() = std::string(""); }
353     ///
354     static void PrintInfo();
355     /// 
356     
357   private:
358     struct MessageType
359     {
360       MessageType(int l, const std::string& h) : Level(l), Help(h) {}
361       int Level;
362       std::string Help;
363       MessageSignalType Signal;
364     };
365     typedef std::map<std::string,MessageType*> MessageMapType;
366     MessageMapType mMessageMap;
367     unsigned int mMaxMessageLength;
368     bool mSendToCout;
369   };
370   //===========================================================
371   
372 }
373
374 #include "creaException.h"
375
376 #endif