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>
55 #include <utilities.h>
62 BusyLocker( bool& busy ) : myPrev( busy ), myBusy( busy ) { myBusy = true; }
63 ~BusyLocker() { myBusy = myPrev; }
71 \brief Create new instance of CAM_Application.
72 \return new instance of CAM_Application class
74 extern "C" CAM_EXPORT SUIT_Application* createApplication()
76 return new CAM_Application();
80 \class CAM_Application
81 \brief Introduces an application class which provides modular architecture.
83 This class defines multi-modular application configuration and behaviour.
84 Each module (CAM_Module) can have own data model, document windows and
87 An application provides all necessary functionality for modules management,
90 - modules activation/deactivation
94 CAM_Application::ModuleInfoList CAM_Application::myInfoList;
99 Read modules list (from command line or from resource file).
100 If \a autoLoad parameter is \c true all the modules will be loaded
101 immediately after application starting, otherwise each module will
102 be loaded by demand (with activateModule()).
104 \param autoLoad auto loading flag
106 CAM_Application::CAM_Application( const bool autoLoad )
109 myAutoLoad( autoLoad ),
118 Does nothing currently.
120 CAM_Application::~CAM_Application()
122 for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end(); ++it )
128 \brief Start an application.
130 Load all modules, if "auto loading" flag has been set to \c true.
132 \sa CAM_Application()
134 void CAM_Application::start()
137 for ( ModuleInfoList::iterator it = myInfoList.begin();
138 it != myInfoList.end(); ++it )
140 if ( (*it).status == stUnknown )
141 (*it).status = checkModule( (*it).title ) ? stReady : stInaccessible;
148 STD_Application::start();
152 \brief Get active module.
153 \return active module or 0 if there are no any
155 CAM_Module* CAM_Application::activeModule() const
161 \brief Get the module with specified name.
162 \return module or 0 if not found
164 CAM_Module* CAM_Application::module( const QString& modName ) const
167 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
168 it != myModules.end() && !mod; ++it )
169 if ( (*it)->moduleName() == modName )
175 \brief Get all loaded modules.
176 \return list of modules
178 CAM_Application::ModuleList CAM_Application::modules() const
184 \brief Get all loaded modules.
185 \param returning list of modules
187 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
191 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
192 it != myModules.end(); ++it )
197 \brief Get names of all modules.
199 Get loaded modules names if \a loaded is \c true,
200 otherwise get all avaiable modules names.
202 \param lst output list of modules names
203 \param loaded boolean flag, defines what modules names to return
205 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
211 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
212 it != myModules.end(); ++it )
213 lst.append( (*it)->moduleName() );
217 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
218 it != myInfoList.end(); ++it )
219 if ( (*it).status != stNoGui )
220 lst.append( (*it).title );
225 \brief Add module \a mod to the modules list.
227 Performes module initialization. Does nothing if the module
230 \param mod module being added
231 \sa CAM_Module::initialize()
233 void CAM_Application::addModule( CAM_Module* mod )
235 if ( !mod || myModules.contains( mod ) )
238 mod->initialize( this );
240 QMap<CAM_Module*, int> map;
243 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
244 it != myInfoList.end(); ++it )
246 if ( (*it).title == mod->moduleName() )
247 newList.append( mod );
250 CAM_Module* curMod = module( (*it).title );
252 newList.append( curMod );
256 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
257 it != myModules.end(); ++it )
259 if ( !newList.contains( *it ) )
260 newList.append( *it );
263 if ( !newList.contains( mod ) )
264 newList.append( mod );
272 \brief Load modules from the modules information list.
274 If some module can not be loaded, an error message is shown.
276 void CAM_Application::loadModules()
278 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
280 CAM_Module* mod = loadModule( (*it).title );
284 QString wrn = tr( "Can not load module %1" ).arg( (*it).title );
285 if ( desktop() && desktop()->isVisible() )
286 SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ), wrn );
288 qWarning( qPrintable( wrn ) );
294 \brief Load module \a modName.
296 The function prints warning message if:
297 - modules information list is empty
298 - modules information list does not include specified module info
299 - module library can not be loaded by some reason
301 \param modName module name
302 \return module object pointer or 0 if module could not be loaded
304 CAM_Module* CAM_Application::loadModule( const QString& modName, const bool showMsg )
306 if ( myInfoList.isEmpty() )
308 qWarning( qPrintable( tr( "Modules configuration is not defined." ) ) );
312 QString libName = moduleLibrary( modName );
313 if ( libName.isEmpty() )
315 qWarning( qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) ) );
320 GET_MODULE_FUNC crtInst = 0;
321 GET_VERSION_FUNC getVersion = 0;
325 LPTSTR str_libname = new TCHAR[libName.length() + 1];
326 str_libname[libName.toWCharArray(str_libname)] = '\0';
328 QByteArray arr = libName.toLatin1();
329 LPTSTR str_libname = arr.constData();
331 HINSTANCE modLib = ::LoadLibrary( str_libname );
338 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
339 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
341 QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
343 QString out_err = (LPTSTR)lpMsgBuf;
345 err = QString( "Failed to load %1. %2" ).arg( libName ).arg(out_err);
346 ::LocalFree( lpMsgBuf );
350 crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
354 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
355 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
357 QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
359 QString out_err = (LPTSTR)lpMsgBuf;
362 err = QString( "Failed to find %1 function. %2" ).arg( GET_MODULE_NAME ).arg( out_err );
363 ::LocalFree( lpMsgBuf );
366 getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
369 void* modLib = dlopen( libName.toUtf8(), RTLD_LAZY | RTLD_GLOBAL );
371 err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
374 crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
376 err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
378 getVersion = (GET_VERSION_FUNC)dlsym( modLib, GET_VERSION_NAME );
382 CAM_Module* module = crtInst ? crtInst() : 0;
385 module->setModuleName( modName );
386 module->setName( moduleName( modName ) );
389 if ( !err.isEmpty() && showMsg ) {
390 if ( desktop() && desktop()->isVisible() )
391 SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
393 qWarning( qPrintable( err ) );
396 char* version = getVersion ? getVersion() : 0;
399 for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
400 if ( (*it).title == modName ) {
401 if( (*it).version.isEmpty() ) {
402 (*it).version = QString(version);
413 \brief Activate module \a modName.
414 \param modName module name
415 \return \c true, if module is loaded and activated successfully and \c false otherwise
417 bool CAM_Application::activateModule( const QString& modName )
419 if ( (!modName.isEmpty() && !activeStudy()) || myBlocked )
422 // VSR 25/10/2011: prevent nested activation/deactivation
423 // See issues 0021307, 0021373
424 BusyLocker lock( myBlocked );
426 QString name = modName;
427 if ( !name.isEmpty() && !moduleTitle( modName ).isEmpty() )
428 name = moduleTitle( modName );
431 if ( !name.isEmpty() )
433 setProperty("activateModule", true);
434 CAM_Module* mod = module( name );
436 mod = loadModule( name );
440 res = activateModule( mod );
441 setProperty("activateModule", QVariant());
444 res = activateModule( 0 );
450 \brief Activate module \a mod.
452 Shows error message if module could not be activated in the current study.
454 \param mod module object pointer
455 \return \c true, if module is loaded and activated successfully and \c false otherwise
457 bool CAM_Application::activateModule( CAM_Module* mod )
459 if ( mod && !activeStudy() )
462 if ( myModule == mod )
467 if ( myModule->deactivateModule( activeStudy() ) )
469 logUserEvent( tr( "MODULE_DEACTIVATED" ).arg( myModule->moduleName() ) );
471 moduleDeactivated( myModule );
477 // Connect the module to the active study
478 myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
479 if ( myModule->activateModule( activeStudy() ) )
481 logUserEvent( tr( "MODULE_ACTIVATED" ).arg( myModule->moduleName() ) );
485 myModule->setMenuShown( false );
486 myModule->setToolShown( false );
487 QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
488 if ( desktop() && desktop()->isVisible() )
489 SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
491 qWarning( qPrintable( wrn ) );
497 updateCommandsStatus();
503 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
504 This method is dedicated to run operations of some module from any other module.
505 \param modName module name
506 \param actionId is a numerical unique operation identifier
507 \return \c true in case of success and \c false otherwise
509 bool CAM_Application::activateOperation( const QString& modName, int actionId )
511 CAM_Module* mod = loadModule(modName, false);
514 return mod->activateOperation(actionId);
520 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
521 This method is dedicated to run operations of some module from any other module.
522 \param modName module name
523 \param actionId is a string unique operation identifier
524 \return \c true in case of success and \c false otherwise
526 bool CAM_Application::activateOperation( const QString& modName, const QString& actionId )
528 CAM_Module* mod = loadModule(modName, false);
531 return mod->activateOperation(actionId);
537 \brief Load module \a modName and activate its operation,
538 corresponding to \a actionId and \a pluginName.
539 This method is dedicated to run operations of some module from any other module.
540 \param modName module name
541 \param actionId is a string unique operation identifier
542 \param pluginName is a name of a plugin where the operation is implemented
543 \return \c true in case of success and \c false otherwise
545 bool CAM_Application::activateOperation( const QString& modName,
546 const QString& actionId,
547 const QString& pluginName )
549 CAM_Module* mod = loadModule(modName, false);
552 return mod->activateOperation(actionId, pluginName);
558 \brief Create new study.
559 \return study object pointer
561 SUIT_Study* CAM_Application::createNewStudy()
563 return new CAM_Study( this );
567 \brief Update menu commands status.
569 void CAM_Application::updateCommandsStatus()
571 STD_Application::updateCommandsStatus();
573 if ( activeModule() )
574 activeModule()->updateCommandsStatus();
578 \brief Prepare application to study closing.
580 Closes all modules in study \a theDoc.
584 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
586 for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
587 (*it)->studyClosed( theDoc );
590 void CAM_Application::afterCloseDoc()
595 \brief Set active study.
596 \param study study to be made active
598 void CAM_Application::setActiveStudy( SUIT_Study* study )
600 STD_Application::setActiveStudy( study );
604 \brief Check module availability.
606 The method can be redefined in successors. Default implementation returns \c true.
608 \param title module title
609 \return \c true if module is accessible; \c false otherwise
611 bool CAM_Application::checkModule( const QString& )
617 \brief Callback function, called when the module is added to the application.
619 This virtual method can be re-implemented in the successors. Base implementation
622 \param mod module being added
624 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
629 \brief Callback function, called when the module is just deactivated.
631 This virtual method can be re-implemented in the successors. Base implementation
634 \param mod module just deactivated
636 void CAM_Application::moduleDeactivated( CAM_Module* /*mod*/ )
641 \brief Get module name by its title (user name).
642 \param title module title (user name)
643 \return module name or null QString if module is not found
645 QString CAM_Application::moduleName( const QString& title )
648 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
650 if ( (*it).title == title )
657 \brief Get module title (user name) by its name.
658 \param name module name
659 \return module title (user name) or null QString if module is not found
661 QString CAM_Application::moduleTitle( const QString& name )
664 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
666 if ( (*it).name == name )
673 \brief Get module icon name.
674 \param name module name or title
675 \return module icon or null QString if module is not found
677 QString CAM_Application::moduleIcon( const QString& name )
680 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
682 if ( (*it).name == name || (*it).title == name )
689 \brief Get module description.
690 \param name module name or title
691 \return module description or null QString if description is not provided in config file.
693 QString CAM_Application::moduleDescription( const QString& name )
696 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
698 if ( (*it).name == name || (*it).title == name )
699 res = tr((*it).description.toUtf8());
705 \brief Get module library name by its title (user name).
706 \param title module name or title
707 \param full if \c true, return full library name, otherwise return its internal name
708 \return module library name or null QString if module is not found
710 QString CAM_Application::moduleLibrary( const QString& name, const bool full )
713 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
715 if ( (*it).name == name || (*it).title == name )
718 if ( !res.isEmpty() && full )
719 res = SUIT_Tools::library( res );
724 \brief Get displayer proxy for given module, by its title (user name).
725 \param name module name or title
726 \return name of module which provides displayer for requested module
728 QString CAM_Application::moduleDisplayer( const QString& name )
732 if ( !name.isEmpty() )
734 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
736 if ( (*it).title == name || (*it).name == name ) {
737 res = (*it).displayer;
748 \brief Read modules information list
750 This function first tries to get the modules names list by parsing
751 the application command line arguments, looking for the
752 "--modules ( <mod_name>[:<mod_name>...] )" option.
753 List of modules is separated by colon symbol (":").
755 If "--modules" command line option is not used, the list of modules
756 is retrieved from the application resource file: parameter "modules" of
757 the section "launch".
759 Then the information about each module (module title (user name),
760 library name) is retrieved from the corresponding section of resource
761 file with help of resources manager.
763 Shows the warning message, if module information list is empty.
767 void CAM_Application::readModuleList()
769 if ( !myInfoList.isEmpty() )
772 // we cannot use own resourceMgr() as this method can be called from constructor
773 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
777 QString args = QApplication::arguments().join( " " );
779 QRegExp rx1("--modules=([\\w,]*)");
780 rx1.setMinimal( false );
781 QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
782 rx2.setMinimal( true );
786 int pos1 = rx1.indexIn( args, pos );
787 int pos2 = rx2.indexIn( args, pos );
788 if ( pos1 != -1 && pos2 != -1 ) {
789 modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
790 pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
792 else if ( pos1 != -1 ) {
793 modules = rx1.cap( 1 );
794 pos = pos1 + rx1.matchedLength();
796 else if ( pos2 != -1 ) {
797 modules = rx2.cap( 1 );
798 pos = pos2 + rx2.matchedLength();
805 QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
806 for ( int i = 0; i < mods.count(); i++ ) {
807 if ( !mods[i].trimmed().isEmpty() )
808 modList.append( mods[i].trimmed() );
812 if ( modList.isEmpty() ) {
813 QString mods = resMgr->stringValue( "launch", "modules", QString() );
814 modList = mods.split( ",", QString::SkipEmptyParts );
817 // extra modules loaded manually on previous session
820 foreach ( QString modName, modList )
821 appendModuleInfo( modName.trimmed() );
823 if ( myInfoList.isEmpty() ) {
824 if ( desktop() && desktop()->isVisible() )
825 SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
828 printf( "****************************************************************\n" );
829 printf( "* Warning: modules list is empty.\n" );
830 printf( "****************************************************************\n" );
835 bool CAM_Application::appendModuleInfo( const QString& modName )
837 MESSAGE("Start to append module info for a given module name: ");
838 SCRUTE(modName.toStdString());
840 if ( modName.isEmpty() )
841 return false; // empty module name
843 if ( !moduleTitle( modName ).isEmpty() )
844 return false; // already added
846 if ( modName == "KERNEL" || modName == "GUI" )
847 return false; // skip KERNEL and GUI modules
849 // we cannot use own resourceMgr() as this method can be called from constructor
850 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
854 // module internal name
857 inf.version = resMgr->stringValue( modName, "version", QString() ).trimmed();
858 // displayer, if module does not have GUI, displayer may be delegated to other module
859 inf.displayer = resMgr->stringValue( modName, "displayer", QString() ).trimmed();
861 // "gui" option explicitly says that module has GUI
862 // Now trying to get the "gui" option value, we always get a default one,
863 // then we can't rely on it.
864 bool hasGui = resMgr->booleanValue(modName, "gui", false);
866 // Additional check if the module actually has a title and icon.
867 // Module with GUI must explicitly specify title (GUI name).
868 inf.title = resMgr->stringValue(modName, "name", QString()).trimmed();
869 const bool hasTitle = !inf.title.isEmpty();
872 if (hasGui && !hasTitle)
874 MESSAGE("Invalid config! The module has gui option, but doesn't have a title.");
878 // While we can't rely on gui option, use a title to make a decision about gui.
881 // status; if module has GUI, availability will be checked on activation
882 inf.status = hasGui ? stUnknown : stNoGui;
887 inf.icon = resMgr->stringValue( modName, "icon", QString() ).trimmed();
888 // description, for Info panel
889 inf.description = resMgr->stringValue( modName, "description", QString() );
890 // library; if not specified, we use internal module name
891 inf.library = SUIT_Tools::libraryName( resMgr->stringValue( modName, "library", QString() ).trimmed() );
892 if ( inf.library.isEmpty() )
893 inf.library = modName;
896 // At this point we should have only valid inf object.
897 myInfoList.append(inf);
899 SCRUTE(inf.name.toStdString());
900 SCRUTE(inf.version.toStdString());
901 SCRUTE(inf.displayer.toStdString());
903 SCRUTE(inf.title.toStdString());
904 SCRUTE(inf.icon.toStdString());
905 SCRUTE(inf.description.toStdString());
906 SCRUTE(inf.library.toStdString());
911 void CAM_Application::removeModuleInfo( const QString& modName )
913 QMutableListIterator<ModuleInfo> it( myInfoList );
914 while ( it.hasNext() )
916 ModuleInfo info = it.next();
917 if ( info.name == modName )
926 \brief Add common menu items to the popup menu.
928 Menu items list is defined by the active module.
930 \param type popup menu context
931 \param menu popup menu
932 \param title popup menu title, which can be set by the module if required
934 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
936 // to do : add common items for popup menu ( if they are exist )
937 if ( activeModule() )
938 activeModule()->contextMenuPopup( type, menu, title );
942 \brief Create new empty study.
944 void CAM_Application::createEmptyStudy()
946 /*SUIT_Study* study = */activeStudy();
947 STD_Application::createEmptyStudy();
951 \brief Return information about version of the each module.
953 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
955 ModuleShortInfoList info;
957 ModuleShortInfo kernel;
958 kernel.name = "KERNEL";
959 kernel.version = KERNEL_VERSION_STR;
964 gui.version = GUI_VERSION_STR;
967 for(int i = 0; i < myInfoList.size(); i++) {
968 ModuleShortInfo infoItem;
969 infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
970 infoItem.version = myInfoList.at(i).version;
971 info.append(infoItem);
977 \brief Abort active operations if there are any
979 Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
981 \return \c false if some operation cannot be aborted
983 bool CAM_Application::abortAllOperations()
986 for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
988 aborted = (*it)->abortAllOperations();
994 \brief Log GUI event.
995 \param eventDescription GUI event description.
997 void CAM_Application::logUserEvent( const QString& eventDescription )
999 static QString guiLogFile; // null string means log file was not initialized yet
1000 static QMutex aGUILogMutex;
1002 if ( guiLogFile.isNull() )
1004 // log file was not initialized yet, try to do that by parsing command line arguments
1005 guiLogFile = ""; // empty string means initialization was done but log file was not set
1006 QStringList args = QApplication::arguments();
1007 for ( int i = 1; i < args.count(); i++ )
1009 QRegExp rxs ( "--gui-log-file=(.+)" );
1010 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 )
1012 QString file = rxs.capturedTexts()[1];
1013 QFileInfo fi ( file );
1014 if ( !fi.isDir() && fi.dir().exists() )
1016 guiLogFile = fi.absoluteFilePath();
1017 if ( fi.exists() ) {
1018 QFile file ( guiLogFile );
1019 file.remove(); // remove probably existing log file, to start with empty one
1026 if ( !guiLogFile.isEmpty() ) // non-empty string means log file was already initialized
1028 QMutexLocker aLocker( &aGUILogMutex );
1029 QFile file ( guiLogFile );
1030 if ( file.open( QFile::Append ) ) // append to log file
1032 QTextStream stream( &file );
1033 stream << eventDescription << endl;
1040 \brief Log given action.
1041 \param action GUI action being logged.
1042 \param moduleName optional name of module, owning an action
1044 void CAM_Application::logAction( QAction* action, const QString& moduleName )
1046 QString text = action->toolTip();
1047 if ( text.isEmpty() )
1048 text = action->text();
1049 if ( text.isEmpty() )
1050 text = action->iconText();
1051 if ( !text.isEmpty() )
1053 QStringList message;
1054 if ( !moduleName.isEmpty() )
1055 message << moduleName;
1056 if ( action->isCheckable() )
1058 message << tr( "ACTION_TOGGLED" );
1059 message << ( action->isChecked() ? tr( "ACTION_ON" ) : tr( "ACTION_OFF" ) );
1063 message << tr( "ACTION_TRIGGERED" );
1066 logUserEvent( message.join( ": " ) );