Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/gui.git] / src / SUIT / SUIT_Session.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 "SUIT_Session.h"
20
21 #include "SUIT_Tools.h"
22 #include "SUIT_Desktop.h"
23 #include "SUIT_MessageBox.h"
24 #include "SUIT_ViewWindow.h"
25 #include "SUIT_ViewManager.h"
26 #include "SUIT_ExceptionHandler.h"
27
28 #include <qtextcodec.h>
29 #include <qmessagebox.h>
30 #include <qapplication.h>
31
32 #ifdef WIN32
33 #include <windows.h>
34 #else
35 #include <dlfcn.h>
36 #endif
37
38 static bool   SUIT_Session_IsPythonExecuted = false;
39 static QMutex SUIT_Session_PythonMutex;
40
41 SUIT_Session* SUIT_Session::mySession = 0;
42
43 /*! Constructor.*/
44
45 SUIT_Session::SUIT_Session()
46 : QObject(),
47 myResMgr( 0 ),
48 myHandler( 0 ),
49 myActiveApp( 0 ),
50 myExitStatus( NORMAL ),
51 myExitFlags ( 0 )
52 {
53   SUIT_ASSERT( !mySession )
54
55   mySession = this;
56
57   myAppList.setAutoDelete( true );
58 }
59
60 /*!destructor. Clear applications list and set mySession to zero.*/
61 SUIT_Session::~SUIT_Session()
62 {
63   myAppList.clear();
64
65   if (myResMgr) {
66     delete myResMgr;
67     myResMgr = 0;
68   }
69   mySession = 0;
70 }
71
72 /*! \retval return mySession */
73 SUIT_Session* SUIT_Session::session()
74 {
75   return mySession;
76 }
77
78 /*!
79   Starts new application using "createApplication" function of loaded DLL.
80 */
81
82 SUIT_Application* SUIT_Session::startApplication( const QString& name, int args, char** argv )
83 {
84   AppLib libHandle = 0;
85
86   QString appName = applicationName( name );
87   if ( myAppLibs.contains( appName ) )
88     libHandle = myAppLibs[appName];
89
90   QString lib;
91   if ( !libHandle )
92     libHandle = loadLibrary( name, lib );
93
94   if ( !libHandle )
95   {
96     SUIT_MessageBox::warn1( 0, tr( "Error" ),
97                             tr( "Can not load application library \"%1\": %2").arg( lib ).arg( lastError() ), tr( "Ok" ) );
98     return 0;
99   }
100
101   if ( !myAppLibs.contains( appName ) || !myAppLibs[appName] ) // jfa 22.06.2005
102     myAppLibs.insert( appName, libHandle );
103
104   APP_CREATE_FUNC crtInst = 0;
105
106 #ifdef WIN32
107   crtInst = (APP_CREATE_FUNC)::GetProcAddress( libHandle, APP_CREATE_NAME );
108 #else
109   crtInst = (APP_CREATE_FUNC)dlsym( libHandle, APP_CREATE_NAME );
110 #endif
111
112   if ( !crtInst )
113   {
114     SUIT_MessageBox::warn1( 0, tr( "Error" ),
115                             tr( "Can not find function \"%1\": %2" ).arg( APP_CREATE_NAME ).arg( lastError() ), tr( "Ok" ) );
116     return 0;
117   }
118
119   // Prepare Resource Manager for the new application if it doesn't exist yet
120   if ( !myResMgr )
121   {
122     myResMgr = createResourceMgr( appName );
123     myResMgr->loadLanguage();
124   }
125
126   //jfa 22.06.2005:SUIT_Application* anApp = crtInst( args, argv );
127   SUIT_Application* anApp = crtInst();
128   if ( !anApp )
129   {
130     SUIT_MessageBox::warn1( 0, tr( "Error" ), tr( "Can not create application \"%1\": %2").arg( appName ).arg( lastError() ), tr( "Ok" ) );
131     return 0;
132   }
133
134   anApp->setName( appName );
135
136   connect( anApp, SIGNAL( applicationClosed( SUIT_Application* ) ),
137            this, SLOT( onApplicationClosed( SUIT_Application* ) ) );
138   connect( anApp, SIGNAL( activated( SUIT_Application* ) ), 
139                  this, SLOT( onApplicationActivated( SUIT_Application* ) ) );
140
141   myAppList.append( anApp );
142
143   if ( !myHandler )
144   {
145     APP_GET_HANDLER_FUNC crtHndlr = 0;
146 #ifdef WIN32
147     crtHndlr = (APP_GET_HANDLER_FUNC)::GetProcAddress( libHandle, APP_GET_HANDLER_NAME );
148 #else
149     crtHndlr = (APP_GET_HANDLER_FUNC)dlsym( libHandle, APP_GET_HANDLER_NAME );
150 #endif
151     if ( crtHndlr )
152       myHandler = crtHndlr();
153   }
154
155   anApp->start();
156
157   // Application can be closed during starting (not started).
158   if ( !myAppList.contains( anApp ) )
159     anApp = 0;
160
161   return anApp;
162 }
163
164 /*!
165   Gets the list of all applications
166 */
167 QPtrList<SUIT_Application> SUIT_Session::applications() const
168 {
169   QPtrList<SUIT_Application> apps;
170   apps.setAutoDelete( false );
171
172   for ( AppListIterator it( myAppList ); it.current(); ++it )
173     apps.append( it.current() );
174
175   return apps;
176 }
177
178 /*!
179   Returns the active application
180 */
181 SUIT_Application* SUIT_Session::activeApplication() const
182 {
183   /*
184   if ( myAppList.count() == 1 )
185     return myAppList.getFirst();
186
187   SUIT_Desktop* desktop = 0;
188   for ( AppListIterator it( myAppList ); it.current() && !desktop; ++it )
189   {
190     SUIT_Desktop* desk = it.current()->desktop();
191     if ( desk && desk->isActiveWindow() )
192       desktop = desk;
193   }
194
195   if ( !desktop )
196     return 0;
197
198   SUIT_ViewWindow* win = desktop->activeWindow();
199   if ( !win || !win->getViewManager() )
200     return 0;
201
202   SUIT_Study* study = win->getViewManager()->study();
203   if ( !study )
204     return 0;
205
206   return study->application();
207   */
208   return myActiveApp;
209 }
210
211 /*!
212   Returns the resource manager for the specified application name.
213 */
214 SUIT_ResourceMgr* SUIT_Session::resourceMgr() const
215 {
216   return myResMgr;
217 }
218
219 /*!
220   Removes the application from the list of launched applications.
221   If it is a last application the session will be closed.
222 */
223 void SUIT_Session::onApplicationClosed( SUIT_Application* theApp )
224 {
225   emit applicationClosed( theApp );
226
227   myAppList.remove( theApp );
228   if ( theApp == myActiveApp )
229     myActiveApp = 0;
230
231   if ( myAppList.isEmpty() )
232   {
233     printf( "Calling QApplication::exit() with exit code = %d\n", myExitStatus );
234     qApp->exit( myExitStatus );
235   }
236 }
237
238 /*!
239   Destroys session by closing all applications.
240 */
241 void SUIT_Session::closeSession( int mode, int flags )
242 {
243   while ( !myAppList.isEmpty() )
244   {
245     SUIT_Application* app = myAppList.getFirst();
246     bool closePermanently;
247     if ( mode == ASK && !app->isPossibleToClose( closePermanently ) )
248       return;
249     else if ( mode == SAVE )
250     {
251       SUIT_Study* study = app->activeStudy();
252       if ( study->isModified() && study->isSaved() )
253         study->saveDocument();
254     }
255     else if ( mode == DONT_SAVE )
256     {
257       myExitStatus = FORCED;
258     }
259
260     app->closeApplication();
261   }
262   myExitFlags = flags;
263 }
264
265 /*!
266   Get session exit flags.
267
268   By default, exit flags are set to 0. You can use pass any flags to the
269   closeSession() method if you need to process them later on application
270   quiting.
271
272   \return exit flags
273 */
274 int SUIT_Session::exitFlags() const
275 {
276   return myExitFlags;
277 }
278
279 /*! \retval return myHandler*/
280 SUIT_ExceptionHandler* SUIT_Session::handler() const
281 {
282   return myHandler;
283 }
284
285 /*! \retval return last error string.*/
286 QString SUIT_Session::lastError() const
287 {
288   QString str;
289 #ifdef WNT
290   LPVOID lpMsgBuf;
291   ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
292                    FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
293   str = QString( (LPTSTR)lpMsgBuf );
294   LocalFree( lpMsgBuf );
295 #else
296   str = QString( dlerror() );
297 #endif
298   return str;
299 }
300
301 /*! Load library to session.
302  * \retval Loaded library.
303  */
304 SUIT_Session::AppLib SUIT_Session::loadLibrary( const QString& name, QString& libName )
305 {
306   QString libFile = SUIT_Tools::library( name );
307
308   libName = libFile;
309   if ( libFile.isEmpty() )
310     return 0;
311
312   AppLib lib = 0;
313 #ifdef WIN32
314   lib = ::LoadLibrary( (char*)libFile.latin1() );
315 #else
316   lib = dlopen( (char*)libFile.latin1(), RTLD_LAZY | RTLD_GLOBAL  );
317 #endif
318   return lib;
319 }
320
321 /*! \retval Return file name by application name.*/
322 QString SUIT_Session::applicationName( const QString& str ) const
323 {
324 #ifdef WIN32
325   return SUIT_Tools::file( str, false );
326 #else
327   QString fileName = SUIT_Tools::file( str, false );
328   if ( fileName.startsWith( "lib" ) )
329     fileName = fileName.right( fileName.length() - 3 );
330   return fileName;
331 #endif
332 }
333
334 /*!
335   Virtual method, creates an instance of ResourceManager
336 */
337 SUIT_ResourceMgr* SUIT_Session::createResourceMgr( const QString& appName ) const
338 {
339   return new SUIT_ResourceMgr( applicationName( appName ) );
340 }
341
342 /*!
343   Slot, called on activation of some application's desktop
344 */
345 void SUIT_Session::onApplicationActivated( SUIT_Application* app )
346 {
347   myActiveApp = app;
348 }
349
350 /*!
351   \retval Return TRUE, if a command is currently executed in Python Console,
352                  FALSE otherwise.
353 */
354 bool SUIT_Session::IsPythonExecuted()
355 {
356   bool ret;
357   SUIT_Session_PythonMutex.lock();
358   ret = SUIT_Session_IsPythonExecuted;
359   SUIT_Session_PythonMutex.unlock();
360   return ret;
361 }
362
363 /*!
364   Set value of boolean flag, being returned by method \a IsPythonExecuted().
365   It is supposed to set the flag to TRUE when any python command starts
366   and reset it to FALSE when the command finishes.
367 */
368 void SUIT_Session::SetPythonExecuted(bool isPythonExecuted)
369 {
370   SUIT_Session_PythonMutex.lock();
371   SUIT_Session_IsPythonExecuted = isPythonExecuted;
372   SUIT_Session_PythonMutex.unlock();
373 }