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