Salome HOME
Unicode support: correct handling of unicode on GUI level
[modules/gui.git] / src / CAM / CAM_Application.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "CAM_Application.h"
24
25 #include "CAM_Study.h"
26 #include "CAM_Module.h"
27
28 #include <SUIT_Tools.h>
29 #include <SUIT_Desktop.h>
30 #include <SUIT_Session.h>
31 #include <SUIT_MessageBox.h>
32 #include <SUIT_ResourceMgr.h>
33
34 #include <KERNEL_version.h>
35 #include <GUI_version.h>
36
37 #include <QApplication>
38 #include <QRegExp>
39
40 #ifdef WIN32
41 #include <windows.h>
42 #else
43 #include <dlfcn.h>
44 #endif
45
46 #include <cstdio>
47 #include <iostream>
48
49 namespace
50 {
51 class BusyLocker
52 {
53 public:
54   BusyLocker( bool& busy ) : myPrev( busy ), myBusy( busy ) { myBusy = true; }
55   ~BusyLocker() { myBusy = myPrev; }
56 private:
57   bool  myPrev;
58   bool& myBusy;
59 };
60 }
61
62 /*!
63   \brief Create new instance of CAM_Application.
64   \return new instance of CAM_Application class
65 */
66 extern "C" CAM_EXPORT SUIT_Application* createApplication()
67 {
68   return new CAM_Application();
69 }
70
71 /*!
72   \class CAM_Application
73   \brief Introduces an application class which provides modular architecture.
74   
75   This class defines multi-modular application configuration and behaviour.
76   Each module (CAM_Module) can have own data model, document windows and 
77   viewers, etc.
78
79   An application provides all necessary functionality for modules management,
80   like
81   - loading of modules
82   - modules activation/deactivation
83   - etc
84 */
85
86 CAM_Application::ModuleInfoList CAM_Application::myInfoList;
87
88 /*!
89   \brief Constructor.
90
91   Read modules list (from command line or from resource file). 
92   If \a autoLoad parameter is \c true all the modules will be loaded
93   immediately after application starting, otherwise each module will
94   be loaded by demand (with activateModule()).
95
96   \param autoLoad auto loading flag
97 */
98 CAM_Application::CAM_Application( const bool autoLoad )
99 : STD_Application(),
100   myModule( 0 ),
101   myAutoLoad( autoLoad ),
102   myBlocked( false )
103 {
104   readModuleList();
105 }
106
107 /*!
108   \brief Destructor.
109
110   Does nothing currently.
111 */
112 CAM_Application::~CAM_Application()
113 {
114   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end(); ++it )
115     delete *it;
116   myModules.clear();
117 }
118
119 /*! 
120   \brief Start an application.
121
122   Load all modules, if "auto loading" flag has been set to \c true.
123
124   \sa CAM_Application()
125 */
126 void CAM_Application::start()
127 {
128   // check modules
129   for ( ModuleInfoList::iterator it = myInfoList.begin(); 
130         it != myInfoList.end(); ++it )
131   {
132     if ( (*it).status == stUnknown )
133       (*it).status = checkModule( (*it).title ) ? stReady : stInaccessible;
134   }
135   
136   // auto-load modules
137   if ( myAutoLoad )
138     loadModules();
139
140   STD_Application::start();
141 }
142
143 /*!
144   \brief Get active module.
145   \return active module or 0 if there are no any
146 */
147 CAM_Module* CAM_Application::activeModule() const
148 {
149   return myModule;
150 }
151
152 /*!
153   \brief Get the module with specified name.
154   \return module or 0 if not found
155 */
156 CAM_Module* CAM_Application::module(  const QString& modName ) const
157 {
158   CAM_Module* mod = 0;
159   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
160         it != myModules.end() && !mod; ++it )
161     if ( (*it)->moduleName() == modName )
162       mod = *it;
163   return mod;
164 }
165
166 /*!
167   \brief Get all loaded modules.
168   \return list of modules
169 */
170 CAM_Application::ModuleList CAM_Application::modules() const
171 {
172   return myModules;
173 }
174
175 /*!
176   \brief Get all loaded modules.
177   \param returning list of modules
178 */
179 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
180 {
181   out.clear();
182
183   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
184         it != myModules.end(); ++it )
185     out.append( *it );
186 }
187
188 /*!
189   \brief Get names of all modules.
190
191   Get loaded modules names if \a loaded is \c true, 
192   otherwise get all avaiable modules names.
193   
194   \param lst output list of modules names
195   \param loaded boolean flag, defines what modules names to return
196 */
197 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
198 {
199   lst.clear();
200
201   if ( loaded )
202   {
203     for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); 
204           it != myModules.end(); ++it )
205       lst.append( (*it)->moduleName() );
206   }
207   else
208   {
209     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
210           it != myInfoList.end(); ++it )
211       lst.append( (*it).title );
212   }
213 }
214
215 /*!
216   \brief Add module \a mod to the modules list.
217
218   Performes module initialization. Does nothing if the module
219   is already added. 
220   
221   \param mod module being added
222   \sa CAM_Module::initialize()
223 */
224 void CAM_Application::addModule( CAM_Module* mod )
225 {
226   if ( !mod || myModules.contains( mod ) )
227     return;
228
229   mod->initialize( this );
230
231   QMap<CAM_Module*, int> map;
232
233   ModuleList newList;
234   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); 
235         it != myInfoList.end(); ++it )
236   {
237     if ( (*it).title == mod->moduleName() )
238       newList.append( mod );
239     else
240     {
241       CAM_Module* curMod = module( (*it).title );
242       if ( curMod )
243         newList.append( curMod );
244     }
245   }
246
247   for ( QList<CAM_Module*>::const_iterator it = myModules.begin();
248         it != myModules.end(); ++it )
249   {
250     if ( !newList.contains( *it ) )
251       newList.append( *it );
252   }
253
254   if ( !newList.contains( mod ) )
255       newList.append( mod );
256
257   myModules = newList;
258
259   moduleAdded( mod );
260 }
261
262 /*!
263   \brief Load modules from the modules information list.
264   
265   If some module can not be loaded, an error message is shown.
266 */
267 void CAM_Application::loadModules()
268 {
269   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
270   {
271     if ( !isModuleAccessible( (*it).title ) ) {
272       continue;
273     }
274     CAM_Module* mod = loadModule( (*it).title );
275     if ( mod )
276       addModule( mod );
277     else {
278       QString wrn = tr( "Can not load module %1" ).arg( (*it).title );
279       if ( desktop() && desktop()->isVisible() )
280         SUIT_MessageBox::critical( desktop(), tr( "Loading modules" ), wrn );
281       else
282         qWarning( qPrintable( wrn ) ); 
283     }
284   }
285 }
286
287 /*!
288   \brief Load module \a modName.
289
290   The function prints warning message if:
291   - modules information list is empty
292   - modules information list does not include specified module info
293   - module library can not be loaded by some reason
294
295   \param modName module name
296   \return module object pointer or 0 if module could not be loaded
297 */
298 CAM_Module* CAM_Application::loadModule( const QString& modName, const bool showMsg )
299 {
300   if ( myInfoList.isEmpty() )
301   {
302     qWarning( qPrintable( tr( "Modules configuration is not defined." ) ) );
303     return 0;
304   }
305
306   if ( !isModuleAccessible( modName ) ) {
307     qWarning( qPrintable( tr( "Module \"%1\" cannot be loaded in this application." ).arg( modName ) ) );
308     return 0;
309   }
310
311   QString libName = moduleLibrary( modName );
312   if ( libName.isEmpty() )
313   {
314     qWarning( qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) ) );
315     return 0;
316   }
317
318   QString err;
319   GET_MODULE_FUNC crtInst = 0;
320   GET_VERSION_FUNC getVersion = 0;
321
322 #ifdef WIN32
323   HINSTANCE modLib = ::LoadLibrary( libName.toUtf8() ); 
324   if ( !modLib )
325   {
326     LPVOID lpMsgBuf;
327     ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
328                      FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
329     err = QString( "Failed to load  %1. %2" ).arg( libName ).arg( (LPTSTR)lpMsgBuf );
330     ::LocalFree( lpMsgBuf );
331   }
332   else
333   {
334     crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
335     if ( !crtInst )
336     {
337       LPVOID lpMsgBuf;
338       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
339                        FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
340     err = QString( "Failed to find  %1 function. %2" ).arg( GET_MODULE_NAME ).arg( (LPTSTR)lpMsgBuf );
341     ::LocalFree( lpMsgBuf );
342     }
343
344     getVersion = (GET_VERSION_FUNC)::GetProcAddress( modLib, GET_VERSION_NAME );
345   }
346 #else
347   void* modLib = dlopen( libName.toUtf8(), RTLD_LAZY | RTLD_GLOBAL );
348   if ( !modLib )
349     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
350   else
351   {
352     crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
353     if ( !crtInst )
354       err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
355
356     getVersion = (GET_VERSION_FUNC)dlsym( modLib, GET_VERSION_NAME );
357   }
358 #endif
359
360   CAM_Module* module = crtInst ? crtInst() : 0;
361   if ( module )
362   {
363     module->setModuleName( modName );
364     module->setName( moduleName( modName ) );
365   }
366
367   if ( !err.isEmpty() && showMsg ) {
368     if ( desktop() && desktop()->isVisible() )
369       SUIT_MessageBox::warning( desktop(), tr( "Error" ), err );
370     else
371       qWarning( qPrintable( err ) ); 
372   }
373
374   char* version = getVersion ? getVersion() : 0;
375
376   if ( version ) {    
377     for ( ModuleInfoList::iterator it = myInfoList.begin(); it != myInfoList.end(); ++it ) {
378       if ( (*it).title == modName ) {
379         if( (*it).version.isEmpty() ) {
380           (*it).version = QString(version);
381         }
382         break;
383       }
384     }
385   }
386   
387   return module;
388 }
389
390 /*!
391   \brief Activate module \a modName.
392   \param modName module name
393   \return \c true, if module is loaded and activated successfully and \c false otherwise
394 */
395 bool CAM_Application::activateModule( const QString& modName )
396 {
397   if ( (!modName.isEmpty() && !activeStudy()) || myBlocked )
398     return false;
399
400   // VSR 25/10/2011: prevent nested activation/deactivation
401   // See issues 0021307, 0021373
402   BusyLocker lock( myBlocked );
403
404   bool res = false;
405   if ( !modName.isEmpty() )
406   {
407     CAM_Module* mod = module( modName );
408     if ( !mod )
409       mod = loadModule( modName );
410     addModule( mod );
411
412     if ( mod )
413       res = activateModule( mod );
414   }
415   else
416     res = activateModule( 0 );
417
418   return res;
419 }
420
421 /*!
422   \brief Activate module \a mod.
423
424   Shows error message if module could not be activated in the current study.
425
426   \param mod module object pointer
427   \return \c true, if module is loaded and activated successfully and \c false otherwise
428 */
429 bool CAM_Application::activateModule( CAM_Module* mod )
430 {
431   if ( mod && !activeStudy() )
432     return false;
433
434   if ( myModule == mod )
435     return true;
436
437   if ( myModule )
438   {
439     if ( !myModule->deactivateModule( activeStudy() ) )
440     {
441       // ....      
442     }    
443   }     
444   myModule = mod;
445
446   if ( myModule ){
447     // Connect the module to the active study
448     myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
449     if ( !myModule->activateModule( activeStudy() ) )
450     {
451       myModule->setMenuShown( false );
452       myModule->setToolShown( false );
453       QString wrn = tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() );
454       if ( desktop() && desktop()->isVisible() )
455         SUIT_MessageBox::critical( desktop(), tr( "ERROR_TLT" ), wrn );
456       else
457         qWarning( qPrintable( wrn ) ); 
458       myModule = 0;
459       return false;
460     }
461   }
462
463   updateCommandsStatus();
464
465   return true;
466 }
467
468 /*!
469   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
470   This method is dedicated to run operations of some module from any other module.
471   \param modName module name
472   \param actionId is a numerical unique operation identifier
473   \return \c true in case of success and \c false otherwise
474 */
475 bool CAM_Application::activateOperation( const QString& modName, int actionId )
476 {
477   if (isModuleAccessible(modName)) {
478     CAM_Module* mod = loadModule(modName, false);
479     if (mod) {
480       addModule(mod);
481       return mod->activateOperation(actionId);
482     }
483   }
484   return false;
485 }
486
487 /*!
488   \brief Load module \a modName and activate its operation, corresponding to \a actionId.
489   This method is dedicated to run operations of some module from any other module.
490   \param modName module name
491   \param actionId is a string unique operation identifier
492   \return \c true in case of success and \c false otherwise
493 */
494 bool CAM_Application::activateOperation( const QString& modName, const QString& actionId )
495 {
496   if (isModuleAccessible(modName)) {
497     CAM_Module* mod = loadModule(modName, false);
498     if (mod) {
499       addModule(mod);
500       return mod->activateOperation(actionId);
501     }
502   }
503   return false;
504 }
505
506 /*!
507   \brief Load module \a modName and activate its operation,
508          corresponding to \a actionId and \a pluginName.
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   \param pluginName is a name of a plugin where the operation is implemented
513   \return \c true in case of success and \c false otherwise
514 */
515 bool CAM_Application::activateOperation( const QString& modName,
516                                          const QString& actionId,
517                                          const QString& pluginName )
518 {
519   if (isModuleAccessible(modName)) {
520     CAM_Module* mod = loadModule(modName, false);
521     if (mod) {
522       addModule(mod);
523       return mod->activateOperation(actionId, pluginName);
524     }
525   }
526   return false;
527 }
528
529 /*!
530   \brief Create new study.
531   \return study object pointer
532 */
533 SUIT_Study* CAM_Application::createNewStudy() 
534
535   return new CAM_Study( this );
536 }
537
538 /*!
539   \brief Update menu commands status.
540 */
541 void CAM_Application::updateCommandsStatus()
542 {
543   STD_Application::updateCommandsStatus();
544
545   if ( activeModule() )
546     activeModule()->updateCommandsStatus();
547 }
548
549 /*!
550   \brief Prepare application to study closing.
551
552   Closes all modules in study \a theDoc.
553   
554   \param theDoc study
555 */
556 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
557 {
558   for ( QList<CAM_Module*>::iterator it = myModules.begin(); it != myModules.end(); ++it )
559     (*it)->studyClosed( theDoc );
560 }
561
562 void CAM_Application::afterCloseDoc()
563 {
564 }
565
566 /*!
567   \brief Set active study.
568   \param study study to be made active
569 */
570 void CAM_Application::setActiveStudy( SUIT_Study* study )
571 {
572   STD_Application::setActiveStudy( study );
573 }
574
575 /*!
576   \brief Check module availability.
577
578   The method can be redefined in successors. Default implementation returns \c true.
579
580   \param title module title
581   \return \c true if module is accessible; \c false otherwise
582 */
583 bool CAM_Application::checkModule( const QString& )
584 {
585   return true;
586 }
587
588 /*!
589   \brief Callback function, called when the module is added to the application.
590   
591   This virtual method can be re-implemented in the successors. Base implementation
592   does nothing.
593
594   \param mod module being added
595 */
596 void CAM_Application::moduleAdded( CAM_Module* /*mod*/ )
597 {
598 }
599
600 /*!
601   \brief Get module name by its title (user name).
602   \param title module title (user name)
603   \return module name or null QString if module is not found
604 */
605 QString CAM_Application::moduleName( const QString& title )
606 {
607   QString res;
608   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
609   {
610     if ( (*it).title == title )
611       res = (*it).name;
612   }
613   return res;
614 }
615
616 /*!
617   \brief Get module title (user name) by its name.
618   \param name module name
619   \return module title (user name) or null QString if module is not found
620 */
621 QString CAM_Application::moduleTitle( const QString& name )
622 {
623   QString res;
624   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
625   {
626     if ( (*it).name == name )
627       res = (*it).title;
628   }
629   return res;
630 }
631
632 /*!
633   \brief Get module icon name.
634   \param name module name
635   \return module icon or null QString if module is not found
636 */
637 QString CAM_Application::moduleIcon( const QString& name )
638 {
639   QString res;
640   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isNull(); ++it )
641   {
642     if ( (*it).name == name )
643       res = (*it).icon;
644   }
645   return res;
646 }
647
648 /*!
649   \brief Returns \c true if module is accessible for the current application.
650   Singleton module can be loaded only in one application object. In other application
651   objects this module will be unavailable.
652   \param title module title (user name)
653   \return \c true if module is accessible (can be loaded) or \c false otherwise
654  */
655 bool CAM_Application::isModuleAccessible( const QString& title )
656 {
657   bool found   = false;
658   bool blocked = false;
659   bool statusOK = false;
660   
661   QStringList somewhereLoaded;
662   QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
663   foreach( SUIT_Application* app, apps ) {
664     CAM_Application* camApp = dynamic_cast<CAM_Application*>( app );
665     if ( !camApp ) continue;
666     QStringList loaded;
667     camApp->modules( loaded, true );
668     foreach( QString lm, loaded ) {
669       if ( !somewhereLoaded.contains( lm ) ) somewhereLoaded << lm;
670     }
671   }
672
673   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && !found; ++it )
674   {
675     found = (*it).title == title;
676     blocked = (*it).isSingleton && somewhereLoaded.contains((*it).title);
677     statusOK = (*it).status == stReady;
678   }
679   return found && statusOK && !blocked;
680 }
681
682 /*!
683   \brief Get module library name by its title (user name).
684   \param title module title (user name)
685   \param full if \c true, return full library name, otherwise return its internal name
686   \return module library name or null QString if module is not found
687  */
688 QString CAM_Application::moduleLibrary( const QString& title, const bool full )
689 {
690   QString res;
691   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
692   {
693     if ( (*it).title == title )
694       res = (*it).library;
695   }
696   if ( !res.isEmpty() && full )
697     res = SUIT_Tools::library( res );
698   return res;
699 }
700
701 /*!
702   \brief Read modules information list
703
704   This function first tries to get the modules names list by parsing
705   the application command line arguments, looking for the
706   "--modules ( <mod_name>[:<mod_name>...] )" option.
707   List of modules is separated by colon symbol (":").
708   
709   If "--modules" command line option is not used, the list of modules
710   is retrieved from the application resource file: parameter "modules" of
711   the section "launch".
712
713   Then the information about each module (module title (user name), 
714   library name) is retrieved from the corresponding section of resource
715   file with help of resources manager.
716
717   Shows the warning message, if module information list is empty.
718
719   \sa SUIT_ResourceMgr
720 */
721 void CAM_Application::readModuleList()
722 {
723   if ( !myInfoList.isEmpty() )
724     return;
725
726   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
727
728   QStringList modList;
729
730   QString args = QApplication::arguments().join( " " );
731
732   QRegExp rx1("--modules=([\\w,]*)");
733   rx1.setMinimal( false );
734   QRegExp rx2("--modules\\s+\\(\\s*(.*)\\s*\\)");
735   rx2.setMinimal( true );
736   int pos = 0;
737   while ( 1 ) {
738     QString modules;
739     int pos1 = rx1.indexIn( args, pos );
740     int pos2 = rx2.indexIn( args, pos );
741     if ( pos1 != -1 && pos2 != -1 ) {
742       modules = pos1 < pos2 ? rx1.cap( 1 ) : rx2.cap(1);
743       pos = pos1 < pos2 ? pos1 + rx1.matchedLength() : pos2 + rx2.matchedLength();
744     }
745     else if ( pos1 != -1 ) {
746       modules = rx1.cap( 1 );
747       pos = pos1 + rx1.matchedLength();
748     }
749     else if ( pos2 != -1 ) {
750       modules = rx2.cap( 1 );
751       pos = pos2 + rx2.matchedLength();
752     }
753     else {
754       break;
755     }
756
757     modList.clear();
758     QStringList mods = modules.split( QRegExp( "[:|,\\s]" ), QString::SkipEmptyParts );
759     for ( int i = 0; i < mods.count(); i++ ) {
760       if ( !mods[i].trimmed().isEmpty() )
761         modList.append( mods[i].trimmed() );
762     }
763   }
764
765   if ( modList.isEmpty() ) {
766     QString mods = resMgr->stringValue( "launch", "modules", QString() );
767     modList = mods.split( ",", QString::SkipEmptyParts );
768   }
769
770   for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
771   {
772     QString modName = (*it).trimmed();
773
774     if ( modName.isEmpty() )
775       continue;  // empty module name
776
777     if ( !moduleTitle( modName ).isEmpty() )
778       continue;  // already added
779
780     if ( modName == "KERNEL" || modName == "GUI" )
781       continue; // omit KERNEL and GUI modules
782
783     QString modTitle = resMgr->stringValue( *it, "name", QString() );
784     if ( modTitle.isEmpty() )
785     {
786       printf( "****************************************************************\n" );
787       printf( "     Warning: module %s is improperly configured!\n", qPrintable(*it) );
788       printf( "     Module %s will not be available in GUI mode!\n", qPrintable(*it) );
789       printf( "****************************************************************\n" );
790       continue;
791     }
792
793     QString modIcon = resMgr->stringValue( *it, "icon", QString() );
794
795     QString modLibrary = resMgr->stringValue( *it, "library", QString() ).trimmed();
796     if ( !modLibrary.isEmpty() )
797     {
798       modLibrary = SUIT_Tools::file( modLibrary.trimmed() );
799 #if defined(WIN32)
800       QString libExt = QString( "dll" );
801 #elif defined(__APPLE__)
802       QString libExt = QString( "dylib" );
803 #else
804       QString libExt = QString( "so" );
805 #endif
806       if ( SUIT_Tools::extension( modLibrary ).toLower() == libExt )
807         modLibrary.truncate( modLibrary.length() - libExt.length() - 1 );
808 #ifndef WIN32
809       QString prefix = QString( "lib" );
810       if ( modLibrary.startsWith( prefix ) )
811         modLibrary.remove( 0, prefix.length() );
812 #endif
813     }
814     else
815       modLibrary = modName;
816
817     bool aIsSingleton = resMgr->booleanValue( *it, "singleton", false );
818     bool hasGui = resMgr->booleanValue( *it, "gui", true );
819     QString version = resMgr->stringValue( *it, "version", QString() );
820
821     ModuleInfo inf;
822     inf.name = modName;
823     inf.title = modTitle;
824     inf.status = hasGui ? stUnknown : stNoGui;
825     if ( hasGui ) inf.library = modLibrary;
826     inf.icon = modIcon;
827     inf.isSingleton = aIsSingleton;
828     inf.version = version;
829     myInfoList.append( inf );
830   }
831
832   if ( myInfoList.isEmpty() ) {
833     if ( desktop() && desktop()->isVisible() )
834       SUIT_MessageBox::warning( desktop(), tr( "Warning" ), tr( "Modules list is empty" ) );
835     else
836       {
837         printf( "****************************************************************\n" );
838         printf( "*    Warning: modules list is empty.\n" );
839         printf( "****************************************************************\n" );
840       }
841   }
842 }
843
844 /*!
845   \brief Add common menu items to the popup menu.
846
847   Menu items list is defined by the active module.
848
849   \param type popup menu context
850   \param menu popup menu
851   \param title popup menu title, which can be set by the module if required
852 */
853 void CAM_Application::contextMenuPopup( const QString& type, QMenu* menu, QString& title )
854 {
855   // to do : add common items for popup menu ( if they are exist )
856   if ( activeModule() ) 
857     activeModule()->contextMenuPopup( type, menu, title );
858 }
859
860 /*!
861   \brief Create new empty study.
862 */
863 void CAM_Application::createEmptyStudy()
864 {
865   /*SUIT_Study* study = */activeStudy();
866   STD_Application::createEmptyStudy();
867 }
868
869 /*!
870   \brief Return information about version of the each module.
871 */
872 CAM_Application::ModuleShortInfoList CAM_Application::getVersionInfo()
873 {
874   ModuleShortInfoList info;
875
876   ModuleShortInfo kernel;
877   kernel.name = "KERNEL";
878   kernel.version = KERNEL_VERSION_STR;
879   info.append(kernel);
880
881   ModuleShortInfo gui;
882   gui.name = "GUI";
883   gui.version = GUI_VERSION_STR;
884   info.append(gui);
885
886   for(int i = 0; i < myInfoList.size(); i++) {
887     ModuleShortInfo infoItem;
888     infoItem.name = myInfoList.at(i).title;
889     infoItem.version = myInfoList.at(i).version;
890     info.append(infoItem);
891   }  
892   return info;
893 }
894
895 /*!
896   \brief Abort active operations if there are any
897  
898   Iterates through all modules and asks each of them if there are pending operations that cannot be aborted.
899  
900   \return \c false if some operation cannot be aborted
901 */
902 bool CAM_Application::abortAllOperations()
903 {
904   bool aborted = true;
905   for ( QList<CAM_Module*>::const_iterator it = myModules.begin(); it != myModules.end() && aborted; ++it )
906   {
907     aborted = (*it)->abortAllOperations();
908   }
909   return aborted;
910 }