Salome HOME
*** empty log message ***
[modules/gui.git] / src / PyInterp / PyInterp_Dispatcher.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
2 //
3 //  Copyright (C) 2005  CEA/DEN, EDF R&D
4 //
5 //
6 //
7 //  File   : PyInterp_Dispatcher.cxx
8 //  Author : Sergey ANIKIN, OCC
9 //  Module : GUI
10 //  $Header$
11
12
13 #include <PyInterp_base.h>
14 #include <PyInterp_Dispatcher.h>
15 #include <PyInterp_Watcher.h>
16
17 #include <qapplication.h>
18 #include <qobject.h>
19
20 //#include <utilities.h>
21 using namespace std;
22
23 PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
24
25 //////////////////////////////////////////////////////////
26 // class : PyInterp_Request
27 //////////////////////////////////////////////////////////
28
29 void PyInterp_Request::process()
30 {
31   safeExecute();
32
33   myMutex.lock();
34   if ( !IsSync() && getListener() && getEvent() )
35     postEvent();
36   myMutex.unlock();
37 }
38
39 void PyInterp_Request::safeExecute()
40 {
41   execute();
42 }
43
44 void PyInterp_Request::Destroy( PyInterp_Request* request )
45 {
46   // Lock and unlock the mutex to avoid errors on its deletion
47   request->myMutex.lock();
48   request->myMutex.unlock();
49   delete request;
50 }
51
52 QEvent* PyInterp_Request::createEvent() const
53 {
54   return new PyInterp_Event( PyInterp_Event::NOTIFY, (PyInterp_Request*)this );
55 }
56
57 QEvent* PyInterp_Request::getEvent()
58 {
59   if ( !myEvent && !IsSync() )
60     myEvent = createEvent();
61   return myEvent;
62 }
63
64 void PyInterp_Request::postEvent()
65 {
66 #if QT_VERSION >= 0x030303
67 //  MESSAGE("*** PyInterp_Request::postEvent(): for Qt 3.3.3")
68   QApplication::postEvent( getListener(), getEvent() );
69 #else
70 //  MESSAGE("*** PyInterp_Request::postEvent(): for Qt 3.0.5")
71   QThread::postEvent( getListener(), getEvent() );
72 #endif
73 }
74
75 void PyInterp_Request::setListener( QObject* o )
76 {
77   myMutex.lock();
78   myListener = o;
79   myMutex.unlock();
80 }
81
82 void PyInterp_LockRequest::safeExecute()
83 {
84   if ( getInterp() ){
85     PyLockWrapper aLock = getInterp()->GetLockWrapper();
86     execute();
87   }
88 }
89
90 //////////////////////////////////////////////////////////
91 // class : PyInterp_Event
92 //////////////////////////////////////////////////////////
93
94 PyInterp_Event::~PyInterp_Event()
95 {
96   PyInterp_Request::Destroy( myRequest );
97   myRequest = 0;
98 }
99
100 //////////////////////////////////////////////////////////
101 // class : PyInterp_Dispatcher
102 //////////////////////////////////////////////////////////
103
104 PyInterp_Dispatcher* PyInterp_Dispatcher::Get()
105 {
106   if ( !myInstance )
107     myInstance = new PyInterp_Dispatcher();
108   return myInstance;
109 }
110
111 PyInterp_Dispatcher::PyInterp_Dispatcher() 
112 : QThread()
113 {
114   myWatcher = new PyInterp_Watcher();
115 }
116
117 PyInterp_Dispatcher::~PyInterp_Dispatcher()
118 {
119   // Clear the request queue
120   myQueueMutex.lock();
121
122   for ( std::list<PyInterp_Request*>::iterator it = myQueue.begin(); it != myQueue.end(); ++it )
123     PyInterp_Request::Destroy( *it );
124   myQueue.clear();
125
126   myQueueMutex.unlock();
127
128   // Wait for run() to finish
129   wait();
130
131   delete myWatcher;
132   myWatcher = 0;
133 }
134
135 bool PyInterp_Dispatcher::IsBusy() const
136 {
137   return running();
138 }
139
140 void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest )
141 {
142   if ( !theRequest )
143     return;
144
145   if ( theRequest->IsSync() && !IsBusy() ) // synchronous processing - nothing is done if dispatcher is busy!
146     processRequest( theRequest );
147   else { // asynchronous processing
148     myQueueMutex.lock();
149     myQueue.push_back( theRequest );
150     if ( theRequest->getListener() )
151       QObject::connect( theRequest->getListener(), SIGNAL( destroyed( QObject* ) ), myWatcher, SLOT( onDestroyed( QObject* ) ) );
152     myQueueMutex.unlock();  
153
154     if ( !IsBusy() )
155       start();
156   }
157 }
158
159 void PyInterp_Dispatcher::run()
160 {
161 //  MESSAGE("*** PyInterp_Dispatcher::run(): STARTED")
162   PyInterp_Request* aRequest;
163
164   // prepare for queue size check
165   myQueueMutex.lock();
166
167   while( myQueue.size() ) {
168 //    MESSAGE("*** PyInterp_Dispatcher::run(): next request taken from the queue")
169     aRequest = myQueue.front();
170
171     // let other threads append their requests to the end of the queue
172     myQueueMutex.unlock();
173
174     // processRequest() may delete a request, so this pointer must not be used
175     // after request is processed!
176     processRequest( aRequest );
177
178     // prepare for removal of the first request in the queue
179     myQueueMutex.lock();
180     // IMPORTANT: the first item could have been removed by objectDestroyed() --> we have to check it
181     if ( myQueue.front() == aRequest ) // It's still here --> remove it
182       myQueue.pop_front();
183
184 //    MESSAGE("*** PyInterp_Dispatcher::run(): request processed")
185   }
186
187   myQueueMutex.unlock();
188 //  MESSAGE("*** PyInterp_Dispatcher::run(): FINISHED")
189 }
190
191 void PyInterp_Dispatcher::processRequest( PyInterp_Request* theRequest )
192 {
193   theRequest->process();
194 }
195
196 void PyInterp_Dispatcher::objectDestroyed( const QObject* o )
197 {
198   // prepare for modification of the queue
199   myQueueMutex.lock();
200
201   for ( std::list<RequestPtr>::iterator it = myQueue.begin(); it != myQueue.end(); ++it ){
202     if ( o == (*it)->getListener() ){
203       (*it)->setListener( 0 ); // to prevent event posting
204       it = myQueue.erase( it );
205     }
206   }
207
208   myQueueMutex.unlock();
209 }
210