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