Salome HOME
Join modifications from branch BR_DEBUG_3_2_0b1
[modules/gui.git] / src / CAM / CAM_Application.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #include "CAM_Application.h"
20
21 #include "CAM_Study.h"
22 #include "CAM_Module.h"
23
24 #include <SUIT_Tools.h>
25 #include <SUIT_Session.h>
26 #include <SUIT_MessageBox.h>
27
28 #include <qfile.h> 
29 #include <qfileinfo.h>
30 #include <qtextstream.h>
31 #include <qlabel.h>
32 #include <qfont.h>
33 #include <qapplication.h>
34 #include <qregexp.h>
35
36 #ifdef WIN32
37 #include <windows.h>
38 #else
39 #include <dlfcn.h>
40 #endif
41
42 /*!Create new instance of CAM_Application*/
43 extern "C" CAM_EXPORT SUIT_Application* createApplication()
44 {
45   return new CAM_Application();
46 }
47
48 /*!Constructor. read module list.
49  * \param autoLoad - auto load flag.
50  */
51 CAM_Application::CAM_Application( const bool autoLoad )
52 : STD_Application(),
53 myModule( 0 ),
54 myAutoLoad( autoLoad )
55 {
56   readModuleList();
57 }
58
59 /*!Destructor. Do nothing.*/
60 CAM_Application::~CAM_Application()
61 {
62 }
63
64 /*! Load modules, if \a myAutoLoad flag is true.\n
65  * Start application - call start() method from parent class.
66  */
67 void CAM_Application::start()
68 {
69   if ( myAutoLoad )
70     loadModules();
71
72   STD_Application::start();
73 }
74
75 /*!Get active module.
76  * \retval CAM_Module - active module.
77  */
78 CAM_Module* CAM_Application::activeModule() const
79 {
80   return myModule;
81 }
82
83 /*!Get module with name \a modName from modules list.
84  * \retval CAM_Module pointer - module.
85  */
86 CAM_Module* CAM_Application::module(  const QString& modName ) const
87 {
88   CAM_Module* mod = 0;
89   for ( ModuleListIterator it( myModules ); it.current() && !mod; ++it )
90     if ( it.current()->moduleName() == modName )
91       mod = it.current();
92   return mod;
93 }
94
95 /*!Gets modules iterator.*/
96 CAM_Application::ModuleListIterator CAM_Application::modules() const
97 {
98   return ModuleListIterator( myModules );
99 }
100
101 /*!Gets modules list.
102  * \param out - output list of modules.
103  */
104 void CAM_Application::modules( CAM_Application::ModuleList& out ) const
105 {
106   out.setAutoDelete( false );
107   out.clear();
108
109   for ( ModuleListIterator it( myModules ); it.current(); ++it )
110     out.append( it.current() );
111 }
112
113 /*!Gets list of names for modules.\n
114  * Get loaded modules names, if \a loaded is true, else \n
115  * get names from information list.
116  * \param lst - output list of names.
117  * \param loaded - boolean flag.
118  */
119 void CAM_Application::modules( QStringList& lst, const bool loaded ) const
120 {
121   lst.clear();
122
123   if ( loaded )
124     for ( ModuleListIterator it( myModules ); it.current(); ++it )
125       lst.append( it.current()->moduleName() );
126   else
127     for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
128       lst.append( (*it).title );
129 }
130
131 /*!Adding module \a mod to list.
132  *\param mod - module.
133  */
134 void CAM_Application::addModule( CAM_Module* mod )
135 {
136   if ( !mod || myModules.contains( mod ) )
137     return;
138
139   mod->initialize( this );
140
141   QMap<CAM_Module*, int> map;
142
143   ModuleList newList;
144   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
145   {
146     if ( (*it).title == mod->moduleName() )
147       newList.append( mod );
148     else
149     {
150       CAM_Module* curMod = module( (*it).title );
151       if ( curMod )
152         newList.append( curMod );
153     }
154     if ( !newList.isEmpty() )
155       map.insert( newList.getLast(), 0 );
156   }
157
158   for ( ModuleListIterator itr( myModules ); itr.current(); ++itr )
159   {
160     if ( !map.contains( itr.current() ) )
161       newList.append( itr.current() );
162   }
163
164   if ( !map.contains( mod ) )
165       newList.append( mod );
166
167   myModules = newList;
168
169   moduleAdded( mod );
170 }
171
172 /*!Load modules from information list.
173  * \warning If some of modules not loaded, error message appear on desktop.
174  */
175 void CAM_Application::loadModules()
176 {
177   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end(); ++it )
178   {
179     CAM_Module* mod = loadModule( (*it).title );
180     if ( mod )
181       addModule( mod );
182     else {
183       if ( desktop() && desktop()->isShown() )
184         SUIT_MessageBox::error1( desktop(), tr( "Loading modules" ),
185                                  tr( "Can not load module %1" ).arg( (*it).title ), tr( "Ok" ) );
186       else
187         qWarning( tr( "Can not load module %1" ).arg( (*it).title ).latin1() ); 
188     }
189   }
190 }
191
192 /*!Load module with name \a modName.
193  *\param modName - module name for loading.
194  *\warning If information list is empty.
195  *\warning If module library (for module with \a modName) is empty.
196  *\warning If module library is not loaded.
197  */
198 CAM_Module* CAM_Application::loadModule( const QString& modName )
199 {
200   if ( myInfoList.isEmpty() )
201   {
202     qWarning( tr( "Modules configuration is not defined." ) );
203     return 0;
204   }
205
206   QString libName = moduleLibrary( modName );
207   if ( libName.isEmpty() )
208   {
209     qWarning( tr( "Information about module \"%1\" doesn't exist." ).arg( modName ) );
210     return 0;
211   }
212
213   QString err;
214   GET_MODULE_FUNC crtInst = 0;
215
216 #ifdef WIN32
217   HINSTANCE modLib = ::LoadLibrary( libName ); 
218   if ( !modLib )
219   {
220     LPVOID lpMsgBuf;
221     ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
222                      FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
223     err = QString( "Failed to load  %1. %2" ).arg( libName ).arg( (LPTSTR)lpMsgBuf );
224     ::LocalFree( lpMsgBuf );
225   }
226   else
227   {
228     crtInst = (GET_MODULE_FUNC)::GetProcAddress( modLib, GET_MODULE_NAME );
229     if ( !crtInst )
230     {
231       LPVOID lpMsgBuf;
232       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
233                        FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
234     err = QString( "Failed to find  %1 function. %2" ).arg( GET_MODULE_NAME ).arg( (LPTSTR)lpMsgBuf );
235     ::LocalFree( lpMsgBuf );
236     }
237   }
238 #else
239   void* modLib = dlopen( (char*)libName.latin1(), RTLD_LAZY );
240   if ( !modLib )
241     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
242   else
243   {
244     crtInst = (GET_MODULE_FUNC)dlsym( modLib, GET_MODULE_NAME );
245     if ( !crtInst )
246       err = QString( "Failed to find function %1. %2" ).arg( GET_MODULE_NAME ).arg( dlerror() );
247   }
248 #endif
249
250   CAM_Module* module = crtInst ? crtInst() : 0;
251   if ( module )
252   {
253     module->setModuleName( modName );
254     module->setName( moduleName( modName ) );
255   }
256
257   if ( !err.isEmpty() ) {
258     if ( desktop() && desktop()->isShown() )
259       SUIT_MessageBox::warn1( desktop(), tr( "Error" ), err, tr( "Ok" ) );
260     else
261       qWarning( err.latin1() ); 
262   }
263
264   return module;
265 }
266
267 /*! @name Activate module group. */
268 //@{
269 /*!Activate module with name \a modName.
270  *\param modName - module name.
271  *\ratval true, if module loaded and activated successful, else false.
272  */
273 bool CAM_Application::activateModule( const QString& modName )
274 {
275   if ( !modName.isEmpty() && !activeStudy() )
276     return false;
277
278   bool res = false;
279   if ( !modName.isEmpty() )
280   {
281     CAM_Module* mod = module( modName );
282     if ( !mod && !moduleLibrary( modName ).isEmpty() )
283     {
284       mod = loadModule( modName );
285       addModule( mod );
286     }
287
288     if ( mod )
289       res = activateModule( mod );
290   }
291   else
292     res = activateModule( 0 );
293
294   return res;
295 }
296
297 /*!Activate module \a mod
298  *\param mod - module for activation.
299  *\retval true - if all sucessful.
300  *\warning Error message if module not activated in active study.
301  */
302 bool CAM_Application::activateModule( CAM_Module* mod )
303 {
304   if ( mod && !activeStudy() )
305     return false;
306
307   if ( myModule == mod )
308     return true;
309
310   if ( myModule )
311   {
312     if ( !myModule->deactivateModule( activeStudy() ) )
313     {
314       // ....      
315     }    
316   }     
317   myModule = mod;
318
319   if ( myModule ){
320     // Connect the module to the active study
321     myModule->connectToStudy( dynamic_cast<CAM_Study*>( activeStudy() ) );
322     if ( !myModule->activateModule( activeStudy() ) )
323     {
324       myModule->setMenuShown( false );
325       myModule->setToolShown( false );
326       if ( desktop() && desktop()->isShown() )
327         SUIT_MessageBox::error1( desktop(), tr( "ERROR_TLT" ), tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() ), tr( "BUT_OK" ) );
328       else
329         qWarning( tr( "ERROR_ACTIVATE_MODULE_MSG" ).arg( myModule->moduleName() ).latin1() ); 
330       myModule = 0;
331       return false;
332     }
333   }
334
335   updateCommandsStatus();
336
337   return true;
338 }
339 //@}
340
341 /*!Create new study for current application.
342  *\retval study pointer.
343  */
344 SUIT_Study* CAM_Application::createNewStudy() 
345
346   return new CAM_Study( this );
347 }
348
349 /*!Update commands status for parent class and for current class(if module is active)*/
350 void CAM_Application::updateCommandsStatus()
351 {
352   STD_Application::updateCommandsStatus();
353
354   if ( activeModule() )
355     activeModule()->updateCommandsStatus();
356 }
357
358 /*!Close all modules in study \a theDoc.
359  *\param theDoc - study
360  */
361 void CAM_Application::beforeCloseDoc( SUIT_Study* theDoc )
362 {
363   for ( ModuleListIterator it( myModules ); it.current(); ++it )
364     it.current()->studyClosed( theDoc );
365 }
366
367 /*!Sets active study for parent class.
368  *\param study - study.
369  */
370 void CAM_Application::setActiveStudy( SUIT_Study* study )
371 {
372   STD_Application::setActiveStudy( study );
373 }
374
375 /*!Do nothing.*/
376 void CAM_Application::moduleAdded( CAM_Module* mod )
377 {
378 //  CAM_Study* study = dynamic_cast<CAM_Study*>( activeStudy() );
379 //  if ( !study )
380 //    return;
381
382 //  study->insertDataModel( mod->dataModel() );
383 }
384
385 /*!Gets module name by title \a title
386  *\param title - title name
387  *\retval QString module name.
388  */
389 QString CAM_Application::moduleName( const QString& title ) const
390 {
391   QString res;
392   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
393   {
394     if ( (*it).title == title )
395       res = (*it).name;
396   }
397   return res;
398 }
399
400 /*!Gets module title by module name \a name
401  *\param name - module name
402  *\retval QString module title.
403  */
404 QString CAM_Application::moduleTitle( const QString& name ) const
405 {
406   QString res;
407   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
408   {
409     if ( (*it).name == name )
410       res = (*it).title;
411   }
412   return res;
413 }
414
415 /*!Get library name for module with title \a title.
416  *\param title - module title name.
417  *\param full  - boolean flag (if true - return full library name, else internal name)
418  *\retval QString - library name.
419  */
420 QString CAM_Application::moduleLibrary( const QString& title, const bool full ) const
421 {
422   QString res;
423   for ( ModuleInfoList::const_iterator it = myInfoList.begin(); it != myInfoList.end() && res.isEmpty(); ++it )
424   {
425     if ( (*it).title == title )
426       res = (*it).internal;
427   }
428   if ( !res.isEmpty() && full )
429     res = SUIT_Tools::library( res );
430   return res;
431 }
432
433 /*!Read modules list*/
434 void CAM_Application::readModuleList()
435 {
436   if ( !myInfoList.isEmpty() )
437     return;
438
439   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
440
441   QStringList modList;
442
443   QStringList args;
444   for (int i = 1; i < qApp->argc(); i++)
445     args.append( qApp->argv()[i] );
446
447   QRegExp rx("--modules\\s+\\(\\s*(.*)\\s*\\)");
448   rx.setMinimal( true );
449   if ( rx.search( args.join(" ") ) >= 0 && rx.capturedTexts().count() > 0 ) {
450     QString modules = rx.capturedTexts()[1];
451     QStringList mods = QStringList::split(":",modules,false);
452     for ( uint i = 0; i < mods.count(); i++ ) {
453       if ( !mods[i].stripWhiteSpace().isEmpty() )
454         modList.append( mods[i].stripWhiteSpace() );
455     }
456   }
457   if ( modList.isEmpty() ) {
458     QString mods = resMgr->stringValue( "launch", "modules", QString::null );
459     modList = QStringList::split( ",", mods );
460   }
461
462   for ( QStringList::const_iterator it = modList.begin(); it != modList.end(); ++it )
463   {
464     QString modName = (*it).stripWhiteSpace();
465     if ( modName.isEmpty() )
466       continue;
467
468     QString modTitle = resMgr->stringValue( *it, QString( "name" ), QString::null );
469     if ( modTitle.isEmpty() )
470       continue;
471
472     QString modLibrary = resMgr->stringValue( *it, QString( "library" ), QString::null ).stripWhiteSpace();
473     if ( !modLibrary.isEmpty() )
474     {
475       QString libExt;
476       modLibrary = SUIT_Tools::file( modLibrary.stripWhiteSpace() );
477       libExt = QString( "so" );
478       if ( SUIT_Tools::extension( modLibrary ).lower() == libExt )
479         modLibrary = modLibrary.mid( 0, modLibrary.length() - libExt.length() - 1 );
480       libExt = QString( "dll" );
481       if ( SUIT_Tools::extension( modLibrary ).lower() == libExt )
482         modLibrary = modLibrary.mid( 0, modLibrary.length() - libExt.length() - 1 );
483 #ifndef WIN32
484       if ( modLibrary.startsWith( "lib" ) )
485         modLibrary = modLibrary.mid( 3 );
486 #endif
487     }
488     else
489       modLibrary = modName;
490
491     ModuleInfo inf;
492     inf.name = modName;
493     inf.title = modTitle;
494     inf.internal = modLibrary;
495     myInfoList.append( inf );
496   }
497
498   if ( myInfoList.isEmpty() ) {
499     if ( desktop() && desktop()->isShown() )
500       SUIT_MessageBox::warn1( desktop(), tr( "Warning" ), tr( "Modules list is empty" ), tr( "&OK" ) );
501     else
502       qWarning( tr( "Modules list is empty" ).latin1() ); 
503   }
504 }
505
506 /*!Add common items for popup menu ( if they are exist )
507  *\param type - type of popup menu
508  *\param thePopup - popup menu
509  *\param title - title of popup menu
510  */
511 void CAM_Application::contextMenuPopup( const QString& type, QPopupMenu* thePopup, QString& title )
512 {
513   // to do : add common items for popup menu ( if they are exist )
514   if ( activeModule() ) 
515     activeModule()->contextMenuPopup( type, thePopup, title );
516 }
517
518 /*!Create empty study.*/
519 void CAM_Application::createEmptyStudy()
520 {
521   /*SUIT_Study* study = */activeStudy();
522   STD_Application::createEmptyStudy();
523 }