8c4a317e698a6894aa3fb7d4d01f1e5cd0180ab3
[occt.git] / src / Message / Message_Algorithm.cxx
1 // Created on: 2003-03-04
2 // Created by: Pavel TELKOV
3 // Copyright (c) 2003-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 // The original implementation copyright (c) RINA S.p.A.
17
18 #include <Message_Algorithm.ixx>
19
20 #include <Message.hxx>
21 #include <Message_Msg.hxx>
22 #include <Message_MsgFile.hxx>
23 #include <Message_Messenger.hxx>
24 #include <TCollection_AsciiString.hxx>
25 #include <TColStd_SequenceOfInteger.hxx>
26 #include <TColStd_HSequenceOfInteger.hxx>
27 #include <TColStd_HSequenceOfHExtendedString.hxx>
28 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
29 #include <TColStd_HPackedMapOfInteger.hxx>
30
31 //=======================================================================
32 //function : SetMessenger
33 //purpose  :
34 //=======================================================================
35
36 Message_Algorithm::Message_Algorithm ()
37 {
38   myMessenger = Message::DefaultMessenger();
39 }
40
41 //=======================================================================
42 //function : SetMessenger
43 //purpose  :
44 //=======================================================================
45
46 void Message_Algorithm::SetMessenger (const Handle(Message_Messenger)& theMsgr)
47 {
48   if ( theMsgr.IsNull() )
49     myMessenger = Message::DefaultMessenger();
50   else
51     myMessenger = theMsgr;
52 }
53
54 //=======================================================================
55 //function : SetStatus
56 //purpose  :
57 //=======================================================================
58
59 void Message_Algorithm::SetStatus(const Message_Status& theStat)
60 {
61   myStatus.Set( theStat );
62 }
63
64 //=======================================================================
65 //function : SetStatus
66 //purpose  :
67 //=======================================================================
68
69 void Message_Algorithm::SetStatus (const Message_Status& theStat, 
70                                    const Standard_Integer theInt)
71 {
72   // Set status flag
73   SetStatus ( theStat );
74
75   // Find index of bit corresponding to that flag
76   Standard_Integer aFlagIndex = Message_ExecStatus::StatusIndex(theStat);
77   if ( !aFlagIndex ) return;
78
79   // Create map of integer parameters for a given flag, if not yet done
80   if ( myReportIntegers.IsNull() )
81     myReportIntegers = new TColStd_HArray1OfTransient (Message_ExecStatus::FirstStatus, 
82                                                        Message_ExecStatus::LastStatus);
83   Handle(Standard_Transient)& aData = 
84     myReportIntegers->ChangeValue(aFlagIndex);
85   if ( aData.IsNull() )
86     aData = new TColStd_HPackedMapOfInteger;
87
88   // add integer parameter for the status
89   Handle(TColStd_HPackedMapOfInteger)::DownCast(aData)->ChangeMap().Add(theInt);
90 }
91
92 //=======================================================================
93 //function : SetStatus
94 //purpose  :
95 //=======================================================================
96
97 void Message_Algorithm::SetStatus (const Message_Status& theStat, 
98                                    const Handle(TCollection_HExtendedString) &theStr,
99                                    const Standard_Boolean noRepetitions)
100 {
101   // Set status flag
102   SetStatus ( theStat );
103   if ( theStr.IsNull() )
104     return;
105
106   // Find index of bit corresponding to that flag
107   Standard_Integer aFlagIndex = Message_ExecStatus::StatusIndex(theStat);
108   if ( !aFlagIndex ) return;
109     
110   // Create sequence of string parameters for a given flag, if not yet done
111   if ( myReportStrings.IsNull() )
112     myReportStrings = new TColStd_HArray1OfTransient (Message_ExecStatus::FirstStatus,
113                                                       Message_ExecStatus::LastStatus);
114   Handle(Standard_Transient)& aData = 
115     myReportStrings->ChangeValue(aFlagIndex);
116   if ( aData.IsNull() )
117     aData = new TColStd_HSequenceOfHExtendedString;
118
119   // Add string parameter
120   Handle(TColStd_HSequenceOfHExtendedString) aReportSeq = 
121     Handle(TColStd_HSequenceOfHExtendedString)::DownCast(aData);
122   if ( aReportSeq.IsNull() )
123     return;
124   if ( noRepetitions )
125   {
126     // if the provided string has been already registered, just do nothing
127     for ( Standard_Integer i=1; i <= aReportSeq->Length(); i++ )
128       if ( aReportSeq->Value(i)->String().IsEqual( theStr->String() ) ) 
129         return;
130   }
131
132   aReportSeq->Append ( theStr );
133 }
134
135 //=======================================================================
136 //function : SetStatus
137 //purpose  :
138 //=======================================================================
139
140 void Message_Algorithm::SetStatus (const Message_Status& theStat,
141                                    const Message_Msg&    theMsg)
142 {
143   // Set status flag
144   SetStatus (theStat);
145
146   // Find index of bit corresponding to that flag
147   Standard_Integer aFlagIndex = Message_ExecStatus::StatusIndex (theStat);
148   if (aFlagIndex == 0)
149   {
150     return;
151   }
152
153   // Create sequence of messages for a given flag, if not yet done
154   if (myReportMessages.IsNull())
155   {
156     myReportMessages = new Message_ArrayOfMsg (Message_ExecStatus::FirstStatus, Message_ExecStatus::LastStatus);
157   }
158
159   myReportMessages->ChangeValue (aFlagIndex) = new Message_Msg (theMsg);
160 }
161
162 //=======================================================================
163 //function : ClearStatus
164 //purpose  :
165 //=======================================================================
166
167 void Message_Algorithm::ClearStatus()
168 {
169   myStatus.Clear(); 
170   myReportIntegers.Nullify();
171   myReportStrings.Nullify();
172   myReportMessages.Nullify();
173 }
174
175 //=======================================================================
176 //function : SendStatusMessages
177 //purpose  :
178 //=======================================================================
179
180 void Message_Algorithm::SendStatusMessages (const Message_ExecStatus& theStatus,
181                                             const Message_Gravity     theTraceLevel,
182                                             const Standard_Integer    theMaxCount) const
183 {
184   Handle(Message_Messenger) aMsgr = GetMessenger();
185   if (aMsgr.IsNull())
186   {
187     return;
188   }
189
190   // Iterate on all set flags in the specified range
191   for ( Standard_Integer i  = Message_ExecStatus::FirstStatus; 
192                          i <= Message_ExecStatus::LastStatus; i++ )
193   {
194     Message_Status stat = Message_ExecStatus::StatusByIndex( i );
195     if (!theStatus.IsSet (stat) || !myStatus.IsSet (stat))
196     {
197       continue;
198     }
199
200     Handle(Message_Msg) aMsgCustom = !myReportMessages.IsNull()
201                                     ? myReportMessages->Value (i)
202                                     : Handle(Message_Msg)();
203     if (!aMsgCustom.IsNull())
204     {
205       // print custom message
206       aMsgr->Send (*aMsgCustom, theTraceLevel);
207       continue;
208     }
209
210     // construct message suffix
211     TCollection_AsciiString aSuffix;
212     switch( Message_ExecStatus::TypeOfStatus( stat ) )
213     {
214     case Message_DONE:  aSuffix.AssignCat( ".Done" ); break;
215     case Message_WARN:  aSuffix.AssignCat( ".Warn" ); break;
216     case Message_ALARM: aSuffix.AssignCat( ".Alarm"); break;
217     case Message_FAIL:  aSuffix.AssignCat( ".Fail" ); break;
218     default:            continue;  
219     }
220     aSuffix.AssignCat( Message_ExecStatus::LocalStatusIndex( stat ) );
221
222     // find message, prefixed by class type name, iterating by base classes if necessary
223     TCollection_AsciiString aMsgName;
224     for (Handle(Standard_Type) aType = DynamicType(); ! aType.IsNull(); aType = aType->Parent())
225     {
226       aMsgName = aType->Name();
227       aMsgName += aSuffix;
228       if (Message_MsgFile::HasMsg(aMsgName))
229         break;
230     }
231
232     // create a message
233     Message_Msg aMsg ( aMsgName );
234
235     // if additional parameters are defined for a given status flag,
236     // try to feed them into the message
237     if (!myReportIntegers.IsNull())
238     {
239       Handle(TColStd_HPackedMapOfInteger) aMapErrors =
240         Handle(TColStd_HPackedMapOfInteger)::DownCast(myReportIntegers->Value(i));
241       if (!aMapErrors.IsNull())
242       {
243         aMsg << PrepareReport (aMapErrors, theMaxCount);
244       }
245     }
246     if (!myReportStrings.IsNull()
247      && !myReportStrings->Value (i).IsNull())
248     {
249       Handle(TColStd_HSequenceOfHExtendedString) aReportSeq =
250         Handle(TColStd_HSequenceOfHExtendedString)::DownCast (myReportStrings->Value(i));
251       if (!aReportSeq.IsNull())
252       {
253         aMsg << PrepareReport (aReportSeq->Sequence(), theMaxCount);
254       }
255     }
256
257     // output the message
258     aMsgr->Send(aMsg, theTraceLevel);
259   }
260 }
261
262 //=======================================================================
263 //function : SendMessages
264 //purpose  : 
265 //=======================================================================
266
267 void Message_Algorithm::SendMessages (const Message_Gravity theTraceLevel,
268                                       const Standard_Integer theMaxCount) const
269 {
270   Message_ExecStatus aStat;
271   aStat.SetAllWarn();
272   aStat.SetAllAlarm();
273   aStat.SetAllFail();
274   SendStatusMessages( aStat, theTraceLevel, theMaxCount );
275 }
276
277 //=======================================================================
278 //function : AddStatus
279 //purpose  : 
280 //=======================================================================
281
282 void Message_Algorithm::AddStatus
283       (const Handle(Message_Algorithm)& theOtherAlgo)
284 {
285   AddStatus( theOtherAlgo->GetStatus(), theOtherAlgo );
286 }
287
288 //=======================================================================
289 //function : AddStatus
290 //purpose  : 
291 //=======================================================================
292
293 void Message_Algorithm::AddStatus
294       (const Message_ExecStatus& theAllowedStatus,
295        const Handle(Message_Algorithm)& theOtherAlgo)
296 {
297   // Iterate on all set flags in the specified range
298   const Message_ExecStatus& aStatusOfAlgo = theOtherAlgo->GetStatus();
299   for ( Standard_Integer i  = Message_ExecStatus::FirstStatus; 
300                          i <= Message_ExecStatus::LastStatus; i++ )
301   {
302     Message_Status stat = Message_ExecStatus::StatusByIndex( i );
303     if ( ! theAllowedStatus.IsSet( stat ) || ! aStatusOfAlgo.IsSet( stat ) )
304       continue;
305
306     SetStatus ( stat );
307
308     // if additional parameters are defined for a given status flag,
309     // move them to <this> algorithm
310     // a) numbers
311     Handle(TColStd_HPackedMapOfInteger) aNumsOther = 
312       theOtherAlgo->GetMessageNumbers (stat); 
313     if ( ! aNumsOther.IsNull() ) 
314     {
315       // Create sequence of integer parameters for a given flag, if not yet done
316       if ( myReportIntegers.IsNull() )
317         myReportIntegers =
318           new TColStd_HArray1OfTransient(Message_ExecStatus::FirstStatus, 
319                                          Message_ExecStatus::LastStatus);
320       Handle(Standard_Transient)& aData = 
321         myReportIntegers->ChangeValue(i);
322       if ( aData.IsNull() )
323         aData = new TColStd_HPackedMapOfInteger;
324
325       // add integer parameter for the status
326       Handle(TColStd_HPackedMapOfInteger)::DownCast(aData)
327         ->ChangeMap().Unite(aNumsOther->Map());
328     }
329     // b) strings
330     Handle(TColStd_HSequenceOfHExtendedString) aStrsOther = 
331       theOtherAlgo->GetMessageStrings (stat); 
332     if ( ! aStrsOther.IsNull() ) 
333     {
334       for (Standard_Integer n=1; n < aStrsOther->Length(); n++ )
335         SetStatus (stat, aStrsOther->Value(n));
336     }
337   }
338 }
339
340 //=======================================================================
341 //function : GetMessageNumbers
342 //purpose  : 
343 //=======================================================================
344
345 Handle(TColStd_HPackedMapOfInteger) Message_Algorithm::GetMessageNumbers 
346        (const Message_Status& theStatus) const
347 {
348   if ( myReportIntegers.IsNull() )
349     return 0;
350
351   // Find index of bit corresponding to that flag
352   Standard_Integer aFlagIndex = Message_ExecStatus::StatusIndex(theStatus);
353   if ( ! aFlagIndex ) return 0;
354     
355   return Handle(TColStd_HPackedMapOfInteger)::DownCast(myReportIntegers->Value(aFlagIndex));
356 }
357
358 //=======================================================================
359 //function : GetMessageStrings
360 //purpose  : 
361 //=======================================================================
362
363 Handle(TColStd_HSequenceOfHExtendedString) Message_Algorithm::GetMessageStrings
364        (const Message_Status& theStatus) const
365 {
366   if ( myReportStrings.IsNull() )
367     return 0;
368
369   // Find index of bit corresponding to that flag
370   Standard_Integer aFlagIndex = Message_ExecStatus::StatusIndex(theStatus);
371   if ( ! aFlagIndex ) return 0;
372     
373   return Handle(TColStd_HSequenceOfHExtendedString)::DownCast(myReportStrings->Value(aFlagIndex));
374 }
375
376 //=======================================================================
377 //function : PrepareReport
378 //purpose  : static method
379 //=======================================================================
380
381 TCollection_ExtendedString Message_Algorithm::PrepareReport 
382   (const Handle(TColStd_HPackedMapOfInteger)& theMapError,
383    const Standard_Integer theMaxCount)
384 {
385   TCollection_ExtendedString aNewReport;
386   TColStd_MapIteratorOfPackedMapOfInteger anIt(theMapError->Map());
387   Standard_Integer nb = 1;
388   for (; anIt.More() && nb <= theMaxCount; anIt.Next(), nb++ )
389   {
390     if ( nb > 1 ) 
391       aNewReport += " ";
392     aNewReport += anIt.Key();
393   }
394  
395   if ( anIt.More() )
396   {
397     aNewReport += " ... (total ";
398     aNewReport += theMapError->Map().Extent();
399     aNewReport += ")";
400   }
401   return aNewReport;
402 }
403
404 //=======================================================================
405 //function : PrepareReport
406 //purpose  : static method
407 //=======================================================================
408
409 TCollection_ExtendedString Message_Algorithm::PrepareReport 
410   (const TColStd_SequenceOfHExtendedString& theReportSeq,
411    const Standard_Integer theMaxCount)
412 {
413   TCollection_ExtendedString aNewReport;
414   Standard_Integer nb = 1;
415   for ( ; nb <= theReportSeq.Length() && nb <= theMaxCount; nb++)
416   {
417     aNewReport += (Standard_CString)( nb > 1 ? ", \'" : "\'" );
418     aNewReport += theReportSeq.Value(nb)->String();
419     aNewReport += "\'";
420   }
421
422   if (theReportSeq.Length() > theMaxCount )
423   {
424     aNewReport += " ... (total ";
425     aNewReport += theReportSeq.Length();
426     aNewReport += ") ";
427   }
428   return aNewReport;
429 }