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