Salome HOME
bos #29467 SALOME GUI logger
authorvsr <vsr@opencascade.com>
Mon, 23 May 2022 12:59:39 +0000 (15:59 +0300)
committerPascal Obry <pascal.obry@edf.fr>
Tue, 5 Sep 2023 09:36:26 +0000 (11:36 +0200)
src/CAM/CAM_Application.cxx
src/CAM/CAM_Application.h
src/CAM/CAM_Module.cxx
src/CAM/CAM_Module.h
src/CAM/resources/CAM_msg_en.ts
src/LightApp/LightApp_Application.cxx
src/LightApp/LightApp_Application.h
src/SALOME_PYQT/SalomePyQt/SalomePyQt.cxx
src/SALOME_PYQT/SalomePyQt/SalomePyQt.h
src/SALOME_PYQT/SalomePyQt/SalomePyQt.sip

index 6547e31cb36548717a04ed53db1e2205cefbb640..1473f6ff2e013c428c40992afcc4c3041e867e06 100644 (file)
 #include <KERNEL_version.h>
 #include <GUI_version.h>
 
+#include <QAction>
 #include <QApplication>
+#include <QDir>
+#include <QFileInfo>
+#include <QMutex>
+#include <QMutexLocker>
 #include <QRegExp>
+#include <QTextStream>
 
 #ifdef WIN32
 #include <windows.h>
@@ -73,9 +79,9 @@ extern "C" CAM_EXPORT SUIT_Application* createApplication()
 /*!
   \class CAM_Application
   \brief Introduces an application class which provides modular architecture.
-  
+
   This class defines multi-modular application configuration and behaviour.
-  Each module (CAM_Module) can have own data model, document windows and 
+  Each module (CAM_Module) can have own data model, document windows and
   viewers, etc.
 
   An application provides all necessary functionality for modules management,
@@ -90,7 +96,7 @@ CAM_Application::ModuleInfoList CAM_Application::myInfoList;
 /*!
   \brief Constructor.
 
-  Read modules list (from command line or from resource file). 
+  Read modules list (from command line or from resource file).
   If \a autoLoad parameter is \c true all the modules will be loaded
   immediately after application starting, otherwise each module will
   be loaded by demand (with activateModule()).
@@ -118,7 +124,7 @@ CAM_Application::~CAM_Application()
   myModules.clear();
 }
 
-/*! 
+/*!
   \brief Start an application.
 
   Load all modules, if "auto loading" flag has been set to \c true.
@@ -128,13 +134,13 @@ CAM_Application::~CAM_Application()
 void CAM_Application::start()
 {
   // check modules
-  for ( ModuleInfoList::iterator it = myInfoList.begin(); 
+  for ( ModuleInfoList::iterator it = myInfoList.begin();
         it != myInfoList.end(); ++it )
   {
     if ( (*it).status == stUnknown )
       (*it).status = checkModule( (*it).title ) ? stReady : stInaccessible;
   }
-  
+
   // auto-load modules
   if ( myAutoLoad )
     loadModules();
@@ -158,7 +164,7 @@ CAM_Module* CAM_Application::activeModule() const
 CAM_Module* CAM_Application::module(  const QString& modName ) const
 {
   CAM_Module* mod = 0;
-  for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
+  for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
         it != myModules.end() && !mod; ++it )
     if ( (*it)->moduleName() == modName )
       mod = *it;
@@ -182,7 +188,7 @@ void CAM_Application::modules( CAM_Application::ModuleList& out ) const
 {
   out.clear();
 
-  for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
+  for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
         it != myModules.end(); ++it )
     out.append( *it );
 }
@@ -190,9 +196,9 @@ void CAM_Application::modules( CAM_Application::ModuleList& out ) const
 /*!
   \brief Get names of all modules.
 
-  Get loaded modules names if \a loaded is \c true, 
+  Get loaded modules names if \a loaded is \c true,
   otherwise get all avaiable modules names.
-  
+
   \param lst output list of modules names
   \param loaded boolean flag, defines what modules names to return
 */
@@ -202,13 +208,13 @@ void CAM_Application::modules( QStringList& lst, const bool loaded ) const
 
   if ( loaded )
   {
-    for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
+    for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
           it != myModules.end(); ++it )
       lst.append( (*it)->moduleName() );
   }
   else
   {
-    for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
+    for ( ModuleInfoList::const_iterator it = myInfoList.begin();
           it != myInfoList.end(); ++it )
       if ( (*it).status != stNoGui )
         lst.append( (*it).title );
@@ -219,8 +225,8 @@ void CAM_Application::modules( QStringList& lst, const bool loaded ) const
   \brief Add module \a mod to the modules list.
 
   Performes module initialization. Does nothing if the module
-  is already added. 
-  
+  is already added.
+
   \param mod module being added
   \sa CAM_Module::initialize()
 */
@@ -234,7 +240,7 @@ void CAM_Application::addModule( CAM_Module* mod )
   QMap<CAM_Module*, int> map;
 
   ModuleList newList;
-  for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
+  for ( ModuleInfoList::const_iterator it = myInfoList.begin();
         it != myInfoList.end(); ++it )
   {
     if ( (*it).title == mod->moduleName() )
@@ -264,7 +270,7 @@ void CAM_Application::addModule( CAM_Module* mod )
 
 /*!
   \brief Load modules from the modules information list.
-  
+
   If some module can not be loaded, an error message is shown.
 */
 void CAM_Application::loadModules()
@@ -279,7 +285,7 @@ void CAM_Application::loadModules()
       if ( desktop() && desktop()->isVisible() )
         SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ), wrn );
       else
-        qWarning( qPrintable( wrn ) ); 
+        qWarning( qPrintable( wrn ) );
     }
   }
 }
@@ -333,7 +339,7 @@ CAM_Module* CAM_Application::loadModule( const QString& modName, const bool show
                      FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
 #ifdef UNICODE
        QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
-#else 
+#else
        QString out_err = (LPTSTR)lpMsgBuf;
 #endif
     err = QString( "Failed to load  %1. %2" ).arg( libName ).arg(out_err);
@@ -349,7 +355,7 @@ CAM_Module* CAM_Application::loadModule( const QString& modName, const bool show
                        FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
 #ifdef UNICODE
          QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
-#else 
+#else
          QString out_err = (LPTSTR)lpMsgBuf;
 #endif
 
@@ -384,12 +390,12 @@ CAM_Module* CAM_Application::loadModule( const QString& modName, const bool show
     if ( desktop() && desktop()->isVisible() )
       SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
     else
-      qWarning( qPrintable( err ) ); 
+      qWarning( qPrintable( err ) );
   }
 
   char* version = getVersion ? getVersion() : 0;
 
-  if ( version ) {    
+  if ( version ) {
     for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
       if ( (*it).title == modName ) {
         if( (*it).version.isEmpty() ) {
@@ -399,7 +405,7 @@ CAM_Module* CAM_Application::loadModule( const QString& modName, const bool show
       }
     }
   }
-  
+
   return module;
 }
 
@@ -463,7 +469,7 @@ bool CAM_Application::activateModule( CAM_Module* mod )
       // ???
     }
     moduleDeactivated( myModule );
-  }     
+  }
   myModule = mod;
 
   if ( myModule )
@@ -478,7 +484,7 @@ bool CAM_Application::activateModule( CAM_Module* mod )
       if ( desktop() && desktop()->isVisible() )
         SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
       else
-        qWarning( qPrintable( wrn ) ); 
+        qWarning( qPrintable( wrn ) );
       myModule = 0;
       return false;
     }
@@ -548,8 +554,8 @@ bool CAM_Application::activateOperation( const QString& modName,
   \brief Create new study.
   \return study object pointer
 */
-SUIT_Study* CAM_Application::createNewStudy() 
-{ 
+SUIT_Study* CAM_Application::createNewStudy()
+{
   return new CAM_Study( this );
 }
 
@@ -568,7 +574,7 @@ void CAM_Application::updateCommandsStatus()
   \brief Prepare application to study closing.
 
   Closes all modules in study \a theDoc.
-  
+
   \param theDoc study
 */
 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
@@ -605,7 +611,7 @@ bool CAM_Application::checkModule( const QString& )
 
 /*!
   \brief Callback function, called when the module is added to the application.
-  
+
   This virtual method can be re-implemented in the successors. Base implementation
   does nothing.
 
@@ -617,7 +623,7 @@ void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
 
 /*!
   \brief Callback function, called when the module is just deactivated.
-  
+
   This virtual method can be re-implemented in the successors. Base implementation
   does nothing.
 
@@ -741,12 +747,12 @@ QString CAM_Application::moduleDisplayer( const QString& name )
   the application command line arguments, looking for the
   "--modules ( <mod_name>[:<mod_name>...] )" option.
   List of modules is separated by colon symbol (":").
-  
+
   If "--modules" command line option is not used, the list of modules
   is retrieved from the application resource file: parameter "modules" of
   the section "launch".
 
-  Then the information about each module (module title (user name), 
+  Then the information about each module (module title (user name),
   library name) is retrieved from the corresponding section of resource
   file with help of resources manager.
 
@@ -924,7 +930,7 @@ void CAM_Application::removeModuleInfo( const QString& modName )
 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
 {
   // to do : add common items for popup menu ( if they are exist )
-  if ( activeModule() ) 
+  if ( activeModule() )
     activeModule()->contextMenuPopup( type, menu, title );
 }
 
@@ -959,15 +965,15 @@ CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
     infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
     infoItem.version = myInfoList.at(i).version;
     info.append(infoItem);
-  }  
+  }
   return info;
 }
 
 /*!
   \brief Abort active operations if there are any
+
   Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
+
   \return \c false if some operation cannot be aborted
 */
 bool CAM_Application::abortAllOperations()
@@ -978,4 +984,81 @@ bool CAM_Application::abortAllOperations()
     aborted = (*it)->abortAllOperations();
   }
   return aborted;
-}
\ No newline at end of file
+}
+
+/*!
+  \brief Log GUI event.
+  \param eventDescription GUI event description.
+*/
+void CAM_Application::logUserEvent( const QString& eventDescription )
+{
+  static QString guiLogFile; // null string means log file was not initialized yet
+  static QMutex aGUILogMutex;
+
+  if ( guiLogFile.isNull() )
+  {
+    // log file was not initialized yet, try to do that by parsing command line arguments
+    guiLogFile = ""; // empty string means initialization was done but log file was not set
+    QStringList args = QApplication::arguments();
+    for ( int i = 1; i < args.count(); i++ )
+    {
+      QRegExp rxs ( "--gui-log-file=(.+)" );
+      if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 )
+      {
+        QString file = rxs.capturedTexts()[1];
+        QFileInfo fi ( file );
+        if ( !fi.isDir() && fi.dir().exists() )
+       {
+         guiLogFile = fi.absoluteFilePath();
+         if ( fi.exists() ) {
+           QFile file ( guiLogFile );
+           file.remove(); // remove probably existing log file, to start with empty one
+          }
+        }
+        break;
+      }
+    }
+  }
+  if ( !guiLogFile.isEmpty() ) // non-empty string means log file was already initialized
+  {
+    QMutexLocker aLocker( &aGUILogMutex );
+    QFile file ( guiLogFile );
+    if ( file.open( QFile::Append ) ) // append to log file
+    {
+      QTextStream stream( &file );
+      stream << eventDescription << endl;
+      file.close();
+    }
+  }
+}
+
+/*!
+  \brief Log given action.
+  \param action GUI action being logged.
+  \param moduleName optional name of module, owning an action
+*/
+void CAM_Application::logAction( QAction* action, const QString& moduleName )
+{
+  QString text = action->toolTip();
+  if ( text.isEmpty() )
+    text = action->text();
+  if ( text.isEmpty() )
+    text = action->iconText();
+  if ( !text.isEmpty() )
+  {
+    QStringList message;
+    if ( !moduleName.isEmpty() )
+      message << moduleName;
+    if ( action->isCheckable() )
+    {
+      message << tr( "ACTION_TOGGLED" );
+      message << ( action->isChecked() ? tr( "ACTION_ON" ) : tr( "ACTION_OFF" ) );
+    }
+    else
+    {
+      message << tr( "ACTION_TRIGGERED" );
+    }
+    message << text;
+    logUserEvent( message.join( ": " ) );
+  }
+}
index 2d41027680c3fdc957642efbfa0a820303737b54..232de82feed5e6f4b3db2e9da819b2e7fdd33169 100644 (file)
@@ -82,6 +82,9 @@ public:
 
   static ModuleShortInfoList getVersionInfo();
 
+  static void         logUserEvent( const QString& );
+  static void         logAction( QAction*, const QString& = QString() );
+
 protected:
   virtual SUIT_Study* createNewStudy();
   virtual void        updateCommandsStatus();
index db3afe298c922643022b347e8c94aca36fa87f61..dc442427df162fb62d44a58f1e6edb0f5ac38065 100644 (file)
@@ -92,7 +92,8 @@ CAM_Module::CAM_Module( const QString& name )
   myName( name ),
   myDataModel( 0 ),
   myMenuShown( false ),
-  myToolShown( false )
+  myToolShown( false ),
+  myActionLoggingEnabled( false )
 {
 }
 
@@ -1018,6 +1019,8 @@ QAction* CAM_Module::createAction( const int id, const QString& text, const QIco
   QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, shortcutAction );
   a->setStatusTip( tip );
 
+  connect( a, SIGNAL( triggered( bool ) ), this, SLOT( moduleActionActivated() ), Qt::UniqueConnection );
+
   if ( reciever && member )
     connect( a, SIGNAL( triggered( bool ) ), reciever, member );
 
@@ -1215,3 +1218,41 @@ bool CAM_Module::abortAllOperations()
 {
   return true;
 }
+
+/*!
+  \brief Called when an action is triggered
+*/
+void CAM_Module::moduleActionActivated()
+{
+  QAction* action = qobject_cast<QAction*>( sender() );
+  if ( action && !action->isSeparator() && isActionLoggingEnabled() )
+    logAction( action );
+}
+
+/*!
+  \brief Log given action.
+  \param action GUI action being logged.
+
+  Default implementation just forwards to CAM_Applicaion::logAction();
+*/
+void CAM_Module::logAction( QAction* action )
+{
+  CAM_Application::logAction( action, moduleName() );
+}
+
+/*!
+  \brief Return \c true if action logging is enabled.
+*/
+bool CAM_Module::isActionLoggingEnabled() const
+{
+  return myActionLoggingEnabled;
+}
+
+/*!
+  \brief Enable / disable action logging.
+  \param enabled \c true to enable logging, or \c false to disable it.
+*/
+void CAM_Module::setActionLoggingEnabled( bool enabled )
+{
+  myActionLoggingEnabled = enabled;
+}
index 2411413e26f7c1065dd0a768c53e40ce49929427..3fedbfc7ee47e1860eb72268df662397f3b7c032 100644 (file)
@@ -122,6 +122,10 @@ public:
   int                    createMenu( QAction*, const int, const int = -1, const int = -1, const int = -1 );
   int                    createMenu( QAction*, const QString&, const int = -1, const int = -1, const int = -1 );
 
+  virtual void           logAction( QAction* );
+  bool                   isActionLoggingEnabled() const;
+  void                   setActionLoggingEnabled( bool );
+  
   static QAction*        separator();
 
 public slots:
@@ -135,6 +139,8 @@ public slots:
 
   virtual void           onApplicationClosed( SUIT_Application* );
 
+  virtual void           moduleActionActivated();
+
 private slots:
   void                   onInfoChanged( QString );
 
@@ -164,6 +170,7 @@ private:
   QMap<int, QAction*>    myActionMap;       //!< menu actions
   bool                   myMenuShown;       //!< menu shown flag
   bool                   myToolShown;       //!< tool shown flag
+  bool                   myActionLoggingEnabled; //!< action logging enabled 
 
   friend class CAM_Application;
 };
index 6779ef2282e2a0d0cf9043aef928bee251b68e5e..fb54357e4d9f608896819db0a746d1ad6387d767 100644 (file)
         <source>MODULE_ROOT_OBJECT_TOOLTIP</source>
         <translation>%1 module root object</translation>
     </message>
+    <message>
+        <source>ACTION_TRIGGERED</source>
+        <translation>action is triggered</translation>
+    </message>
+    <message>
+        <source>ACTION_TOGGLED</source>
+        <translation>action is toggled</translation>
+    </message>
+    <message>
+        <source>ACTION_ON</source>
+        <translation>on</translation>
+    </message>
+    <message>
+        <source>ACTION_OFF</source>
+        <translation>off</translation>
+    </message>
+    <message>
+        <source>OPERATION_APPLIED</source>
+        <translation>operation applied</translation>
+    </message>
 </context>
 </TS>
index 0d706cb2fcc9fa03e102775580bddbb70807cfed..19639c2812cea9d2732149a0cecf41434ad2d981 100644 (file)
 #include <QMimeData>
 #include <QShortcut>
 #include <QRegExp>
-#include <QMutex>
-#include <QMutexLocker>
 
 #include <utilities.h>
 
@@ -5775,45 +5773,6 @@ bool LightApp_Application::checkExistingDoc( bool closeExistingDoc )
   return result;
 }
 
-/*!
-  Log GUI action
-*/
-void LightApp_Application::logUserEvent(const QString& eventDescription)
-{
-  static QString _gui_log_file_ = "Not initialized";
-  static QMutex aGUILogMutex;
-  if (_gui_log_file_ == "Not initialized") {
-    _gui_log_file_ = "";
-    QStringList args = QApplication::arguments();
-    for (int i = 1; i < args.count(); i++) {
-      QRegExp rxs ("--gui-log-file=(.+)");
-      if (rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1) {
-        QString file = rxs.capturedTexts()[1];
-        QFileInfo fi ( file );
-        if (!fi.isDir()) {
-          if (fi.dir().exists()) {
-            _gui_log_file_ = fi.absoluteFilePath();
-            if (fi.exists()) {
-              QFile file (_gui_log_file_);
-              file.remove();
-            }
-          }
-        }
-        break;
-      }
-    }
-  }
-  if (_gui_log_file_ != "") {
-    QMutexLocker aLocker (&aGUILogMutex);
-    QFile file (_gui_log_file_);
-    if (file.open(QFile::Append)) {
-      QTextStream stream( &file );
-      stream << eventDescription << endl;
-      file.close();
-    }
-  }
-}
-
 #ifndef DISABLE_PYCONSOLE
 
 PyConsole_Interp* LightApp_Application::getPyInterp()
index 351c1663ce5b8f8e3813d506097f2a30f171e7a8..cb2102e1977519d6a6cbee1ba89ae6dd65f777bb 100644 (file)
@@ -191,8 +191,6 @@ public:
 
   virtual bool                        checkExistingDoc( bool = true );
 
-  static void                         logUserEvent(const QString& eventDescription);
-
 #ifndef DISABLE_PYCONSOLE
   PyConsole_Interp*                   getPyInterp();
 #endif
index b0c23974bc23fa20ce1e58646c94c97b149e4c2b..25efe528da1fd8165f57e18b5424be241d771667 100644 (file)
@@ -5104,3 +5104,43 @@ void SalomePyQt::stopPyLog()
   };
   ProcessVoidEvent( new TEvent() );
 }
+
+/*!
+  \brief Log GUI event.
+  \param eventDescription GUI event description.
+*/
+void SalomePyQt::logUserEvent( const QString& eventDescription )
+{
+  class TEvent: public SALOME_Event
+  {
+    QString myEventDescription;
+  public:
+    TEvent( const QString& theDescription ) : myEventDescription( theDescription ) {}
+    virtual void Execute() 
+    {
+      LightApp_Application::logUserEvent( myEventDescription );
+    }
+  };
+  ProcessVoidEvent( new TEvent( eventDescription ) );
+}
+
+/*!
+  \brief Log given action.
+  \param action GUI action being logged.
+  \param moduleName optional name of module, owning an action
+*/
+void SalomePyQt::logAction( QAction* action, const QString& moduleName )
+{
+  class TEvent: public SALOME_Event
+  {
+    QAction* myAction;
+    QString myModuleName;
+  public:
+    TEvent( QAction* theAction, const QString& theModuleName ) : myAction( theAction ), myModuleName( theModuleName ) {}
+    virtual void Execute() 
+    {
+      LightApp_Application::logAction( myAction, myModuleName );
+    }
+  };
+  ProcessVoidEvent( new TEvent( action, moduleName ) );
+}
index 89eda97567be02e8e1411188ef9bc179fcedeeea..38a3801febaf88ba58f50ceed3e2c6e3a149aa61 100644 (file)
@@ -377,6 +377,8 @@ public:
   static void              startPyLog(const QString&);
   static void              stopPyLog();
 
+  static void              logUserEvent( const QString& );
+  static void              logAction( QAction*, const QString& = QString() );
 };
 
 #endif // SALOME_PYQT_H
index 30e3d2dabf97839ad31536e3e0b7f9aa8a626750..6f6d5fc37c29fc116d09f2bd40499dffcf908d4c 100644 (file)
@@ -495,4 +495,7 @@ public:
 
   static void              startPyLog(const QString&) /ReleaseGIL/ ;
   static void              stopPyLog() /ReleaseGIL/ ;
+
+  static void              logUserEvent( const QString& ) /ReleaseGIL/ ;
+  static void              logAction( QAction*, const QString& = QString() ) /ReleaseGIL/ ;
 };