Salome HOME
873951c8a0c430a97bc6ff52fdd210c50c6a348d
[modules/gui.git] / src / CAM / CAM_Application.cxx
1 // Copyright (C) 2007-2023  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 #include <utilities.h>
50
51 namespace
52 {
53 class BusyLocker
54 {
55 public:
56   BusyLocker( bool& busy ) : myPrev( busy ), myBusy( busy ) { myBusy = true; }
57   ~BusyLocker() { myBusy = myPrev; }
58 private:
59   bool  myPrev;
60   bool& myBusy;
61 };
62 }
63
64 /*!
65   \brief Create new instance of CAM_Application.
66   \return new instance of CAM_Application class
67 */
68 extern "C" CAM_EXPORT SUIT_Application* createApplication()
69 {
70   return new CAM_Application();
71 }
72
73 /*!
74   \class CAM_Application
75   \brief Introduces an application class which provides modular architecture.
76   
77   This class defines multi-modular application configuration and behaviour.
78   Each module (CAM_Module) can have own data model, document windows and 
79   viewers, etc.
80
81   An application provides all necessary functionality for modules management,
82   like
83   - loading of modules
84   - modules activation/deactivation
85   - etc
86 */
87
88 CAM_Application::ModuleInfoList CAM_Application::myInfoList;
89
90 /*!
91   \brief Constructor.
92
93   Read modules list (from command line or from resource file). 
94   If \a autoLoad parameter is \c true all the modules will be loaded
95   immediately after application starting, otherwise each module will
96   be loaded by demand (with activateModule()).
97
98   \param autoLoad auto loading flag
99 */
100 CAM_Application::CAM_Application( const bool autoLoad )
101 : STD_Application(),
102   myModule( 0 ),
103   myAutoLoad( autoLoad ),
104   myBlocked( false )
105 {
106   readModuleList();
107 }
108
109 /*!
110   \brief Destructor.
111
112   Does nothing currently.
113 */
114 CAM_Application::~CAM_Application()
115 {
116   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end(); ++it )
117     delete *it;
118   myModules.clear();
119 }
120
121 /*! 
122   \brief Start an application.
123
124   Load all modules, if "auto loading" flag has been set to \c true.
125
126   \sa CAM_Application()
127 */
128 void CAM_Application::start()
129 {
130   // check modules
131   for ( ModuleInfoList::iterator it = myInfoList.begin(); 
132         it != myInfoList.end(); ++it )
133   {
134     if ( (*it).status == stUnknown )
135       (*it).status = checkModule( (*it).title ) ? stReady : stInaccessible;
136   }
137   
138   // auto-load modules
139   if ( myAutoLoad )
140     loadModules();
141
142   STD_Application::start();
143 }
144
145 /*!
146   \brief Get active module.
147   \return active module or 0 if there are no any
148 */
149 CAM_Module* CAM_Application::activeModule() const
150 {
151   return myModule;
152 }
153
154 /*!
155   \brief Get the module with specified name.
156   \return module or 0 if not found
157 */
158 CAM_Module* CAM_Application::module(  const QString& modName ) const
159 {
160   CAM_Module* mod = 0;
161   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
162         it != myModules.end() && !mod; ++it )
163     if ( (*it)->moduleName() == modName )
164       mod = *it;
165   return mod;
166 }
167
168 /*!
169   \brief Get all loaded modules.
170   \return list of modules
171 */
172 CAM_Application::ModuleList CAM_Application::modules() const
173 {
174   return myModules;
175 }
176
177 /*!
178   \brief Get all loaded modules.
179   \param returning list of modules
180 */
181 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
182 {
183   out.clear();
184
185   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
186         it != myModules.end(); ++it )
187     out.append( *it );
188 }
189
190 /*!
191   \brief Get names of all modules.
192
193   Get loaded modules names if \a loaded is \c true, 
194   otherwise get all avaiable modules names.
195   
196   \param lst output list of modules names
197   \param loaded boolean flag, defines what modules names to return
198 */
199 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
200 {
201   lst.clear();
202
203   if ( loaded )
204   {
205     for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
206           it != myModules.end(); ++it )
207       lst.append( (*it)->moduleName() );
208   }
209   else
210   {
211     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
212           it != myInfoList.end(); ++it )
213       if ( (*it).status != stNoGui )
214         lst.append( (*it).title );
215   }
216 }
217
218 /*!
219   \brief Add module \a mod to the modules list.
220
221   Performes module initialization. Does nothing if the module
222   is already added. 
223   
224   \param mod module being added
225   \sa CAM_Module::initialize()
226 */
227 void CAM_Application::addModule( CAM_Module* mod )
228 {
229   if ( !mod || myModules.contains( mod ) )
230     return;
231
232   mod->initialize( this );
233
234   QMap<CAM_Module*, int> map;
235
236   ModuleList newList;
237   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
238         it != myInfoList.end(); ++it )
239   {
240     if ( (*it).title == mod->moduleName() )
241       newList.append( mod );
242     else
243     {
244       CAM_Module* curMod = module( (*it).title );
245       if ( curMod )
246         newList.append( curMod );
247     }
248   }
249
250   for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
251         it != myModules.end(); ++it )
252   {
253     if ( !newList.contains( *it ) )
254       newList.append( *it );
255   }
256
257   if ( !newList.contains( mod ) )
258       newList.append( mod );
259
260   myModules = newList;
261
262   moduleAdded( mod );
263 }
264
265 /*!
266   \brief Load modules from the modules information list.
267   
268   If some module can not be loaded, an error message is shown.
269 */
270 void CAM_Application::loadModules()
271 {
272   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
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   QString libName = moduleLibrary( modName );
307   if ( libName.isEmpty() )
308   {
309     qWarning( qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) ) );
310     return 0;
311   }
312
313   QString err;
314   GET_MODULE_FUNC crtInst = 0;
315   GET_VERSION_FUNC getVersion = 0;
316
317 #ifdef WIN32
318 #ifdef UNICODE
319   LPTSTR str_libname = new TCHAR[libName.length() + 1];
320   str_libname[libName.toWCharArray(str_libname)] = '\0';
321 #else
322   QByteArray arr = libName.toLatin1();
323   LPTSTR str_libname = arr.constData();
324 #endif
325   HINSTANCE modLib = ::LoadLibrary( str_libname );
326 #ifdef UNICODE
327   delete str_libname;
328 #endif
329   if ( !modLib )
330   {
331     LPVOID lpMsgBuf;
332     ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
333                      FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
334 #ifdef UNICODE
335         QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
336 #else 
337         QString out_err = (LPTSTR)lpMsgBuf;
338 #endif
339     err = QString( "Failed to load  %1. %2" ).arg( libName ).arg(out_err);
340     ::LocalFree( lpMsgBuf );
341   }
342   else
343   {
344     crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
345     if ( !crtInst )
346     {
347       LPVOID lpMsgBuf;
348       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
349                        FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
350 #ifdef UNICODE
351           QString out_err = QString::fromWCharArray((LPTSTR)lpMsgBuf);
352 #else 
353           QString out_err = (LPTSTR)lpMsgBuf;
354 #endif
355
356           err = QString( "Failed to find  %1 function. %2" ).arg( GET_MODULE_NAME ).arg( out_err );
357           ::LocalFree( lpMsgBuf );
358     }
359
360     getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
361   }
362 #else
363   void* modLib = dlopen( libName.toUtf8(), RTLD_LAZY | RTLD_GLOBAL );
364   if ( !modLib )
365     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
366   else
367   {
368     crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
369     if ( !crtInst )
370       err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
371
372     getVersion = (GET_VERSION_FUNC)dlsym( modLib, GET_VERSION_NAME );
373   }
374 #endif
375
376   CAM_Module* module = crtInst ? crtInst() : 0;
377   if ( module )
378   {
379     module->setModuleName( modName );
380     module->setName( moduleName( modName ) );
381   }
382
383   if ( !err.isEmpty() && showMsg ) {
384     if ( desktop() && desktop()->isVisible() )
385       SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
386     else
387       qWarning( qPrintable( err ) ); 
388   }
389
390   char* version = getVersion ? getVersion() : 0;
391
392   if ( version ) {    
393     for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
394       if ( (*it).title == modName ) {
395         if( (*it).version.isEmpty() ) {
396           (*it).version = QString(version);
397         }
398         break;
399       }
400     }
401   }
402   
403   return module;
404 }
405
406 /*!
407   \brief Activate module \a modName.
408   \param modName module name
409   \return \c true, if module is loaded and activated successfully and \c false otherwise
410 */
411 bool CAM_Application::activateModule( const QString& modName )
412 {
413   if ( (!modName.isEmpty() && !activeStudy()) || myBlocked )
414     return false;
415
416   // VSR 25/10/2011: prevent nested activation/deactivation
417   // See issues 0021307, 0021373
418   BusyLocker lock( myBlocked );
419
420   QString name = modName;
421   if ( !name.isEmpty() && !moduleTitle( modName ).isEmpty() )
422     name = moduleTitle( modName );
423
424   bool res = false;
425   if ( !name.isEmpty() )
426   {
427     setProperty("activateModule", true);
428     CAM_Module* mod = module( name );
429     if ( !mod )
430       mod = loadModule( name );
431     addModule( mod );
432
433     if ( mod )
434       res = activateModule( mod );
435     setProperty("activateModule", QVariant());
436   }
437   else
438     res = activateModule( 0 );
439
440   return res;
441 }
442
443 /*!
444   \brief Activate module \a mod.
445
446   Shows error message if module could not be activated in the current study.
447
448   \param mod module object pointer
449   \return \c true, if module is loaded and activated successfully and \c false otherwise
450 */
451 bool CAM_Application::activateModule( CAM_Module* mod )
452 {
453   if ( mod && !activeStudy() )
454     return false;
455
456   if ( myModule == mod )
457     return true;
458
459   if ( myModule )
460   {
461     if ( !myModule->deactivateModule( activeStudy() ) )
462     {
463       // ???
464     }
465     moduleDeactivated( myModule );
466   }     
467   myModule = mod;
468
469   if ( myModule )
470   {
471     // Connect the module to the active study
472     myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
473     if ( !myModule->activateModule( activeStudy() ) )
474     {
475       myModule->setMenuShown( false );
476       myModule->setToolShown( false );
477       QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
478       if ( desktop() && desktop()->isVisible() )
479         SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
480       else
481         qWarning( qPrintable( wrn ) ); 
482       myModule = 0;
483       return false;
484     }
485   }
486
487   updateCommandsStatus();
488
489   return true;
490 }
491
492 /*!
493   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
494   This method is dedicated to run operations of some module from any other module.
495   \param modName module name
496   \param actionId is a numerical unique operation identifier
497   \return \c true in case of success and \c false otherwise
498 */
499 bool CAM_Application::activateOperation( const QString& modName, int actionId )
500 {
501   CAM_Module* mod = loadModule(modName, false);
502   if (mod) {
503     addModule(mod);
504     return mod->activateOperation(actionId);
505   }
506   return false;
507 }
508
509 /*!
510   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
511   This method is dedicated to run operations of some module from any other module.
512   \param modName module name
513   \param actionId is a string unique operation identifier
514   \return \c true in case of success and \c false otherwise
515 */
516 bool CAM_Application::activateOperation( const QString& modName, const QString& actionId )
517 {
518   CAM_Module* mod = loadModule(modName, false);
519   if (mod) {
520     addModule(mod);
521     return mod->activateOperation(actionId);
522   }
523   return false;
524 }
525
526 /*!
527   \brief Load module \a modName and activate its operation,
528          corresponding to \a actionId and \a pluginName.
529   This method is dedicated to run operations of some module from any other module.
530   \param modName module name
531   \param actionId is a string unique operation identifier
532   \param pluginName is a name of a plugin where the operation is implemented
533   \return \c true in case of success and \c false otherwise
534 */
535 bool CAM_Application::activateOperation( const QString& modName,
536                                          const QString& actionId,
537                                          const QString& pluginName )
538 {
539   CAM_Module* mod = loadModule(modName, false);
540   if (mod) {
541     addModule(mod);
542     return mod->activateOperation(actionId, pluginName);
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 Callback function, called when the module is just deactivated.
620   
621   This virtual method can be re-implemented in the successors. Base implementation
622   does nothing.
623
624   \param mod module just deactivated
625 */
626 void CAM_Application::moduleDeactivated( CAM_Module* /*mod*/ )
627 {
628 }
629
630 /*!
631   \brief Get module name by its title (user name).
632   \param title module title (user name)
633   \return module name or null QString if module is not found
634 */
635 QString CAM_Application::moduleName( const QString& title )
636 {
637   QString res;
638   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
639   {
640     if ( (*it).title == title )
641       res = (*it).name;
642   }
643   return res;
644 }
645
646 /*!
647   \brief Get module title (user name) by its name.
648   \param name module name
649   \return module title (user name) or null QString if module is not found
650 */
651 QString CAM_Application::moduleTitle( const QString& name )
652 {
653   QString res;
654   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
655   {
656     if ( (*it).name == name )
657       res = (*it).title;
658   }
659   return res;
660 }
661
662 /*!
663   \brief Get module icon name.
664   \param name module name or title
665   \return module icon or null QString if module is not found
666 */
667 QString CAM_Application::moduleIcon( const QString& name )
668 {
669   QString res;
670   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
671   {
672     if ( (*it).name == name || (*it).title == name )
673       res = (*it).icon;
674   }
675   return res;
676 }
677
678 /*!
679   \brief Get module description.
680   \param name module name or title
681   \return module description or null QString if description is not provided in config file.
682 */
683 QString CAM_Application::moduleDescription( const QString& name )
684 {
685   QString res;
686   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
687   {
688     if ( (*it).name == name || (*it).title == name )
689       res = tr((*it).description.toUtf8());
690   }
691   return res;
692 }
693
694 /*!
695   \brief Get module library name by its title (user name).
696   \param title module name or title
697   \param full if \c true, return full library name, otherwise return its internal name
698   \return module library name or null QString if module is not found
699  */
700 QString CAM_Application::moduleLibrary( const QString& name, const bool full )
701 {
702   QString res;
703   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
704   {
705     if ( (*it).name == name || (*it).title == name )
706       res = (*it).library;
707   }
708   if ( !res.isEmpty() && full )
709     res = SUIT_Tools::library( res );
710   return res;
711 }
712
713 /*!
714   \brief Get displayer proxy for given module, by its title (user name).
715   \param name module name or title
716   \return name of module which provides displayer for requested module
717  */
718 QString CAM_Application::moduleDisplayer( const QString& name )
719 {
720   QString res;
721
722   if ( !name.isEmpty() )
723   {
724     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
725     {
726       if ( (*it).title == name || (*it).name == name ) {
727         res = (*it).displayer;
728         if ( res.isEmpty() )
729           res = (*it).title;
730       }
731     }
732   }
733
734   return res;
735 }
736
737 /*!
738   \brief Read modules information list
739
740   This function first tries to get the modules names list by parsing
741   the application command line arguments, looking for the
742   "--modules ( <mod_name>[:<mod_name>...] )" option.
743   List of modules is separated by colon symbol (":").
744   
745   If "--modules" command line option is not used, the list of modules
746   is retrieved from the application resource file: parameter "modules" of
747   the section "launch".
748
749   Then the information about each module (module title (user name), 
750   library name) is retrieved from the corresponding section of resource
751   file with help of resources manager.
752
753   Shows the warning message, if module information list is empty.
754
755   \sa SUIT_ResourceMgr
756 */
757 void CAM_Application::readModuleList()
758 {
759   if ( !myInfoList.isEmpty() )
760     return;
761
762   // we cannot use own resourceMgr() as this method can be called from constructor
763   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
764
765   QStringList modList;
766
767   QString args = QApplication::arguments().join( " " );
768
769   QRegExp rx1("--modules=([\\w,]*)");
770   rx1.setMinimal( false );
771   QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
772   rx2.setMinimal( true );
773   int pos = 0;
774   while ( 1 ) {
775     QString modules;
776     int pos1 = rx1.indexIn( args, pos );
777     int pos2 = rx2.indexIn( args, pos );
778     if ( pos1 != -1 && pos2 != -1 ) {
779       modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
780       pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
781     }
782     else if ( pos1 != -1 ) {
783       modules = rx1.cap( 1 );
784       pos = pos1 + rx1.matchedLength();
785     }
786     else if ( pos2 != -1 ) {
787       modules = rx2.cap( 1 );
788       pos = pos2 + rx2.matchedLength();
789     }
790     else {
791       break;
792     }
793
794     modList.clear();
795     QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
796     for ( int i = 0; i < mods.count(); i++ ) {
797       if ( !mods[i].trimmed().isEmpty() )
798         modList.append( mods[i].trimmed() );
799     }
800   }
801
802   if ( modList.isEmpty() ) {
803     QString mods = resMgr->stringValue( "launch", "modules", QString() );
804     modList = mods.split( ",", QString::SkipEmptyParts );
805   }
806
807   // extra modules loaded manually on previous session
808   // ...
809
810   foreach ( QString modName, modList )
811     appendModuleInfo( modName.trimmed() );
812
813   if ( myInfoList.isEmpty() ) {
814     if ( desktop() && desktop()->isVisible() )
815       SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
816     else
817       {
818         printf( "****************************************************************\n" );
819         printf( "*    Warning: modules list is empty.\n" );
820         printf( "****************************************************************\n" );
821       }
822   }
823 }
824
825 bool CAM_Application::appendModuleInfo( const QString& modName )
826 {
827   MESSAGE("Start to append module info for a given module name: ");
828   SCRUTE(modName.toStdString());
829
830   if ( modName.isEmpty() )
831     return false;  // empty module name
832
833   if ( !moduleTitle( modName ).isEmpty() )
834     return false;  // already added
835
836   if ( modName == "KERNEL" || modName == "GUI" )
837     return false; // skip KERNEL and GUI modules
838
839   // we cannot use own resourceMgr() as this method can be called from constructor
840   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
841
842   ModuleInfo inf;
843
844   // module internal name
845   inf.name = modName;
846   // module version
847   inf.version = resMgr->stringValue( modName, "version", QString() ).trimmed();
848   // displayer, if module does not have GUI, displayer may be delegated to other module
849   inf.displayer = resMgr->stringValue( modName, "displayer", QString() ).trimmed();
850
851   // "gui" option explicitly says that module has GUI
852   // Now trying to get the "gui" option value, we always get a default one,
853   // then we can't rely on it.
854   bool hasGui = resMgr->booleanValue(modName, "gui", false);
855
856   // Additional check if the module actually has a title and icon.
857   // Module with GUI must explicitly specify title (GUI name).
858   inf.title = resMgr->stringValue(modName, "name", QString()).trimmed();
859   const bool hasTitle = !inf.title.isEmpty();
860   SCRUTE(hasGui);
861   SCRUTE(hasTitle);
862   if (hasGui && !hasTitle)
863   {
864     MESSAGE("Invalid config! The module has gui option, but doesn't have a title.");
865     return false;
866   }
867
868   // While we can't rely on gui option, use a title to make a decision about gui.
869   hasGui = hasTitle;
870
871   // status; if module has GUI, availability will be checked on activation
872   inf.status = hasGui ? stUnknown : stNoGui;
873
874   if ( hasGui )
875   {
876     // icon
877     inf.icon = resMgr->stringValue( modName, "icon", QString() ).trimmed();
878     // description, for Info panel
879     inf.description = resMgr->stringValue( modName, "description", QString() );
880     // library; if not specified, we use internal module name
881     inf.library = SUIT_Tools::libraryName( resMgr->stringValue( modName, "library", QString() ).trimmed() );
882     if ( inf.library.isEmpty() )
883       inf.library = modName;
884   }
885
886   // At this point we should have only valid inf object.
887   myInfoList.append(inf);
888
889   SCRUTE(inf.name.toStdString());
890   SCRUTE(inf.version.toStdString());
891   SCRUTE(inf.displayer.toStdString());
892   SCRUTE(inf.status);
893   SCRUTE(inf.title.toStdString());
894   SCRUTE(inf.icon.toStdString());
895   SCRUTE(inf.description.toStdString());
896   SCRUTE(inf.library.toStdString());
897
898   return true;
899 }
900
901 void CAM_Application::removeModuleInfo( const QString& modName )
902 {
903   QMutableListIterator<ModuleInfo> it( myInfoList );
904   while ( it.hasNext() )
905   {
906     ModuleInfo info = it.next();
907     if ( info.name == modName )
908     {
909       it.remove();
910       break;
911     }
912   }
913 }
914
915 /*!
916   \brief Add common menu items to the popup menu.
917
918   Menu items list is defined by the active module.
919
920   \param type popup menu context
921   \param menu popup menu
922   \param title popup menu title, which can be set by the module if required
923 */
924 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
925 {
926   // to do : add common items for popup menu ( if they are exist )
927   if ( activeModule() ) 
928     activeModule()->contextMenuPopup( type, menu, title );
929 }
930
931 /*!
932   \brief Create new empty study.
933 */
934 void CAM_Application::createEmptyStudy()
935 {
936   /*SUIT_Study* study = */activeStudy();
937   STD_Application::createEmptyStudy();
938 }
939
940 /*!
941   \brief Return information about version of the each module.
942 */
943 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
944 {
945   ModuleShortInfoList info;
946
947   ModuleShortInfo kernel;
948   kernel.name = "KERNEL";
949   kernel.version = KERNEL_VERSION_STR;
950   info.append(kernel);
951
952   ModuleShortInfo gui;
953   gui.name = "GUI";
954   gui.version = GUI_VERSION_STR;
955   info.append(gui);
956
957   for(int i = 0; i < myInfoList.size(); i++) {
958     ModuleShortInfo infoItem;
959     infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
960     infoItem.version = myInfoList.at(i).version;
961     info.append(infoItem);
962   }  
963   return info;
964 }
965
966 /*!
967   \brief Abort active operations if there are any
968  
969   Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
970  
971   \return \c false if some operation cannot be aborted
972 */
973 bool CAM_Application::abortAllOperations()
974 {
975   bool aborted = true;
976   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
977   {
978     aborted = (*it)->abortAllOperations();
979   }
980   return aborted;
981 }