]> OCCT Git - occt-copy.git/commitdiff
0029451: Information Message Alert to debug an algorithm or object functionality
authornds <nds@opencascade.com>
Wed, 12 Feb 2020 20:41:59 +0000 (23:41 +0300)
committernds <nds@opencascade.com>
Wed, 12 Feb 2020 22:31:09 +0000 (01:31 +0300)
(cherry picked from commit f36aa84ef8e8efa1ed6d12efabce1d4e6de940d1)

31 files changed:
src/DDocStd/DDocStd_ToolsCommands.cxx
src/Draw/Draw_BasicCommands.cxx
src/Message/FILES
src/Message/Message.cxx
src/Message/Message.hxx
src/Message/Message_Alert.hxx
src/Message/Message_AlertExtended.cxx [new file with mode: 0644]
src/Message/Message_AlertExtended.hxx [new file with mode: 0644]
src/Message/Message_Attribute.cxx [new file with mode: 0644]
src/Message/Message_Attribute.hxx [new file with mode: 0644]
src/Message/Message_AttributeMeter.cxx [new file with mode: 0644]
src/Message/Message_AttributeMeter.hxx [new file with mode: 0644]
src/Message/Message_AttributeObject.hxx [new file with mode: 0644]
src/Message/Message_AttributeStream.cxx [new file with mode: 0644]
src/Message/Message_AttributeStream.hxx [new file with mode: 0644]
src/Message/Message_CompositeAlerts.cxx [new file with mode: 0644]
src/Message/Message_CompositeAlerts.hxx [new file with mode: 0644]
src/Message/Message_Level.cxx [new file with mode: 0644]
src/Message/Message_Level.hxx [new file with mode: 0644]
src/Message/Message_Messenger.cxx
src/Message/Message_Messenger.hxx
src/Message/Message_MetricType.hxx [new file with mode: 0644]
src/Message/Message_Printer.cxx
src/Message/Message_Printer.hxx
src/Message/Message_PrinterToReport.cxx [new file with mode: 0644]
src/Message/Message_PrinterToReport.hxx [new file with mode: 0644]
src/Message/Message_Report.cxx
src/Message/Message_Report.hxx
src/XmlDrivers/FILES
src/XmlDrivers/XmlDrivers_MessageReportStorage.cxx [new file with mode: 0644]
src/XmlDrivers/XmlDrivers_MessageReportStorage.hxx [new file with mode: 0644]

index 9d925859c9332d5095c8eb8f1827b88de5b9d43d..d31e9e0440a552e89d59c901393a94a320b3b086 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <Draw.hxx>
 #include <Draw_Interpretor.hxx>
+#include <Message.hxx>
 #include <TDocStd_Document.hxx>
 #include <TDF_Label.hxx>
 #include <TCollection_AsciiString.hxx>
@@ -34,6 +35,7 @@
 #include <TDF_ListIteratorOfAttributeDeltaList.hxx> 
 #include <Standard_DomainError.hxx>
 
+#include <XmlDrivers_MessageReportStorage.hxx>
 
 
 //=======================================================================
@@ -151,7 +153,23 @@ static Standard_Integer DDocStd_DumpCommand (Draw_Interpretor& di,
   return 1;
 }
 
+//=======================================================================
+//function : DDocStd_WriteReport 
+//=======================================================================
+
+static Standard_Integer DDocStd_WriteReport(Draw_Interpretor& di,Standard_Integer n, const char** a)
+{
+  if (n < 2)
+  {
+    di << "DDocStd_WriteReport : Error not enough argument\n";
+    return 1;
+  }
 
+  TCollection_ExtendedString aPath (a[1]); 
+  MESSAGE_STORE_XML_REPORT (aPath);
+
+  return 0;
+}
 
 //=======================================================================
 //function : ModificationCommands
@@ -174,5 +192,9 @@ void DDocStd::ToolsCommands(Draw_Interpretor& theCommands)
                    "DumpCommand (DOC)",
                   __FILE__, DDocStd_DumpCommand, g);   
 
+  theCommands.Add ("WriteReport", 
+                   "WriteReport path",
+                  __FILE__, DDocStd_WriteReport, g);   
+
 }
 
index 7943efc645367bc0e45ea23f9b201443be463a6c..8ccfa0093425dd899bad65f03f58131747367700 100644 (file)
@@ -23,6 +23,7 @@
 #include <Draw_ProgressIndicator.hxx>
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
+#include <Message_Report.hxx>
 #include <OSD.hxx>
 #include <OSD_Chronometer.hxx>
 #include <OSD_Environment.hxx>
@@ -1005,6 +1006,115 @@ static int dsetsignal (Draw_Interpretor& theDI, Standard_Integer theArgNb, const
   return 0;
 }
 
+//==============================================================================
+//function : dsetreportprinter
+//purpose  :
+//==============================================================================
+static Message_SequenceOfPrinters MyDeactivatedPrinters;
+
+static Standard_Integer dsetreportprinter(Draw_Interpretor&, Standard_Integer n, const char** a)
+{
+  if (n != 2)
+  {
+    std::cout << "Enable or disable report printer: " << a[0] << " {on|off}" << std::endl;
+    return 1;
+  }
+
+  const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True);
+  const Handle(Message_Messenger)& aMessenger = Message::DefaultMessenger();
+  if (! strcmp (a[1], "on") && n == 2)
+  {
+    if (aReport->IsActiveInMessenger (aMessenger))
+    {
+      std::cout << "Error: report printer has been already activated." << std::endl;
+      return 1;
+    }
+    // store current printers in cache to restore them by deactivation current printer
+    MyDeactivatedPrinters = aMessenger->Printers();
+    aMessenger->ChangePrinters().Clear();
+
+    aReport->ActivateInMessenger (Standard_True);
+  }
+  else if (! strcmp (a[1], "off") && n == 2)
+  {
+    if (!aReport->IsActiveInMessenger())
+    {
+      std::cout << "Report printer was not activated." << std::endl;
+      return 1;
+    }
+    aReport->ActivateInMessenger (Standard_False);
+
+    aMessenger->ChangePrinters().Assign (MyDeactivatedPrinters);
+  }
+  else
+  {
+    std::cout << "Unrecognized option(s): " << a[1] << std::endl;
+    return 1;
+  }
+  return 0;
+}
+
+//==============================================================================
+//function : dsetreportmetric
+//purpose  :
+//==============================================================================
+static Standard_Integer dsetreportmetric(Draw_Interpretor&, Standard_Integer n, const char** a)
+{
+  if (n < 1)
+  {
+    std::cout << "Report metric activation: " << a[0] << " [metric_1 metric_2 ...]" << std::endl;
+    return 1;
+  }
+
+  const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True);
+  if (aReport.IsNull())
+    return 1;
+
+  aReport->ClearMetrics();
+  for (int i = 1; i < n; i++)
+  {
+    Standard_Integer aMetricId = Draw::Atoi (a [i]);
+    if (aMetricId < Message_MetricType_UserTimeCPU || aMetricId > Message_MetricType_MemHeapUsage)
+    {
+      std::cout << "Unrecognized message metric: " << aMetricId << std::endl;
+      return 1;
+    }
+    aReport->SetActiveMetric ((Message_MetricType)aMetricId, Standard_True);
+  }
+
+  return 0;
+}
+
+//==============================================================================
+//function : dprintreport
+//purpose  :
+//==============================================================================
+static Standard_Integer dprintreport(Draw_Interpretor& di, Standard_Integer n, const char** a)
+{
+  if (n < 1)
+  {
+    std::cout << "Report metric activation: " << a[0] << " [messenger]" << std::endl;
+    return 1;
+  }
+
+  const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True);
+  if (aReport.IsNull())
+    return 1;
+
+  if (n > 1) // default messenger
+  {
+    aReport->SendMessages (Message::DefaultMessenger());
+  }
+  else // stream
+  {
+    Standard_SStream aSStream;
+    aReport->Dump (aSStream);
+    di << aSStream;
+  }
+
+  return 0;
+}
+
 //==============================================================================
 //function : dtracelevel
 //purpose  :
@@ -1133,6 +1243,12 @@ void Draw::BasicCommands(Draw_Interpretor& theCommands)
                  __FILE__,dperf,g);
   theCommands.Add("dsetsignal","dsetsignal [{asis|set|unhandled|unset}=set] [{0|1|default=$CSF_FPE}]\n -- set OSD signal handler, with FPE option if argument is given",
                  __FILE__,dsetsignal,g);
+  theCommands.Add("dsetreportprinter", "manage logging of messenger into default report",
+                 __FILE__,dsetreportprinter,g);
+  theCommands.Add("dsetreportmetric", "dsetreportmetric [metric...] \n Activate report metrics, deactivate all if there are no parameters.\n",
+                 __FILE__,dsetreportmetric,g);
+  theCommands.Add("dprintreport", "dprintreport [messenger] \n Send report content to default messenger or stream (if parameter is absent).\n",
+                 __FILE__,dprintreport,g);
 
   theCommands.Add("dparallel",
     "dparallel [-occt {0|1}] [-nbThreads Count] [-nbDefThreads Count]"
index 76f6fbebe5f20751d55011532d5c24a1d47bd61b..88cc7f75eab129fca0e1b7d32452d697852e22eb 100755 (executable)
@@ -1,16 +1,32 @@
 Message.cxx
 Message.hxx
+Message_Alert.cxx
+Message_Alert.hxx
+Message_AlertExtended.cxx
+Message_AlertExtended.hxx
 Message_Algorithm.cxx
 Message_Algorithm.hxx
 Message_Algorithm.lxx
 Message_ConsoleColor.hxx
+Message_Attribute.cxx
+Message_Attribute.hxx
+Message_AttributeMeter.cxx
+Message_AttributeMeter.hxx
+Message_AttributeObject.hxx
+Message_AttributeStream.cxx
+Message_AttributeStream.hxx
+Message_CompositeAlerts.cxx
+Message_CompositeAlerts.hxx
 Message_ExecStatus.hxx
 Message_Gravity.hxx
 Message_HArrayOfMsg.hxx
+Message_Level.cxx
+Message_Level.hxx
 Message_ListIteratorOfListOfMsg.hxx
 Message_ListOfMsg.hxx
 Message_Messenger.cxx
 Message_Messenger.hxx
+Message_MetricType.hxx
 Message_Msg.cxx
 Message_Msg.hxx
 Message_Msg.lxx
@@ -22,6 +38,8 @@ Message_PrinterOStream.cxx
 Message_PrinterOStream.hxx
 Message_PrinterSystemLog.cxx
 Message_PrinterSystemLog.hxx
+Message_PrinterToReport.cxx
+Message_PrinterToReport.hxx
 Message_ProgressIndicator.cxx
 Message_ProgressIndicator.hxx
 Message_ProgressIndicator.lxx
@@ -35,8 +53,6 @@ Message_SequenceOfPrinters.hxx
 Message_SequenceOfProgressScale.hxx
 Message_Status.hxx
 Message_StatusType.hxx
-Message_Alert.cxx
-Message_Alert.hxx
 Message_ListOfAlert.hxx
 Message_Report.cxx
 Message_Report.hxx
index b540ae5fb291a83a530de83e54e994db0e7cd51b..f15d8c51d46ba95ebb92ebff35c014a9effd37fe 100644 (file)
 
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
+#include <Message_Report.hxx>
 #include <TCollection_AsciiString.hxx>
 
 #include <stdio.h>
 #include <string.h>
+
+static Handle(Message_Messenger) MyMessenger;
+
 //=======================================================================
 //function : DefaultMessenger
 //purpose  : 
 //=======================================================================
-const Handle(Message_Messenger)& Message::DefaultMessenger ()
+
+const Handle(Message_Messenger)& Message::DefaultMessenger()
+{
+  if (MyMessenger.IsNull())
+   MyMessenger = new Message_Messenger;
+  return MyMessenger;
+}
+
+//=======================================================================
+//function : SetDefaultMessenger
+//purpose  : 
+//=======================================================================
+
+void Message::SetDefaultMessenger (const Handle(Message_Messenger)& theMessenger)
+{
+  MyMessenger = theMessenger;
+}
+
+//=======================================================================
+//function : DefaultReport
+//purpose  :
+//=======================================================================
+
+const Handle(Message_Report)& Message::DefaultReport(const Standard_Boolean theToCreate)
 {
-  static Handle(Message_Messenger) aMessenger = new Message_Messenger;
-  return aMessenger;
+  static Handle(Message_Report) MyReport;
+
+  if (MyReport.IsNull() && theToCreate)
+    MyReport = new Message_Report();
+
+  return MyReport;
 }
 
 //=======================================================================
@@ -49,3 +80,82 @@ TCollection_AsciiString Message::FillTime (const Standard_Integer hour,
     Sprintf (t, "%.2fs", second);
   return TCollection_AsciiString (t);
 }
+
+namespace
+{
+  static Standard_CString Message_Table_PrintMetricTypeEnum[10] =
+  {
+    "NONE", "UserTimeCPU", "SystemTimeInfo", "MemPrivate", "MemVirtual",
+    "MemWorkingSet", "MemWorkingSetPeak", "MemSwapUsage", "MemSwapUsagePeak", "MemHeapUsage"
+  };
+}
+
+//=======================================================================
+//function : MetricToString
+//purpose  :
+//=======================================================================
+
+Standard_CString Message::MetricToString (const Message_MetricType theType)
+{
+  return Message_Table_PrintMetricTypeEnum[theType];
+}
+
+//=======================================================================
+//function : MetricFromString
+//purpose  :
+//=======================================================================
+
+Standard_Boolean Message::MetricFromString (const Standard_CString theString,
+                                            Message_MetricType& theGravity)
+{
+  TCollection_AsciiString aName (theString);
+  for (Standard_Integer aMetricIter = 0; aMetricIter <= Message_MetricType_MemHeapUsage; ++aMetricIter)
+  {
+    Standard_CString aMetricName = Message_Table_PrintMetricTypeEnum[aMetricIter];
+    if (aName == aMetricName)
+    {
+      theGravity = Message_MetricType (aMetricIter);
+      return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
+// =======================================================================
+// function : ToOSDMetric
+// purpose :
+// =======================================================================
+Standard_Boolean Message::ToOSDMetric (const Message_MetricType theMetric, OSD_MemInfo::Counter& theMemInfo)
+{
+  switch (theMetric)
+  {
+    case Message_MetricType_MemPrivate:        theMemInfo = OSD_MemInfo::MemPrivate; break;
+    case Message_MetricType_MemVirtual:        theMemInfo = OSD_MemInfo::MemVirtual; break;
+    case Message_MetricType_MemWorkingSet:     theMemInfo = OSD_MemInfo::MemWorkingSet; break;
+    case Message_MetricType_MemWorkingSetPeak: theMemInfo = OSD_MemInfo::MemWorkingSetPeak; break;
+    case Message_MetricType_MemSwapUsage:      theMemInfo = OSD_MemInfo::MemSwapUsage; break;
+    case Message_MetricType_MemSwapUsagePeak:  theMemInfo = OSD_MemInfo::MemSwapUsagePeak; break;
+    case Message_MetricType_MemHeapUsage:      theMemInfo = OSD_MemInfo::MemHeapUsage; break;
+  }
+  return Standard_True;
+}
+
+// =======================================================================
+// function : ToMessageMetric
+// purpose :
+// =======================================================================
+Standard_Boolean Message::ToMessageMetric (const OSD_MemInfo::Counter theMemInfo, Message_MetricType& theMetric)
+{
+  switch (theMemInfo)
+  {
+    case OSD_MemInfo::MemPrivate:        theMetric = Message_MetricType_MemPrivate;        break;
+    case OSD_MemInfo::MemVirtual:        theMetric = Message_MetricType_MemVirtual;        break;
+    case OSD_MemInfo::MemWorkingSet:     theMetric = Message_MetricType_MemWorkingSet;     break;
+    case OSD_MemInfo::MemWorkingSetPeak: theMetric = Message_MetricType_MemWorkingSetPeak; break;
+    case OSD_MemInfo::MemSwapUsage:      theMetric = Message_MetricType_MemSwapUsage;      break;
+    case OSD_MemInfo::MemSwapUsagePeak:  theMetric = Message_MetricType_MemSwapUsagePeak;  break;
+    case OSD_MemInfo::MemHeapUsage:      theMetric = Message_MetricType_MemHeapUsage;      break;
+    default: return Standard_False;
+  }
+  return Standard_True;
+}
index 4be71135b3580949da7dbc6d0188305865d0634f..4d728159e4394f1ab628a08ee1611b9527f271c8 100644 (file)
 #ifndef _Message_HeaderFile
 #define _Message_HeaderFile
 
+#include <Message_Gravity.hxx>
+#include <Message_MetricType.hxx>
+#include <NCollection_Vector.hxx>
+#include <OSD_MemInfo.hxx>
+
 #include <Standard.hxx>
 #include <Standard_DefineAlloc.hxx>
 #include <Standard_Handle.hxx>
 
 #include <Standard_Integer.hxx>
 #include <Standard_Real.hxx>
+#include <TCollection_AsciiString.hxx>
+
 class Message_Messenger;
-class TCollection_AsciiString;
 class Message_Msg;
 class Message_MsgFile;
 class Message_Messenger;
@@ -34,6 +40,7 @@ class Message_PrinterOStream;
 class Message_ProgressIndicator;
 class Message_ProgressScale;
 class Message_ProgressSentry;
+class Message_Report;
 
 
 //! Defines
@@ -51,7 +58,15 @@ public:
   //! By default, it contains single printer directed to std::cout.
   //! It can be customized according to the application needs.
   Standard_EXPORT static const Handle(Message_Messenger)& DefaultMessenger();
-  
+
+  //! Sets default messenger.
+  Standard_EXPORT static void SetDefaultMessenger (const Handle(Message_Messenger)& theMessenger);
+
+  //! returns the only one instance of Report
+  //! When theToCreate is true - automatically creates message report when not exist.
+  //! that has been created.
+  Standard_EXPORT static const Handle(Message_Report)& DefaultReport (const Standard_Boolean theToCreate = Standard_False);
+
   //! Returns the string filled with values of hours, minutes and seconds.
   //! Example:
   //! 1. (5, 12, 26.3345) returns "05h:12m:26.33s",
@@ -59,15 +74,45 @@ public:
   //! 3. (0,  0,  4.5   ) returns "4.50s"
   Standard_EXPORT static TCollection_AsciiString FillTime (const Standard_Integer Hour, const Standard_Integer Minute, const Standard_Real Second);
 
-
-
+  //! Determines the metric from the given string identifier.
+  //! @param theString string identifier
+  //! @param theType detected type of metric
+  //! @return TRUE if string identifier is known
+  Standard_EXPORT static Standard_Boolean MetricFromString (const Standard_CString theString,
+                                                            Message_MetricType& theType);
+
+  //! Returns the string name for a given metric type.
+  //! @param theType metric type
+  //! @return string identifier from the list of Message_MetricType
+  Standard_EXPORT static Standard_CString MetricToString (const Message_MetricType theType);
+
+  //! Returns the metric type from the given string identifier.
+  //! @param theString string identifier
+  //! @return metric type or Message_MetricType_None if string identifier is invalid
+  static Message_MetricType MetricFromString (const Standard_CString theString)
+  {
+    Message_MetricType aMetric = Message_MetricType_None;
+    MetricFromString (theString, aMetric);
+    return aMetric;
+  }
+
+  //! Converts message metric to OSD memory info type.
+  //! @param theMetric [in] message metric
+  //! @param theMemInfo [out] filled memory info type
+  //! @return true if converted
+  static Standard_EXPORT Standard_Boolean ToOSDMetric (const Message_MetricType theMetric, OSD_MemInfo::Counter& theMemInfo);
+
+  //! Converts OSD memory info type to message metric.
+  //! @param theMemInfo [int] memory info type
+  //! @param theMetric [out] filled message metric
+  //! @return true if converted
+  static Standard_EXPORT Standard_Boolean ToMessageMetric (const OSD_MemInfo::Counter theMemInfo, Message_MetricType& theMetric);
 
 protected:
 
 
 
 
-
 private:
 
 
index 030efb0f99d51125c8adc02fd574020806ba4dea..a460787354e88bc6a9121068d88b299deb6fe689 100644 (file)
@@ -54,7 +54,6 @@ public:
   //! Base implementation always returns true.
   virtual Standard_EXPORT Standard_Boolean Merge (const Handle(Message_Alert)& theTarget);
   
-  // OCCT RTTI
   DEFINE_STANDARD_RTTIEXT(Message_Alert,Standard_Transient)
 };
 
diff --git a/src/Message/Message_AlertExtended.cxx b/src/Message/Message_AlertExtended.cxx
new file mode 100644 (file)
index 0000000..843c3b6
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Message_AlertExtended.hxx>
+#include <Message_Attribute.hxx>
+#include <Message_CompositeAlerts.hxx>
+#include <Message_Report.hxx>
+
+#include <Precision.hxx>
+#include <Standard_Assert.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_AlertExtended,Message_Alert)
+
+//=======================================================================
+//function : GetMessageKey
+//purpose  :
+//=======================================================================
+
+Standard_CString Message_AlertExtended::GetMessageKey () const
+{
+  if (myAttribute.IsNull())
+    return Message_Alert::GetMessageKey();
+
+  return myAttribute->GetMessageKey();
+}
+
+//=======================================================================
+//function : CompositeAlerts
+//purpose  : 
+//=======================================================================
+Handle(Message_CompositeAlerts) Message_AlertExtended::CompositeAlerts (const Standard_Boolean theToCreate)
+{
+  if (myCompositAlerts.IsNull() && theToCreate)
+    myCompositAlerts = new Message_CompositeAlerts();
+
+  return myCompositAlerts;
+}
+
+//=======================================================================
+//function : SupportsMerge
+//purpose  : 
+//=======================================================================
+Standard_Boolean Message_AlertExtended::SupportsMerge () const
+{
+  if (myCompositAlerts.IsNull())
+    return Standard_True;
+
+  // hierarchical alerts can not be merged
+  for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter)
+  {
+    if (!myCompositAlerts->Alerts ((Message_Gravity)aGravIter).IsEmpty())
+      return Standard_False;
+  }
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : Merge
+//purpose  : 
+//=======================================================================
+Standard_Boolean Message_AlertExtended::Merge (const Handle(Message_Alert)& /*theTarget*/)
+{
+  // by default, merge trivially
+  return Standard_False;
+}
+
+//=======================================================================
+//function : AddAlert
+//purpose  : 
+//=======================================================================
+Handle(Message_Alert) Message_AlertExtended::AddAlert (const Handle(Message_Report)& theReport,
+                                                       const Handle(Message_Attribute)& theAttribute,
+                                                       const Message_Gravity theGravity)
+{
+  Handle(Message_AlertExtended) anAlert = new Message_AlertExtended();
+  anAlert->SetAttribute (theAttribute);
+  theReport->AddAlert (theGravity, anAlert);
+
+  return anAlert;
+}
diff --git a/src/Message/Message_AlertExtended.hxx b/src/Message/Message_AlertExtended.hxx
new file mode 100644 (file)
index 0000000..8c04208
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_AlertExtended_HeaderFile
+#define _Message_AlertExtended_HeaderFile
+
+#include <Message_Alert.hxx>
+#include <Message_Gravity.hxx>
+#include <TCollection_AsciiString.hxx>
+
+class Message_Attribute;
+class Message_Report;
+
+DEFINE_STANDARD_HANDLE(Message_AlertExtended, Message_Alert)
+
+class Message_CompositeAlerts;
+
+//! Inherited class of Message_Alert with some additional information.
+//!
+//! It has Message_Attributes to provide the alert name, and other custom information
+//!
+//! It has a container of composite alerts, if the alert might provide
+//! sub-alerts collecting.
+//!
+class Message_AlertExtended : public Message_Alert
+{
+public:
+  //! Empty constructor
+  Standard_EXPORT Message_AlertExtended() : Message_Alert() {}
+
+  //! Return a C string to be used as a key for generating text user 
+  //! messages describing this alert.
+  //! The messages are generated with help of Message_Msg class, in
+  //! Message_Report::Dump().
+  //! Base implementation returns dynamic type name of the instance.
+  Standard_EXPORT virtual Standard_CString GetMessageKey () const Standard_OVERRIDE;
+
+  //! Sets container of the alert attributes
+  //! @param theAttributes an attribute values
+  void SetAttribute (const Handle(Message_Attribute)& theAttribute) { myAttribute = theAttribute; }
+
+  //! Returns container of the alert attributes
+  //! @param theAttributes an attribute values
+  const Handle(Message_Attribute)& Attribute() const { return myAttribute; }
+
+  //! Returns class provided hierarchy of alerts if created or create if the parameter is true
+  //! @param isCreate if composite alert has not been created for this alert, it should be created
+  //! @return instance or NULL
+  Standard_EXPORT Handle(Message_CompositeAlerts) CompositeAlerts (const Standard_Boolean theToCreate = Standard_False);
+
+  //! Return true if this type of alert can be merged with other
+  //! of the same type to avoid duplication.
+  //! Hierarchical alerts can not be merged
+  //! Basis implementation returns true.
+  virtual Standard_EXPORT Standard_Boolean SupportsMerge() const Standard_OVERRIDE;
+
+  //! If possible, merge data contained in this alert to theTarget.
+  //! @return True if merged.
+  //! Base implementation always returns false.
+  virtual Standard_EXPORT Standard_Boolean Merge (const Handle(Message_Alert)& theTarget) Standard_OVERRIDE;
+
+  //! Creates new instance of the alert and put it into report with Message_Info gravity.
+  //! It does nothing if such kind of gravity is not active in the report
+  //! @param theReport the message report where new alert is placed
+  //! @param theAttribute container of additional values of the alert
+  //! @return created alert or NULL if Message_Info is not active in report
+  static Standard_EXPORT Handle(Message_Alert) AddAlert (const Handle(Message_Report)& theReport,
+                                                         const Handle(Message_Attribute)& theAttribute,
+                                                         const Message_Gravity theGravity);
+
+  DEFINE_STANDARD_RTTIEXT(Message_AlertExtended, Message_Alert)
+
+protected:
+
+  Handle(Message_CompositeAlerts) myCompositAlerts; //!< class provided hierarchical structure of alerts
+  Handle(Message_Attribute) myAttribute; //!< container of the alert attributes
+};
+
+#endif // _Message_Alert_HeaderFile
diff --git a/src/Message/Message_Attribute.cxx b/src/Message/Message_Attribute.cxx
new file mode 100644 (file)
index 0000000..6efcd0f
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Message_Attribute.hxx>
+
+#include <Standard_Assert.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_Attribute, Standard_Transient)
+
+//=======================================================================
+//function : GetMessageKey
+//purpose  :
+//=======================================================================
+
+Standard_CString Message_Attribute::GetMessageKey () const
+{
+  return !myName.IsEmpty() ? myName.ToCString() : "";
+}
diff --git a/src/Message/Message_Attribute.hxx b/src/Message/Message_Attribute.hxx
new file mode 100644 (file)
index 0000000..cce24fd
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_Attribute_HeaderFile
+#define _Message_Attribute_HeaderFile
+
+#include <Standard_Transient.hxx>
+#include <TCollection_AsciiString.hxx>
+
+DEFINE_STANDARD_HANDLE(Message_Attribute, Standard_Transient)
+
+//! Additional information of extended alert attribute
+//! To provide other custom attribute container, it might be redefined.
+class Message_Attribute : public Standard_Transient
+{
+public:
+  //! Empty constructor
+  Standard_EXPORT Message_Attribute (const TCollection_AsciiString& theName = TCollection_AsciiString())
+    : myName (theName) {}
+
+  //! Return a C string to be used as a key for generating text user 
+  //! messages describing this alert.
+  //! The messages are generated with help of Message_Msg class, in
+  //! Message_Report::Dump().
+  //! Base implementation returns dynamic type name of the instance.
+  virtual Standard_EXPORT Standard_CString GetMessageKey () const;
+
+  //! Returns custom name of alert if it is set
+  //! @return alert name
+  const TCollection_AsciiString& GetName() const { return myName; }
+
+  //! Sets the custom name of alert
+  //! @param theName a name for the alert
+  void SetName (const TCollection_AsciiString& theName) { myName = theName; }
+
+  DEFINE_STANDARD_RTTIEXT(Message_Attribute, Standard_Transient)
+
+private:
+  TCollection_AsciiString myName; //!< alert name, if defined is used in GetMessageKey
+
+};
+
+#endif // _Message_Attribute_HeaderFile
diff --git a/src/Message/Message_AttributeMeter.cxx b/src/Message/Message_AttributeMeter.cxx
new file mode 100644 (file)
index 0000000..227c4b5
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Message_AttributeMeter.hxx>
+
+#include <Precision.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_AttributeMeter, Message_Attribute)
+
+//=======================================================================
+//function : SetValues
+//purpose  : 
+//=======================================================================
+Message_AttributeMeter::Message_AttributeMeter (const TCollection_AsciiString& theName)
+: Message_Attribute(theName)
+{
+}
+
+//=======================================================================
+//function : HasMetric
+//purpose  : 
+//=======================================================================
+Standard_Boolean Message_AttributeMeter::HasMetric (const Message_MetricType& theMetric) const
+{
+  return myMetrics.IsBound (theMetric);
+}
+
+//=======================================================================
+//function : IsMetricValid
+//purpose  : 
+//=======================================================================
+Standard_Boolean Message_AttributeMeter::IsMetricValid (const Message_MetricType& theMetric) const
+{
+  return Abs (StartValue (theMetric) - UndefinedMetricValue()) > Precision::Confusion() &&
+         Abs (StopValue (theMetric) - UndefinedMetricValue()) > Precision::Confusion();
+}
+
+//=======================================================================
+//function : StartValue
+//purpose  : 
+//=======================================================================
+Standard_Real Message_AttributeMeter::StartValue (const Message_MetricType& theMetric) const
+{
+  if (!HasMetric (theMetric))
+    return UndefinedMetricValue();
+
+  return myMetrics.Seek (theMetric)->first;
+}
+
+//=======================================================================
+//function : SetStartValue
+//purpose  : 
+//=======================================================================
+void Message_AttributeMeter::SetStartValue (const Message_MetricType& theMetric, const Standard_Real theValue)
+{
+  if (!HasMetric (theMetric))
+  {
+    myMetrics.Bind (theMetric, std::make_pair (theValue, UndefinedMetricValue()));
+  }
+  myMetrics.ChangeFind (theMetric).first = theValue;
+}
+
+//=======================================================================
+//function : StopValue
+//purpose  : 
+//=======================================================================
+Standard_Real Message_AttributeMeter::StopValue (const Message_MetricType& theMetric) const
+{
+  if (!HasMetric (theMetric))
+    return UndefinedMetricValue();
+
+  return myMetrics.Find (theMetric).second;
+}
+
+//=======================================================================
+//function : SetStopValue
+//purpose  : 
+//=======================================================================
+void Message_AttributeMeter::SetStopValue (const Message_MetricType& theMetric, const Standard_Real theValue)
+{
+  if (!HasMetric (theMetric))
+  {
+    // start value should be already set
+    return;
+  }
+  myMetrics.ChangeFind (theMetric).second = theValue;
+}
diff --git a/src/Message/Message_AttributeMeter.hxx b/src/Message/Message_AttributeMeter.hxx
new file mode 100644 (file)
index 0000000..f563c28
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_AttributeMeter_HeaderFile
+#define _Message_AttributeMeter_HeaderFile
+
+#include <Message_Attribute.hxx>
+#include <Message_MetricType.hxx>
+
+#include <NCollection_DataMap.hxx>
+
+class Message_Alert;
+
+//! Alert object storing alert metrics values.
+//! Start and stop values for each metric.
+class Message_AttributeMeter : public Message_Attribute
+{
+public:
+
+  //! Returns default value of the metric when it is not defined
+  //! @return undefined value
+  static Standard_Real UndefinedMetricValue() { return -1.0; }
+
+public:
+
+  //! Constructor with string argument
+  Standard_EXPORT Message_AttributeMeter (const TCollection_AsciiString& theName = TCollection_AsciiString());
+
+  //! Checks whether the attribute has values for the metric
+  //! @param theMetric [in] metric type
+  //! @return true if the metric values exist in the attribute
+  Standard_EXPORT Standard_Boolean HasMetric (const Message_MetricType& theMetric) const;
+
+  //! Returns true when both values of the metric are set.
+  //! @param theMetric [in] metric type
+  //! @return true if metric values are valid
+  Standard_EXPORT Standard_Boolean IsMetricValid (const Message_MetricType& theMetric) const;
+
+  //! Returns start value for the metric
+  //! @param theMetric [in] metric type
+  //! @return real value
+  Standard_EXPORT Standard_Real StartValue (const Message_MetricType& theMetric) const;
+
+  //! Sets start values for the metric
+  //! @param theMetric [in] metric type
+  Standard_EXPORT void SetStartValue (const Message_MetricType& theMetric, const Standard_Real theValue);
+
+  //! Returns stop value for the metric
+  //! @param theMetric [in] metric type
+  //! @return real value
+  Standard_EXPORT Standard_Real StopValue (const Message_MetricType& theMetric) const;
+
+  //! Sets stop values for the metric
+  //! @param theMetric [in] metric type
+  Standard_EXPORT void SetStopValue (const Message_MetricType& theMetric, const Standard_Real theValue);
+
+  DEFINE_STANDARD_RTTIEXT(Message_AttributeMeter, Message_Attribute)
+
+private:
+
+  typedef std::pair<Standard_Real, Standard_Real> StartToStopValue;
+  NCollection_DataMap<Message_MetricType, StartToStopValue> myMetrics; //!< computed metrics
+};
+
+#endif // _Message_AttributeMeter_HeaderFile
diff --git a/src/Message/Message_AttributeObject.hxx b/src/Message/Message_AttributeObject.hxx
new file mode 100644 (file)
index 0000000..3775685
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_AttributeObject_HeaderFile
+#define _Message_AttributeObject_HeaderFile
+
+#include <Message_Attribute.hxx>
+
+class Standard_Transient;
+
+//! Alert object storing a transient object
+class Message_AttributeObject : public Message_Attribute
+{
+public:
+  //! Constructor with string argument
+  Message_AttributeObject (const Handle(Standard_Transient)& theObject,
+    const TCollection_AsciiString& theName = TCollection_AsciiString())
+  : Message_Attribute (theName) { myObject = theObject; }
+
+  //! Returns object
+  //! @return the object instance
+  const Handle(Standard_Transient)& Object() { return myObject; }
+
+  //! Sets the object
+  //! @param theObject an instance
+  void SetObject (const Handle(Standard_Transient)& theObject) { myObject = theObject; }
+
+  DEFINE_STANDARD_RTTI_INLINE(Message_AttributeObject, Message_Attribute)
+
+private:
+  Handle(Standard_Transient) myObject; //!< alert object
+};
+
+#endif // _Message_AttributeObject_HeaderFile
diff --git a/src/Message/Message_AttributeStream.cxx b/src/Message/Message_AttributeStream.cxx
new file mode 100644 (file)
index 0000000..f0cf931
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Message_AttributeStream.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_AttributeStream, Message_Attribute)
+
+//=======================================================================
+//function : SetValues
+//purpose  : 
+//=======================================================================
+Message_AttributeStream::Message_AttributeStream (const Standard_SStream& theStream,
+                                                  const TCollection_AsciiString& theName)
+: Message_Attribute(theName)
+{
+  SetStream (theStream);
+}
+
+//=======================================================================
+//function : SetStream
+//purpose  : 
+//=======================================================================
+
+void Message_AttributeStream::SetStream (const Standard_SStream& theStream)
+{
+  myStream.str ("");
+
+  TCollection_AsciiString aStreamStr (theStream.str().c_str());
+  myStream << aStreamStr;
+}
+
diff --git a/src/Message/Message_AttributeStream.hxx b/src/Message/Message_AttributeStream.hxx
new file mode 100644 (file)
index 0000000..c4a7352
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_AttributeStream_HeaderFile
+#define _Message_AttributeStream_HeaderFile
+
+#include <Message_Attribute.hxx>
+
+#include <NCollection_Vector.hxx>
+#include <Standard_SStream.hxx>
+
+//! Alert object storing stream values
+class Message_AttributeStream : public Message_Attribute
+{
+public:
+
+  //! Constructor with string argument
+  Standard_EXPORT Message_AttributeStream (const Standard_SStream& theStream,
+    const TCollection_AsciiString& theName = TCollection_AsciiString());
+
+  //! Returns stream value
+  const Standard_SStream& Stream() const { return myStream; }
+
+  //! Sets stream value
+  Standard_EXPORT void SetStream (const Standard_SStream& theStream);
+
+  DEFINE_STANDARD_RTTIEXT(Message_AttributeStream, Message_Attribute)
+
+private:
+  Standard_SStream myStream; //!< container of values
+};
+
+#endif // _Message_AttributeStream_HeaderFile
diff --git a/src/Message/Message_CompositeAlerts.cxx b/src/Message/Message_CompositeAlerts.cxx
new file mode 100644 (file)
index 0000000..48d0e14
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Message_CompositeAlerts.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Standard_Assert.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_CompositeAlerts, Standard_Transient)
+
+//=======================================================================
+//function : Alerts
+//purpose  :
+//=======================================================================
+const Message_ListOfAlert& Message_CompositeAlerts::Alerts (const Message_Gravity theGravity) const
+{
+  static const Message_ListOfAlert anEmptyList;
+  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
+                          "Requesting alerts for gravity not in valid range", anEmptyList);
+
+  return myAlerts[theGravity];
+}
+
+//=======================================================================
+//function : AddAlert
+//purpose  :
+//=======================================================================
+Standard_Boolean Message_CompositeAlerts::AddAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert)
+{
+  Standard_ASSERT_RETURN (! theAlert.IsNull(), "Attempt to add null alert", Standard_False);
+  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
+                          "Adding alert with gravity not in valid range", Standard_False);
+
+  Message_ListOfAlert& aList = myAlerts[theGravity];
+  if (theAlert->SupportsMerge() && ! aList.IsEmpty())
+  {
+    // merge is performed only for alerts of exactly same type
+    const Handle(Standard_Type)& aType = theAlert->DynamicType();
+    for (Message_ListOfAlert::Iterator anIt(aList); anIt.More(); anIt.Next())
+    {
+      // if merged successfully, just return
+      if (aType == anIt.Value()->DynamicType() && theAlert->Merge (anIt.Value()))
+        return Standard_False;
+    }
+  }
+
+  // if not merged, just add to the list
+  aList.Append (theAlert);
+  return Standard_True;
+}
+
+//=======================================================================
+//function : RemoveAlert
+//purpose  : 
+//=======================================================================
+Standard_Boolean Message_CompositeAlerts::RemoveAlert (Message_Gravity theGravity,
+                                                       const Handle(Message_Alert)& theAlert)
+{
+  Standard_ASSERT_RETURN (! theAlert.IsNull(), "Attempt to add null alert", Standard_False);
+  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
+                          "Adding alert with gravity not in valid range", Standard_False);
+
+  Message_ListOfAlert& anAlerts = myAlerts[theGravity];
+  if (!anAlerts.Contains (theAlert))
+      return Standard_False;
+
+  return anAlerts.Remove (theAlert);
+}
+
+//=======================================================================
+//function : HasAlerts
+//purpose  :
+//=======================================================================
+
+Standard_Boolean Message_CompositeAlerts::HasAlert (const Handle(Message_Alert)& theAlert)
+{
+  for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter)
+  {
+    const Message_ListOfAlert& anAlerts = Alerts ((Message_Gravity)aGravIter);
+    if (anAlerts.Contains (theAlert))
+      return Standard_True;
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+//function : HasAlerts
+//purpose  :
+//=======================================================================
+Standard_Boolean Message_CompositeAlerts::HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity)
+{
+  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
+                          "Requesting alerts for gravity not in valid range", Standard_False);
+
+  for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next())
+  {
+    if (anIt.Value()->IsInstance(theType))
+      return Standard_True;
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+//function : Clear
+//purpose  :
+//=======================================================================
+void Message_CompositeAlerts::Clear ()
+{
+  for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i)
+  {
+    myAlerts[i].Clear();
+  }
+}
+
+//=======================================================================
+//function : Clear
+//purpose  :
+//=======================================================================
+void Message_CompositeAlerts::Clear (Message_Gravity theGravity)
+{
+  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
+                          "Requesting alerts for gravity not in valid range", );
+  myAlerts[theGravity].Clear();
+}
+
+//=======================================================================
+//function : Clear
+//purpose  :
+//=======================================================================
+void Message_CompositeAlerts::Clear (const Handle(Standard_Type)& theType)
+{
+  for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i)
+  {
+    for (Message_ListOfAlert::Iterator anIt (myAlerts[i]); anIt.More(); )
+    {
+      if (anIt.Value().IsNull() || anIt.Value()->IsInstance (theType))
+      {
+        myAlerts[i].Remove (anIt);
+      }
+      else
+      {
+        anIt.More();
+      }
+    }
+  }
+}
diff --git a/src/Message/Message_CompositeAlerts.hxx b/src/Message/Message_CompositeAlerts.hxx
new file mode 100644 (file)
index 0000000..0864e05
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_CompositeAlerts_HeaderFile
+#define _Message_CompositeAlerts_HeaderFile
+
+#include <Message_Alert.hxx>
+#include <Message_Gravity.hxx>
+#include <Message_ListOfAlert.hxx>
+#include <Standard_Transient.hxx>
+
+class Message_CompositeAlerts;
+DEFINE_STANDARD_HANDLE(Message_CompositeAlerts, Standard_Transient)
+
+//! Class providing container of alerts
+class Message_CompositeAlerts : public Standard_Transient
+{
+public:
+  //! Empty constructor
+  Standard_EXPORT Message_CompositeAlerts() {}
+
+  //! Returns list of collected alerts with specified gravity
+  Standard_EXPORT const Message_ListOfAlert& Alerts (const Message_Gravity theGravity) const;
+
+  //! Add alert with specified gravity. If the alert supports merge it will be merged.
+  //! @param theGravity an alert gravity
+  //! @param theAlert an alert to be added as a child alert
+  //! @return true if the alert is added or merged
+  Standard_EXPORT Standard_Boolean AddAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert);
+
+  //! Removes alert with specified gravity.
+  //! @param theGravity an alert gravity
+  //! @param theAlert an alert to be removed from the children
+  //! @return true if the alert is removed
+  Standard_EXPORT Standard_Boolean RemoveAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert);
+
+  //! Returns true if the alert belong the list of the child alerts.
+  //! @param theAlert an alert to be checked as a child alert
+  //! @return true if the alert is found in a container of children
+  Standard_EXPORT Standard_Boolean HasAlert (const Handle(Message_Alert)& theAlert);
+
+  //! Returns true if specific type of alert is recorded with specified gravity
+  //! @param theType an alert type
+  //! @param theGravity an alert gravity
+  //! @return true if the alert is found in a container of children
+  Standard_EXPORT Standard_Boolean HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity);
+
+  //! Clears all collected alerts
+  Standard_EXPORT void Clear ();
+
+  //! Clears collected alerts with specified gravity
+  //! @param theGravity an alert gravity
+  Standard_EXPORT void Clear (Message_Gravity theGravity);
+
+  //! Clears collected alerts with specified type
+  //! @param theType an alert type
+  Standard_EXPORT void Clear (const Handle(Standard_Type)& theType);
+
+  DEFINE_STANDARD_RTTIEXT(Message_CompositeAlerts,Standard_Transient)
+
+protected:
+  // store messages in a lists sorted by gravity;
+  // here we rely on knowledge that Message_Fail is the last element of the enum
+  Message_ListOfAlert myAlerts[Message_Fail + 1]; //!< container of child alert for each type of gravity
+};
+
+#endif // _Message_CompositeAlerts_HeaderFile
diff --git a/src/Message/Message_Level.cxx b/src/Message/Message_Level.cxx
new file mode 100644 (file)
index 0000000..e022264
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Message_Level.hxx>
+
+#include <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_CompositeAlerts.hxx>
+#include <Message_AttributeMeter.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_Report.hxx>
+
+#include <OSD_Chronometer.hxx>
+#include <OSD_MemInfo.hxx>
+
+//=======================================================================
+//function : Message_Level
+//purpose  :
+//=======================================================================
+Message_Level::Message_Level()
+{
+  const Handle(Message_Report)& aDefaultReport = Message::DefaultReport();
+  if (!aDefaultReport.IsNull() && aDefaultReport->IsActiveInMessenger())
+    aDefaultReport->AddLevel (this);
+}
+
+//=======================================================================
+//function : Destructor
+//purpose  :
+//=======================================================================
+Message_Level::~Message_Level()
+{
+  Remove();
+}
+
+//=======================================================================
+//function : SetRootAlert
+//purpose  :
+//=======================================================================
+void Message_Level::SetRootAlert (const Handle(Message_AlertExtended)& theAlert)
+{
+  myRootAlert = theAlert;
+  startAlert (myRootAlert);
+}
+
+//=======================================================================
+//function : AddAlert
+//purpose  :
+//=======================================================================
+Standard_Boolean Message_Level::AddAlert (const Message_Gravity theGravity,
+                                          const Handle(Message_Alert)& theAlert)
+{
+  Handle(Message_AlertExtended) anAlertExtended = Handle(Message_AlertExtended)::DownCast (theAlert);
+  if (anAlertExtended.IsNull())
+    return Standard_False;
+
+  if (myRootAlert.IsNull())
+    return Standard_False;
+
+  // looking for the parent of the parameter alert to release the previous alert
+  Handle(Message_AlertExtended) aRootAlert = myRootAlert;
+  Handle(Message_CompositeAlerts) aCompositeAlert = aRootAlert->CompositeAlerts (Standard_True);
+
+  // update metrics of the previous alert
+  stopAlert (myLastAlert);
+
+  myLastAlert = anAlertExtended;
+
+  // set start metrics of the new alert
+  startAlert (myLastAlert);
+
+  // add child alert
+  aCompositeAlert->AddAlert (theGravity, theAlert);
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : AddLevelAlert
+//purpose  :
+//=======================================================================
+Standard_Boolean Message_Level::AddLevelAlert (const Message_Gravity theGravity,
+                                               const Handle(Message_Alert)& theAlert)
+{
+  Handle(Message_AlertExtended) aRootAlert = !myLastAlert.IsNull() ? myLastAlert : myRootAlert;
+  if (aRootAlert.IsNull())
+    return Standard_False;
+
+  Handle(Message_CompositeAlerts) aCompositeAlert = aRootAlert->CompositeAlerts (Standard_True);
+  // add child alert
+  aCompositeAlert->AddAlert (theGravity, theAlert);
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : Remove()
+//purpose  :
+//=======================================================================
+void Message_Level::Remove()
+{
+  const Handle(Message_Report)& aDefaultReport = Message::DefaultReport();
+  if (aDefaultReport.IsNull() || !aDefaultReport->IsActiveInMessenger())
+    return;
+
+  stopAlert (myLastAlert);
+  stopAlert (myRootAlert);
+
+  if (!Message::DefaultReport().IsNull())
+    Message::DefaultReport()->RemoveLevel (this);
+}
+
+//=======================================================================
+//function : setAlertMetrics
+//purpose  :
+//=======================================================================
+void Message_Level::setAlertMetrics (const Handle(Message_AlertExtended)& theAlert,
+                                                 const Standard_Boolean theStartValue)
+{
+  if (theAlert.IsNull())
+    return;
+
+  Handle(Message_AttributeMeter) aMeterAttribute = Handle(Message_AttributeMeter)::DownCast (theAlert->Attribute());
+  if (aMeterAttribute.IsNull())
+    return;
+
+  Handle(Message_Report) aReport = Message::DefaultReport (Standard_True);
+  const NCollection_Map<Message_MetricType>& anActiveMetrics = aReport->ActiveMetrics();
+
+  // time metrics
+  if (anActiveMetrics.Contains (Message_MetricType_UserTimeCPU) ||
+      anActiveMetrics.Contains (Message_MetricType_SystemTimeInfo))
+  {
+    Standard_Real aUserSeconds, aSystemSeconds;
+    OSD_Chronometer::GetThreadCPU (aUserSeconds, aSystemSeconds);
+
+    if (anActiveMetrics.Contains (Message_MetricType_UserTimeCPU))
+    {
+      if (theStartValue)
+        aMeterAttribute->SetStartValue (Message_MetricType_UserTimeCPU, aUserSeconds);
+      else
+        aMeterAttribute->SetStopValue (Message_MetricType_UserTimeCPU, aUserSeconds);
+    }
+    if (anActiveMetrics.Contains (Message_MetricType_SystemTimeInfo))
+    {
+      if (theStartValue)
+        aMeterAttribute->SetStartValue (Message_MetricType_SystemTimeInfo, aSystemSeconds);
+      else
+        aMeterAttribute->SetStopValue (Message_MetricType_SystemTimeInfo, aSystemSeconds);
+    }
+  }
+  // memory metrics
+  NCollection_Map<OSD_MemInfo::Counter> aCounters;
+  for (NCollection_Map<Message_MetricType>::Iterator anIterator (anActiveMetrics); anIterator.More(); anIterator.Next())
+  {
+    OSD_MemInfo::Counter aMemInfo;
+    if (!Message::ToOSDMetric (anIterator.Value(), aMemInfo))
+      continue;
+
+    aCounters.Add (aMemInfo);
+  }
+  if (aCounters.IsEmpty())
+    return;
+
+  OSD_MemInfo aMemInfo (Standard_False);
+  //aMemInfo.SetActiveCounters (aCounters);
+  aMemInfo.Update ();
+  Message_MetricType aMetricType;
+  for (NCollection_Map<OSD_MemInfo::Counter>::Iterator anIterator (aCounters); anIterator.More(); anIterator.Next())
+  {
+    if (!Message::ToMessageMetric (anIterator.Value(), aMetricType))
+      continue;
+
+    if (theStartValue)
+      aMeterAttribute->SetStartValue (aMetricType, (Standard_Real)aMemInfo.ValuePreciseMiB (anIterator.Value()));
+    else
+      aMeterAttribute->SetStopValue (aMetricType, (Standard_Real)aMemInfo.ValuePreciseMiB (anIterator.Value()));
+  }
+}
diff --git a/src/Message/Message_Level.hxx b/src/Message/Message_Level.hxx
new file mode 100644 (file)
index 0000000..0433722
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_Level_HeaderFile
+#define _Message_Level_HeaderFile
+
+#include <Message_AlertExtended.hxx>
+#include <Message_Gravity.hxx>
+#include <Message_MetricType.hxx>
+
+#include <NCollection_DataMap.hxx>
+#include <Standard.hxx>
+
+//! This class is an instance of Sentry to create a level in a message report
+//! Constructor of the class add new (active) level in the report, destructor removes it
+//! While the level is active in the report, new alerts are added below the level root alert.
+//!
+//! The first added alert is a root alert, other are added below the root alert
+//!
+//! If alert has Message_AttributeMeter attribute, active metrics of the default report are stored in
+//! the attriute: start value of metric on adding alert, stop on adding another alert or closing (delete) the level
+//! in the report.
+//!
+//! Processing of this class is implemented in Message_Report, it is used only insided it.
+//! Levels using should be only through using MESSAGE_ADD_LEVEL_SENTRY only. No other code is required outside.
+class Message_Level
+{
+
+public:
+  //! Constructor. Append
+  //! One string key is used for all alert meters. The perf meter is not started automatically, it will be done in
+  //! AddAlert method
+  Standard_EXPORT Message_Level();
+
+  //! Assures stopping upon destruction
+  Standard_EXPORT ~Message_Level();
+
+  //! Returns root alert of the level
+  //! @return alert instance or NULL
+  const Handle(Message_AlertExtended)& RootAlert() const { return myRootAlert; }
+
+  //! Sets the root alert. Starts collects alert metrics if active.
+  //! @param theAlert an alert  
+  Standard_EXPORT void SetRootAlert (const Handle(Message_AlertExtended)& theAlert);
+
+  //! Adds new alert on the level. Stops the last alert metric, appends the alert and starts the alert metrics collecting.
+  //! Sets root alert beforehead this method using, if the root is NULL, it does nothing.
+  //! @param theGravity an alert gravity
+  //! @param theAlert an alert  
+  //! @return true if alert is added
+  Standard_EXPORT Standard_Boolean AddAlert (const Message_Gravity theGravity,
+                                             const Handle(Message_Alert)& theAlert);
+
+  //! Add new alert as a child of the last alert if exists or as a child of the root alert.
+  //! @param theGravity an alert gravity
+  //! @param theAlert an alert  
+  //! @return true if alert is added
+  Standard_EXPORT Standard_Boolean AddLevelAlert (const Message_Gravity theGravity,
+                                                  const Handle(Message_Alert)& theAlert);
+
+  //! Remove the current level from the report. It stops metric collecting for the last and the root alerts.
+  Standard_EXPORT void Remove();
+
+protected:
+  //! Sets start values of default report metrics into the alert
+  //! @param theAlert an alert  
+  void startAlert (const Handle(Message_AlertExtended)& theAlert) { setAlertMetrics (theAlert, Standard_True); }
+
+  //! Sets stop values of default report metrics into the alert
+  //! @param theAlert an alert  
+  void stopAlert (const Handle(Message_AlertExtended)& theAlert) { setAlertMetrics (theAlert, Standard_True); }
+
+  //! Sets current values of default report metrics into the alert.
+  //! Processed oly alert with Message_AttributeMeter attribute
+  //! @param theAlert an alert  
+  //! @param theStartValue flag, if true, the start value is collected otherwise stop
+  Standard_EXPORT void setAlertMetrics (const Handle(Message_AlertExtended)& theAlert,
+                                        const Standard_Boolean theStartValue);
+
+protected:
+  Handle(Message_AlertExtended) myRootAlert; //!< root alert
+  Handle(Message_AlertExtended) myLastAlert; //!< last added alert on the root alert
+};
+
+//! @def MESSAGE_NEW_LEVEL
+//! Creates a new level instance of Sentry. This row should be inserted before messages using in the method.
+#define MESSAGE_ADD_LEVEL_SENTRY Message_Level aLevel;
+
+#endif // _Message_Level_HeaderFile
index 1e44c8b22088a0df17d6cb11cda947fa5e0a4451..c2e2c71799d579279fda8b135968e49a8b2fd4dc 100644 (file)
@@ -25,6 +25,7 @@ IMPLEMENT_STANDARD_RTTIEXT(Message_Messenger,Standard_Transient)
 //purpose  : 
 //=======================================================================
 Message_Messenger::Message_Messenger ()
+: myOutputGravity (Message_Info)
 {
   AddPrinter ( new Message_PrinterOStream );
 }
@@ -35,6 +36,7 @@ Message_Messenger::Message_Messenger ()
 //=======================================================================
 
 Message_Messenger::Message_Messenger (const Handle(Message_Printer)& thePrinter)
+: myOutputGravity (Message_Info)
 {
   AddPrinter (thePrinter);
 }
@@ -161,3 +163,41 @@ void Message_Messenger::Send (const TCollection_ExtendedString& theString,
     }
   }
 }
+
+//=======================================================================
+//function : Send
+//purpose  : 
+//=======================================================================
+
+void Message_Messenger::Send (const Standard_SStream& theStream,
+                              const Message_Gravity theGravity,
+                              const Standard_Boolean putEndl) const
+{
+  for (Message_SequenceOfPrinters::Iterator aPrinterIter (myPrinters); aPrinterIter.More(); aPrinterIter.Next())
+  {
+    const Handle(Message_Printer)& aPrinter = aPrinterIter.Value();
+    if (!aPrinter.IsNull())
+    {
+      aPrinter->Send (theStream, theGravity, putEndl);
+    }
+  }
+}
+
+//=======================================================================
+//function : Send
+//purpose  : 
+//=======================================================================
+
+void Message_Messenger::Send (const Handle(Standard_Transient)& theObject,
+                              const Message_Gravity theGravity,
+                              const Standard_Boolean putEndl) const
+{
+  for (Message_SequenceOfPrinters::Iterator aPrinterIter (myPrinters); aPrinterIter.More(); aPrinterIter.Next())
+  {
+    const Handle(Message_Printer)& aPrinter = aPrinterIter.Value();
+    if (!aPrinter.IsNull())
+    {
+      aPrinter->Send (theObject, theGravity, putEndl);
+    }
+  }
+}
index 675fba34360e9ebac56b817193ccafb769e5f1ba..398c92792f51173d115a3ae992d999d6064878f7 100644 (file)
@@ -84,6 +84,12 @@ public:
   //! The sequence can be modified.
   Message_SequenceOfPrinters& ChangePrinters() { return myPrinters; }
 
+  //! Returns the output gavity used in operator <<
+  Message_Gravity OuputGravity() const { return myOutputGravity; }
+
+  //! Sets the output gavity used in operator <<
+  void SetOuputGravity (const Message_Gravity theValue) { myOutputGravity = theValue; }
+
   //! Dispatch a message to all the printers in the list.
   //! Three versions of string representations are accepted for
   //! convenience, by default all are converted to ExtendedString.
@@ -98,17 +104,23 @@ public:
   //! See above
   Standard_EXPORT void Send (const TCollection_ExtendedString& theString, const Message_Gravity theGravity = Message_Warning, const Standard_Boolean putEndl = Standard_True) const;
 
+  //! See above
+  Standard_EXPORT void Send (const Standard_SStream& theStream, const Message_Gravity theGravity = Message_Warning, const Standard_Boolean putEndl = Standard_True) const;
+
+  //! See above
+  Standard_EXPORT void Send (const Handle(Standard_Transient)& theObject, const Message_Gravity theGravity = Message_Warning, const Standard_Boolean putEndl = Standard_True) const;
+
 private:
 
   Message_SequenceOfPrinters myPrinters;
-
+  Message_Gravity myOutputGravity; //!< gravity used in operator <<
 };
 
 // CString
 inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
                                                     const Standard_CString theStr)
 {
-  theMessenger->Send (theStr, Message_Info, Standard_False);
+  theMessenger->Send (theStr, theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -116,7 +128,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng
 inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
                                                     const TCollection_AsciiString& theStr)
 {
-  theMessenger->Send (theStr, Message_Info, Standard_False);
+  theMessenger->Send (theStr, theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -124,7 +136,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng
 inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
                                                     const Handle(TCollection_HAsciiString)& theStr)
 {
-  theMessenger->Send (theStr->String(), Message_Info, Standard_False);
+  theMessenger->Send (theStr->String(), theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -132,7 +144,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng
 inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
                                                     const TCollection_ExtendedString& theStr)
 {
-  theMessenger->Send (theStr, Message_Info, Standard_False);
+  theMessenger->Send (theStr, theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -140,7 +152,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng
 inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
                                                     const Handle(TCollection_HExtendedString)& theStr)
 {
-  theMessenger->Send (theStr->String(), Message_Info, Standard_False);
+  theMessenger->Send (theStr->String(), theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -149,7 +161,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng
                                                     const Standard_Integer theVal)
 {
   TCollection_AsciiString aStr (theVal);
-  theMessenger->Send (aStr, Message_Info, Standard_False);
+  theMessenger->Send (aStr, theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -158,7 +170,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng
                                                     const Standard_Real theVal)
 {
   TCollection_AsciiString aStr (theVal);
-  theMessenger->Send (aStr, Message_Info, Standard_False);
+  theMessenger->Send (aStr, theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -166,7 +178,15 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng
 inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
                                                     const Standard_SStream& theStream)
 {
-  theMessenger->Send (theStream.str().c_str(), Message_Info, Standard_False);
+  theMessenger->Send (theStream, theMessenger->OuputGravity(), Standard_False);
+  return theMessenger;
+}
+
+// AsciiString
+inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
+                                                    const Handle(Standard_Transient)& theObject)
+{
+  theMessenger->Send (theObject, theMessenger->OuputGravity(), Standard_False);
   return theMessenger;
 }
 
@@ -181,7 +201,7 @@ inline const Handle(Message_Messenger)&
 // Message_EndLine
 inline const Handle(Message_Messenger)& Message_EndLine (const Handle(Message_Messenger)& theMessenger)
 {
-  theMessenger->Send ("", Message_Info, Standard_True);
+  theMessenger->Send ("", theMessenger->OuputGravity(), Standard_True);
   return theMessenger;
 }
 
diff --git a/src/Message/Message_MetricType.hxx b/src/Message/Message_MetricType.hxx
new file mode 100644 (file)
index 0000000..a99db83
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_MetricType_HeaderFile
+#define _Message_MetricType_HeaderFile
+
+//! Specifies kind of report information to collect
+enum Message_MetricType
+{
+  Message_MetricType_None,              //!< no computation
+  Message_MetricType_UserTimeCPU,       //!< the current CPU user time in seconds
+  Message_MetricType_SystemTimeInfo,    //!< the current CPU system time in seconds
+  Message_MetricType_MemPrivate,        //!< OSD_MemInfo::MemPrivate
+  Message_MetricType_MemVirtual,        //!< OSD_MemInfo::MemVirtual
+  Message_MetricType_MemWorkingSet,     //!< OSD_MemInfo::MemWorkingSet
+  Message_MetricType_MemWorkingSetPeak, //!< OSD_MemInfo::MemWorkingSetPeak
+  Message_MetricType_MemSwapUsage,      //!< OSD_MemInfo::MemSwapUsage
+  Message_MetricType_MemSwapUsagePeak,  //!< OSD_MemInfo::MemSwapUsagePeak
+  Message_MetricType_MemHeapUsage       //!< OSD_MemInfo::MemHeapUsage
+};
+
+#endif // _Message_MetricType_HeaderFile
index 8ed2b87e6a5a52d142bfa885557c8b9e90e4a259..cc1c09878d8beb2b94f0270446f4daad9be5de0a 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <Message_Printer.hxx>
 
+#include <Standard_Dump.hxx>
 #include <TCollection_AsciiString.hxx>
 #include <TCollection_ExtendedString.hxx>
 
@@ -58,3 +59,37 @@ void Message_Printer::Send (const TCollection_AsciiString& theString,
     Send (TCollection_ExtendedString (theString), theGravity, theToOutEol);
   }
 }
+
+//=======================================================================
+//function : Send
+//purpose  :
+//=======================================================================
+
+void Message_Printer::Send (const Standard_SStream& theStream,
+                            const Message_Gravity   theGravity,
+                            const Standard_Boolean  theToOutEol) const
+{
+  if (theGravity >= myTraceLevel)
+  {
+    Send (TCollection_ExtendedString (theStream.str().c_str()), theGravity, theToOutEol);
+  }
+}
+
+//=======================================================================
+//function : Send
+//purpose  :
+//=======================================================================
+void Message_Printer::Send (const Handle(Standard_Transient)& theObject,
+                            const Message_Gravity          theGravity,
+                            const Standard_Boolean         theToOutEol) const
+{
+  if (theObject.IsNull())
+    return;
+
+  if (theGravity >= myTraceLevel)
+  {
+    TCollection_ExtendedString aString = TCollection_ExtendedString (theObject->DynamicType()->Name())
+      + ": " + Standard_Dump::GetPointerInfo (theObject);
+    Send (aString, theGravity, theToOutEol);
+  }
+}
index e7e70ddfbd8694b548ab749a00cc2570236cc3cb..ae877c7081efcf803b460640225c2e8ac6321626 100644 (file)
@@ -23,6 +23,8 @@
 #include <Standard_Transient.hxx>
 #include <Standard_Boolean.hxx>
 #include <Standard_CString.hxx>
+#include <Standard_SStream.hxx>
+
 class TCollection_ExtendedString;
 class TCollection_AsciiString;
 
@@ -62,6 +64,18 @@ public:
   //! Default implementation calls first method Send().
   Standard_EXPORT virtual void Send (const TCollection_AsciiString& theString, const Message_Gravity theGravity, const Standard_Boolean theToPutEol) const;
 
+  //! Send a string message with specified trace level.
+  //! Stream is converted to string value.
+  //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message.
+  //! Default implementation calls first method Send().
+  Standard_EXPORT virtual void Send (const Standard_SStream& theStream, const Message_Gravity theGravity, const Standard_Boolean theToPutEol) const;
+
+  //! Send a string message with specified trace level.
+  //! The object is converted to string in format: <object kind> : <object pointer>.
+  //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message.
+  //! Default implementation calls first method Send().
+  Standard_EXPORT virtual void Send (const Handle(Standard_Transient)& theObject, const Message_Gravity theGravity, const Standard_Boolean theToPutEol) const;
+
 protected:
 
   //! Empty constructor with Message_Info trace level
diff --git a/src/Message/Message_PrinterToReport.cxx b/src/Message/Message_PrinterToReport.cxx
new file mode 100644 (file)
index 0000000..a36885f
--- /dev/null
@@ -0,0 +1,119 @@
+// Created on: 2001-01-06
+// Created by: OCC Team
+// Copyright (c) 2001-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Message_PrinterToReport.hxx>
+
+#include <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_Attribute.hxx>
+#include <Message_AttributeMeter.hxx>
+#include <Message_AttributeObject.hxx>
+#include <Message_AttributeStream.hxx>
+#include <Message_Report.hxx>
+
+#include <Standard_Dump.hxx>
+#include <TCollection_ExtendedString.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_PrinterToReport, Message_Printer)
+
+//=======================================================================
+//function : Report
+//purpose  : 
+//=======================================================================
+const Handle(Message_Report)& Message_PrinterToReport::Report() const
+{
+  if (!myReport.IsNull())
+    return myReport;
+
+  return Message::DefaultReport (Standard_True);
+}
+
+//=======================================================================
+//function : Send
+//purpose  : 
+//=======================================================================
+void Message_PrinterToReport::Send (const TCollection_ExtendedString& theString,
+                                    const Message_Gravity theGravity,
+                                    const Standard_Boolean putEndl) const
+{
+  TCollection_AsciiString aString (theString/*, myUseUtf8 ? Standard_Character(0) : '?'*/);
+
+  if (putEndl)
+  {
+    if (myValue.IsEmpty())
+      return;
+
+    const Handle(Message_Report)& aReport = Report();
+    if (!aReport->ActiveMetrics().IsEmpty())
+    {
+      sendMetricAlert (myValue, theGravity);
+      return;
+    }
+    Message_AlertExtended::AddAlert (aReport, new Message_Attribute (myValue), theGravity);
+    ((Message_PrinterToReport*)this)->Clear();
+    return;
+  }
+  ((Message_PrinterToReport*)this)->myValue += aString;
+}
+
+//=======================================================================
+//function : Send
+//purpose  : 
+//=======================================================================
+void Message_PrinterToReport::Send (const Standard_SStream& theStream,
+                                    const Message_Gravity theGravity,
+                                    const Standard_Boolean /*putEndl*/) const
+{
+  const Handle(Message_Report)& aReport = Report();
+  if (!aReport->ActiveMetrics().IsEmpty())
+  {
+    sendMetricAlert (myValue, theGravity);
+    return;
+  }
+  Message_AlertExtended::AddAlert (aReport, new Message_AttributeStream (theStream, myValue), theGravity);
+  ((Message_PrinterToReport*)this)->Clear();
+
+  return;
+}
+
+//=======================================================================
+//function : Send
+//purpose  : 
+//=======================================================================
+void Message_PrinterToReport::Send (const Handle(Standard_Transient)& theObject,
+                                    const Message_Gravity theGravity,
+                                    const Standard_Boolean /*putEndl*/) const
+{
+  const Handle(Message_Report)& aReport = Report();
+  if (!aReport->ActiveMetrics().IsEmpty())
+  {
+    sendMetricAlert (myValue, theGravity);
+    return;
+  }
+
+  Message_AlertExtended::AddAlert (aReport, new Message_AttributeObject (theObject, myValue), theGravity);
+  ((Message_PrinterToReport*)this)->Clear();
+}
+
+//=======================================================================
+//function : sendMetricAlert
+//purpose  : 
+//=======================================================================
+void Message_PrinterToReport::sendMetricAlert (const TCollection_AsciiString theValue,
+                                               const Message_Gravity theGravity) const
+{
+  Message_AlertExtended::AddAlert (Report(), new Message_AttributeMeter (theValue), theGravity);
+  ((Message_PrinterToReport*)this)->Clear();
+}
diff --git a/src/Message/Message_PrinterToReport.hxx b/src/Message/Message_PrinterToReport.hxx
new file mode 100644 (file)
index 0000000..8de6832
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Message_PrinterToReport_HeaderFile
+#define _Message_PrinterToReport_HeaderFile
+
+#include <Message_Printer.hxx>
+#include <Standard_Address.hxx>
+#include <Standard_OStream.hxx>
+#include <TCollection_AsciiString.hxx>
+
+class Message_Report;
+
+class Message_PrinterToReport;
+DEFINE_STANDARD_HANDLE(Message_PrinterToReport, Message_Printer)
+
+//! Implementation of a message printer associated with Message_Report
+//! Send will create a new alert of the report. If string is sent, an alert is created by Eol only.
+//! The alerts are sent into set report or default report of Message.
+class Message_PrinterToReport : public Message_Printer
+{
+  DEFINE_STANDARD_RTTIEXT(Message_PrinterToReport, Message_Printer)
+
+public:
+  //! Create printer for redirecting messages into report.
+  Message_PrinterToReport() {}
+
+  ~Message_PrinterToReport() {}
+
+  //! Returns the current or default report
+  Standard_EXPORT const Handle(Message_Report)& Report() const;
+
+  //! Sets the printer report
+  //! @param theReport report for messages processing, if NULL, the default report is used
+  Standard_EXPORT void SetReport (const Handle(Message_Report)& theReport) { myReport = theReport; }
+
+  //!< Returns the first sent value
+  const TCollection_AsciiString& Value() { return myValue; }
+
+  //! Clears current values
+  Standard_EXPORT void Clear() { myValue.Clear(); }
+
+  //! Appends a new alert into message report if Endl is false or send a new extended alert with attribute on value
+  //! Use Message_EndLine to finalize the current alert
+  Standard_EXPORT virtual void Send (const TCollection_ExtendedString& theString,
+                                     const Message_Gravity theGravity,
+                                     const Standard_Boolean putEndl = Standard_True) const Standard_OVERRIDE;
+
+  //! Send a string message with specified trace level.
+  //! Stream is converted to string value.
+  //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message.
+  //! Default implementation calls first method Send().
+  Standard_EXPORT virtual void Send (const Standard_SStream& theStream,
+                                     const Message_Gravity theGravity,
+                                     const Standard_Boolean theToPutEol) const Standard_OVERRIDE;
+
+  //! Send a string message with specified trace level.
+  //! The object is converted to string in format: <object kind> : <object pointer>.
+  //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message.
+  //! Default implementation calls first method Send().
+  Standard_EXPORT virtual void Send (const Handle(Standard_Transient)& theObject,
+                                     const Message_Gravity theGravity,
+                                     const Standard_Boolean theToPutEol) const Standard_OVERRIDE;
+protected:
+
+  //! Send an alert with metrics active in the current report
+  Standard_EXPORT void sendMetricAlert (const TCollection_AsciiString theValue,
+                                        const Message_Gravity theGravity) const;
+
+private:
+  Handle(Message_Report) myReport; //!< the report for sending alerts
+  TCollection_AsciiString myValue; //!< the union of sent strings until Eol
+};
+
+#endif // _Message_PrinterToReport_HeaderFile
index 07324599d2fc5bbed00fe24b37848cd2221143b9..74e1eff6e40ba25bb17cc8b3a0505215cc6d18fc 100644 (file)
 // commercial license or contractual agreement.
 
 #include <Message_Report.hxx>
+
+#include <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_CompositeAlerts.hxx>
 #include <Message_Msg.hxx>
 #include <Message_Messenger.hxx>
+#include <Message_PrinterToReport.hxx>
+
 #include <NCollection_Map.hxx>
+#include <Precision.hxx>
+#include <Standard_Dump.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(Message_Report,Standard_Transient)
 
@@ -26,6 +34,7 @@ IMPLEMENT_STANDARD_RTTIEXT(Message_Report,Standard_Transient)
 //=======================================================================
 
 Message_Report::Message_Report ()
+: myLimit (-1)
 {
 }
 
@@ -36,28 +45,50 @@ Message_Report::Message_Report ()
 
 void Message_Report::AddAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert)
 {
-  Standard_ASSERT_RETURN (! theAlert.IsNull(), "Attempt to add null alert",);
-  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
-                          "Adding alert with gravity not in valid range",);
-
   Standard_Mutex::Sentry aSentry (myMutex);
 
-  // iterate by already recorded alerts and try to merge new one with one of those
-  Message_ListOfAlert &aList = myAlerts[theGravity];
-  if (theAlert->SupportsMerge() && ! aList.IsEmpty())
+   // alerts of the top level
+  if (myAlertLevels.IsEmpty())
   {
-    // merge is performed only for alerts of exactly same type
-    const Handle(Standard_Type)& aType = theAlert->DynamicType();
-    for (Message_ListOfAlert::Iterator anIt(aList); anIt.More(); anIt.Next())
+    Handle (Message_CompositeAlerts) aCompositeAlert = compositeAlerts (Standard_True);
+    if (aCompositeAlert->AddAlert (theGravity, theAlert))
+      return;
+
+    // remove alerts under the report only
+    const Message_ListOfAlert& anAlerts = aCompositeAlert->Alerts (theGravity);
+    if (anAlerts.Extent() > myLimit)
     {
-      // if merged successfully, just return
-      if (aType == anIt.Value()->DynamicType() && theAlert->Merge (anIt.Value()))
-        return;
+      aCompositeAlert->RemoveAlert (theGravity, anAlerts.First());
     }
+    return;
   }
 
-  // if not merged, just add to the list
-  aList.Append (theAlert);
+  // if there are some levels of alerts
+  // iterate by already recorded alerts and try to merge new one with one of those
+  Message_Level* aLevel = myAlertLevels.Last();
+
+  // level has root alert, the new alert will be placed below the root
+  if (!aLevel->RootAlert().IsNull())
+  {
+    aLevel->AddAlert (theGravity, theAlert);
+    return;
+  }
+
+  Handle(Message_AlertExtended) anAlert = Handle(Message_AlertExtended)::DownCast (theAlert);
+  if (anAlert.IsNull())
+    return;
+  // place new alert as a root of the level, after place the level alert below the report or
+  // below the previous level
+  aLevel->SetRootAlert (anAlert);
+
+  if (myAlertLevels.Size() == 1) // this is the first level, so root alert should be pushed in the report composite of alerts
+    compositeAlerts (Standard_True)->AddAlert (theGravity, theAlert);
+  else
+  {
+    // root alert of next levels should be pushed under the previous level
+    Message_Level* aPrevLevel = myAlertLevels.Value (myAlertLevels.Size() - 1); // previous level
+    aPrevLevel->AddLevelAlert (theGravity, theAlert);
+  }
 }
 
 //=======================================================================
@@ -68,9 +99,10 @@ void Message_Report::AddAlert (Message_Gravity theGravity, const Handle(Message_
 const Message_ListOfAlert& Message_Report::GetAlerts (Message_Gravity theGravity) const
 {
   static const Message_ListOfAlert anEmptyList;
-  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
-                          "Requesting alerts for gravity not in valid range", anEmptyList);
-  return myAlerts[theGravity];
+  if (myCompositAlerts.IsNull())
+    return anEmptyList;
+
+  return myCompositAlerts->Alerts (theGravity);
 }
 
 //=======================================================================
@@ -80,9 +112,9 @@ const Message_ListOfAlert& Message_Report::GetAlerts (Message_Gravity theGravity
 
 Standard_Boolean Message_Report::HasAlert (const Handle(Standard_Type)& theType)
 {
-  for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity)
+  for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter)
   {
-    if (HasAlert (theType, (Message_Gravity)iGravity))
+    if (HasAlert (theType, (Message_Gravity)aGravIter))
       return Standard_True;
   }
   return Standard_False;
@@ -95,27 +127,103 @@ Standard_Boolean Message_Report::HasAlert (const Handle(Standard_Type)& theType)
 
 Standard_Boolean Message_Report::HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity)
 {
-  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
-                          "Requesting alerts for gravity not in valid range", Standard_False);
-  for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next())
+  if (compositeAlerts().IsNull())
+    return Standard_False;
+
+  return compositeAlerts()->HasAlert (theType, theGravity);
+}
+
+//=======================================================================
+//function : IsActiveInMessenger
+//purpose  :
+//=======================================================================
+
+Standard_Boolean Message_Report::IsActiveInMessenger (const Handle(Message_Messenger)& theMessenger) const
+{
+  Handle(Message_Messenger) aMessenger = theMessenger.IsNull() ? Message::DefaultMessenger() : theMessenger;
+  for (Message_SequenceOfPrinters::Iterator anIterator (aMessenger->Printers()); anIterator.More(); anIterator.Next())
   {
-    if (anIt.Value()->IsInstance(theType))
+    if (anIterator.Value()->IsKind(STANDARD_TYPE (Message_PrinterToReport)) &&
+        Handle(Message_PrinterToReport)::DownCast (anIterator.Value())->Report() == this)
       return Standard_True;
   }
   return Standard_False;
 }
 
 //=======================================================================
-//function : Clear
+//function : ActivateInMessenger
 //purpose  :
 //=======================================================================
 
-void Message_Report::Clear ()
+void Message_Report::ActivateInMessenger (const Standard_Boolean toActivate,
+                                          const Handle(Message_Messenger)& theMessenger) const
 {
-  for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i)
+  if (toActivate == IsActiveInMessenger())
+    return;
+
+  Handle(Message_Messenger) aMessenger = theMessenger.IsNull() ? Message::DefaultMessenger() : theMessenger;
+  if (toActivate)
   {
-    myAlerts[i].Clear();
+    Handle (Message_PrinterToReport) aPrinterToReport = new Message_PrinterToReport();
+    aPrinterToReport->SetReport (this);
+    aMessenger->AddPrinter (aPrinterToReport);
   }
+  else // deactivate
+  {
+    Message_SequenceOfPrinters aPrintersToRemove;
+    for (Message_SequenceOfPrinters::Iterator anIterator (aMessenger->Printers()); anIterator.More(); anIterator.Next())
+    {
+      const Handle(Message_Printer) aPrinter = anIterator.Value();
+      if (aPrinter->IsKind(STANDARD_TYPE (Message_PrinterToReport)) &&
+          Handle(Message_PrinterToReport)::DownCast (aPrinter)->Report() == this)
+        aPrintersToRemove.Append (aPrinter);
+    }
+    for (Message_SequenceOfPrinters::Iterator anIterator (aPrintersToRemove); anIterator.More(); anIterator.Next())
+    {
+      aMessenger->RemovePrinter (anIterator.Value());
+    }
+  }
+}
+
+//=======================================================================
+//function : AddLevel
+//purpose  :
+//=======================================================================
+
+void Message_Report::AddLevel (Message_Level* theLevel)
+{
+  myAlertLevels.Append (theLevel);
+}
+
+//=======================================================================
+//function : RemoveLevel
+//purpose  :
+//=======================================================================
+
+void Message_Report::RemoveLevel (Message_Level* theLevel)
+{
+  for (int aLevelIndex = myAlertLevels.Size(); aLevelIndex >= 1; aLevelIndex--)
+  {
+    Message_Level* aLevel = myAlertLevels.Value (aLevelIndex);
+    myAlertLevels.Remove (aLevelIndex);
+
+    if (aLevel == theLevel)
+      return;
+  }
+}
+
+//=======================================================================
+//function : Clear
+//purpose  :
+//=======================================================================
+
+void Message_Report::Clear()
+{
+  if (compositeAlerts().IsNull())
+    return;
+
+  compositeAlerts()->Clear();
+  myAlertLevels.Clear();
 }
 
 //=======================================================================
@@ -125,9 +233,11 @@ void Message_Report::Clear ()
 
 void Message_Report::Clear (Message_Gravity theGravity)
 {
-  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
-                          "Requesting alerts for gravity not in valid range", );
-  myAlerts[theGravity].Clear();
+  if (compositeAlerts().IsNull())
+    return;
+
+  compositeAlerts()->Clear (theGravity);
+  myAlertLevels.Clear();
 }
 
 //=======================================================================
@@ -137,20 +247,28 @@ void Message_Report::Clear (Message_Gravity theGravity)
 
 void Message_Report::Clear (const Handle(Standard_Type)& theType)
 {
-  for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i)
-  {
-    for (Message_ListOfAlert::Iterator anIt (myAlerts[i]); anIt.More(); )
-    {
-      if (anIt.Value().IsNull() || anIt.Value()->IsInstance (theType))
-      {
-        myAlerts[i].Remove (anIt);
-      }
-      else
-      {
-        anIt.More();
-      }
-    }
-  }
+  if (compositeAlerts().IsNull())
+    return;
+
+  compositeAlerts()->Clear (theType);
+  myAlertLevels.Clear();
+}
+
+//=======================================================================
+//function : SetActiveMetric
+//purpose  :
+//=======================================================================
+
+void Message_Report::SetActiveMetric (const Message_MetricType theMetricType,
+                                      const Standard_Boolean theActivate)
+{
+  if (theActivate == myActiveMetrics.Contains (theMetricType))
+    return;
+
+  if (theActivate)
+    myActiveMetrics.Add (theMetricType);
+  else
+    myActiveMetrics.Remove (theMetricType);
 }
 
 //=======================================================================
@@ -160,9 +278,9 @@ void Message_Report::Clear (const Handle(Standard_Type)& theType)
 
 void Message_Report::Dump (Standard_OStream& theOS)
 {
-  for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity)
+  for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter)
   {
-    Dump (theOS, (Message_Gravity)iGravity);
+    Dump (theOS, (Message_Gravity)aGravIter);
   }
 }
 
@@ -173,19 +291,13 @@ void Message_Report::Dump (Standard_OStream& theOS)
 
 void Message_Report::Dump (Standard_OStream& theOS, Message_Gravity theGravity)
 {
-  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
-                          "Requesting alerts for gravity not in valid range", );
+  if (compositeAlerts().IsNull())
+    return;
 
-  // report each type of warning only once
-  NCollection_Map<Handle(Standard_Type)> aPassedAlerts;
-  for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next())
-  {
-    if (aPassedAlerts.Add (anIt.Value()->DynamicType()))
-    {
-      Message_Msg aMsg (anIt.Value()->GetMessageKey());
-      theOS << aMsg.Original() << std::endl;
-    }
-  }
+  if (compositeAlerts().IsNull())
+    return;
+
+  dumpMessages (theOS, theGravity, compositeAlerts());
 }
 
 //=======================================================================
@@ -195,9 +307,9 @@ void Message_Report::Dump (Standard_OStream& theOS, Message_Gravity theGravity)
 
 void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger)
 {
-  for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity)
+  for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter)
   {
-    SendMessages (theMessenger, (Message_Gravity)iGravity);
+    SendMessages (theMessenger, (Message_Gravity)aGravIter);
   }
 }
 
@@ -208,19 +320,10 @@ void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger
 
 void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger, Message_Gravity theGravity)
 {
-  Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), 
-                          "Requesting alerts for gravity not in valid range", );
+  if (compositeAlerts().IsNull())
+    return;
 
-  // report each type of warning only once
-  NCollection_Map<Handle(Standard_Type)> aPassedAlerts;
-  for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next())
-  {
-    if (aPassedAlerts.Add (anIt.Value()->DynamicType()))
-    {
-      Message_Msg aMsg (anIt.Value()->GetMessageKey());
-      theMessenger->Send (aMsg, theGravity);
-    }
-  }
+  sendMessages (theMessenger, theGravity, compositeAlerts());
 }
 
 //=======================================================================
@@ -230,9 +333,9 @@ void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger
 
 void Message_Report::Merge (const Handle(Message_Report)& theOther)
 {
-  for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity)
+  for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter)
   {
-    Merge (theOther, (Message_Gravity)iGravity);
+    Merge (theOther, (Message_Gravity)aGravIter);
   }
 }
 
@@ -248,3 +351,78 @@ void Message_Report::Merge (const Handle(Message_Report)& theOther, Message_Grav
     AddAlert (theGravity, anIt.Value());
   }
 }
+
+//=======================================================================
+//function : ñompositeAlerts
+//purpose  : 
+//=======================================================================
+const Handle(Message_CompositeAlerts)& Message_Report::compositeAlerts (const Standard_Boolean isCreate)
+{
+  if (myCompositAlerts.IsNull() && isCreate)
+    myCompositAlerts = new Message_CompositeAlerts();
+
+  return myCompositAlerts;
+}
+
+//=======================================================================
+//function : sendMessages
+//purpose  :
+//=======================================================================
+
+void Message_Report::sendMessages (const Handle(Message_Messenger)& theMessenger, Message_Gravity theGravity,
+                                   const Handle(Message_CompositeAlerts)& theCompositeAlert)
+{
+  if (theCompositeAlert.IsNull())
+    return;
+
+  const Message_ListOfAlert& anAlerts = theCompositeAlert->Alerts (theGravity);
+  // report each type of warning only once
+  //NCollection_Map<Handle(Standard_Type)> aPassedAlerts;
+  for (Message_ListOfAlert::Iterator anIt (anAlerts); anIt.More(); anIt.Next())
+  {
+    //if (aPassedAlerts.Add (anIt.Value()->DynamicType()))
+    {
+      //Message_Msg aMsg (anIt.Value()->GetMessageKey());
+      //theMessenger->Send (aMsg, theGravity);
+      theMessenger->Send (anIt.Value()->GetMessageKey(), theGravity);
+    }
+    Handle(Message_AlertExtended) anExtendedAlert = Handle(Message_AlertExtended)::DownCast (anIt.Value());
+    if (anExtendedAlert.IsNull())
+      continue;
+
+    Handle(Message_CompositeAlerts) aCompositeAlerts = anExtendedAlert->CompositeAlerts();
+    if (aCompositeAlerts.IsNull())
+      continue;
+
+    sendMessages (theMessenger, theGravity, aCompositeAlerts);
+  }
+}
+
+//=======================================================================
+//function : dumpMessages
+//purpose  :
+//=======================================================================
+void Message_Report::dumpMessages (Standard_OStream& theOS, Message_Gravity theGravity,
+                                   const Handle(Message_CompositeAlerts)& theCompositeAlert)
+{
+  if (theCompositeAlert.IsNull())
+    return;
+
+  const Message_ListOfAlert& anAlerts = theCompositeAlert->Alerts (theGravity);
+  // report each type of war++ning only once
+  //NCollection_Map<Handle(Standard_Type)> aPassedAlerts;
+  for (Message_ListOfAlert::Iterator anIt (anAlerts); anIt.More(); anIt.Next())
+  {
+    //if (aPassedAlerts.Add (anIt.Value()->DynamicType()))
+    {
+      //Message_Msg aMsg (anIt.Value()->GetMessageKey());
+      //theOS << aMsg.Original() << std::endl;
+      theOS << anIt.Value()->GetMessageKey() << std::endl;
+    }
+
+    Handle(Message_AlertExtended) anExtendedAlert = Handle(Message_AlertExtended)::DownCast (anIt.Value());
+    if (anExtendedAlert.IsNull())
+      continue;
+    dumpMessages (theOS, theGravity, anExtendedAlert->CompositeAlerts());
+  }
+}
index 8440ba81498a823a8d8039a0b0caa345f16cd4be..292600bd39f4cb5d3132e0f712231a7dfa41fe4e 100644 (file)
 #define _Message_Report_HeaderFile
 
 #include <Message_Gravity.hxx>
+#include <Message_Level.hxx>
 #include <Message_ListOfAlert.hxx>
+#include <Message_MetricType.hxx>
+#include <NCollection_Map.hxx>
+#include <NCollection_Sequence.hxx>
 #include <Standard_Mutex.hxx>
 
+class Message_CompositeAlerts;
 class Message_Messenger;
-
 class Message_Report;
-DEFINE_STANDARD_HANDLE(Message_Report, MMgt_TShared)
+
+DEFINE_STANDARD_HANDLE(Message_Report, Standard_Transient)
 
 //! Container for alert messages, sorted according to their gravity.
 //! 
@@ -46,6 +51,8 @@ DEFINE_STANDARD_HANDLE(Message_Report, MMgt_TShared)
 //!   Dump() or in more advanced way, by iterating over lists returned by GetAlerts()
 //!
 //! - Report can be cleared by methods Clear() (usually after reporting)
+//!
+//! Message_PrinterToReport is a printer in Messenger to convert data sent to messenger into report
 
 class Message_Report : public Standard_Transient
 {
@@ -67,6 +74,22 @@ public:
   //! Returns true if specific type of alert is recorded with specified gravity
   Standard_EXPORT Standard_Boolean HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity);
 
+  //! Returns true if a report printer for the current report is registered in the messenger
+  // @param theMessenger the messenger. If it's NULL, the default messenger is used
+  Standard_EXPORT Standard_Boolean IsActiveInMessenger (const Handle(Message_Messenger)& theMessenger = NULL) const;
+
+  //! Creates an instance of Message_PrinterToReport with the current report and register it in messenger
+  //! @param toActivate if true, activated else deactivated
+  // @param theMessenger the messenger. If it's NULL, the default messenger is used
+  Standard_EXPORT void ActivateInMessenger (const Standard_Boolean toActivate, const Handle(Message_Messenger)& theMessenger = NULL) const;
+
+  //! Add new level of alerts
+  //! @param theLevel a level 
+  Standard_EXPORT void AddLevel (Message_Level* theLevel);
+
+  //! Remove level of alerts
+  Standard_EXPORT void RemoveLevel (Message_Level* theLevel);
+
   //! Clears all collected alerts
   Standard_EXPORT void Clear ();
 
@@ -76,6 +99,25 @@ public:
   //! Clears collected alerts with specified type
   Standard_EXPORT void Clear (const Handle(Standard_Type)& theType);
 
+  //! Returns computed metrics when alerts are performed
+  const NCollection_Map<Message_MetricType>& ActiveMetrics() const { return myActiveMetrics; }
+
+  //! Sets metrics to compute when alerts are performed
+  //! @param theMetrics container of metrics
+  Standard_EXPORT void SetActiveMetric (const Message_MetricType theMetricType, const Standard_Boolean theActivate);
+
+  //! Removes all activated metrics
+  void ClearMetrics() { myActiveMetrics.Clear(); }
+
+  //! Returns maximum number of collecting alerts. If the limit is achieved,
+  //! first alert is removed, the new alert is added in the container.
+  //! @return the limit value
+  Standard_Integer Limit() const { return myLimit; }
+
+  //! Sets maximum number of collecting alerts.
+  //! @return theLimit limit value
+  void SetLimit(const Standard_Integer theLimit) { myLimit = theLimit; }
+
   //! Dumps all collected alerts to stream
   Standard_EXPORT void Dump (Standard_OStream& theOS);
 
@@ -94,15 +136,31 @@ public:
   //! Merges alerts with specified gravity from theOther report into this
   Standard_EXPORT void Merge (const Handle(Message_Report)& theOther, Message_Gravity theGravity);
 
-  // OCCT RTTI
   DEFINE_STANDARD_RTTIEXT(Message_Report,Standard_Transient)
 
+protected:
+  //! Returns class provided hierarchy of alerts if created or create if the parameter is true
+  //! @param isCreate if composite alert has not been created for this alert, it should be created
+  //! @return instance or NULL
+  Standard_EXPORT const Handle(Message_CompositeAlerts)& compositeAlerts (const Standard_Boolean isCreate = Standard_False);
+
+  //! Sends alerts to messenger
+  Standard_EXPORT void sendMessages (const Handle(Message_Messenger)& theMessenger, Message_Gravity theGravity,
+                                     const Handle(Message_CompositeAlerts)& theCompositeAlert);
+
+  //! Dumps collected alerts with specified gravity to stream
+  Standard_EXPORT void dumpMessages (Standard_OStream& theOS, Message_Gravity theGravity,
+                                     const Handle(Message_CompositeAlerts)& theCompositeAlert);
+
 protected:
   Standard_Mutex myMutex;
 
-  // store messages in a lists sorted by gravity;
-  // here we rely on knowledge that Message_Fail is the last element of the enum
-  Message_ListOfAlert myAlerts[Message_Fail + 1];
+  Handle(Message_CompositeAlerts) myCompositAlerts; //! container of alerts
+
+  NCollection_Sequence<Message_Level*> myAlertLevels; //! container of active levels, new alerts are added below the latest level
+  NCollection_Map<Message_MetricType> myActiveMetrics; //! metrics to compute on alerts
+
+  Standard_Integer myLimit; //! Maximum number of collected alerts on the top level
 };
 
 #endif // _Message_Report_HeaderFile
index 058b8acc20f0d2644227e9ada3c180631c144b43..d4a93d94ff64b87d880556880189189475da7ac9 100644 (file)
@@ -4,3 +4,5 @@ XmlDrivers_DocumentRetrievalDriver.cxx
 XmlDrivers_DocumentRetrievalDriver.hxx
 XmlDrivers_DocumentStorageDriver.cxx
 XmlDrivers_DocumentStorageDriver.hxx
+XmlDrivers_MessageReportStorage.cxx
+XmlDrivers_MessageReportStorage.hxx
diff --git a/src/XmlDrivers/XmlDrivers_MessageReportStorage.cxx b/src/XmlDrivers/XmlDrivers_MessageReportStorage.cxx
new file mode 100644 (file)
index 0000000..c0d1088
--- /dev/null
@@ -0,0 +1,333 @@
+// Created on: 2018-06-10
+// Created by: Natalia Ermolaeva
+// Copyright (c) 2001-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <XmlDrivers_MessageReportStorage.hxx>
+
+#include <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_AttributeObject.hxx>
+#include <Message_AttributeStream.hxx>
+#include <Message_CompositeAlerts.hxx>
+#include <Message_Level.hxx>
+#include <Message_Report.hxx>
+
+#include <Standard_Dump.hxx>
+
+#include <TCollection.hxx>
+#include <TDataStd_AsciiString.hxx>
+#include <TDataStd_Comment.hxx>
+#include <TDataStd_Real.hxx>
+#include <TDataStd_Name.hxx>
+#include <TDataStd_ExtStringArray.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TDocStd_Application.hxx>
+#include <TDocStd_Document.hxx>
+
+#include <XmlDrivers.hxx>
+
+// =======================================================================
+// function : GetApplication
+// purpose :
+// =======================================================================
+
+const Handle(TDocStd_Application)& GetApplication()
+{
+  static Handle(TDocStd_Application) anApp;
+  if (anApp.IsNull())
+  {
+    anApp = new TDocStd_Application;
+    XmlDrivers::DefineFormat (anApp);
+  }
+  return anApp;
+}
+
+// =======================================================================
+// function : ExportReport
+// purpose :
+// =======================================================================
+
+void XmlDrivers_MessageReportStorage::ExportReport (const Handle(Message_Report)& theReport,
+                                                    const TCollection_AsciiString& theFileName)
+{
+  if (theReport.IsNull())
+    return;
+
+  Handle(TDocStd_Document) aDocument;
+  GetApplication()->NewDocument (TCollection_ExtendedString ("XmlOcaf"), aDocument);
+
+  TDF_Label aMainLabel = aDocument->Main();
+
+  for (int aGravityId = Message_Trace; aGravityId <= Message_Fail; aGravityId++)
+  {
+    Message_Gravity aGravity = (Message_Gravity)aGravityId;
+
+    if (theReport->GetAlerts (aGravity).Size() == 0)
+      continue;
+    // Gravity Label
+    TDF_Label aGravityLabel = aMainLabel.NewChild();
+    // set gravity kind string
+    TCollection_ExtendedString aName (aGravity);
+    if (!aName.IsEmpty())
+      TDataStd_Name::Set (aGravityLabel, aName);
+
+    /// reserved label to store gravity information
+    //TDF_Label aFirstAlertLabel = aGravityLabel.NewChild();
+
+    // Alert Labels: labels are started from the second index
+    const Message_ListOfAlert& anAlerts = theReport->GetAlerts (aGravity);
+    for (Message_ListOfAlert::Iterator anAlertsIt (anAlerts); anAlertsIt.More(); anAlertsIt.Next())
+    {
+      exportAlert (anAlertsIt.Value(), aGravityLabel);
+    }
+  }
+  GetApplication()->SaveAs (aDocument, theFileName);
+  GetApplication()->Close (aDocument);
+}
+
+// =======================================================================
+// function : ImportReport
+// purpose :
+// =======================================================================
+
+Handle(Message_Report) XmlDrivers_MessageReportStorage::ImportReport (const TCollection_AsciiString& theFileName)
+{
+  Handle(TDocStd_Application) anApplication = GetApplication();
+  Standard_Integer aDocumentId = anApplication->IsInSession (theFileName);
+  if (aDocumentId > 0)
+  {
+    Handle(TDocStd_Document) aDocument;
+    anApplication->GetDocument (aDocumentId, aDocument);
+    anApplication->Close (aDocument);
+  }
+
+  Handle(TDocStd_Document) aDocument;
+  GetApplication()->Open (theFileName, aDocument);
+  if (aDocument.IsNull())
+    return Handle(Message_Report)();
+
+  TDF_Label aMainLabel = aDocument->Main();
+  if (aMainLabel.IsNull())
+    return Handle(Message_Report)();
+
+  TDF_Label aLabel;
+  Handle(Message_Report) aReport = new Message_Report();
+  for (TDF_ChildIterator aLabelsIt(aMainLabel); aLabelsIt.More(); aLabelsIt.Next())
+  {
+    TDF_Label aGravityLabel = aLabelsIt.Value();
+    if (aGravityLabel.IsNull())
+      continue;
+    Handle(TDF_Attribute) anAttribute;
+    if (!aGravityLabel.FindAttribute (TDataStd_Name::GetID(), anAttribute))
+      continue;
+    Handle(TDataStd_Name) aNameAttribute = Handle(TDataStd_Name)::DownCast (anAttribute);
+    if (aNameAttribute.IsNull())
+      continue;
+
+    // get gravity type
+    const TCollection_ExtendedString& aGravityName = aNameAttribute->Get();
+    Message_Gravity aGravity = (Message_Gravity) (TCollection_AsciiString (aGravityName).IntegerValue());
+
+    /// reserved label to store gravity information
+    //TDF_Label aFirstAlertLabel = aGravityLabel.FindChild (1, Standard_False);
+
+    // find alerts information, add corresponded alerts to the report
+    for (TDF_ChildIterator anAlertLabelsIt (aGravityLabel); anAlertLabelsIt.More(); anAlertLabelsIt.Next())
+    {
+      TDF_Label anAlertLabel = anAlertLabelsIt.Value();
+      if (anAlertLabel.IsNull())
+        continue;
+
+      importAlert (anAlertLabel, aGravity, aReport, Handle(Message_Alert)());
+    }
+  }
+  return aReport;
+}
+
+// =======================================================================
+// function : exportAlert
+// purpose :
+// =======================================================================
+void XmlDrivers_MessageReportStorage::exportAlert (const Handle(Message_Alert)& theAlert, const TDF_Label& theParentLabel)
+{
+   TDF_Label anAlertLabel = theParentLabel.NewChild();
+  TDataStd_Name::Set (anAlertLabel, theAlert->DynamicType()->Name());
+
+  /// reserved label to store parameters of the current label
+  TDF_Label anAlertParmetersLabel = anAlertLabel.NewChild();
+  exportAlertParameters (theAlert, anAlertParmetersLabel);
+
+  for (int aGravityId = Message_Trace; aGravityId <= Message_Fail; aGravityId++)
+  {
+    // Gravity Label
+    TDF_Label aGravityLabel = anAlertLabel.NewChild();
+    // set gravity kind string
+    TDataStd_Name::Set (aGravityLabel, aGravityId);
+
+    Handle(Message_AlertExtended) anAlertExtended = Handle(Message_AlertExtended)::DownCast (theAlert);
+    if (anAlertExtended.IsNull())
+      continue;
+    Handle(Message_CompositeAlerts) aComposite = anAlertExtended->CompositeAlerts();
+    if (aComposite.IsNull())
+      continue;
+
+    const Message_ListOfAlert& anAlerts = aComposite->Alerts ((Message_Gravity)aGravityId);
+    for (Message_ListOfAlert::Iterator anAlertsIt (anAlerts); anAlertsIt.More(); anAlertsIt.Next())
+      exportAlert (anAlertsIt.Value(), aGravityLabel);
+  }
+}
+
+// =======================================================================
+// function : importAlert
+// purpose :
+// =======================================================================
+
+void XmlDrivers_MessageReportStorage::importAlert (const TDF_Label& theAlertLabel,
+                                                   const Message_Gravity theGravity,
+                                                   Handle(Message_Report)& theReport,
+                                                   const Handle(Message_Alert)& theParentAlert)
+{
+  TDF_Label aParametersLabel = theAlertLabel.FindChild (1, Standard_False);
+  Handle(Message_Alert) anAlert = importAlertParameters (aParametersLabel);
+  if (anAlert.IsNull())
+    return;
+
+  TDF_Label aLabel;
+  TDF_ChildIterator aSubAlertsLabelsIt (theAlertLabel);
+  aSubAlertsLabelsIt.Next(); // do not processing the first (parameters) label
+  for (; aSubAlertsLabelsIt.More(); aSubAlertsLabelsIt.Next())
+  {
+    TDF_Label aGravityLabel = aSubAlertsLabelsIt.Value();
+    if (aGravityLabel.IsNull())
+      continue;
+    Handle(TDF_Attribute) anAttribute;
+    if (!aGravityLabel.FindAttribute (TDataStd_Name::GetID(), anAttribute))
+      continue;
+    Handle(TDataStd_Name) aNameAttribute = Handle(TDataStd_Name)::DownCast (anAttribute);
+    if (aNameAttribute.IsNull())
+      continue;
+
+    // get gravity type
+    Message_Gravity aGravity = (Message_Gravity) (TCollection_AsciiString (aNameAttribute->Get()).IntegerValue());
+    // find alerts information, add corresponded alerts to the report
+    for (TDF_ChildIterator anAlertLabelsIt (aGravityLabel); anAlertLabelsIt.More(); anAlertLabelsIt.Next())
+    {
+      TDF_Label anAlertLabel = anAlertLabelsIt.Value();
+      if (anAlertLabel.IsNull())
+        continue;
+
+      importAlert (anAlertLabel, aGravity, theReport, anAlert);
+    }
+  }
+  if (theParentAlert.IsNull())
+    theReport->AddAlert (theGravity, anAlert);
+  else
+  {
+    MESSAGE_ADD_LEVEL_SENTRY
+    theReport->AddAlert (theGravity, anAlert);
+  }
+}
+
+// =======================================================================
+// function : exportAlertParameters
+// purpose :
+// =======================================================================
+void XmlDrivers_MessageReportStorage::exportAlertParameters (const Handle(Message_Alert)& theAlert, const TDF_Label& theAlertLabel)
+{
+  Handle(Message_AlertExtended) anAlertExtended = Handle(Message_AlertExtended)::DownCast (theAlert);
+  if (anAlertExtended.IsNull()) // name attribute is empty
+    return;
+
+  // store attribute time
+  Handle(Message_Attribute) anAttribute = anAlertExtended->Attribute();
+
+  TDataStd_Name::Set (theAlertLabel, anAttribute->DynamicType()->Name());
+  //TDataStd_Real::Set (theAlertLabel, anAlertExtended->CumulativeMetric());
+
+  TDataStd_AsciiString::Set (theAlertLabel, anAttribute->GetName());
+
+  Standard_CString aDynamicTypeName = anAttribute->DynamicType()->Name();
+  if (aDynamicTypeName == STANDARD_TYPE (Message_AttributeStream)->Name())
+  {
+    Handle(Message_AttributeStream) aValuesArrayAlert = Handle(Message_AttributeStream)::DownCast (anAttribute);
+    // store values
+    TCollection_AsciiString aStreamText = Standard_Dump::Text (aValuesArrayAlert->Stream());
+    if (aStreamText.IsEmpty())
+      return;
+    Handle(TDataStd_ExtStringArray) aListAttribute = TDataStd_ExtStringArray::Set (theAlertLabel, 0, 0);
+    aListAttribute->SetValue (0, aStreamText);
+  }
+}
+
+// =======================================================================
+// function : importAlertParameters
+// purpose :
+// =======================================================================
+Handle(Message_Alert) XmlDrivers_MessageReportStorage::importAlertParameters (const TDF_Label& aParametersLabel)
+{
+  Handle(TDF_Attribute) anAttribute;
+  if (!aParametersLabel.FindAttribute (TDataStd_Name::GetID(), anAttribute))
+    return Handle(Message_Alert)();
+
+  Handle(TDataStd_Name) aDynamicTypeAttribute = Handle(TDataStd_Name)::DownCast (anAttribute);
+  if (aDynamicTypeAttribute.IsNull())
+    return Handle(Message_Alert)();
+  const TCollection_ExtendedString& aDynamicTypeName = aDynamicTypeAttribute->Get();
+
+  Handle(Message_AlertExtended) anAlert = new Message_AlertExtended();
+  Handle(Message_Attribute) aMessageAttribute;
+  if (aDynamicTypeName == STANDARD_TYPE (Message_Attribute)->Name())
+    aMessageAttribute = new Message_Attribute();
+  else if (aDynamicTypeName == STANDARD_TYPE (Message_AttributeStream)->Name())
+  {
+    // values
+    NCollection_Vector<TCollection_AsciiString> anArrayValues;
+    if (!aParametersLabel.FindAttribute (TDataStd_ExtStringArray::GetID(), anAttribute))
+      return Handle(Message_Alert)();
+
+    Handle(TDataStd_ExtStringArray) aValuesAttribute = Handle(TDataStd_ExtStringArray)::DownCast (anAttribute);
+    if (aValuesAttribute.IsNull())
+      return Handle(Message_Alert)();
+
+    Standard_SStream aStream;
+    for (int aValueId = aValuesAttribute->Lower(); aValueId <= aValuesAttribute->Upper(); aValueId++)
+    {
+      aStream << aValuesAttribute->Value (aValueId);
+    }
+    aMessageAttribute = new Message_AttributeStream (aStream);
+  }
+
+  if (!aMessageAttribute.IsNull())
+  {
+    // name
+    if (!aParametersLabel.FindAttribute (TDataStd_AsciiString::GetID(), anAttribute))
+      return Handle(Message_Alert)();
+    Handle(TDataStd_AsciiString) aNameAttribute = Handle(TDataStd_AsciiString)::DownCast (anAttribute);
+    if (aNameAttribute.IsNull())
+      return Handle(Message_Alert)();
+
+    aMessageAttribute->SetName (aNameAttribute->Get());
+    anAlert->SetAttribute (aMessageAttribute);
+  }
+
+  // time
+  //Standard_Real aTime = -1;
+  //Handle(TDataStd_Real) aTimeAttribute;
+  //if (aParametersLabel.FindAttribute (TDataStd_Real::GetID(), aTimeAttribute))
+  //  aTime = aTimeAttribute->Get();
+
+  //anAlert->SetCumulativeMetric (aTime);
+  return anAlert;
+}
diff --git a/src/XmlDrivers/XmlDrivers_MessageReportStorage.hxx b/src/XmlDrivers/XmlDrivers_MessageReportStorage.hxx
new file mode 100644 (file)
index 0000000..81e1db8
--- /dev/null
@@ -0,0 +1,74 @@
+// Created on: 2018-06-10
+// Created by: Natalia Ermolaeva
+// Copyright (c) 2001-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _XmlDrivers_MessageReportStorage
+#define _XmlDrivers_MessageReportStorage
+
+#include <Standard_Handle.hxx>
+
+#include <Message_Report.hxx>
+#include <Message_Alert.hxx>
+#include <TDF_Label.hxx>
+
+//! Base class to store/restore Message_Report content in XML document
+class XmlDrivers_MessageReportStorage
+{
+public:
+  //! Create document for the report
+  //! \param theReport the source report
+  //! \param theFileName a file name
+  Standard_EXPORT static void ExportReport (const Handle(Message_Report)& theReport, const TCollection_AsciiString& theFileName);
+
+  //! Restores document file content into report instance
+  //! \param theFileName a file name
+  //! \return new report or NULL
+  Standard_EXPORT static Handle(Message_Report) ImportReport (const TCollection_AsciiString& theFileName);
+
+private:
+  //! Create labels/attributes for the alert and place it under the parent label.
+  //! It is recursive as alerts may contains other alerts
+  //! \param theAlert a source alert
+  //! \parm theParentLabel a label where alert label is placed
+  static void exportAlert (const Handle(Message_Alert)& theAlert, const TDF_Label& theParentLabel);
+
+  //! Creates a new alert by the label parameters
+  //! \param theAlertLabel a source document label
+  //! \param theGravity an alert gravity
+  //! \param theReport a container of alerts
+  //! \param theParentAlert a parent alert, if null, the parent is report
+  static void importAlert (const TDF_Label& theAlertLabel,
+                           const Message_Gravity theGravity,
+                           Handle(Message_Report)& theReport,
+                           const Handle(Message_Alert)& theParentAlert);
+
+  //! Convert alert to a custom type and store parameters in child labels and attributes
+  //! \param theAlert a source alert
+  //! \parm theAlertLabel an alert label
+  static void exportAlertParameters (const Handle(Message_Alert)& theAlert,
+                                     const TDF_Label& theAlertLabel);
+
+  //! Creates alert by label type filled by the label content
+  //! \param theParametersLabel a label
+  //! \return new alert or NULL
+  static Handle(Message_Alert) importAlertParameters (const TDF_Label& aParametersLabel);
+};
+
+#define MESSAGE_STORE_XML_REPORT(FileName) \
+{ \
+  Handle(Message_Report) aReport = Message::DefaultReport (Standard_False); \
+  if (!aReport.IsNull()) XmlDrivers_MessageReportStorage::ExportReport (aReport, FileName); \
+}
+
+#endif // _XmlDrivers_MessageReportStorage