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 logUserEvent( tr( "MODULE_DEACTIVATED" ).arg( myModule->moduleName() ) );
472 moduleDeactivated( myModule );
478 // Connect the module to the active study
479 myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
480 if ( myModule->activateModule( activeStudy() ) )
482 logUserEvent( tr( "MODULE_ACTIVATED" ).arg( myModule->moduleName() ) );
486 myModule->setMenuShown( false );
487 myModule->setToolShown( false );
488 QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
489 if ( desktop() && desktop()->isVisible() )
490 SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
492 qWarning( qPrintable( wrn ) );
498 updateCommandsStatus();
504 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
505 This method is dedicated to run operations of some module from any other module.
506 \param modName module name
507 \param actionId is a numerical unique operation identifier
508 \return \c true in case of success and \c false otherwise
510 bool CAM_Application::activateOperation( const QString& modName,
513 CAM_Module* mod = loadModule(modName, false);
516 return mod->activateOperation(actionId);
522 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
523 This method is dedicated to run operations of some module from any other module.
524 \param modName module name
525 \param actionId is a string unique operation identifier
526 \return \c true in case of success and \c false otherwise
528 bool CAM_Application::activateOperation( const QString& modName,
529 const QString& actionId )
531 CAM_Module* mod = loadModule(modName, false);
534 return mod->activateOperation(actionId);
540 \brief Load module \a modName and activate its operation,
541 corresponding to \a actionId and \a pluginName.
542 This method is dedicated to run operations of some module from any other module.
543 \param modName module name
544 \param actionId is a string unique operation identifier
545 \param pluginName is a name of a plugin where the operation is implemented
546 \return \c true in case of success and \c false otherwise
548 bool CAM_Application::activateOperation( const QString& modName,
549 const QString& actionId,
550 const QString& pluginName )
552 CAM_Module* mod = loadModule(modName, false);
555 return mod->activateOperation(actionId, pluginName);
561 \brief Create new study.
562 \return study object pointer
564 SUIT_Study* CAM_Application::createNewStudy()
566 return new CAM_Study( this );
570 \brief Update menu commands status.
572 void CAM_Application::updateCommandsStatus()
574 STD_Application::updateCommandsStatus();
576 if ( activeModule() )
577 activeModule()->updateCommandsStatus();
581 \brief Prepare application to study closing.
583 Closes all modules in study \a theDoc.
587 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
589 for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
590 (*it)->studyClosed( theDoc );
593 void CAM_Application::afterCloseDoc()
598 \brief Set active study.
599 \param study study to be made active
601 void CAM_Application::setActiveStudy( SUIT_Study* study )
603 STD_Application::setActiveStudy( study );
607 \brief Check module availability.
609 The method can be redefined in successors. Default implementation returns \c true.
611 \param title module title
612 \return \c true if module is accessible; \c false otherwise
614 bool CAM_Application::checkModule( const QString& )
620 \brief Callback function, called when the module is added to the application.
622 This virtual method can be re-implemented in the successors. Base implementation
625 \param mod module being added
627 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
632 \brief Callback function, called when the module is just deactivated.
634 This virtual method can be re-implemented in the successors. Base implementation
637 \param mod module just deactivated
639 void CAM_Application::moduleDeactivated( CAM_Module* /*mod*/ )
644 \brief Get module name by its title (user name).
645 \param title module title (user name)
646 \return module name or null QString if module is not found
648 QString CAM_Application::moduleName( const QString& title )
651 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
653 if ( (*it).title == title )
660 \brief Get module title (user name) by its name.
661 \param name module name
662 \return module title (user name) or null QString if module is not found
664 QString CAM_Application::moduleTitle( const QString& name )
667 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
669 if ( (*it).name == name )
676 \brief Get module icon name.
677 \param name module name or title
678 \return module icon or null QString if module is not found
680 QString CAM_Application::moduleIcon( const QString& name )
683 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
685 if ( (*it).name == name || (*it).title == name )
692 \brief Get module description.
693 \param name module name or title
694 \return module description or null QString if description is not provided in config file.
696 QString CAM_Application::moduleDescription( const QString& name )
699 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
701 if ( (*it).name == name || (*it).title == name )
702 res = tr((*it).description.toUtf8());
708 \brief Get module library name by its title (user name).
709 \param title module name or title
710 \param full if \c true, return full library name, otherwise return its internal name
711 \return module library name or null QString if module is not found
713 QString CAM_Application::moduleLibrary( const QString& name, const bool full )
716 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
718 if ( (*it).name == name || (*it).title == name )
721 if ( !res.isEmpty() && full )
722 res = SUIT_Tools::library( res );
727 \brief Get displayer proxy for given module, by its title (user name).
728 \param name module name or title
729 \return name of module which provides displayer for requested module
731 QString CAM_Application::moduleDisplayer( const QString& name )
735 if ( !name.isEmpty() )
737 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
739 if ( (*it).title == name || (*it).name == name ) {
740 res = (*it).displayer;
751 \brief Read modules information list
753 This function first tries to get the modules names list by parsing
754 the application command line arguments, looking for the
755 "--modules ( <mod_name>[:<mod_name>...] )" option.
756 List of modules is separated by colon symbol (":").
758 If "--modules" command line option is not used, the list of modules
759 is retrieved from the application resource file: parameter "modules" of
760 the section "launch".
762 Then the information about each module (module title (user name),
763 library name) is retrieved from the corresponding section of resource
764 file with help of resources manager.
766 Shows the warning message, if module information list is empty.
770 void CAM_Application::readModuleList()
772 if ( !myInfoList.isEmpty() )
775 // we cannot use own resourceMgr() as this method can be called from constructor
776 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
780 QString args = QApplication::arguments().join( " " );
782 QRegExp rx1("--modules=([\\w,]*)");
783 rx1.setMinimal( false );
784 QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
785 rx2.setMinimal( true );
789 int pos1 = rx1.indexIn( args, pos );
790 int pos2 = rx2.indexIn( args, pos );
791 if ( pos1 != -1 && pos2 != -1 ) {
792 modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
793 pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
795 else if ( pos1 != -1 ) {
796 modules = rx1.cap( 1 );
797 pos = pos1 + rx1.matchedLength();
799 else if ( pos2 != -1 ) {
800 modules = rx2.cap( 1 );
801 pos = pos2 + rx2.matchedLength();
808 QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
809 for ( int i = 0; i < mods.count(); i++ ) {
810 if ( !mods[i].trimmed().isEmpty() )
811 modList.append( mods[i].trimmed() );
815 if ( modList.isEmpty() ) {
816 QString mods = resMgr->stringValue( "launch", "modules", QString() );
817 modList = mods.split( ",", QString::SkipEmptyParts );
820 // extra modules loaded manually on previous session
823 foreach ( QString modName, modList )
824 appendModuleInfo( modName.trimmed() );
826 if ( myInfoList.isEmpty() ) {
827 if ( desktop() && desktop()->isVisible() )
828 SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
831 printf( "****************************************************************\n" );
832 printf( "* Warning: modules list is empty.\n" );
833 printf( "****************************************************************\n" );
838 bool CAM_Application::appendModuleInfo( const QString& modName )
840 MESSAGE("Start to append module info for a given module name: ");
841 SCRUTE(modName.toStdString());
843 if ( modName.isEmpty() )
844 return false; // empty module name
846 if ( !moduleTitle( modName ).isEmpty() )
847 return false; // already added
849 if ( modName == "KERNEL" || modName == "GUI" )
850 return false; // skip KERNEL and GUI modules
852 // we cannot use own resourceMgr() as this method can be called from constructor
853 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
857 // module internal name
860 inf.version = resMgr->stringValue( modName, "version", QString() ).trimmed();
861 // displayer, if module does not have GUI, displayer may be delegated to other module
862 inf.displayer = resMgr->stringValue( modName, "displayer", QString() ).trimmed();
864 // "gui" option explicitly says that module has GUI
865 // Now trying to get the "gui" option value, we always get a default one,
866 // then we can't rely on it.
867 bool hasGui = resMgr->booleanValue(modName, "gui", false);
869 // Additional check if the module actually has a title and icon.
870 // Module with GUI must explicitly specify title (GUI name).
871 inf.title = resMgr->stringValue(modName, "name", QString()).trimmed();
872 const bool hasTitle = !inf.title.isEmpty();
875 if (hasGui && !hasTitle)
877 MESSAGE("Invalid config! The module has gui option, but doesn't have a title.");
881 // While we can't rely on gui option, use a title to make a decision about gui.
884 // status; if module has GUI, availability will be checked on activation
885 inf.status = hasGui ? stUnknown : stNoGui;
890 inf.icon = resMgr->stringValue( modName, "icon", QString() ).trimmed();
891 // description, for Info panel
892 inf.description = resMgr->stringValue( modName, "description", QString() );
893 // library; if not specified, we use internal module name
894 inf.library = SUIT_Tools::libraryName( resMgr->stringValue( modName, "library", QString() ).trimmed() );
895 if ( inf.library.isEmpty() )
896 inf.library = modName;
899 // At this point we should have only valid inf object.
900 myInfoList.append(inf);
902 SCRUTE(inf.name.toStdString());
903 SCRUTE(inf.version.toStdString());
904 SCRUTE(inf.displayer.toStdString());
906 SCRUTE(inf.title.toStdString());
907 SCRUTE(inf.icon.toStdString());
908 SCRUTE(inf.description.toStdString());
909 SCRUTE(inf.library.toStdString());
914 void CAM_Application::removeModuleInfo( const QString& modName )
916 QMutableListIterator<ModuleInfo> it( myInfoList );
917 while ( it.hasNext() )
919 ModuleInfo info = it.next();
920 if ( info.name == modName )
929 \brief Add common menu items to the popup menu.
931 Menu items list is defined by the active module.
933 \param type popup menu context
934 \param menu popup menu
935 \param title popup menu title, which can be set by the module if required
937 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
939 // to do : add common items for popup menu ( if they are exist )
940 if ( activeModule() )
941 activeModule()->contextMenuPopup( type, menu, title );
945 \brief Create new empty study.
947 void CAM_Application::createEmptyStudy()
949 /*SUIT_Study* study = */activeStudy();
950 STD_Application::createEmptyStudy();
954 \brief Return information about version of the each module.
956 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
958 ModuleShortInfoList info;
960 ModuleShortInfo kernel;
961 kernel.name = "KERNEL";
962 kernel.version = KERNEL_VERSION_STR;
967 gui.version = GUI_VERSION_STR;
970 for(int i = 0; i < myInfoList.size(); i++) {
971 ModuleShortInfo infoItem;
972 infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
973 infoItem.version = myInfoList.at(i).version;
974 info.append(infoItem);
980 \brief Abort active operations if there are any
982 Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
984 \return \c false if some operation cannot be aborted
986 bool CAM_Application::abortAllOperations()
989 for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
991 aborted = (*it)->abortAllOperations();
997 \brief Log GUI event.
998 \param eventDescription GUI event description.
1000 void CAM_Application::logUserEvent( const QString& eventDescription )
1002 static QString guiLogFile; // null string means log file was not initialized yet
1003 static QMutex aGUILogMutex;
1005 if ( guiLogFile.isNull() )
1007 // log file was not initialized yet, try to do that by parsing command line arguments
1008 guiLogFile = ""; // empty string means initialization was done but log file was not set
1009 QStringList args = QApplication::arguments();
1010 for ( int i = 1; i < args.count(); i++ )
1012 QRegExp rxs ( "--gui-log-file=(.+)" );
1013 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 )
1015 QString file = rxs.capturedTexts()[1];
1016 QFileInfo fi ( file );
1017 if ( !fi.isDir() && fi.dir().exists() )
1019 guiLogFile = fi.absoluteFilePath();
1020 if ( fi.exists() ) {
1021 QFile file ( guiLogFile );
1022 file.remove(); // remove probably existing log file, to start with empty one
1029 if ( !guiLogFile.isEmpty() ) // non-empty string means log file was already initialized
1031 QMutexLocker aLocker( &aGUILogMutex );
1032 QFile file ( guiLogFile );
1033 if ( file.open( QFile::Append ) ) // append to log file
1035 QDateTime current = QDateTime::currentDateTime();
1036 QTextStream stream( &file );
1037 stream << current.toString("yyyyMMdd-hhmmss") << ": " << eventDescription << endl;
1044 \brief Log given action.
1045 \param action GUI action being logged.
1046 \param moduleName optional name of module, owning an action
1048 void CAM_Application::logAction( QAction* action, const QString& moduleName )
1050 QString text = action->toolTip();
1051 if ( text.isEmpty() )
1052 text = action->text();
1053 if ( text.isEmpty() )
1054 text = action->iconText();
1055 if ( !text.isEmpty() )
1057 QStringList message;
1058 if ( !moduleName.isEmpty() )
1059 message << moduleName;
1060 if ( action->isCheckable() )
1062 message << tr( "ACTION_TOGGLED" );
1063 message << ( action->isChecked() ? tr( "ACTION_ON" ) : tr( "ACTION_OFF" ) );
1067 message << tr( "ACTION_TRIGGERED" );
1070 logUserEvent( message.join( ": " ) );