Salome HOME
GUI launcher: systematize run procedure
[modules/gui.git] / src / SUIT / SUIT_Session.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 "SUIT_Session.h"
24
25 #include "SUIT_Study.h"
26 #include "SUIT_Tools.h"
27 #include "SUIT_MessageBox.h"
28 #include "SUIT_ExceptionHandler.h"
29 #include "SUIT_ResourceMgr.h"
30
31 #include <QApplication>
32
33 #ifdef WIN32
34 #include <windows.h>
35 #else
36 #include <dlfcn.h>
37 #endif
38
39 SUIT_Session* SUIT_Session::mySession = 0;
40
41 /*! Constructor.*/
42
43 SUIT_Session::SUIT_Session()
44 : QObject(),
45   myResMgr( 0 ),
46   myActiveApp( 0 ),
47   myHandler( 0 ),
48   myExitStatus( NORMAL ),
49   myExitFlags ( 0 )
50 {
51   SUIT_ASSERT( !mySession )
52
53   mySession = this;
54 }
55
56 /*!destructor. Clear applications list and set mySession to zero.*/
57 SUIT_Session::~SUIT_Session()
58 {
59   for ( AppList::iterator it = myAppList.begin(); it != myAppList.end(); ++it )
60     delete *it;
61
62   myAppList.clear();
63
64   if ( myResMgr )
65   {
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::warning( 0, tr( "Error" ),
97                               tr( "Can not load application library \"%1\": %2").arg( lib ).arg( lastError() ) );
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( (HINSTANCE)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::warning( 0, tr( "Error" ),
115                               tr( "Can not find function \"%1\": %2" ).arg( APP_CREATE_NAME ).arg( lastError() ) );
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::warning( 0, tr( "Error" ), tr( "Can not create application \"%1\": %2").arg( appName ).arg( lastError() ) );
131     return 0;
132   }
133
134   anApp->setObjectName( appName );
135
136   insertApplication( anApp );
137
138   if ( !myHandler )
139   {
140     APP_GET_HANDLER_FUNC crtHndlr = 0;
141 #ifdef WIN32
142     crtHndlr = (APP_GET_HANDLER_FUNC)::GetProcAddress( (HINSTANCE)libHandle, APP_GET_HANDLER_NAME );
143 #else
144     crtHndlr = (APP_GET_HANDLER_FUNC)dlsym( libHandle, APP_GET_HANDLER_NAME );
145 #endif
146     if ( crtHndlr )
147       myHandler = crtHndlr();
148   }
149
150   anApp->start();
151
152   // Application can be closed during starting (not started).
153   if ( !myAppList.contains( anApp ) )
154     anApp = 0;
155
156   return anApp;
157 }
158
159 /*!
160   Gets the list of all applications
161 */
162 QList<SUIT_Application*> SUIT_Session::applications() const
163 {
164   return myAppList;
165 }
166
167 void SUIT_Session::insertApplication( SUIT_Application* app )
168 {
169   if ( !app || myAppList.contains( app ) )
170     return;
171
172   myAppList.append( app );
173
174   connect( app, SIGNAL( applicationClosed( SUIT_Application* ) ),
175            this, SLOT( onApplicationClosed( SUIT_Application* ) ) );
176   connect( app, SIGNAL( activated( SUIT_Application* ) ), 
177                  this, SLOT( onApplicationActivated( SUIT_Application* ) ) );
178 }
179
180 /*!
181   Returns the active application
182 */
183 SUIT_Application* SUIT_Session::activeApplication() const
184 {
185   /*
186   if ( myAppList.count() == 1 )
187     return myAppList.getFirst();
188
189   SUIT_Desktop* desktop = 0;
190   for ( AppListIterator it( myAppList ); it.current() && !desktop; ++it )
191   {
192     SUIT_Desktop* desk = it.current()->desktop();
193     if ( desk && desk->isActiveWindow() )
194       desktop = desk;
195   }
196
197   if ( !desktop )
198     return 0;
199
200   SUIT_ViewWindow* win = desktop->activeWindow();
201   if ( !win || !win->getViewManager() )
202     return 0;
203
204   SUIT_Study* study = win->getViewManager()->study();
205   if ( !study )
206     return 0;
207
208   return study->application();
209   */
210   return myActiveApp;
211 }
212
213 /*!
214   Returns the resource manager for the specified application name.
215 */
216 SUIT_ResourceMgr* SUIT_Session::resourceMgr() const
217 {
218   return myResMgr;
219 }
220
221 /*!
222   Removes the application from the list of launched applications.
223   If it is a last application the session will be closed.
224 */
225 void SUIT_Session::onApplicationClosed( SUIT_Application* theApp )
226 {
227   emit applicationClosed( theApp );
228
229   myAppList.removeAll( theApp );
230   delete theApp;
231
232   if ( theApp == myActiveApp )
233     myActiveApp = 0;
234
235   if ( myAppList.isEmpty() )
236   {
237     //printf( "Calling QApplication::exit() with exit code = %d\n", myExitStatus );
238     QApplication::instance()->exit( myExitStatus );
239   }
240 }
241
242 /*!
243   Destroys session by closing all applications.
244 */
245 void SUIT_Session::closeSession( int mode, int flags )
246 {
247   AppList apps = myAppList;
248   for ( AppList::const_iterator it = apps.begin(); it != apps.end(); ++it )
249   {
250     SUIT_Application* app = *it;
251     bool closePermanently;
252     if ( mode == ASK && !app->isPossibleToClose( closePermanently ) )
253       return;
254     else if ( mode == SAVE )
255     {
256       SUIT_Study* study = app->activeStudy();
257       if ( study->isModified() && study->isSaved() )
258               study->saveDocument();
259     }
260     else if ( mode == DONT_SAVE )
261     {
262       myExitStatus = FORCED;
263     }
264
265     app->closeApplication();
266   }
267
268   myExitFlags = flags;
269 }
270
271 /*!
272   Get session exit flags.
273
274   By default, exit flags are set to 0. You can use pass any flags to the
275   closeSession() method if you need to process them later on application
276   quiting.
277
278   \return exit flags
279 */
280 int SUIT_Session::exitFlags() const
281 {
282   return myExitFlags;
283 }
284
285 /*! \retval return myHandler*/
286 SUIT_ExceptionHandler* SUIT_Session::handler() const
287 {
288   return myHandler;
289 }
290
291 /*! \retval return last error string.*/
292 QString SUIT_Session::lastError() const
293 {
294   QString str;
295 #ifdef WIN32
296   LPVOID lpMsgBuf;
297   ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
298                    FORMAT_MESSAGE_IGNORE_INSERTS, 0, ::GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, 0 );
299   LPTSTR msg = (LPTSTR)lpMsgBuf;
300 #ifdef UNICODE
301   str = QString::fromWCharArray(msg);
302 #else
303   str = QString( SUIT_Tools::toQString( msg ) );
304 #endif
305   LocalFree( lpMsgBuf );
306 #else
307   str = QString( dlerror() );
308 #endif
309   return str;
310 }
311
312 /*! Load library to session.
313  * \retval Loaded library.
314  */
315 SUIT_Session::AppLib SUIT_Session::loadLibrary( const QString& name, QString& libName )
316 {
317   QString libFile = SUIT_Tools::library( name );
318
319   libName = libFile;
320   if ( libFile.isEmpty() )
321     return 0;
322
323   AppLib lib = 0;
324   QByteArray bid = libFile.toUtf8();
325 #ifdef WIN32
326 #ifdef UNICODE
327   LPTSTR str = (LPTSTR)libFile.utf16();
328 #else
329   LPTSTR str = (LPTSTR)(const char*)bid;
330 #endif
331   lib = ::LoadLibrary( str );
332 #else
333   lib = dlopen( (const char*)libFile.toUtf8(), RTLD_LAZY | RTLD_GLOBAL  );
334 #endif
335   return lib;
336 }
337
338 /*! \retval Return file name by application name.*/
339 QString SUIT_Session::applicationName( const QString& str ) const
340 {
341 #ifdef WIN32
342   return SUIT_Tools::file( str, false );
343 #else
344   QString fileName = SUIT_Tools::file( str, false );
345   if ( fileName.startsWith( "lib" ) )
346     fileName = fileName.right( fileName.length() - 3 );
347   return fileName;
348 #endif
349 }
350
351 /*!
352   Virtual method, creates an instance of ResourceManager
353 */
354 SUIT_ResourceMgr* SUIT_Session::createResourceMgr( const QString& appName ) const
355 {
356   return new SUIT_ResourceMgr( applicationName( appName ) );
357 }
358
359 /*!
360   Slot, called on activation of some application's desktop
361 */
362 void SUIT_Session::onApplicationActivated( SUIT_Application* app ) 
363 {
364   myActiveApp = app;
365 }