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