Salome HOME
59a7f7ed82a5886bc30d9bbfcc00abb42cb586af
[modules/gui.git] / src / CAM / CAM_Application.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "CAM_Application.h"
24
25 #include "CAM_Study.h"
26 #include "CAM_Module.h"
27
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>
33
34 #include <KERNEL_version.h>
35 #include <GUI_version.h>
36
37 #include <QApplication>
38 #include <QRegExp>
39
40 #ifdef WIN32
41 #include <windows.h>
42 #else
43 #include <dlfcn.h>
44 #endif
45
46 #include <cstdio>
47 #include <iostream>
48
49 namespace
50 {
51 class BusyLocker
52 {
53 public:
54   BusyLocker( bool& busy ) : myPrev( busy ), myBusy( busy ) { myBusy = true; }
55   ~BusyLocker() { myBusy = myPrev; }
56 private:
57   bool  myPrev;
58   bool& myBusy;
59 };
60 }
61
62 /*!
63   \brief Create new instance of CAM_Application.
64   \return new instance of CAM_Application class
65 */
66 extern "C" CAM_EXPORT SUIT_Application* createApplication()
67 {
68   return new CAM_Application();
69 }
70
71 /*!
72   \class CAM_Application
73   \brief Introduces an application class which provides modular architecture.
74   
75   This class defines multi-modular application configuration and behaviour.
76   Each module (CAM_Module) can have own data model, document windows and 
77   viewers, etc.
78
79   An application provides all necessary functionality for modules management,
80   like
81   - loading of modules
82   - modules activation/deactivation
83   - etc
84 */
85
86 CAM_Application::ModuleInfoList CAM_Application::myInfoList;
87
88 /*!
89   \brief Constructor.
90
91   Read modules list (from command line or from resource file). 
92   If \a autoLoad parameter is \c true all the modules will be loaded
93   immediately after application starting, otherwise each module will
94   be loaded by demand (with activateModule()).
95
96   \param autoLoad auto loading flag
97 */
98 CAM_Application::CAM_Application( const bool autoLoad )
99 : STD_Application(),
100   myModule( 0 ),
101   myAutoLoad( autoLoad ),
102   myBlocked( false )
103 {
104   readModuleList();
105 }
106
107 /*!
108   \brief Destructor.
109
110   Does nothing currently.
111 */
112 CAM_Application::~CAM_Application()
113 {
114   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end(); ++it )
115     delete *it;
116   myModules.clear();
117 }
118
119 /*! 
120   \brief Start an application.
121
122   Load all modules, if "auto loading" flag has been set to \c true.
123
124   \sa CAM_Application()
125 */
126 void CAM_Application::start()
127 {
128   if ( myAutoLoad )
129     loadModules();
130
131   STD_Application::start();
132 }
133
134 /*!
135   \brief Get active module.
136   \return active module or 0 if there are no any
137 */
138 CAM_Module* CAM_Application::activeModule() const
139 {
140   return myModule;
141 }
142
143 /*!
144   \brief Get the module with specified name.
145   \return module or 0 if not found
146 */
147 CAM_Module* CAM_Application::module(  const QString& modName ) const
148 {
149   CAM_Module* mod = 0;
150   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
151         it != myModules.end() && !mod; ++it )
152     if ( (*it)->moduleName() == modName )
153       mod = *it;
154   return mod;
155 }
156
157 /*!
158   \brief Get all loaded modules.
159   \return list of modules
160 */
161 CAM_Application::ModuleList CAM_Application::modules() const
162 {
163   return myModules;
164 }
165
166 /*!
167   \brief Get all loaded modules.
168   \param returning list of modules
169 */
170 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
171 {
172   out.clear();
173
174   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
175         it != myModules.end(); ++it )
176     out.append( *it );
177 }
178
179 /*!
180   \brief Get names of all modules.
181
182   Get loaded modules names if \a loaded is \c true, 
183   otherwise get all avaiable modules names.
184   
185   \param lst output list of modules names
186   \param loaded boolean flag, defines what modules names to return
187 */
188 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
189 {
190   lst.clear();
191
192   if ( loaded )
193   {
194     for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
195           it != myModules.end(); ++it )
196       lst.append( (*it)->moduleName() );
197   }
198   else
199   {
200     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
201           it != myInfoList.end(); ++it )
202       lst.append( (*it).title );
203   }
204 }
205
206 /*!
207   \brief Add module \a mod to the modules list.
208
209   Performes module initialization. Does nothing if the module
210   is already added. 
211   
212   \param mod module being added
213   \sa CAM_Module::initialize()
214 */
215 void CAM_Application::addModule( CAM_Module* mod )
216 {
217   if ( !mod || myModules.contains( mod ) )
218     return;
219
220   mod->initialize( this );
221
222   QMap<CAM_Module*, int> map;
223
224   ModuleList newList;
225   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
226         it != myInfoList.end(); ++it )
227   {
228     if ( (*it).title == mod->moduleName() )
229       newList.append( mod );
230     else
231     {
232       CAM_Module* curMod = module( (*it).title );
233       if ( curMod )
234         newList.append( curMod );
235     }
236   }
237
238   for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
239         it != myModules.end(); ++it )
240   {
241     if ( !newList.contains( *it ) )
242       newList.append( *it );
243   }
244
245   if ( !newList.contains( mod ) )
246       newList.append( mod );
247
248   myModules = newList;
249
250   moduleAdded( mod );
251 }
252
253 /*!
254   \brief Load modules from the modules information list.
255   
256   If some module can not be loaded, an error message is shown.
257 */
258 void CAM_Application::loadModules()
259 {
260   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
261   {
262     if ( !isModuleAccessible( (*it).title ) ) {
263       continue;
264     }
265     CAM_Module* mod = loadModule( (*it).title );
266     if ( mod )
267       addModule( mod );
268     else {
269       QString wrn = tr( "Can not load module %1" ).arg( (*it).title );
270       if ( desktop() && desktop()->isVisible() )
271         SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ), wrn );
272       else
273         qWarning( qPrintable( wrn ) ); 
274     }
275   }
276 }
277
278 /*!
279   \brief Load module \a modName.
280
281   The function prints warning message if:
282   - modules information list is empty
283   - modules information list does not include specified module info
284   - module library can not be loaded by some reason
285
286   \param modName module name
287   \return module object pointer or 0 if module could not be loaded
288 */
289 CAM_Module* CAM_Application::loadModule( const QString& modName, const bool showMsg )
290 {
291   if ( myInfoList.isEmpty() )
292   {
293     qWarning( qPrintable( tr( "Modules configuration is not defined." ) ) );
294     return 0;
295   }
296
297   if ( !isModuleAccessible( modName ) ) {
298     qWarning( qPrintable( tr( "Module \"%1\" cannot be loaded in this application." ).arg( modName ) ) );
299     return 0;
300   }
301
302   QString libName = moduleLibrary( modName );
303   if ( libName.isEmpty() )
304   {
305     qWarning( qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) ) );
306     return 0;
307   }
308
309   QString err;
310   GET_MODULE_FUNC crtInst = 0;
311   GET_VERSION_FUNC getVersion = 0;
312
313 #ifdef WIN32
314   HINSTANCE modLib = ::LoadLibrary( libName.toLatin1() ); 
315   if ( !modLib )
316   {
317     LPVOID lpMsgBuf;
318     ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
319                      FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
320     err = QString( "Failed to load  %1. %2" ).arg( libName ).arg( (LPTSTR)lpMsgBuf );
321     ::LocalFree( lpMsgBuf );
322   }
323   else
324   {
325     crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
326     if ( !crtInst )
327     {
328       LPVOID lpMsgBuf;
329       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
330                        FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
331     err = QString( "Failed to find  %1 function. %2" ).arg( GET_MODULE_NAME ).arg( (LPTSTR)lpMsgBuf );
332     ::LocalFree( lpMsgBuf );
333     }
334
335     getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
336   }
337 #else
338   void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY | RTLD_GLOBAL );
339   if ( !modLib )
340     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
341   else
342   {
343     crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
344     if ( !crtInst )
345       err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
346
347     getVersion = (GET_VERSION_FUNC)dlsym( modLib, GET_VERSION_NAME );
348   }
349 #endif
350
351   CAM_Module* module = crtInst ? crtInst() : 0;
352   if ( module )
353   {
354     module->setModuleName( modName );
355     module->setName( moduleName( modName ) );
356   }
357
358   if ( !err.isEmpty() && showMsg ) {
359     if ( desktop() && desktop()->isVisible() )
360       SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
361     else
362       qWarning( qPrintable( err ) ); 
363   }
364
365   char* version = getVersion ? getVersion() : 0;
366
367   if ( version ) {    
368     for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
369       if ( (*it).title == modName ) {
370         if( (*it).version.isEmpty() ) {
371           (*it).version = QString(version);
372         }
373         break;
374       }
375     }
376   }
377   
378   return module;
379 }
380
381 /*!
382   \brief Activate module \a modName.
383   \param modName module name
384   \return \c true, if module is loaded and activated successfully and \c false otherwise
385 */
386 bool CAM_Application::activateModule( const QString& modName )
387 {
388   if ( (!modName.isEmpty() && !activeStudy()) || myBlocked )
389     return false;
390
391   // VSR 25/10/2011: prevent nested activation/deactivation
392   // See issues 0021307, 0021373
393   BusyLocker lock( myBlocked );
394
395   bool res = false;
396   if ( !modName.isEmpty() )
397   {
398     CAM_Module* mod = module( modName );
399     if ( !mod && !moduleLibrary( modName ).isEmpty() )
400     {
401       mod = loadModule( modName );
402       addModule( mod );
403     }
404
405     if ( mod )
406       res = activateModule( mod );
407   }
408   else
409     res = activateModule( 0 );
410
411   return res;
412 }
413
414 /*!
415   \brief Activate module \a mod.
416
417   Shows error message if module could not be activated in the current study.
418
419   \param mod module object pointer
420   \return \c true, if module is loaded and activated successfully and \c false otherwise
421 */
422 bool CAM_Application::activateModule( CAM_Module* mod )
423 {
424   if ( mod && !activeStudy() )
425     return false;
426
427   if ( myModule == mod )
428     return true;
429
430   if ( myModule )
431   {
432     if ( !myModule->deactivateModule( activeStudy() ) )
433     {
434       // ....      
435     }    
436   }     
437   myModule = mod;
438
439   if ( myModule ){
440     // Connect the module to the active study
441     myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
442     if ( !myModule->activateModule( activeStudy() ) )
443     {
444       myModule->setMenuShown( false );
445       myModule->setToolShown( false );
446       QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
447       if ( desktop() && desktop()->isVisible() )
448         SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
449       else
450         qWarning( qPrintable( wrn ) ); 
451       myModule = 0;
452       return false;
453     }
454   }
455
456   updateCommandsStatus();
457
458   return true;
459 }
460
461 /*!
462   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
463   This method is dedicated to run operations of some module from any other module.
464   \param modName module name
465   \param actionId is a numerical unique operation identifier
466   \return \c true in case of success and \c false otherwise
467 */
468 bool CAM_Application::activateOperation( const QString& modName, int actionId )
469 {
470   if (isModuleAccessible(modName)) {
471     CAM_Module* mod = loadModule(modName, false);
472     if (mod) {
473       addModule(mod);
474       return mod->activateOperation(actionId);
475     }
476   }
477   return false;
478 }
479
480 /*!
481   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
482   This method is dedicated to run operations of some module from any other module.
483   \param modName module name
484   \param actionId is a string unique operation identifier
485   \return \c true in case of success and \c false otherwise
486 */
487 bool CAM_Application::activateOperation( const QString& modName, const QString& actionId )
488 {
489   if (isModuleAccessible(modName)) {
490     CAM_Module* mod = loadModule(modName, false);
491     if (mod) {
492       addModule(mod);
493       return mod->activateOperation(actionId);
494     }
495   }
496   return false;
497 }
498
499 /*!
500   \brief Load module \a modName and activate its operation,
501          corresponding to \a actionId and \a pluginName.
502   This method is dedicated to run operations of some module from any other module.
503   \param modName module name
504   \param actionId is a string unique operation identifier
505   \param pluginName is a name of a plugin where the operation is implemented
506   \return \c true in case of success and \c false otherwise
507 */
508 bool CAM_Application::activateOperation( const QString& modName,
509                                          const QString& actionId,
510                                          const QString& pluginName )
511 {
512   if (isModuleAccessible(modName)) {
513     CAM_Module* mod = loadModule(modName, false);
514     if (mod) {
515       addModule(mod);
516       return mod->activateOperation(actionId, pluginName);
517     }
518   }
519   return false;
520 }
521
522 /*!
523   \brief Create new study.
524   \return study object pointer
525 */
526 SUIT_Study* CAM_Application::createNewStudy() 
527
528   return new CAM_Study( this );
529 }
530
531 /*!
532   \brief Update menu commands status.
533 */
534 void CAM_Application::updateCommandsStatus()
535 {
536   STD_Application::updateCommandsStatus();
537
538   if ( activeModule() )
539     activeModule()->updateCommandsStatus();
540 }
541
542 /*!
543   \brief Prepare application to study closing.
544
545   Closes all modules in study \a theDoc.
546   
547   \param theDoc study
548 */
549 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
550 {
551   for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
552     (*it)->studyClosed( theDoc );
553 }
554
555 void CAM_Application::afterCloseDoc()
556 {
557 }
558
559 /*!
560   \brief Set active study.
561   \param study study to be made active
562 */
563 void CAM_Application::setActiveStudy( SUIT_Study* study )
564 {
565   STD_Application::setActiveStudy( study );
566 }
567
568 /*!
569   \brief Callback function, called when the module is added to the application.
570   
571   This virtual method can be re-implemented in the successors. Base implementation
572   does nothing.
573
574   \param mod module being added
575 */
576 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
577 {
578 }
579
580 /*!
581   \brief Get module name by its title (user name).
582   \param title module title (user name)
583   \return module name or null QString if module is not found
584 */
585 QString CAM_Application::moduleName( const QString& title )
586 {
587   QString res;
588   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
589   {
590     if ( (*it).title == title )
591       res = (*it).name;
592   }
593   return res;
594 }
595
596 /*!
597   \brief Get module title (user name) by its name.
598   \param name module name
599   \return module title (user name) or null QString if module is not found
600 */
601 QString CAM_Application::moduleTitle( const QString& name )
602 {
603   QString res;
604   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
605   {
606     if ( (*it).name == name )
607       res = (*it).title;
608   }
609   return res;
610 }
611
612 /*!
613   \brief Get module icon name.
614   \param name module name
615   \return module icon or null QString if module is not found
616 */
617 QString CAM_Application::moduleIcon( const QString& name )
618 {
619   QString res;
620   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
621   {
622     if ( (*it).name == name )
623       res = (*it).icon;
624   }
625   return res;
626 }
627
628 /*!
629   \brief Returns \c true if module is accessible for the current application.
630   Singleton module can be loaded only in one application object. In other application
631   objects this module will be unavailable.
632   \param title module title (user name)
633   \return \c true if module is accessible (can be loaded) or \c false otherwise
634  */
635 bool CAM_Application::isModuleAccessible( const QString& title )
636 {
637   bool found   = false;
638   bool blocked = false;
639   
640   QStringList somewhereLoaded;
641   QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
642   foreach( SUIT_Application* app, apps ) {
643     CAM_Application* camApp = dynamic_cast<CAM_Application*>( app );
644     if ( !camApp ) continue;
645     QStringList loaded;
646     camApp->modules( loaded, true );
647     foreach( QString lm, loaded ) {
648       if ( !somewhereLoaded.contains( lm ) ) somewhereLoaded << lm;
649     }
650   }
651
652   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && !found; ++it )
653   {
654     found = (*it).title == title;
655     blocked = (*it).isSingleton && somewhereLoaded.contains((*it).title);
656   }
657   return found && !blocked;
658 }
659
660 /*!
661   \brief Get module library name by its title (user name).
662   \param title module title (user name)
663   \param full if \c true, return full library name, otherwise return its internal name
664   \return module library name or null QString if module is not found
665  */
666 QString CAM_Application::moduleLibrary( const QString& title, const bool full )
667 {
668   QString res;
669   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
670   {
671     if ( (*it).title == title )
672       res = (*it).internal;
673   }
674   if ( !res.isEmpty() && full )
675     res = SUIT_Tools::library( res );
676   return res;
677 }
678
679 /*!
680   \brief Read modules information list
681
682   This function first tries to get the modules names list by parsing
683   the application command line arguments, looking for the
684   "--modules ( <mod_name>[:<mod_name>...] )" option.
685   List of modules is separated by colon symbol (":").
686   
687   If "--modules" command line option is not used, the list of modules
688   is retrieved from the application resource file: parameter "modules" of
689   the section "launch".
690
691   Then the information about each module (module title (user name), 
692   library name) is retrieved from the corresponding section of resource
693   file with help of resources manager.
694
695   Shows the warning message, if module information list is empty.
696
697   \sa SUIT_ResourceMgr
698 */
699 void CAM_Application::readModuleList()
700 {
701   if ( !myInfoList.isEmpty() )
702     return;
703
704   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
705
706   QStringList modList;
707
708   QString args = QApplication::arguments().join( " " );
709
710   QRegExp rx1("--modules=([\\w,]*)");
711   rx1.setMinimal( false );
712   QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
713   rx2.setMinimal( true );
714   int pos = 0;
715   while ( 1 ) {
716     QString modules;
717     int pos1 = rx1.indexIn( args, pos );
718     int pos2 = rx2.indexIn( args, pos );
719     if ( pos1 != -1 && pos2 != -1 ) {
720       modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
721       pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
722     }
723     else if ( pos1 != -1 ) {
724       modules = rx1.cap( 1 );
725       pos = pos1 + rx1.matchedLength();
726     }
727     else if ( pos2 != -1 ) {
728       modules = rx2.cap( 1 );
729       pos = pos2 + rx2.matchedLength();
730     }
731     else {
732       break;
733     }
734
735     modList.clear();
736     QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
737     for ( int i = 0; i < mods.count(); i++ ) {
738       if ( !mods[i].trimmed().isEmpty() )
739         modList.append( mods[i].trimmed() );
740     }
741   }
742
743   if ( modList.isEmpty() ) {
744     QString mods = resMgr->stringValue( "launch", "modules", QString() );
745     modList = mods.split( ",", QString::SkipEmptyParts );
746   }
747
748   for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
749   {
750     QString modName = (*it).trimmed();
751
752     if ( modName.isEmpty() )
753       continue;  // empty module name
754
755     if ( !moduleTitle( modName ).isEmpty() )
756       continue;  // already added
757
758     QString modTitle = resMgr->stringValue( *it, "name", QString() );
759     if ( modTitle.isEmpty() )
760     {
761       printf( "****************************************************************\n" );
762       printf( "*    Warning: %s GUI resources are not found.\n", qPrintable(*it) );
763       printf( "*    %s GUI will not be available.\n", qPrintable(*it) );
764       printf( "****************************************************************\n" );
765       continue;
766     }
767
768     QString modIcon = resMgr->stringValue( *it, "icon", QString() );
769
770     QString modLibrary = resMgr->stringValue( *it, "library", QString() ).trimmed();
771     if ( !modLibrary.isEmpty() )
772     {
773       modLibrary = SUIT_Tools::file( modLibrary.trimmed() );
774 #if defined(WIN32)
775       QString libExt = QString( "dll" );
776 #elif defined(__APPLE__)
777       QString libExt = QString( "dylib" );
778 #else
779       QString libExt = QString( "so" );
780 #endif
781       if ( SUIT_Tools::extension( modLibrary ).toLower() == libExt )
782         modLibrary.truncate( modLibrary.length() - libExt.length() - 1 );
783 #ifndef WIN32
784       QString prefix = QString( "lib" );
785       if ( modLibrary.startsWith( prefix ) )
786         modLibrary.remove( 0, prefix.length() );
787 #endif
788     }
789     else
790       modLibrary = modName;
791
792     bool aIsSingleton = resMgr->booleanValue(*it, "singleton", false);
793
794     QString ver = resMgr->stringValue(*it, "version", QString());
795
796     ModuleInfo inf;
797     inf.name = modName;
798     inf.title = modTitle;
799     inf.internal = modLibrary;
800     inf.icon = modIcon;
801     inf.isSingleton = aIsSingleton;
802     inf.version = ver;
803     myInfoList.append( inf );
804   }
805
806   if ( myInfoList.isEmpty() ) {
807     if ( desktop() && desktop()->isVisible() )
808       SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
809     else
810       {
811         printf( "****************************************************************\n" );
812         printf( "*    Warning: modules list is empty.\n" );
813         printf( "****************************************************************\n" );
814       }
815   }
816 }
817
818 /*!
819   \brief Add common menu items to the popup menu.
820
821   Menu items list is defined by the active module.
822
823   \param type popup menu context
824   \param menu popup menu
825   \param title popup menu title, which can be set by the module if required
826 */
827 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
828 {
829   // to do : add common items for popup menu ( if they are exist )
830   if ( activeModule() ) 
831     activeModule()->contextMenuPopup( type, menu, title );
832 }
833
834 /*!
835   \brief Create new empty study.
836 */
837 void CAM_Application::createEmptyStudy()
838 {
839   /*SUIT_Study* study = */activeStudy();
840   STD_Application::createEmptyStudy();
841 }
842
843 /*!
844   \brief Return information about version of the each module.
845 */
846 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
847 {
848   ModuleShortInfoList info;
849
850   ModuleShortInfo kernel;
851   kernel.name = "KERNEL";
852   kernel.version = KERNEL_VERSION_STR;
853   info.append(kernel);
854
855   ModuleShortInfo gui;
856   gui.name = "GUI";
857   gui.version = GUI_VERSION_STR;
858   info.append(gui);
859
860   for(int i = 0; i < myInfoList.size(); i++) {
861     ModuleShortInfo infoItem;
862     infoItem.name = myInfoList.at(i).title;
863     infoItem.version = myInfoList.at(i).version;
864     info.append(infoItem);
865   }  
866   return info;
867 }
868
869 /*!
870   \brief Abort active operations if there are any
871  
872   Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
873  
874   \return \c false if some operation cannot be aborted
875 */
876 bool CAM_Application::abortAllOperations()
877 {
878   bool aborted = true;
879   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
880   {
881     aborted = (*it)->abortAllOperations();
882   }
883   return aborted;
884 }