Salome HOME
bos #29458 Salome on demand
[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   QString name = modName;
419   if ( !name.isEmpty() && !moduleTitle( modName ).isEmpty() )
420     name = moduleTitle( modName );
421
422   bool res = false;
423   if ( !name.isEmpty() )
424   {
425     setProperty("activateModule", true);
426     CAM_Module* mod = module( name );
427     if ( !mod )
428       mod = loadModule( name );
429     addModule( mod );
430
431     if ( mod )
432       res = activateModule( mod );
433     setProperty("activateModule", QVariant());
434   }
435   else
436     res = activateModule( 0 );
437
438   return res;
439 }
440
441 /*!
442   \brief Activate module \a mod.
443
444   Shows error message if module could not be activated in the current study.
445
446   \param mod module object pointer
447   \return \c true, if module is loaded and activated successfully and \c false otherwise
448 */
449 bool CAM_Application::activateModule( CAM_Module* mod )
450 {
451   if ( mod && !activeStudy() )
452     return false;
453
454   if ( myModule == mod )
455     return true;
456
457   if ( myModule )
458   {
459     if ( !myModule->deactivateModule( activeStudy() ) )
460     {
461       // ???
462     }
463     moduleDeactivated( myModule );
464   }     
465   myModule = mod;
466
467   if ( myModule )
468   {
469     // Connect the module to the active study
470     myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
471     if ( !myModule->activateModule( activeStudy() ) )
472     {
473       myModule->setMenuShown( false );
474       myModule->setToolShown( false );
475       QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
476       if ( desktop() && desktop()->isVisible() )
477         SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
478       else
479         qWarning( qPrintable( wrn ) ); 
480       myModule = 0;
481       return false;
482     }
483   }
484
485   updateCommandsStatus();
486
487   return true;
488 }
489
490 /*!
491   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
492   This method is dedicated to run operations of some module from any other module.
493   \param modName module name
494   \param actionId is a numerical unique operation identifier
495   \return \c true in case of success and \c false otherwise
496 */
497 bool CAM_Application::activateOperation( const QString& modName, int actionId )
498 {
499   CAM_Module* mod = loadModule(modName, false);
500   if (mod) {
501     addModule(mod);
502     return mod->activateOperation(actionId);
503   }
504   return false;
505 }
506
507 /*!
508   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
509   This method is dedicated to run operations of some module from any other module.
510   \param modName module name
511   \param actionId is a string unique operation identifier
512   \return \c true in case of success and \c false otherwise
513 */
514 bool CAM_Application::activateOperation( const QString& modName, const QString& actionId )
515 {
516   CAM_Module* mod = loadModule(modName, false);
517   if (mod) {
518     addModule(mod);
519     return mod->activateOperation(actionId);
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   CAM_Module* mod = loadModule(modName, false);
538   if (mod) {
539     addModule(mod);
540     return mod->activateOperation(actionId, pluginName);
541   }
542   return false;
543 }
544
545 /*!
546   \brief Create new study.
547   \return study object pointer
548 */
549 SUIT_Study* CAM_Application::createNewStudy() 
550
551   return new CAM_Study( this );
552 }
553
554 /*!
555   \brief Update menu commands status.
556 */
557 void CAM_Application::updateCommandsStatus()
558 {
559   STD_Application::updateCommandsStatus();
560
561   if ( activeModule() )
562     activeModule()->updateCommandsStatus();
563 }
564
565 /*!
566   \brief Prepare application to study closing.
567
568   Closes all modules in study \a theDoc.
569   
570   \param theDoc study
571 */
572 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
573 {
574   for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
575     (*it)->studyClosed( theDoc );
576 }
577
578 void CAM_Application::afterCloseDoc()
579 {
580 }
581
582 /*!
583   \brief Set active study.
584   \param study study to be made active
585 */
586 void CAM_Application::setActiveStudy( SUIT_Study* study )
587 {
588   STD_Application::setActiveStudy( study );
589 }
590
591 /*!
592   \brief Check module availability.
593
594   The method can be redefined in successors. Default implementation returns \c true.
595
596   \param title module title
597   \return \c true if module is accessible; \c false otherwise
598 */
599 bool CAM_Application::checkModule( const QString& )
600 {
601   return true;
602 }
603
604 /*!
605   \brief Callback function, called when the module is added to the application.
606   
607   This virtual method can be re-implemented in the successors. Base implementation
608   does nothing.
609
610   \param mod module being added
611 */
612 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
613 {
614 }
615
616 /*!
617   \brief Callback function, called when the module is just deactivated.
618   
619   This virtual method can be re-implemented in the successors. Base implementation
620   does nothing.
621
622   \param mod module just deactivated
623 */
624 void CAM_Application::moduleDeactivated( CAM_Module* /*mod*/ )
625 {
626 }
627
628 /*!
629   \brief Get module name by its title (user name).
630   \param title module title (user name)
631   \return module name or null QString if module is not found
632 */
633 QString CAM_Application::moduleName( const QString& title )
634 {
635   QString res;
636   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
637   {
638     if ( (*it).title == title )
639       res = (*it).name;
640   }
641   return res;
642 }
643
644 /*!
645   \brief Get module title (user name) by its name.
646   \param name module name
647   \return module title (user name) or null QString if module is not found
648 */
649 QString CAM_Application::moduleTitle( const QString& name )
650 {
651   QString res;
652   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
653   {
654     if ( (*it).name == name )
655       res = (*it).title;
656   }
657   return res;
658 }
659
660 /*!
661   \brief Get module icon name.
662   \param name module name or title
663   \return module icon or null QString if module is not found
664 */
665 QString CAM_Application::moduleIcon( const QString& name )
666 {
667   QString res;
668   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
669   {
670     if ( (*it).name == name || (*it).title == name )
671       res = (*it).icon;
672   }
673   return res;
674 }
675
676 /*!
677   \brief Get module description.
678   \param name module name or title
679   \return module description or null QString if description is not provided in config file.
680 */
681 QString CAM_Application::moduleDescription( const QString& name )
682 {
683   QString res;
684   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
685   {
686     if ( (*it).name == name || (*it).title == name )
687       res = tr((*it).description.toUtf8());
688   }
689   return res;
690 }
691
692 /*!
693   \brief Get module library name by its title (user name).
694   \param title module name or title
695   \param full if \c true, return full library name, otherwise return its internal name
696   \return module library name or null QString if module is not found
697  */
698 QString CAM_Application::moduleLibrary( const QString& name, const bool full )
699 {
700   QString res;
701   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
702   {
703     if ( (*it).name == name || (*it).title == name )
704       res = (*it).library;
705   }
706   if ( !res.isEmpty() && full )
707     res = SUIT_Tools::library( res );
708   return res;
709 }
710
711 /*!
712   \brief Get displayer proxy for given module, by its title (user name).
713   \param name module name or title
714   \return name of module which provides displayer for requested module
715  */
716 QString CAM_Application::moduleDisplayer( const QString& name )
717 {
718   QString res;
719
720   if ( !name.isEmpty() )
721   {
722     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
723     {
724       if ( (*it).title == name || (*it).name == name ) {
725         res = (*it).displayer;
726         if ( res.isEmpty() )
727           res = (*it).title;
728       }
729     }
730   }
731
732   return res;
733 }
734
735 /*!
736   \brief Read modules information list
737
738   This function first tries to get the modules names list by parsing
739   the application command line arguments, looking for the
740   "--modules ( <mod_name>[:<mod_name>...] )" option.
741   List of modules is separated by colon symbol (":").
742   
743   If "--modules" command line option is not used, the list of modules
744   is retrieved from the application resource file: parameter "modules" of
745   the section "launch".
746
747   Then the information about each module (module title (user name), 
748   library name) is retrieved from the corresponding section of resource
749   file with help of resources manager.
750
751   Shows the warning message, if module information list is empty.
752
753   \sa SUIT_ResourceMgr
754 */
755 void CAM_Application::readModuleList()
756 {
757   if ( !myInfoList.isEmpty() )
758     return;
759
760   // we cannot use own resourceMgr() as this method can be called from constructor
761   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
762
763   QStringList modList;
764
765   QString args = QApplication::arguments().join( " " );
766
767   QRegExp rx1("--modules=([\\w,]*)");
768   rx1.setMinimal( false );
769   QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
770   rx2.setMinimal( true );
771   int pos = 0;
772   while ( 1 ) {
773     QString modules;
774     int pos1 = rx1.indexIn( args, pos );
775     int pos2 = rx2.indexIn( args, pos );
776     if ( pos1 != -1 && pos2 != -1 ) {
777       modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
778       pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
779     }
780     else if ( pos1 != -1 ) {
781       modules = rx1.cap( 1 );
782       pos = pos1 + rx1.matchedLength();
783     }
784     else if ( pos2 != -1 ) {
785       modules = rx2.cap( 1 );
786       pos = pos2 + rx2.matchedLength();
787     }
788     else {
789       break;
790     }
791
792     modList.clear();
793     QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
794     for ( int i = 0; i < mods.count(); i++ ) {
795       if ( !mods[i].trimmed().isEmpty() )
796         modList.append( mods[i].trimmed() );
797     }
798   }
799
800   if ( modList.isEmpty() ) {
801     QString mods = resMgr->stringValue( "launch", "modules", QString() );
802     modList = mods.split( ",", QString::SkipEmptyParts );
803   }
804
805   // extra modules loaded manually on previous session
806   // ...
807
808   foreach ( QString modName, modList )
809     appendModuleInfo( modName.trimmed() );
810
811   if ( myInfoList.isEmpty() ) {
812     if ( desktop() && desktop()->isVisible() )
813       SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
814     else
815       {
816         printf( "****************************************************************\n" );
817         printf( "*    Warning: modules list is empty.\n" );
818         printf( "****************************************************************\n" );
819       }
820   }
821 }
822
823 bool CAM_Application::appendModuleInfo( const QString& modName )
824 {
825   if ( modName.isEmpty() )
826     return false;  // empty module name
827
828   if ( !moduleTitle( modName ).isEmpty() )
829     return false;  // already added
830
831   if ( modName == "KERNEL" || modName == "GUI" )
832     return false; // skip KERNEL and GUI modules
833
834   // we cannot use own resourceMgr() as this method can be called from constructor
835   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
836
837   // "gui" option explicitly says that module has GUI
838   bool hasGui = resMgr->booleanValue( modName, "gui", true );
839
840   ModuleInfo inf;
841
842   // module internal name
843   inf.name = modName;
844   // module version
845   inf.version = resMgr->stringValue( modName, "version", QString() ).trimmed();
846   // displayer, if module does not have GUI, displayer may be delegated to other module
847   inf.displayer = resMgr->stringValue( modName, "displayer", QString() ).trimmed();
848   // status; if module has GUI, availability will be checked on activation
849   inf.status = hasGui ? stUnknown : stNoGui;
850
851   if ( hasGui )
852   {
853     // module with GUI must explicitly specify title (GUI name)
854     inf.title = resMgr->stringValue( modName, "name", QString() ).trimmed();
855     if ( inf.title.isEmpty() )
856       inf.status = stInvalid;
857     // icon
858     inf.icon = resMgr->stringValue( modName, "icon", QString() ).trimmed();
859     // description, for Info panel
860     inf.description = resMgr->stringValue( modName, "description", QString() );
861     // library; if not specified, we use internal module name
862     inf.library = SUIT_Tools::libraryName( resMgr->stringValue( modName, "library", QString() ).trimmed() );
863     if ( inf.library.isEmpty() )
864       inf.library = modName;
865   }
866
867   if ( inf.status != stInvalid )
868     myInfoList.append( inf );
869
870   return true;
871 }
872
873 void CAM_Application::removeModuleInfo( const QString& modName )
874 {
875   QMutableListIterator<ModuleInfo> it( myInfoList );
876   while ( it.hasNext() )
877   {
878     ModuleInfo info = it.next();
879     if ( info.name == modName )
880     {
881       it.remove();
882       break;
883     }
884   }
885 }
886
887 /*!
888   \brief Add common menu items to the popup menu.
889
890   Menu items list is defined by the active module.
891
892   \param type popup menu context
893   \param menu popup menu
894   \param title popup menu title, which can be set by the module if required
895 */
896 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
897 {
898   // to do : add common items for popup menu ( if they are exist )
899   if ( activeModule() ) 
900     activeModule()->contextMenuPopup( type, menu, title );
901 }
902
903 /*!
904   \brief Create new empty study.
905 */
906 void CAM_Application::createEmptyStudy()
907 {
908   /*SUIT_Study* study = */activeStudy();
909   STD_Application::createEmptyStudy();
910 }
911
912 /*!
913   \brief Return information about version of the each module.
914 */
915 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
916 {
917   ModuleShortInfoList info;
918
919   ModuleShortInfo kernel;
920   kernel.name = "KERNEL";
921   kernel.version = KERNEL_VERSION_STR;
922   info.append(kernel);
923
924   ModuleShortInfo gui;
925   gui.name = "GUI";
926   gui.version = GUI_VERSION_STR;
927   info.append(gui);
928
929   for(int i = 0; i < myInfoList.size(); i++) {
930     ModuleShortInfo infoItem;
931     infoItem.name = myInfoList.at(i).title.isEmpty() ? myInfoList.at(i).name : myInfoList.at(i).title;
932     infoItem.version = myInfoList.at(i).version;
933     info.append(infoItem);
934   }  
935   return info;
936 }
937
938 /*!
939   \brief Abort active operations if there are any
940  
941   Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
942  
943   \return \c false if some operation cannot be aborted
944 */
945 bool CAM_Application::abortAllOperations()
946 {
947   bool aborted = true;
948   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
949   {
950     aborted = (*it)->abortAllOperations();
951   }
952   return aborted;
953 }