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() ) )
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 myModule->setMenuShown( false );
482 myModule->setToolShown( false );
483 QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
484 if ( desktop() && desktop()->isVisible() )
485 SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
487 qWarning( qPrintable( wrn ) );
493 updateCommandsStatus();
499 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
500 This method is dedicated to run operations of some module from any other module.
501 \param modName module name
502 \param actionId is a numerical unique operation identifier
503 \return \c true in case of success and \c false otherwise
505 bool CAM_Application::activateOperation( const QString& modName, int actionId )
507 CAM_Module* mod = loadModule(modName, false);
510 return mod->activateOperation(actionId);
516 \brief Load module \a modName and activate its operation, corresponding to \a actionId.
517 This method is dedicated to run operations of some module from any other module.
518 \param modName module name
519 \param actionId is a string unique operation identifier
520 \return \c true in case of success and \c false otherwise
522 bool CAM_Application::activateOperation( const QString& modName, const QString& actionId )
524 CAM_Module* mod = loadModule(modName, false);
527 return mod->activateOperation(actionId);
533 \brief Load module \a modName and activate its operation,
534 corresponding to \a actionId and \a pluginName.
535 This method is dedicated to run operations of some module from any other module.
536 \param modName module name
537 \param actionId is a string unique operation identifier
538 \param pluginName is a name of a plugin where the operation is implemented
539 \return \c true in case of success and \c false otherwise
541 bool CAM_Application::activateOperation( const QString& modName,
542 const QString& actionId,
543 const QString& pluginName )
545 CAM_Module* mod = loadModule(modName, false);
548 return mod->activateOperation(actionId, pluginName);
554 \brief Create new study.
555 \return study object pointer
557 SUIT_Study* CAM_Application::createNewStudy()
559 return new CAM_Study( this );
563 \brief Update menu commands status.
565 void CAM_Application::updateCommandsStatus()
567 STD_Application::updateCommandsStatus();
569 if ( activeModule() )
570 activeModule()->updateCommandsStatus();
574 \brief Prepare application to study closing.
576 Closes all modules in study \a theDoc.
580 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
582 for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
583 (*it)->studyClosed( theDoc );
586 void CAM_Application::afterCloseDoc()
591 \brief Set active study.
592 \param study study to be made active
594 void CAM_Application::setActiveStudy( SUIT_Study* study )
596 STD_Application::setActiveStudy( study );
600 \brief Check module availability.
602 The method can be redefined in successors. Default implementation returns \c true.
604 \param title module title
605 \return \c true if module is accessible; \c false otherwise
607 bool CAM_Application::checkModule( const QString& )
613 \brief Callback function, called when the module is added to the application.
615 This virtual method can be re-implemented in the successors. Base implementation
618 \param mod module being added
620 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
625 \brief Callback function, called when the module is just deactivated.
627 This virtual method can be re-implemented in the successors. Base implementation
630 \param mod module just deactivated
632 void CAM_Application::moduleDeactivated( CAM_Module* /*mod*/ )
637 \brief Get module name by its title (user name).
638 \param title module title (user name)
639 \return module name or null QString if module is not found
641 QString CAM_Application::moduleName( const QString& title )
644 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
646 if ( (*it).title == title )
653 \brief Get module title (user name) by its name.
654 \param name module name
655 \return module title (user name) or null QString if module is not found
657 QString CAM_Application::moduleTitle( const QString& name )
660 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
662 if ( (*it).name == name )
669 \brief Get module icon name.
670 \param name module name or title
671 \return module icon or null QString if module is not found
673 QString CAM_Application::moduleIcon( const QString& name )
676 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
678 if ( (*it).name == name || (*it).title == name )
685 \brief Get module description.
686 \param name module name or title
687 \return module description or null QString if description is not provided in config file.
689 QString CAM_Application::moduleDescription( const QString& name )
692 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
694 if ( (*it).name == name || (*it).title == name )
695 res = tr((*it).description.toUtf8());
701 \brief Get module library name by its title (user name).
702 \param title module name or title
703 \param full if \c true, return full library name, otherwise return its internal name
704 \return module library name or null QString if module is not found
706 QString CAM_Application::moduleLibrary( const QString& name, const bool full )
709 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
711 if ( (*it).name == name || (*it).title == name )
714 if ( !res.isEmpty() && full )
715 res = SUIT_Tools::library( res );
720 \brief Get displayer proxy for given module, by its title (user name).
721 \param name module name or title
722 \return name of module which provides displayer for requested module
724 QString CAM_Application::moduleDisplayer( const QString& name )
728 if ( !name.isEmpty() )
730 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
732 if ( (*it).title == name || (*it).name == name ) {
733 res = (*it).displayer;
744 \brief Read modules information list
746 This function first tries to get the modules names list by parsing
747 the application command line arguments, looking for the
748 "--modules ( <mod_name>[:<mod_name>...] )" option.
749 List of modules is separated by colon symbol (":").
751 If "--modules" command line option is not used, the list of modules
752 is retrieved from the application resource file: parameter "modules" of
753 the section "launch".
755 Then the information about each module (module title (user name),
756 library name) is retrieved from the corresponding section of resource
757 file with help of resources manager.
759 Shows the warning message, if module information list is empty.
763 void CAM_Application::readModuleList()
765 if ( !myInfoList.isEmpty() )
768 // we cannot use own resourceMgr() as this method can be called from constructor
769 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
773 QString args = QApplication::arguments().join( " " );
775 QRegExp rx1("--modules=([\\w,]*)");
776 rx1.setMinimal( false );
777 QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
778 rx2.setMinimal( true );
782 int pos1 = rx1.indexIn( args, pos );
783 int pos2 = rx2.indexIn( args, pos );
784 if ( pos1 != -1 && pos2 != -1 ) {
785 modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
786 pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
788 else if ( pos1 != -1 ) {
789 modules = rx1.cap( 1 );
790 pos = pos1 + rx1.matchedLength();
792 else if ( pos2 != -1 ) {
793 modules = rx2.cap( 1 );
794 pos = pos2 + rx2.matchedLength();
801 QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
802 for ( int i = 0; i < mods.count(); i++ ) {
803 if ( !mods[i].trimmed().isEmpty() )
804 modList.append( mods[i].trimmed() );
808 if ( modList.isEmpty() ) {
809 QString mods = resMgr->stringValue( "launch", "modules", QString() );
810 modList = mods.split( ",", QString::SkipEmptyParts );
813 // extra modules loaded manually on previous session
816 foreach ( QString modName, modList )
817 appendModuleInfo( modName.trimmed() );
819 if ( myInfoList.isEmpty() ) {
820 if ( desktop() && desktop()->isVisible() )
821 SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
824 printf( "****************************************************************\n" );
825 printf( "* Warning: modules list is empty.\n" );
826 printf( "****************************************************************\n" );
831 bool CAM_Application::appendModuleInfo( const QString& modName )
833 MESSAGE("Start to append module info for a given module name: ");
834 SCRUTE(modName.toStdString());
836 if ( modName.isEmpty() )
837 return false; // empty module name
839 if ( !moduleTitle( modName ).isEmpty() )
840 return false; // already added
842 if ( modName == "KERNEL" || modName == "GUI" )
843 return false; // skip KERNEL and GUI modules
845 // we cannot use own resourceMgr() as this method can be called from constructor
846 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
850 // module internal name
853 inf.version = resMgr->stringValue( modName, "version", QString() ).trimmed();
854 // displayer, if module does not have GUI, displayer may be delegated to other module
855 inf.displayer = resMgr->stringValue( modName, "displayer", QString() ).trimmed();
857 // "gui" option explicitly says that module has GUI
858 // Now trying to get the "gui" option value, we always get a default one,
859 // then we can't rely on it.
860 bool hasGui = resMgr->booleanValue(modName, "gui", false);
862 // Additional check if the module actually has a title and icon.
863 // Module with GUI must explicitly specify title (GUI name).
864 inf.title = resMgr->stringValue(modName, "name", QString()).trimmed();
865 const bool hasTitle = !inf.title.isEmpty();
868 if (hasGui && !hasTitle)
870 MESSAGE("Invalid config! The module has gui option, but doesn't have a title.");
874 // While we can't rely on gui option, use a title to make a decision about gui.
877 // status; if module has GUI, availability will be checked on activation
878 inf.status = hasGui ? stUnknown : stNoGui;
883 inf.icon = resMgr->stringValue( modName, "icon", QString() ).trimmed();
884 // description, for Info panel
885 inf.description = resMgr->stringValue( modName, "description", QString() );
886 // library; if not specified, we use internal module name
887 inf.library = SUIT_Tools::libraryName( resMgr->stringValue( modName, "library", QString() ).trimmed() );
888 if ( inf.library.isEmpty() )
889 inf.library = modName;
892 // At this point we should have only valid inf object.
893 myInfoList.append(inf);
895 SCRUTE(inf.name.toStdString());
896 SCRUTE(inf.version.toStdString());
897 SCRUTE(inf.displayer.toStdString());
899 SCRUTE(inf.title.toStdString());
900 SCRUTE(inf.icon.toStdString());
901 SCRUTE(inf.description.toStdString());
902 SCRUTE(inf.library.toStdString());
907 void CAM_Application::removeModuleInfo( const QString& modName )
909 QMutableListIterator<ModuleInfo> it( myInfoList );
910 while ( it.hasNext() )
912 ModuleInfo info = it.next();
913 if ( info.name == modName )
922 \brief Add common menu items to the popup menu.
924 Menu items list is defined by the active module.
926 \param type popup menu context
927 \param menu popup menu
928 \param title popup menu title, which can be set by the module if required
930 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
932 // to do : add common items for popup menu ( if they are exist )
933 if ( activeModule() )
934 activeModule()->contextMenuPopup( type, menu, title );
938 \brief Create new empty study.
940 void CAM_Application::createEmptyStudy()
942 /*SUIT_Study* study = */activeStudy();
943 STD_Application::createEmptyStudy();
947 \brief Return information about version of the each module.
949 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
951 ModuleShortInfoList info;
953 ModuleShortInfo kernel;
954 kernel.name = "KERNEL";
955 kernel.version = KERNEL_VERSION_STR;
960 gui.version = GUI_VERSION_STR;
963 for(int i = 0; i < myInfoList.size(); i++) {
964 ModuleShortInfo infoItem;
965 infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
966 infoItem.version = myInfoList.at(i).version;
967 info.append(infoItem);
973 \brief Abort active operations if there are any
975 Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
977 \return \c false if some operation cannot be aborted
979 bool CAM_Application::abortAllOperations()
982 for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
984 aborted = (*it)->abortAllOperations();
990 \brief Log GUI event.
991 \param eventDescription GUI event description.
993 void CAM_Application::logUserEvent( const QString& eventDescription )
995 static QString guiLogFile; // null string means log file was not initialized yet
996 static QMutex aGUILogMutex;
998 if ( guiLogFile.isNull() )
1000 // log file was not initialized yet, try to do that by parsing command line arguments
1001 guiLogFile = ""; // empty string means initialization was done but log file was not set
1002 QStringList args = QApplication::arguments();
1003 for ( int i = 1; i < args.count(); i++ )
1005 QRegExp rxs ( "--gui-log-file=(.+)" );
1006 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 )
1008 QString file = rxs.capturedTexts()[1];
1009 QFileInfo fi ( file );
1010 if ( !fi.isDir() && fi.dir().exists() )
1012 guiLogFile = fi.absoluteFilePath();
1013 if ( fi.exists() ) {
1014 QFile file ( guiLogFile );
1015 file.remove(); // remove probably existing log file, to start with empty one
1022 if ( !guiLogFile.isEmpty() ) // non-empty string means log file was already initialized
1024 QMutexLocker aLocker( &aGUILogMutex );
1025 QFile file ( guiLogFile );
1026 if ( file.open( QFile::Append ) ) // append to log file
1028 QTextStream stream( &file );
1029 stream << eventDescription << endl;
1036 \brief Log given action.
1037 \param action GUI action being logged.
1038 \param moduleName optional name of module, owning an action
1040 void CAM_Application::logAction( QAction* action, const QString& moduleName )
1042 QString text = action->toolTip();
1043 if ( text.isEmpty() )
1044 text = action->text();
1045 if ( text.isEmpty() )
1046 text = action->iconText();
1047 if ( !text.isEmpty() )
1049 QStringList message;
1050 if ( !moduleName.isEmpty() )
1051 message << moduleName;
1052 if ( action->isCheckable() )
1054 message << tr( "ACTION_TOGGLED" );
1055 message << ( action->isChecked() ? tr( "ACTION_ON" ) : tr( "ACTION_OFF" ) );
1059 message << tr( "ACTION_TRIGGERED" );
1062 logUserEvent( message.join( ": " ) );