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