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