Parcourir la source

Merge branch 'tweak-error-log-api'

* tweak-error-log-api:
  Extend error log API so that observer can be notified of new log entries
Jean-Christophe Fillion-Robin il y a 11 ans
Parent
commit
76219ba324

+ 100 - 9
Libs/Core/Testing/Cpp/ctkErrorLogModelTest1.cpp

@@ -21,6 +21,7 @@
 // Qt includes
 #include <QCoreApplication>
 #include <QDebug>
+#include <QSignalSpy>
 
 // CTK includes
 #include "ctkErrorLogFDMessageHandler.h"
@@ -65,7 +66,18 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       model.registerMsgHandler(new ctkErrorLogQtMessageHandler);
       model.setMsgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName, true);
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ 0);
+      QSignalSpy entryAddedSpy(&model, SIGNAL(entryAdded(ctkErrorLogLevel::LogLevel)));
+
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -89,7 +101,16 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       QStringList expectedQtMessages;
       expectedQtMessages << qtMessage0 << qtMessage1 << qtMessage2;
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ expectedQtMessages.count());
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ expectedQtMessages.count());
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ expectedQtMessages.count());
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -128,6 +149,7 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
 
       // Clear
       model.clear();
+      entryAddedSpy.clear();
 
       // Disable Qt messages monitoring
       model.setMsgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName, false);
@@ -136,7 +158,16 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       qWarning() << "This qWarning message should appear in the console";
       qCritical() << "This qCritical message should appear in the console";
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ 0);
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -152,6 +183,8 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       model.registerMsgHandler(new ctkErrorLogStreamMessageHandler);
       model.setMsgHandlerEnabled(ctkErrorLogStreamMessageHandler::HandlerName, true);
 
+      QSignalSpy entryAddedSpy(&model, SIGNAL(entryAdded(ctkErrorLogLevel::LogLevel)));
+
       // Make sure Qt message handler is still disabled
       if (model.msgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName))
         {
@@ -162,7 +195,16 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
         return EXIT_FAILURE;
         }
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ 0);
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -183,7 +225,16 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       QStringList expectedStreamMessages;
       expectedStreamMessages << streamMessage0 << streamMessage1;
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ expectedStreamMessages.count());
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ expectedStreamMessages.count());
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ expectedStreamMessages.count());
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -210,6 +261,7 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
         
       // Clear
       model.clear();
+      entryAddedSpy.clear();
 
       // Disable Stream messages monitoring
       model.setMsgHandlerEnabled(ctkErrorLogStreamMessageHandler::HandlerName, false);
@@ -217,7 +269,16 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       std::cout << "This std::cout message should appear in the console" << std::endl;
       std::cerr << "This std::cerr message should appear in the console" << std::endl;
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ 0);
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -233,7 +294,18 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       model.registerMsgHandler(new ctkErrorLogFDMessageHandler);
       model.setMsgHandlerEnabled(ctkErrorLogFDMessageHandler::HandlerName, true);
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ 0);
+      QSignalSpy entryAddedSpy(&model, SIGNAL(entryAdded(ctkErrorLogLevel::LogLevel)));
+
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -272,7 +344,16 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       // to consider the updated files.
       processEvents(1500);
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ expectedFDMessages.count());
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ expectedFDMessages.count());
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ expectedFDMessages.count());
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();
@@ -299,6 +380,7 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
 
       // Clear
       model.clear();
+      entryAddedSpy.clear();
 
       // Disable FD messages monitoring
       model.setMsgHandlerEnabled(ctkErrorLogFDMessageHandler::HandlerName, false);
@@ -307,7 +389,16 @@ int ctkErrorLogModelTest1(int argc, char * argv [])
       fprintf(stderr, "%s", "This stderr message should appear in the console\n");
       fflush(stderr);
 
-      errorMsg = checkRowCount(__LINE__, model.rowCount(), /* expected = */ 0);
+      errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
+      if (!errorMsg.isEmpty())
+        {
+        model.disableAllMsgHandler();
+        printErrorMessage(errorMsg);
+        printTextMessages(model);
+        return EXIT_FAILURE;
+        }
+
+      errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
       if (!errorMsg.isEmpty())
         {
         model.disableAllMsgHandler();

+ 11 - 0
Libs/Core/Testing/Cpp/ctkErrorLogModelTestHelper.cpp

@@ -47,6 +47,17 @@ QString checkRowCount(int line, int currentRowCount, int expectedRowCount)
 }
 
 //-----------------------------------------------------------------------------
+QString checkSpyCount(int line, int currentSpyCount, int expectedSpyCount)
+{
+  if (currentSpyCount != expectedSpyCount)
+    {
+    QString errorMsg("Line %1 - Expected spyCount: %2 - Current spyCount: %3\n");
+    return errorMsg.arg(line).arg(expectedSpyCount).arg(currentSpyCount);
+    }
+  return QString();
+}
+
+//-----------------------------------------------------------------------------
 QString checkTextMessages(int line, const QStringList& currentMessages, const QStringList& expectedMessages)
 {
   for(int i = 0; i < expectedMessages.count(); ++i)

+ 37 - 19
Libs/Core/ctkErrorLogModel.cpp

@@ -437,29 +437,19 @@ void ctkErrorLogModel::addEntry(const QDateTime& currentDateTime, const QString&
   bool groupEntry = false;
   if (d->LogEntryGrouping)
     {
-    // Retrieve threadId associated with last row
-    QModelIndex lastRowThreadIdIndex =
-        d->StandardItemModel.index(d->StandardItemModel.rowCount() - 1, ctkErrorLogModel::ThreadIdColumn);
+    int lastRowIndex = d->StandardItemModel.rowCount() - 1;
 
-    bool threadIdMatched = threadId == lastRowThreadIdIndex.data().toString();
+    QString lastRowThreadId = this->logEntryData(lastRowIndex, Self::ThreadIdColumn).toString();
+    bool threadIdMatched = threadId == lastRowThreadId;
 
-    // Retrieve logLevel associated with last row
-    QModelIndex lastRowLogLevelIndex =
-        d->StandardItemModel.index(d->StandardItemModel.rowCount() - 1, ctkErrorLogModel::LogLevelColumn);
+    QString lastRowLogLevel = this->logEntryData(lastRowIndex, Self::LogLevelColumn).toString();
+    bool logLevelMatched = d->ErrorLogLevel(logLevel) == lastRowLogLevel;
 
-    bool logLevelMatched = d->ErrorLogLevel(logLevel) == lastRowLogLevelIndex.data().toString();
-
-    // Retrieve origin associated with last row
-    QModelIndex lastRowOriginIndex =
-        d->StandardItemModel.index(d->StandardItemModel.rowCount() - 1, ctkErrorLogModel::OriginColumn);
-
-    bool originMatched = origin == lastRowOriginIndex.data().toString();
-
-    // Retrieve time associated with last row
-    QModelIndex lastRowTimeIndex =
-            d->StandardItemModel.index(d->StandardItemModel.rowCount() - 1, ctkErrorLogModel::TimeColumn);
-    QDateTime lastRowDateTime = QDateTime::fromString(lastRowTimeIndex.data().toString(), timeFormat);
+    QString lastRowOrigin = this->logEntryData(lastRowIndex, Self::OriginColumn).toString();
+    bool originMatched = origin == lastRowOrigin;
 
+    QDateTime lastRowDateTime =
+        QDateTime::fromString(this->logEntryData(lastRowIndex, Self::TimeColumn).toString(), timeFormat);
     int groupingIntervalInMsecs = 1000;
     bool withinGroupingInterval = lastRowDateTime.time().msecsTo(currentDateTime.time()) <= groupingIntervalInMsecs;
 
@@ -522,6 +512,8 @@ void ctkErrorLogModel::addEntry(const QDateTime& currentDateTime, const QString&
     }
 
   d->AddingEntry = false;
+
+  emit this->entryAdded(logLevel);
 }
 
 //------------------------------------------------------------------------------
@@ -654,6 +646,32 @@ void ctkErrorLogModel::setAsynchronousLogging(bool value)
 }
 
 // --------------------------------------------------------------------------
+QVariant ctkErrorLogModel::logEntryData(int row, int column, int role) const
+{
+  Q_D(const ctkErrorLogModel);
+  if (column < 0 || column > Self::MaxColumn
+      || row < 0 || row > this->logEntryCount())
+    {
+    return QVariant();
+    }
+  QModelIndex rowDescriptionIndex = d->StandardItemModel.index(row, column);
+  return rowDescriptionIndex.data(role);
+}
+
+// --------------------------------------------------------------------------
+QString ctkErrorLogModel::logEntryDescription(int row) const
+{
+  return this->logEntryData(row, Self::DescriptionColumn, Self::DescriptionTextRole).toString();
+}
+
+// --------------------------------------------------------------------------
+int ctkErrorLogModel::logEntryCount()const
+{
+  Q_D(const ctkErrorLogModel);
+  return d->StandardItemModel.rowCount();
+}
+
+// --------------------------------------------------------------------------
 // ctkErrorLogAbstractMessageHandlerPrivate
 
 // --------------------------------------------------------------------------

+ 24 - 4
Libs/Core/ctkErrorLogModel.h

@@ -110,7 +110,8 @@ public:
     ThreadIdColumn,
     LogLevelColumn,
     OriginColumn,
-    DescriptionColumn
+    DescriptionColumn,
+    MaxColumn = DescriptionColumn
     };
 
   enum ItemDataRole{
@@ -156,9 +157,6 @@ public:
   /// \sa TerminalOutput
   void setTerminalOutputs(const TerminalOutputs& terminalOutput);
 
-  /// Remove all message from model
-  void clear();
-
   ctkErrorLogLevel::LogLevels logLevelFilter()const;
 
   void filterEntry(const ctkErrorLogLevel::LogLevels& logLevel = ctkErrorLogLevel::Unknown, bool disableFilter = false);
@@ -169,13 +167,35 @@ public:
   bool asynchronousLogging()const;
   void setAsynchronousLogging(bool value);
 
+  /// Return log entry information associated with \a row and \a column.
+  /// \internal
+  QVariant logEntryData(int row,
+                        int column = ctkErrorLogModel::DescriptionColumn,
+                        int role = Qt::DisplayRole) const;
+
+  /// Return log entry information associated with Description column.
+  /// \sa ctkErrorLogModel::DescriptionColumn, logEntryData()
+  Q_INVOKABLE QString logEntryDescription(int row) const;
+
+  /// Return current number of log entries.
+  /// \sa clear()
+  Q_INVOKABLE int logEntryCount() const;
+
 public Q_SLOTS:
+
+  /// Remove all log entries from model
+  void clear();
+
+  /// \sa logEntryGrouping(), asynchronousLogging()
   void addEntry(const QDateTime& currentDateTime, const QString& threadId,
                 ctkErrorLogLevel::LogLevel logLevel, const QString& origin, const QString& text);
 
 Q_SIGNALS:
   void logLevelFilterChanged();
 
+  /// \sa addEntry()
+  void entryAdded(ctkErrorLogLevel::LogLevel logLevel);
+
 protected:
   QScopedPointer<ctkErrorLogModelPrivate> d_ptr;