]> Creatis software - crea.git/blob - src/creaMessageManager.h
Feature #1763
[crea.git] / src / creaMessageManager.h
1 /*
2 # ---------------------------------------------------------------------
3 #
4 # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image 
5 #                        pour la Santé)
6 # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
7 #
8 #  This software is governed by the CeCILL-B license under French law and 
9 #  abiding by the rules of distribution of free software. You can  use, 
10 #  modify and/ or redistribute the software under the terms of the CeCILL-B 
11 #  license as circulated by CEA, CNRS and INRIA at the following URL 
12 #  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html 
13 #  or in the file LICENSE.txt.
14 #
15 #  As a counterpart to the access to the source code and  rights to copy,
16 #  modify and redistribute granted by the license, users are provided only
17 #  with a limited warranty  and the software's author,  the holder of the
18 #  economic rights,  and the successive licensors  have only  limited
19 #  liability. 
20 #
21 #  The fact that you are presently reading this means that you have had
22 #  knowledge of the CeCILL-B license and that you accept its terms.
23 # ------------------------------------------------------------------------ */ 
24
25 /*! \file
26   \brief Class creaMessageManager and Macros for outputing messages in crea
27   There are 4 kinds of messages :
28   - Messages (normal messages)
29   - Debug messages (not compiled in release)
30   - Warnings 
31   - Errors
32   There are also "types" of messages which are strings which identify the nature of the message 
33   (for example : "Kernel" messages are generated by the core classes of the library, there can be a type of 
34   message for each type of Node, and so on...)
35   A type of message must be declared by registering it into the MessageManager. This is done by a line like :
36   crea::MessageManager::RegisterMessageType("Kernel","Messages generated by the core classes of the library",5);
37   where : 
38   -The first string is the type of the message (the category which will be used to generate a message of this type)
39   -The second string is help string
40   -The integer is the initial level for the messages of this type (see below).
41   To generate a message of a known type then use one of the macros :
42   creaMessage, creaDebugMessage, creaWarning, creaError or their variants.
43   example :
44   creaMessage("Kernel",4,"problem with "<<GetName()<<creaendl);
45   will push the 3rd argument in std::cout if the message level of "Kernel" messages is greater or equal to 4.
46   which means that it generates a message of level 4 (0 : very important/always displayed ... 9 : deep debug message).
47   At run time, one is able to change the level of the messages displayed by using a command like :
48   crea::MessageManager::SetMessageLevel("Kernel",5); 
49   which tells the manager to display all Kernel messages of level up to 5.
50   Variants :
51   crea*Cont : continues a previous creaMessage on the same line (without rewriting the type and level)
52   crea*Inc / Dec : displays the message and then increments/decrement the messages tabulation 
53 */
54
55   //===========================================================
56   /**
57      \class crea::MessageManager
58      \brief Manages the messages displayed by crea
59   */
60
61 #ifndef __creaMessageManager_h__
62 #define __creaMessageManager_h__
63
64 // The do { } while(0) statement in macros is made to "swallow the semicolon" 
65 // see http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html#Swallowing-the-Semicolon
66 #include "creaSystem.h"
67 #include "creaRTTI.h" // for CREA_GET_CURRENT_OBJECT_NAME
68 // Signal/slot mechanism for message events
69 #include <boost/signal.hpp>
70 #include <boost/bind.hpp>
71 #include <string>
72 #include <map>
73 #include <iostream>
74 #include <sstream>
75 // Comment out these symbols to prevent compilation 
76 //#define CREA_COMPILE_MESSAGES
77 //#define CREA_COMPILE_DEBUG_MESSAGES
78 //#define CREA_COMPILE_WARNING_MESSAGES
79 //#define CREA_COMPILE_ERROR_MESSAGES
80 #define creaOnMessageLevel(key,value)                   \
81   int __creaOnMessageLevelVariable =                    \
82     crea::MessageManager::GetMessageLevel(key);         \
83   if ( __creaOnMessageLevelVariable<0)                  \
84     {                                                   \
85       creaWarning("message type '"<<key<<"' unknown");  \
86     }                                                   \
87   else if (value<= __creaOnMessageLevelVariable) 
88
89 #ifdef CREA_PREPEND_MESSAGE_WITH_CODE
90 #define creaMessageCode                         \
91   key[0] << key[1] << key[2] << value << " "
92 #else 
93 #define creaMessageCode ""
94 #endif 
95
96 #ifdef CREA_PREPEND_MESSAGE_WITH_TAB
97 #define creaMessageTab                          \
98   crea::MessageManager::GetTab()
99 #else 
100 #define creaMessageTab ""
101 #endif
102
103 //#define CREA_PREPEND_MESSAGE_WITH_SPACE
104 #ifdef CREA_PREPEND_MESSAGE_WITH_SPACE
105 #define creaMessageSpace(value)                 \
106   crea::MessageManager::GetSpace(value)
107 #else 
108 #define creaMessageSpace(value) ""
109 #endif
110
111  
112
113
114
115 //===========================================================
116
117 #ifdef CREA_COMPILE_MESSAGES
118
119 // Macro for messages
120 #define creaMessage(key,value,MESSAGE)                  \
121   do {                                                  \
122     creaOnMessageLevel(key,value)                       \
123       {                                                 \
124         std::ostringstream s;                           \
125         s << creaMessageCode                            \
126           << creaMessageTab                             \
127           << creaMessageSpace(value)                    \
128           << MESSAGE;                                   \
129         crea::MessageManager::SendMessage(key,s.str()); \
130       }                                                 \
131   }                                                     \
132   while (0)
133
134
135
136 // Macro for continuing a message (when one wants to split the macro
137 // call into multiple lines)
138 #define creaMessageCont(key,value,MESSAGE)              \
139   do                                                    \
140     {                                                   \
141       creaOnMessageLevel(key,value)                     \
142         {                                               \
143         std::ostringstream s;                           \
144         s << MESSAGE;                                   \
145         crea::MessageManager::SendMessage(key,s.str()); \
146         }                                               \
147     }                                                   \
148   while (0)
149
150
151 #define creaMessageInc(key,value,MESSAGE)               \
152   do                                                    \
153     {                                                   \
154         std::ostringstream s;                           \
155         s << creaMessageCode                            \
156           << creaMessageTab                             \
157           << creaMessageSpace(value)                    \
158           << MESSAGE;                                   \
159         crea::MessageManager::SendMessage(key,s.str()); \
160         crea::MessageManager::IncTab();                 \
161         }                                               \
162     }                                                   \
163   while (0)
164
165
166 #define creaMessageDec(key,value,MESSAGE)                       \
167   do                                                            \
168     {                                                           \
169       creaOnMessageLevel(key,value)                             \
170         {                                                       \
171           crea::MessageManager::DecTab();                       \
172           std::ostringstream s;                                 \
173           s << creaMessageCode                                  \
174             << creaMessageTab                                   \
175             << creaMessageSpace(value)                          \
176             << MESSAGE;                                         \
177           crea::MessageManager::SendMessage(key,s.str());       \
178         }                                                       \
179     }                                                           \
180   while (0)
181
182
183 #define creaDecTab(key,value)                   \
184   do                                            \
185     {                                           \
186       creaOnMessageLevel(key,value)             \
187         {                                       \
188           crea::MessageManager::DecTab();       \
189         }                                       \
190     }                                           \
191   while (0)
192
193
194 #define creaIncTab(key,value)                   \
195   do                                            \
196     {                                           \
197       creaOnMessageLevel(key,value)             \
198         {                                       \
199           crea::MessageManager::IncTab();       \
200         }                                       \
201     }                                           \
202   while (0)
203
204
205 #define creaResetTab()                          \
206   do                                            \
207     {                                           \
208       crea::MessageManager::ResetTab();         \
209     }                                           \
210   while (0)
211
212 #else
213 #define creaMessage(key,value,MESSAGE)
214 #define creaMessageInc(key,value,MESSAGE)
215 #define creaMessageDec(key,value,MESSAGE)
216 #define creaMessageCont(key,value,MESSAGE)
217 #define creaDecTab(key,value)
218 #define creaIncTab(key,value)
219 #define creaResetTab()
220 #endif
221
222 //===========================================================
223
224
225
226
227
228
229
230 //===========================================================
231
232 // Macros for debug messages
233
234 #ifdef CREA_COMPILE_DEBUG_MESSAGES
235
236 #define creaDebugMessage(key,value,MESSAGE) creaMessage(key,value,MESSAGE)
237
238 #define creaDebugMessageCont(key,value,MESSAGE) creaMessageCont(key,value,MESSAGE)
239
240 #define creaDebugMessageInc(key,value,MESSAGE) creaMessageInc(key,value,MESSAGE)  
241
242 #define creaDebugMessageDec(key,value,MESSAGE) creaMessageDec(key,value,MESSAGE)
243
244 #define creaDebugDecTab(key,value) creaDecTab(key,value)
245
246 #define creaDebugIncTab(key,value) creaIncTab(key,value)
247
248 #define creaDebugResetTab() creaResetTab()
249
250 #else
251
252 #define creaDebugMessage(key,value,MESSAGE) 
253
254 #define creaDebugMessageCont(key,value,MESSAGE) 
255
256 #define creaDebugMessageInc(key,value,MESSAGE)
257
258 #define creaDebugMessageDec(key,value,MESSAGE) 
259
260 #define creaDebugDecTab(key,value)
261
262 #define creaDebugIncTab(key,value)
263
264 #endif
265
266 //===========================================================
267
268
269
270 //===========================================================
271
272 #ifdef CREA_COMPILE_WARNING_MESSAGES
273 #define creaWarning(MESSAGE)                                            \
274   do                                                                    \
275     {                                                                   \
276       int lev = crea::MessageManager::GetMessageLevel("warning");       \
277       if (lev >0)                                                       \
278         {                                                               \
279           std::cerr << "!! WARNING !! " << MESSAGE << std::endl;        \
280           if (lev >1)                                                   \
281             {                                                           \
282               std::cerr << "!! WARNING !! In file '"<<__FILE__          \
283                         <<"' ; Line "<<__LINE__<<std::endl;             \
284             }                                                           \
285         }                                                               \
286     }                                                                   \
287   while (0) 
288
289 #else
290 #define creaWarning(MESSAGE) 
291 #endif
292
293 //===========================================================
294
295
296
297
298
299 //===========================================================
300
301 #ifdef CREA_COMPILE_ERROR_MESSAGES
302 //#include "creaWx.h"
303 #define creaError(MESSAGE)                              \
304   do                                                    \
305     {                                                   \
306       std::ostringstream s;                             \
307       s << MESSAGE;                                     \
308       std::ostringstream f;                             \
309       f << __FILE__ << " (l."<<__LINE__<<")";           \
310       crea::Exception e( CREA_GET_CURRENT_OBJECT_NAME,  \
311                         f.str(),                        \
312                         s.str());                       \
313       throw e;                                          \
314     }                                                   \
315   while (0) 
316
317
318
319 #define creaGlobalError(MESSAGE)                                \
320   do                                                    \
321     {                                                   \
322       std::ostringstream s;                             \
323       s << MESSAGE;                                     \
324       std::ostringstream f;                             \
325       f << __FILE__ << " (l."<<__LINE__<<")";           \
326       crea::Exception e( "global scope",                \
327                         f.str(),                        \
328                         s.str());                       \
329       throw e;                                          \
330     }                                                   \
331   while (0) 
332
333
334
335 #define CREA_INTERNAL_ERROR_MESSAGE \
336   "\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"
337
338 #define creaInternalError(MESSAGE)                      \
339   do                                                    \
340     {                                                   \
341       std::ostringstream s;                             \
342       s << MESSAGE << CREA_INTERNAL_ERROR_MESSAGE;      \
343       std::ostringstream f;                             \
344       f << __FILE__ << " (l."<<__LINE__<<")";           \
345       crea::Exception e( CREA_GET_CURRENT_OBJECT_NAME,  \
346                          f.str(),                       \
347                          s.str());                      \
348       throw e;                                          \
349     }                                                   \
350   while (0) 
351
352
353
354 #else
355 #define creaError(MESSAGE)
356 #define creaGlobalError(MESSAGE)
357 #define creaInternalError(MESSAGE)
358 #endif
359
360 //===========================================================
361
362
363
364 //===========================================================
365
366 #define creaendl std::endl
367
368 //===========================================================
369
370
371
372
373
374 namespace crea 
375
376 {
377
378   
379
380   class CREA_EXPORT MessageManager
381
382   {
383
384   public:
385
386     //=============================================
387
388     typedef boost::signal<void (const std::string&)>  MessageSignalType;
389
390     typedef MessageSignalType::slot_function_type MessageCallbackType;
391
392     //=============================================
393
394     ///
395
396     MessageManager();
397
398     ///
399
400     ~MessageManager();
401
402     ///
403
404     static MessageManager* GetInstance();
405
406     ///
407
408     static void RegisterMessageType(const std::string& key, 
409
410                                     const std::string& help,
411
412                                     unsigned char default_level = 9);
413
414     ///
415
416     static void SetMessageLevel(const std::string& key, unsigned char level);
417
418     ///
419
420     static int GetMessageLevel(const std::string& key);
421
422     ///  
423
424     static void SendMessage(const std::string& key, const std::string& mess);
425
426     ///
427
428     static void AddMessageObserver(const std::string& key, MessageCallbackType callback );
429
430     ///
431
432     static void SendMessagesToCout(bool v = true);
433
434     ///
435
436     static std::string& GetTab() { static std::string s; return s; }
437
438     ///
439
440     static std::string GetSpace(int n) { 
441
442       std::string s; s.insert(0,"                ",n); return s; }
443
444     ///
445
446     static void IncTab() { GetTab() += std::string(" "); }
447
448     ///
449
450     static void DecTab() { GetTab() = GetTab().substr(0,GetTab().length()-1); }
451
452     ///
453
454     static void ResetTab() { GetTab() = std::string(""); }
455
456     ///
457
458     static void PrintInfo();
459
460     /// 
461
462     
463
464   private:
465
466     struct MessageType
467
468     {
469
470       MessageType(int l, const std::string& h) : Level(l), Help(h) {}
471
472       int Level;
473
474       std::string Help;
475
476       MessageSignalType Signal;
477
478     };
479
480     typedef std::map<std::string,MessageType*> MessageMapType;
481
482     MessageMapType mMessageMap;
483
484     unsigned int mMaxMessageLength;
485
486     bool mSendToCout;
487
488   };
489
490   //===========================================================
491
492   
493
494 }
495
496
497
498 #include "creaException.h"
499
500
501
502 #endif
503