1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, 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.
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>
37 #include <QApplication>
53 BusyLocker( bool& busy ) : myPrev( busy ), myBusy( busy ) { myBusy = true; }
54 ~BusyLocker() { myBusy = myPrev; }
62 \brief Create new instance of CAM_Application.
63 \return new instance of CAM_Application class
65 extern "C" CAM_EXPORT SUIT_Application* createApplication()
67 return new CAM_Application();
71 \class CAM_Application
72 \brief Introduces an application class which provides modular architecture.
74 This class defines multi-modular application configuration and behaviour.
75 Each module (CAM_Module) can have own data model, document windows and
78 An application provides all necessary functionality for modules management,
81 - modules activation/deactivation
88 Read modules list (from command line or from resource file).
89 If \a autoLoad parameter is \c true all the modules will be loaded
90 immediately after application starting, otherwise each module will
91 be loaded by demand (with activateModule()).
93 \param autoLoad auto loading flag
95 CAM_Application::CAM_Application( const bool autoLoad )
98 myAutoLoad( autoLoad ),
107 Does nothing currently.
109 CAM_Application::~CAM_Application()
111 for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end(); ++it )
117 \brief Start an application.
119 Load all modules, if "auto loading" flag has been set to \c true.
121 \sa CAM_Application()
123 void CAM_Application::start()
128 STD_Application::start();
132 \brief Get active module.
133 \return active module or 0 if there are no any
135 CAM_Module* CAM_Application::activeModule() const
141 \brief Get the module with specified name.
142 \return module or 0 if not found
144 CAM_Module* CAM_Application::module( const QString& modName ) const
147 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
148 it != myModules.end() && !mod; ++it )
149 if ( (*it)->moduleName() == modName )
155 \brief Get all loaded modules.
156 \return list of modules
158 CAM_Application::ModuleList CAM_Application::modules() const
164 \brief Get all loaded modules.
165 \param returning list of modules
167 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
171 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
172 it != myModules.end(); ++it )
177 \brief Get names of all modules.
179 Get loaded modules names if \a loaded is \c true,
180 otherwise get all avaiable modules names.
182 \param lst output list of modules names
183 \param loaded boolean flag, defines what modules names to return
185 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
191 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
192 it != myModules.end(); ++it )
193 lst.append( (*it)->moduleName() );
197 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
198 it != myInfoList.end(); ++it )
199 lst.append( (*it).title );
204 \brief Add module \a mod to the modules list.
206 Performes module initialization. Does nothing if the module
209 \param mod module being added
210 \sa CAM_Module::initialize()
212 void CAM_Application::addModule( CAM_Module* mod )
214 if ( !mod || myModules.contains( mod ) )
217 mod->initialize( this );
219 QMap<CAM_Module*, int> map;
222 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
223 it != myInfoList.end(); ++it )
225 if ( (*it).title == mod->moduleName() )
226 newList.append( mod );
229 CAM_Module* curMod = module( (*it).title );
231 newList.append( curMod );
235 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
236 it != myModules.end(); ++it )
238 if ( !newList.contains( *it ) )
239 newList.append( *it );
242 if ( !newList.contains( mod ) )
243 newList.append( mod );
251 \brief Load modules from the modules information list.
253 If some module can not be loaded, an error message is shown.
255 void CAM_Application::loadModules()
257 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
259 if ( !isModuleAccessible( (*it).title ) ) {
262 CAM_Module* mod = loadModule( (*it).title );
266 QString wrn = tr( "Can not load module %1" ).arg( (*it).title );
267 if ( desktop() && desktop()->isVisible() )
268 SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ), wrn );
270 qWarning( qPrintable( wrn ) );
276 \brief Load module \a modName.
278 The function prints warning message if:
279 - modules information list is empty
280 - modules information list does not include specified module info
281 - module library can not be loaded by some reason
283 \param modName module name
284 \return module object pointer or 0 if module could not be loaded
286 CAM_Module* CAM_Application::loadModule( const QString& modName, const bool showMsg )
288 if ( myInfoList.isEmpty() )
290 qWarning( qPrintable( tr( "Modules configuration is not defined." ) ) );
294 if ( !isModuleAccessible( modName ) ) {
295 qWarning( qPrintable( tr( "Module \"%1\" cannot be loaded in this application." ).arg( modName ) ) );
299 QString libName = moduleLibrary( modName );
300 if ( libName.isEmpty() )
302 qWarning( qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) ) );
307 GET_MODULE_FUNC crtInst = 0;
308 GET_VERSION_FUNC getVersion = 0;
311 HINSTANCE modLib = ::LoadLibrary( libName.toLatin1() );
315 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
316 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
317 err = QString( "Failed to load %1. %2" ).arg( libName ).arg( (LPTSTR)lpMsgBuf );
318 ::LocalFree( lpMsgBuf );
322 crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
326 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
327 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
328 err = QString( "Failed to find %1 function. %2" ).arg( GET_MODULE_NAME ).arg( (LPTSTR)lpMsgBuf );
329 ::LocalFree( lpMsgBuf );
332 getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
335 void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY );
337 err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
340 crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
342 err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
344 getVersion = (GET_VERSION_FUNC)dlsym( modLib, GET_VERSION_NAME );
348 CAM_Module* module = crtInst ? crtInst() : 0;
351 module->setModuleName( modName );
352 module->setName( moduleName( modName ) );
355 if ( !err.isEmpty() && showMsg ) {
356 if ( desktop() && desktop()->isVisible() )
357 SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
359 qWarning( qPrintable( err ) );
362 char* version = getVersion ? getVersion() : 0;
365 for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
366 if ( (*it).title == modName ) {
367 if( (*it).version.isEmpty() ) {
368 (*it).version = QString(version);
379 \brief Activate module \a modName.
380 \param modName module name
381 \return \c true, if module is loaded and activated successfully and \c false otherwise
383 bool CAM_Application::activateModule( const QString& modName )
385 if ( !modName.isEmpty() && !activeStudy() || myBlocked )
388 // VSR 25/10/2011: prevent nested activation/deactivation
389 // See issues 0021307, 0021373
390 BusyLocker lock( myBlocked );
393 if ( !modName.isEmpty() )
395 CAM_Module* mod = module( modName );
396 if ( !mod && !moduleLibrary( modName ).isEmpty() )
398 mod = loadModule( modName );
403 res = activateModule( mod );
406 res = activateModule( 0 );
412 \brief Activate module \a mod.
414 Shows error message if module could not be activated in the current study.
416 \param mod module object pointer
417 \return \c true, if module is loaded and activated successfully and \c false otherwise
419 bool CAM_Application::activateModule( CAM_Module* mod )
421 if ( mod && !activeStudy() )
424 if ( myModule == mod )
429 if ( !myModule->deactivateModule( activeStudy() ) )
437 // Connect the module to the active study
438 myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
439 if ( !myModule->activateModule( activeStudy() ) )
441 myModule->setMenuShown( false );
442 myModule->setToolShown( false );
443 QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
444 if ( desktop() && desktop()->isVisible() )
445 SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
447 qWarning( qPrintable( wrn ) );
453 updateCommandsStatus();
459 \brief Create new study.
460 \return study object pointer
462 SUIT_Study* CAM_Application::createNewStudy()
464 return new CAM_Study( this );
468 \brief Update menu commands status.
470 void CAM_Application::updateCommandsStatus()
472 STD_Application::updateCommandsStatus();
474 if ( activeModule() )
475 activeModule()->updateCommandsStatus();
479 \brief Prepare application to study closing.
481 Closes all modules in study \a theDoc.
485 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
487 for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
488 (*it)->studyClosed( theDoc );
491 void CAM_Application::afterCloseDoc()
496 \brief Set active study.
497 \param study study to be made active
499 void CAM_Application::setActiveStudy( SUIT_Study* study )
501 STD_Application::setActiveStudy( study );
505 \brief Callback function, called when the module is added to the application.
507 This virtual method can be re-implemented in the successors. Base implementation
510 \param mod module being added
512 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
517 \brief Get module name by its title (user name).
518 \param title module title (user name)
519 \return module name or null QString if module is not found
521 QString CAM_Application::moduleName( const QString& title ) const
524 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
526 if ( (*it).title == title )
533 \brief Get module title (user name) by its name.
534 \param name module name
535 \return module title (user name) or null QString if module is not found
537 QString CAM_Application::moduleTitle( const QString& name ) const
540 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
542 if ( (*it).name == name )
549 \brief Get module icon name.
550 \param name module name
551 \return module icon or null QString if module is not found
553 QString CAM_Application::moduleIcon( const QString& name ) const
556 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
558 if ( (*it).name == name )
565 \brief Returns \c true if module is accessible for the current application.
566 Singleton module can be loaded only in one application object. In other application
567 objects this module will be unavailable.
568 \param title module title (user name)
569 \return \c true if module is accessible (can be loaded) or \c false otherwise
571 bool CAM_Application::isModuleAccessible( const QString& title ) const
574 bool blocked = false;
576 QStringList somewhereLoaded;
577 QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
578 foreach( SUIT_Application* app, apps ) {
579 CAM_Application* camApp = dynamic_cast<CAM_Application*>( app );
580 if ( !camApp ) continue;
582 camApp->modules( loaded, true );
583 foreach( QString lm, loaded ) {
584 if ( !somewhereLoaded.contains( lm ) ) somewhereLoaded << lm;
588 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && !found; ++it )
590 found = (*it).title == title;
591 blocked = (*it).isSingleton && somewhereLoaded.contains((*it).title);
593 return found && !blocked;
597 \brief Get module library name by its title (user name).
598 \param title module title (user name)
599 \param full if \c true, return full library name, otherwise return its internal name
600 \return module library name or null QString if module is not found
602 QString CAM_Application::moduleLibrary( const QString& title, const bool full ) const
605 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
607 if ( (*it).title == title )
608 res = (*it).internal;
610 if ( !res.isEmpty() && full )
611 res = SUIT_Tools::library( res );
616 \brief Read modules information list
618 This function first tries to get the modules names list by parsing
619 the application command line arguments, looking for the
620 "--modules ( <mod_name>[:<mod_name>...] )" option.
621 List of modules is separated by colon symbol (":").
623 If "--modules" command line option is not used, the list of modules
624 is retrieved from the application resource file: parameter "modules" of
625 the section "launch".
627 Then the information about each module (module title (user name),
628 library name) is retrieved from the corresponding section of resource
629 file with help of resources manager.
631 Shows the warning message, if module information list is empty.
635 void CAM_Application::readModuleList()
637 if ( !myInfoList.isEmpty() )
640 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
644 QString args = QApplication::arguments().join( " " );
646 QRegExp rx1("--modules=([\\w,]*)");
647 rx1.setMinimal( false );
648 QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
649 rx2.setMinimal( true );
653 int pos1 = rx1.indexIn( args, pos );
654 int pos2 = rx2.indexIn( args, pos );
655 if ( pos1 != -1 && pos2 != -1 ) {
656 modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
657 pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
659 else if ( pos1 != -1 ) {
660 modules = rx1.cap( 1 );
661 pos = pos1 + rx1.matchedLength();
663 else if ( pos2 != -1 ) {
664 modules = rx2.cap( 1 );
665 pos = pos2 + rx2.matchedLength();
672 QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
673 for ( int i = 0; i < mods.count(); i++ ) {
674 if ( !mods[i].trimmed().isEmpty() )
675 modList.append( mods[i].trimmed() );
679 if ( modList.isEmpty() ) {
680 QString mods = resMgr->stringValue( "launch", "modules", QString() );
681 modList = mods.split( ",", QString::SkipEmptyParts );
684 for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
686 QString modName = (*it).trimmed();
688 if ( modName.isEmpty() )
689 continue; // empty module name
691 if ( !moduleTitle( modName ).isEmpty() )
692 continue; // already added
694 QString modTitle = resMgr->stringValue( *it, "name", QString() );
695 if ( modTitle.isEmpty() )
697 printf( "****************************************************************\n" );
698 printf( "* Warning: %s GUI resources are not found.\n", qPrintable(*it) );
699 printf( "* %s GUI will not be available.\n", qPrintable(*it) );
700 printf( "****************************************************************\n" );
704 QString modIcon = resMgr->stringValue( *it, "icon", QString() );
706 QString modLibrary = resMgr->stringValue( *it, "library", QString() ).trimmed();
707 if ( !modLibrary.isEmpty() )
709 modLibrary = SUIT_Tools::file( modLibrary.trimmed() );
711 QString libExt = QString( "dll" );
713 QString libExt = QString( "so" );
715 if ( SUIT_Tools::extension( modLibrary ).toLower() == libExt )
716 modLibrary.truncate( modLibrary.length() - libExt.length() - 1 );
718 QString prefix = QString( "lib" );
719 if ( modLibrary.startsWith( prefix ) )
720 modLibrary.remove( 0, prefix.length() );
724 modLibrary = modName;
726 bool aIsSingleton = resMgr->booleanValue(*it, "singleton", false);
728 QString ver = resMgr->stringValue(*it, "version", QString());
732 inf.title = modTitle;
733 inf.internal = modLibrary;
735 inf.isSingleton = aIsSingleton;
737 myInfoList.append( inf );
740 if ( myInfoList.isEmpty() ) {
741 if ( desktop() && desktop()->isVisible() )
742 SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
745 printf( "****************************************************************\n" );
746 printf( "* Warning: modules list is empty.\n" );
747 printf( "****************************************************************\n" );
753 \brief Add common menu items to the popup menu.
755 Menu items list is defined by the active module.
757 \param type popup menu context
758 \param menu popup menu
759 \param title popup menu title, which can be set by the module if required
761 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
763 // to do : add common items for popup menu ( if they are exist )
764 if ( activeModule() )
765 activeModule()->contextMenuPopup( type, menu, title );
769 \brief Create new empty study.
771 void CAM_Application::createEmptyStudy()
773 /*SUIT_Study* study = */activeStudy();
774 STD_Application::createEmptyStudy();
778 \brief Return information about version of the each module.
780 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo() const {
782 ModuleShortInfoList info;
784 ModuleShortInfo kernel;
785 kernel.name = "KERNEL";
786 kernel.version = KERNEL_VERSION_STR;
791 gui.version = GUI_VERSION_STR;
794 for(int i = 0; i < myInfoList.size(); i++) {
795 ModuleShortInfo infoItem;
796 infoItem.name = myInfoList.at(i).title;
797 infoItem.version = myInfoList.at(i).version;
798 info.append(infoItem);