1 // Copyright (C) 2007-2008 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
22 #include "CAM_Application.h"
24 #include "CAM_Study.h"
25 #include "CAM_Module.h"
27 #include <SUIT_Tools.h>
28 #include <SUIT_Desktop.h>
29 #include <SUIT_Session.h>
30 #include <SUIT_MessageBox.h>
31 #include <SUIT_ResourceMgr.h>
33 #include <QApplication>
43 \brief Create new instance of CAM_Application.
44 \return new instance of CAM_Application class
46 extern "C" CAM_EXPORT SUIT_Application* createApplication()
48 return new CAM_Application();
52 \class CAM_Application
53 \brief Introduces an application class which provides modular architecture.
55 This class defines multi-modular application configuration and behaviour.
56 Each module (CAM_Module) can have own data model, document windows and
59 An application provides all necessary functionality for modules management,
62 - modules activation/deactivation
69 Read modules list (from command line or from resource file).
70 If \a autoLoad parameter is \c true all the modules will be loaded
71 immediately after application starting, otherwise each module will
72 be loaded by demand (with activateModule()).
74 \param autoLoad auto loading flag
76 CAM_Application::CAM_Application( const bool autoLoad )
79 myAutoLoad( autoLoad )
87 Does nothing currently.
89 CAM_Application::~CAM_Application()
94 \brief Start an application.
96 Load all modules, if "auto loading" flag has been set to \c true.
100 void CAM_Application::start()
105 STD_Application::start();
109 \brief Get active module.
110 \return active module or 0 if there are no any
112 CAM_Module* CAM_Application::activeModule() const
118 \brief Get the module with specified name.
119 \return module or 0 if not found
121 CAM_Module* CAM_Application::module( const QString& modName ) const
124 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
125 it != myModules.end() && !mod; ++it )
126 if ( (*it)->moduleName() == modName )
132 \brief Get all loaded modules.
133 \return list of modules
135 CAM_Application::ModuleList CAM_Application::modules() const
141 \brief Get all loaded modules.
142 \param returning list of modules
144 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
148 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
149 it != myModules.end(); ++it )
154 \brief Get names of all modules.
156 Get loaded modules names if \a loaded is \c true,
157 otherwise get all avaiable modules names.
159 \param lst output list of modules names
160 \param loaded boolean flag, defines what modules names to return
162 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
168 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
169 it != myModules.end(); ++it )
170 lst.append( (*it)->moduleName() );
174 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
175 it != myInfoList.end(); ++it )
176 lst.append( (*it).title );
181 \brief Add module \a mod to the modules list.
183 Performes module initialization. Does nothing if the module
186 \param mod module being added
187 \sa CAM_Module::initialize()
189 void CAM_Application::addModule( CAM_Module* mod )
191 if ( !mod || myModules.contains( mod ) )
194 mod->initialize( this );
196 QMap<CAM_Module*, int> map;
199 for ( ModuleInfoList::const_iterator it = myInfoList.begin();
200 it != myInfoList.end(); ++it )
202 if ( (*it).title == mod->moduleName() )
203 newList.append( mod );
206 CAM_Module* curMod = module( (*it).title );
208 newList.append( curMod );
212 for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
213 it != myModules.end(); ++it )
215 if ( !newList.contains( *it ) )
216 newList.append( *it );
219 if ( !newList.contains( mod ) )
220 newList.append( mod );
228 \brief Load modules from the modules information list.
230 If some module can not be loaded, an error message is shown.
232 void CAM_Application::loadModules()
234 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
236 CAM_Module* mod = loadModule( (*it).title );
240 if ( desktop() && desktop()->isVisible() )
241 SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ),
242 tr( "Can not load module %1" ).arg( (*it).title ) );
244 qWarning( tr( "Can not load module %1" ).arg( (*it).title ).toLatin1().data() );
250 \brief Load module \a modName.
252 The function prints warning message if:
253 - modules information list is empty
254 - modules information list does not include specified module info
255 - module library can not be loaded by some reason
257 \param modName module name
258 \return module object pointer or 0 if module could not be loaded
260 CAM_Module* CAM_Application::loadModule( const QString& modName, const bool showMsg )
262 if ( myInfoList.isEmpty() )
264 qWarning( tr( "Modules configuration is not defined." ).toLatin1().data() );
268 QString libName = moduleLibrary( modName );
269 if ( libName.isEmpty() )
271 qWarning( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ).toLatin1().data() );
276 GET_MODULE_FUNC crtInst = 0;
279 HINSTANCE modLib = ::LoadLibrary( libName.toLatin1() );
283 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
284 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
285 err = QString( "Failed to load %1. %2" ).arg( libName ).arg( (LPTSTR)lpMsgBuf );
286 ::LocalFree( lpMsgBuf );
290 crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
294 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
295 FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
296 err = QString( "Failed to find %1 function. %2" ).arg( GET_MODULE_NAME ).arg( (LPTSTR)lpMsgBuf );
297 ::LocalFree( lpMsgBuf );
301 void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY );
303 err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
306 crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
308 err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
312 CAM_Module* module = crtInst ? crtInst() : 0;
315 module->setModuleName( modName );
316 module->setName( moduleName( modName ) );
319 if ( !err.isEmpty() && showMsg ) {
320 if ( desktop() && desktop()->isVisible() )
321 SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
323 qWarning( err.toLatin1().data() );
330 \brief Activate module \a modName.
331 \param modName module name
332 \return \c true, if module is loaded and activated successfully and \c false otherwise
334 bool CAM_Application::activateModule( const QString& modName )
336 if ( !modName.isEmpty() && !activeStudy() )
340 if ( !modName.isEmpty() )
342 CAM_Module* mod = module( modName );
343 if ( !mod && !moduleLibrary( modName ).isEmpty() )
345 mod = loadModule( modName );
350 res = activateModule( mod );
353 res = activateModule( 0 );
359 \brief Activate module \a mod.
361 Shows error message if module could not be activated in the current study.
363 \param mod module object pointer
364 \return \c true, if module is loaded and activated successfully and \c false otherwise
366 bool CAM_Application::activateModule( CAM_Module* mod )
368 if ( mod && !activeStudy() )
371 if ( myModule == mod )
376 if ( !myModule->deactivateModule( activeStudy() ) )
384 // Connect the module to the active study
385 myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
386 if ( !myModule->activateModule( activeStudy() ) )
388 myModule->setMenuShown( false );
389 myModule->setToolShown( false );
390 if ( desktop() && desktop()->isVisible() )
391 SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() ) );
393 qWarning( tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() ).toLatin1().data() );
399 updateCommandsStatus();
405 \brief Create new study.
406 \return study object pointer
408 SUIT_Study* CAM_Application::createNewStudy()
410 return new CAM_Study( this );
414 \brief Update menu commands status.
416 void CAM_Application::updateCommandsStatus()
418 STD_Application::updateCommandsStatus();
420 if ( activeModule() )
421 activeModule()->updateCommandsStatus();
425 \brief Prepare application to study closing.
427 Closes all modules in study \a theDoc.
431 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
433 for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
434 (*it)->studyClosed( theDoc );
438 \brief Set active study.
439 \param study study to be made active
441 void CAM_Application::setActiveStudy( SUIT_Study* study )
443 STD_Application::setActiveStudy( study );
447 \brief Callback function, called when the module is added to the application.
449 This virtual method can be re-implemented in the successors. Base implementation
452 \param mod module being added
454 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
459 \brief Get module name by its title (user name).
460 \param title module title (user name)
461 \return module name or null QString if module is not found
463 QString CAM_Application::moduleName( const QString& title ) const
466 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
468 if ( (*it).title == title )
475 \brief Get module title (user name) by its name.
476 \param name module name
477 \return module title (user name) or null QString if module is not found
479 QString CAM_Application::moduleTitle( const QString& name ) const
482 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
484 if ( (*it).name == name )
491 \brief Get module icon name.
492 \param name module name
493 \return module icon or null QString if module is not found
495 QString CAM_Application::moduleIcon( const QString& name ) const
498 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
500 if ( (*it).name == name )
507 \brief Get module library name by its title (user name).
508 \param title module title (user name)
509 \param full if \c true, return full library name, otherwise return its internal name
510 \return module library name or null QString if module is not found
512 QString CAM_Application::moduleLibrary( const QString& title, const bool full ) const
515 for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
517 if ( (*it).title == title )
518 res = (*it).internal;
520 if ( !res.isEmpty() && full )
521 res = SUIT_Tools::library( res );
526 \brief Read modules information list
528 This function first tries to get the modules names list by parsing
529 the application command line arguments, looking for the
530 "--modules ( <mod_name>[:<mod_name>...] )" option.
531 List of modules is separated by colon symbol (":").
533 If "--modules" command line option is not used, the list of modules
534 is retrieved from the application resource file: parameter "modules" of
535 the section "launch".
537 Then the information about each module (module title (user name),
538 library name) is retrieved from the corresponding section of resource
539 file with help of resources manager.
541 Shows the warning message, if module information list is empty.
545 void CAM_Application::readModuleList()
547 if ( !myInfoList.isEmpty() )
550 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
554 QString args = QApplication::arguments().join( " " );
556 QRegExp rx1("--modules=([\\w,]*)");
557 rx1.setMinimal( false );
558 QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
559 rx2.setMinimal( true );
563 int pos1 = rx1.indexIn( args, pos );
564 int pos2 = rx2.indexIn( args, pos );
565 if ( pos1 != -1 && pos2 != -1 ) {
566 modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
567 pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
569 else if ( pos1 != -1 ) {
570 modules = rx1.cap( 1 );
571 pos = pos1 + rx1.matchedLength();
573 else if ( pos2 != -1 ) {
574 modules = rx2.cap( 1 );
575 pos = pos2 + rx2.matchedLength();
582 QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
583 for ( int i = 0; i < mods.count(); i++ ) {
584 if ( !mods[i].trimmed().isEmpty() )
585 modList.append( mods[i].trimmed() );
589 if ( modList.isEmpty() ) {
590 QString mods = resMgr->stringValue( "launch", "modules", QString() );
591 modList = mods.split( ",", QString::SkipEmptyParts );
594 for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
596 QString modName = (*it).trimmed();
598 if ( modName.isEmpty() )
599 continue; // empty module name
601 if ( !moduleTitle( modName ).isEmpty() )
602 continue; // already added
604 QString modTitle = resMgr->stringValue( *it, "name", QString() );
605 if ( modTitle.isEmpty() )
607 printf( "****************************************************************\n" );
608 printf( "* Warning: %s not found in resources.\n", (*it).toLatin1().data() );
609 printf( "* Module will not be available\n" );
610 printf( "****************************************************************\n" );
614 QString modIcon = resMgr->stringValue( *it, "icon", QString() );
616 QString modLibrary = resMgr->stringValue( *it, "library", QString() ).trimmed();
617 if ( !modLibrary.isEmpty() )
619 modLibrary = SUIT_Tools::file( modLibrary.trimmed() );
621 QString libExt = QString( "dll" );
623 QString libExt = QString( "so" );
625 if ( SUIT_Tools::extension( modLibrary ).toLower() == libExt )
626 modLibrary.truncate( modLibrary.length() - libExt.length() - 1 );
628 QString prefix = QString( "lib" );
629 if ( modLibrary.startsWith( prefix ) )
630 modLibrary.remove( 0, prefix.length() );
634 modLibrary = modName;
638 inf.title = modTitle;
639 inf.internal = modLibrary;
641 myInfoList.append( inf );
644 if ( myInfoList.isEmpty() ) {
645 if ( desktop() && desktop()->isVisible() )
646 SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
649 printf( "****************************************************************\n" );
650 printf( "* Warning: modules list is empty.\n" );
651 printf( "****************************************************************\n" );
657 \brief Add common menu items to the popup menu.
659 Menu items list is defined by the active module.
661 \param type popup menu context
662 \param menu popup menu
663 \param title popup menu title, which can be set by the module if required
665 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
667 // to do : add common items for popup menu ( if they are exist )
668 if ( activeModule() )
669 activeModule()->contextMenuPopup( type, menu, title );
673 \brief Create new empty study.
675 void CAM_Application::createEmptyStudy()
677 /*SUIT_Study* study = */activeStudy();
678 STD_Application::createEmptyStudy();