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