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