1 // Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "CAM_Application.h"
25 #include "CAM_Study.h"
26 #include "CAM_Module.h"
28 #include <SUIT_Tools.h>
29 #include <SUIT_Desktop.h>
30 #include <SUIT_Session.h>
31 #include <SUIT_MessageBox.h>
32 #include <SUIT_ResourceMgr.h>
34 #include <KERNEL_version.h>
35 #include <GUI_version.h>
38 #include <QApplication>
42 #include <QMutexLocker>
44 #include <QTextStream>
56 #include <utilities.h>
63 BusyLocker( bool& busy ) : myPrev( busy ), myBusy( busy ) { myBusy = true; }
64 ~BusyLocker() { myBusy = myPrev; }
72 \brief Create new instance of CAM_Application.
73 \return new instance of CAM_Application class
75 extern "C" CAM_EXPORT SUIT_Application* createApplication()
77 return new CAM_Application();
81 \class CAM_Application
82 \brief Introduces an application class which provides modular architecture.
84 This class defines multi-modular application configuration and behaviour.
85 Each module (CAM_Module) can have own data model, document windows and
88 An application provides all necessary functionality for modules management,
91 - modules activation/deactivation
95 CAM_Application::ModuleInfoList CAM_Application::myInfoList;
100 Read modules list (from command line or from resource file).
101 If \a autoLoad parameter is \c true all the modules will be loaded
102 immediately after application starting, otherwise each module will
103 be loaded by demand (with activateModule()).
105 \param autoLoad auto loading flag
107 CAM_Application::CAM_Application( const bool autoLoad )
110 myAutoLoad( autoLoad ),
119 Does nothing currently.
121 CAM_Application::~CAM_Application()
123 for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end(); ++it )
129 \brief Start an application.
131 Load all modules, if "auto loading" flag has been set to \c true.
133 \sa CAM_Application()
135 void CAM_Application::start()
138 for ( ModuleInfoList::iterator it = myInfoList.begin();
139 it != myInfoList.end(); ++it )
141 if ( (*it).status == stUnknown )
142 (*it).status = checkModule( (*it).title ) ? stReady : stInaccessible;
149 STD_Application::start();
153 \brief Get active module.
154 \return active module or 0 if there are no any
156 CAM_Module* CAM_Application::activeModule() const
162 \brief Get the module with specified name.
163 \return module or 0 if not found
165 CAM_Module* CAM_Application::module( const QString& modName ) const
168 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
169 it != myModules.end() && !mod; ++it )
170 if ( (*it)->moduleName() == modName )
176 \brief Get all loaded modules.
177 \return list of modules
179 CAM_Application::ModuleList CAM_Application::modules() const
185 \brief Get all loaded modules.
186 \param returning list of modules
188 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
192 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
193 it != myModules.end(); ++it )
198 \brief Get names of all modules.
200 Get loaded modules names if \a loaded is \c true,
201 otherwise get all avaiable modules names.
203 \param lst output list of modules names
204 \param loaded boolean flag, defines what modules names to return
206 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
212 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
213 it != myModules.end(); ++it )
214 lst.append( (*it)->moduleName() );
218 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
219 it != myInfoList.end(); ++it )
220 if ( (*it).status != stNoGui )
221 lst.append( (*it).title );
226 \brief Add module \a mod to the modules list.
228 Performes module initialization. Does nothing if the module
231 \param mod module being added
232 \sa CAM_Module::initialize()
234 void CAM_Application::addModule( CAM_Module* mod )
236 if ( !mod || myModules.contains( mod ) )
239 mod->initialize( this );
241 QMap<CAM_Module*, int> map;
244 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
245 it != myInfoList.end(); ++it )
247 if ( (*it).title == mod->moduleName() )
248 newList.append( mod );
251 CAM_Module* curMod = module( (*it).title );
253 newList.append( curMod );
257 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
258 it != myModules.end(); ++it )
260 if ( !newList.contains( *it ) )
261 newList.append( *it );
264 if ( !newList.contains( mod ) )
265 newList.append( mod );
273 \brief Load modules from the modules information list.
275 If some module can not be loaded, an error message is shown.
277 void CAM_Application::loadModules()
279 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
281 CAM_Module* mod = loadModule( (*it).title );
285 QString wrn = tr( "Can not load module %1" ).arg( (*it).title );
286 if ( desktop() && desktop()->isVisible() )
287 SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ), wrn );
289 qWarning( qPrintable( wrn ) );
295 \brief Load module \a modName.
297 The function prints warning message if:
298 - modules information list is empty
299 - modules information list does not include specified module info
300 - module library can not be loaded by some reason
302 \param modName module name
303 \return module object pointer or 0 if module could not be loaded
305 CAM_Module* CAM_Application::loadModule( const QString& modName, const bool showMsg )
307 if ( myInfoList.isEmpty() )
309 qWarning( qPrintable( tr( "Modules configuration is not defined." ) ) );
313 QString libName = moduleLibrary( modName );
314 if ( libName.isEmpty() )
316 qWarning( qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) ) );
321 GET_MODULE_FUNC crtInst = 0;
322 GET_VERSION_FUNC getVersion = 0;
326 LPTSTR str_libname = new TCHAR[libName.length() + 1];
327 str_libname[libName.toWCharArray(str_libname)] = '\0';
329 QByteArray arr = libName.toLatin1();
330 LPTSTR str_libname = arr.constData();
332 HINSTANCE modLib = ::LoadLibrary( str_libname );
339 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
340 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
342 QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
344 QString out_err = (LPTSTR)lpMsgBuf;
346 err = QString( "Failed to load %1. %2" ).arg( libName ).arg(out_err);
347 ::LocalFree( lpMsgBuf );
351 crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
355 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
356 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
358 QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
360 QString out_err = (LPTSTR)lpMsgBuf;
363 err = QString( "Failed to find %1 function. %2" ).arg( GET_MODULE_NAME ).arg( out_err );
364 ::LocalFree( lpMsgBuf );
367 getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
370 void* modLib = dlopen( libName.toUtf8(), RTLD_LAZY | RTLD_GLOBAL );
372 err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
375 crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
377 err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
379 getVersion = (GET_VERSION_FUNC)dlsym( modLib, GET_VERSION_NAME );
383 CAM_Module* module = crtInst ? crtInst() : 0;
386 module->setModuleName( modName );
387 module->setName( moduleName( modName ) );
390 if ( !err.isEmpty() && showMsg ) {
391 if ( desktop() && desktop()->isVisible() )
392 SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
394 qWarning( qPrintable( err ) );
397 char* version = getVersion ? getVersion() : 0;
400 for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
401 if ( (*it).title == modName ) {
402 if( (*it).version.isEmpty() ) {
403 (*it).version = QString(version);
414 \brief Activate module \a modName.
415 \param modName module name
416 \return \c true, if module is loaded and activated successfully and \c false otherwise
418 bool CAM_Application::activateModule( const QString& modName )
420 if ( (!modName.isEmpty() && !activeStudy()) || myBlocked )
423 // VSR 25/10/2011: prevent nested activation/deactivation
424 // See issues 0021307, 0021373
425 BusyLocker lock( myBlocked );
427 QString name = modName;
428 if ( !name.isEmpty() && !moduleTitle( modName ).isEmpty() )
429 name = moduleTitle( modName );
432 if ( !name.isEmpty() )
434 setProperty("activateModule", true);
435 CAM_Module* mod = module( name );
437 mod = loadModule( name );
441 res = activateModule( mod );
442 setProperty("activateModule", QVariant());
445 res = activateModule( 0 );
451 \brief Activate module \a mod.
453 Shows error message if module could not be activated in the current study.
455 \param mod module object pointer
456 \return \c true, if module is loaded and activated successfully and \c false otherwise
458 bool CAM_Application::activateModule( CAM_Module* mod )
460 if ( mod && !activeStudy() )
463 if ( myModule == mod )
468 if ( myModule->deactivateModule( activeStudy() ) )
470 logStructuredUserEvent( myModule->moduleName(),
475 moduleDeactivated( myModule );
481 // Connect the module to the active study
482 myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
483 if ( myModule->activateModule( activeStudy() ) )
485 logStructuredUserEvent( myModule->moduleName(),
492 myModule->setMenuShown( false );
493 myModule->setToolShown( false );
494 QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
495 if ( desktop() && desktop()->isVisible() )
496 SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
498 qWarning( qPrintable( wrn ) );
504 updateCommandsStatus();
510 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
511 This method is dedicated to run operations of some module from any other module.
512 \param modName module name
513 \param actionId is a numerical unique operation identifier
514 \return \c true in case of success and \c false otherwise
516 bool CAM_Application::activateOperation( const QString& modName,
519 CAM_Module* mod = loadModule(modName, false);
522 return mod->activateOperation(actionId);
528 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
529 This method is dedicated to run operations of some module from any other module.
530 \param modName module name
531 \param actionId is a string unique operation identifier
532 \return \c true in case of success and \c false otherwise
534 bool CAM_Application::activateOperation( const QString& modName,
535 const QString& actionId )
537 CAM_Module* mod = loadModule(modName, false);
540 return mod->activateOperation(actionId);
546 \brief Load module \a modName and activate its operation,
547 corresponding to \a actionId and \a pluginName.
548 This method is dedicated to run operations of some module from any other module.
549 \param modName module name
550 \param actionId is a string unique operation identifier
551 \param pluginName is a name of a plugin where the operation is implemented
552 \return \c true in case of success and \c false otherwise
554 bool CAM_Application::activateOperation( const QString& modName,
555 const QString& actionId,
556 const QString& pluginName )
558 CAM_Module* mod = loadModule(modName, false);
561 return mod->activateOperation(actionId, pluginName);
567 \brief Create new study.
568 \return study object pointer
570 SUIT_Study* CAM_Application::createNewStudy()
572 return new CAM_Study( this );
576 \brief Update menu commands status.
578 void CAM_Application::updateCommandsStatus()
580 STD_Application::updateCommandsStatus();
582 if ( activeModule() )
583 activeModule()->updateCommandsStatus();
587 \brief Prepare application to study closing.
589 Closes all modules in study \a theDoc.
593 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
595 for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
596 (*it)->studyClosed( theDoc );
599 void CAM_Application::afterCloseDoc()
604 \brief Set active study.
605 \param study study to be made active
607 void CAM_Application::setActiveStudy( SUIT_Study* study )
609 STD_Application::setActiveStudy( study );
613 \brief Check module availability.
615 The method can be redefined in successors. Default implementation returns \c true.
617 \param title module title
618 \return \c true if module is accessible; \c false otherwise
620 bool CAM_Application::checkModule( const QString& )
626 \brief Callback function, called when the module is added to the application.
628 This virtual method can be re-implemented in the successors. Base implementation
631 \param mod module being added
633 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
638 \brief Callback function, called when the module is just deactivated.
640 This virtual method can be re-implemented in the successors. Base implementation
643 \param mod module just deactivated
645 void CAM_Application::moduleDeactivated( CAM_Module* /*mod*/ )
650 \brief Get module name by its title (user name).
651 \param title module title (user name)
652 \return module name or null QString if module is not found
654 QString CAM_Application::moduleName( const QString& title )
657 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
659 if ( (*it).title == title )
666 \brief Get module title (user name) by its name.
667 \param name module name
668 \return module title (user name) or null QString if module is not found
670 QString CAM_Application::moduleTitle( const QString& name )
673 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
675 if ( (*it).name == name )
682 \brief Get module icon name.
683 \param name module name or title
684 \return module icon or null QString if module is not found
686 QString CAM_Application::moduleIcon( const QString& name )
689 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
691 if ( (*it).name == name || (*it).title == name )
698 \brief Get module description.
699 \param name module name or title
700 \return module description or null QString if description is not provided in config file.
702 QString CAM_Application::moduleDescription( const QString& name )
705 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
707 if ( (*it).name == name || (*it).title == name )
708 res = tr((*it).description.toUtf8());
714 \brief Get module library name by its title (user name).
715 \param title module name or title
716 \param full if \c true, return full library name, otherwise return its internal name
717 \return module library name or null QString if module is not found
719 QString CAM_Application::moduleLibrary( const QString& name, const bool full )
722 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
724 if ( (*it).name == name || (*it).title == name )
727 if ( !res.isEmpty() && full )
728 res = SUIT_Tools::library( res );
733 \brief Get displayer proxy for given module, by its title (user name).
734 \param name module name or title
735 \return name of module which provides displayer for requested module
737 QString CAM_Application::moduleDisplayer( const QString& name )
741 if ( !name.isEmpty() )
743 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
745 if ( (*it).title == name || (*it).name == name ) {
746 res = (*it).displayer;
757 \brief Read modules information list
759 This function first tries to get the modules names list by parsing
760 the application command line arguments, looking for the
761 "--modules ( <mod_name>[:<mod_name>...] )" option.
762 List of modules is separated by colon symbol (":").
764 If "--modules" command line option is not used, the list of modules
765 is retrieved from the application resource file: parameter "modules" of
766 the section "launch".
768 Then the information about each module (module title (user name),
769 library name) is retrieved from the corresponding section of resource
770 file with help of resources manager.
772 Shows the warning message, if module information list is empty.
776 void CAM_Application::readModuleList()
778 if ( !myInfoList.isEmpty() )
781 // we cannot use own resourceMgr() as this method can be called from constructor
782 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
786 QString args = QApplication::arguments().join( " " );
788 QRegExp rx1("--modules=([\\w,]*)");
789 rx1.setMinimal( false );
790 QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
791 rx2.setMinimal( true );
795 int pos1 = rx1.indexIn( args, pos );
796 int pos2 = rx2.indexIn( args, pos );
797 if ( pos1 != -1 && pos2 != -1 ) {
798 modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
799 pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
801 else if ( pos1 != -1 ) {
802 modules = rx1.cap( 1 );
803 pos = pos1 + rx1.matchedLength();
805 else if ( pos2 != -1 ) {
806 modules = rx2.cap( 1 );
807 pos = pos2 + rx2.matchedLength();
814 QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
815 for ( int i = 0; i < mods.count(); i++ ) {
816 if ( !mods[i].trimmed().isEmpty() )
817 modList.append( mods[i].trimmed() );
821 if ( modList.isEmpty() ) {
822 QString mods = resMgr->stringValue( "launch", "modules", QString() );
823 modList = mods.split( ",", QString::SkipEmptyParts );
826 // extra modules loaded manually on previous session
829 foreach ( QString modName, modList )
830 appendModuleInfo( modName.trimmed() );
832 if ( myInfoList.isEmpty() ) {
833 if ( desktop() && desktop()->isVisible() )
834 SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
837 printf( "****************************************************************\n" );
838 printf( "* Warning: modules list is empty.\n" );
839 printf( "****************************************************************\n" );
844 bool CAM_Application::appendModuleInfo( const QString& modName )
846 MESSAGE("Start to append module info for a given module name: ");
847 SCRUTE(modName.toStdString());
849 if ( modName.isEmpty() )
850 return false; // empty module name
852 if ( !moduleTitle( modName ).isEmpty() )
853 return false; // already added
855 if ( modName == "KERNEL" || modName == "GUI" )
856 return false; // skip KERNEL and GUI modules
858 // we cannot use own resourceMgr() as this method can be called from constructor
859 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
863 // module internal name
866 inf.version = resMgr->stringValue( modName, "version", QString() ).trimmed();
867 // displayer, if module does not have GUI, displayer may be delegated to other module
868 inf.displayer = resMgr->stringValue( modName, "displayer", QString() ).trimmed();
870 // "gui" option explicitly says that module has GUI
871 // Now trying to get the "gui" option value, we always get a default one,
872 // then we can't rely on it.
873 bool hasGui = resMgr->booleanValue(modName, "gui", false);
875 // Additional check if the module actually has a title and icon.
876 // Module with GUI must explicitly specify title (GUI name).
877 inf.title = resMgr->stringValue(modName, "name", QString()).trimmed();
878 const bool hasTitle = !inf.title.isEmpty();
881 if (hasGui && !hasTitle)
883 MESSAGE("Invalid config! The module has gui option, but doesn't have a title.");
887 // While we can't rely on gui option, use a title to make a decision about gui.
890 // status; if module has GUI, availability will be checked on activation
891 inf.status = hasGui ? stUnknown : stNoGui;
896 inf.icon = resMgr->stringValue( modName, "icon", QString() ).trimmed();
897 // description, for Info panel
898 inf.description = resMgr->stringValue( modName, "description", QString() );
899 // library; if not specified, we use internal module name
900 inf.library = SUIT_Tools::libraryName( resMgr->stringValue( modName, "library", QString() ).trimmed() );
901 if ( inf.library.isEmpty() )
902 inf.library = modName;
905 // At this point we should have only valid inf object.
906 myInfoList.append(inf);
908 SCRUTE(inf.name.toStdString());
909 SCRUTE(inf.version.toStdString());
910 SCRUTE(inf.displayer.toStdString());
912 SCRUTE(inf.title.toStdString());
913 SCRUTE(inf.icon.toStdString());
914 SCRUTE(inf.description.toStdString());
915 SCRUTE(inf.library.toStdString());
920 void CAM_Application::removeModuleInfo( const QString& modName )
922 QMutableListIterator<ModuleInfo> it( myInfoList );
923 while ( it.hasNext() )
925 ModuleInfo info = it.next();
926 if ( info.name == modName )
935 \brief Add common menu items to the popup menu.
937 Menu items list is defined by the active module.
939 \param type popup menu context
940 \param menu popup menu
941 \param title popup menu title, which can be set by the module if required
943 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
945 // to do : add common items for popup menu ( if they are exist )
946 if ( activeModule() )
947 activeModule()->contextMenuPopup( type, menu, title );
951 \brief Create new empty study.
953 void CAM_Application::createEmptyStudy()
955 /*SUIT_Study* study = */activeStudy();
956 STD_Application::createEmptyStudy();
960 \brief Return information about version of the each module.
962 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
964 ModuleShortInfoList info;
966 ModuleShortInfo kernel;
967 kernel.name = "KERNEL";
968 kernel.version = KERNEL_VERSION_STR;
973 gui.version = GUI_VERSION_STR;
976 for(int i = 0; i < myInfoList.size(); i++) {
977 ModuleShortInfo infoItem;
978 infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
979 infoItem.version = myInfoList.at(i).version;
980 info.append(infoItem);
986 \brief Abort active operations if there are any
988 Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
990 \return \c false if some operation cannot be aborted
992 bool CAM_Application::abortAllOperations()
995 for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
997 aborted = (*it)->abortAllOperations();
1003 \brief Log GUI event.
1004 \param eventDescription GUI event description.
1006 void CAM_Application::logUserEvent( const QString& eventDescription )
1008 static QString guiLogFile; // null string means log file was not initialized yet
1009 static QMutex aGUILogMutex;
1011 if ( guiLogFile.isNull() )
1013 // log file was not initialized yet, try to do that by parsing command line arguments
1014 guiLogFile = ""; // empty string means initialization was done but log file was not set
1015 QStringList args = QApplication::arguments();
1016 for ( int i = 1; i < args.count(); i++ )
1018 QRegExp rxs ( "--gui-log-file=(.+)" );
1019 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 )
1021 QString file = rxs.capturedTexts()[1];
1022 QFileInfo fi ( file );
1023 if ( !fi.isDir() && fi.dir().exists() )
1025 guiLogFile = fi.absoluteFilePath();
1026 if ( fi.exists() ) {
1027 QFile file ( guiLogFile );
1028 file.remove(); // remove probably existing log file, to start with empty one
1035 if ( !guiLogFile.isEmpty() ) // non-empty string means log file was already initialized
1037 QMutexLocker aLocker( &aGUILogMutex );
1038 QFile file ( guiLogFile );
1039 if ( file.open( QFile::Append ) ) // append to log file
1041 QDateTime current = QDateTime::currentDateTime();
1042 QTextStream stream( &file );
1043 stream << current.toString("yyyyMMdd-hhmmss")
1044 << "," << eventDescription
1051 void CAM_Application::logStructuredUserEvent( const QString& module,
1052 const QString& section,
1053 const QString& action,
1054 const QString& event,
1055 const QString& message )
1057 const QStringList mes = (QStringList() << module
1063 logUserEvent( mes.join( "," ) );
1067 \brief Log given action.
1068 \param action GUI action being logged.
1069 \param moduleName optional name of module, owning an action
1071 void CAM_Application::logAction( QAction* action, const QString& moduleName )
1073 QString text = action->toolTip();
1074 if ( text.isEmpty() )
1075 text = action->text();
1076 if ( text.isEmpty() )
1077 text = action->iconText();
1079 if ( !text.isEmpty() )
1081 if ( action->isCheckable() )
1083 logStructuredUserEvent ( moduleName,
1085 tr( "ACTION_TOGGLED" ),
1086 action->isChecked() ? tr( "ACTION_ON" ) : tr( "ACTION_OFF" ),
1091 logStructuredUserEvent ( moduleName,
1093 tr( "ACTION_TRIGGERED" ),