Status bar fixed
[qtmeetings] / src / BusinessLogic / Engine.cpp
1 #include "Engine.h"
2 #include "Room.h"
3 #include "Meeting.h"
4 #include "ConnectionSettings.h"
5 #include "Configuration.h"
6 #include "DisplaySettings.h"
7 #include "CommunicationManager.h"
8 // #include "DeviceManager.h"
9 #include "Clock.h"
10 #include "ErrorMapper.h"
11 #include "UIManager.h"
12
13 #include <QApplication>
14 #include <QTimer>
15 #include <QList>
16 #include <QtDebug>
17
18 QTime Engine::endOfTheDay = QTime( 23, 59, 0, 0); // end of the day is 11:59pm
19 const int IDLE_TIME_MULTIPLIER = 60000; // Multiplies milliseconds to minutes
20
21 // Macro to help deleting objects. This could be global.
22 #define QT_DELETE(X) \
23         if ( X != 0 ) \
24         { \
25                 delete X; \
26                 X = 0; \
27         }
28
29
30 Engine::Engine() :
31                 iClock( 0 ), iConfiguration( 0 ), iCommunication( 0 ),
32                 iWindowManager( 0 ), iUIManager( 0 )
33 {
34         qDebug() << "Engine::Engine()";
35         iCommunicationFailed = true;
36         
37         initConfiguration();
38         initDevice();
39         initCommunication();
40         initUserInterface();
41         
42         //initialize idle time counter
43         iIdleTimeCounter = new QTimer();
44         iIdleTimeCounter->setSingleShot( true);
45         iIdleTimeCounter->setInterval(IDLE_TIME_MULTIPLIER * iConfiguration->displaySettings()->screensaver() );
46         iIdleTimeCounter->start();
47
48         // create application clock
49         iClock = new Clock;
50         connect( iClock, SIGNAL( tick( QDateTime ) ), this, SLOT( tick( QDateTime )/*checkStatusOfAllRooms()*/ ) );
51         // connect( iClock, SIGNAL( tick( QDateTime ) ), iWindowManager, SLOT( distributeDateTimeInfo( QDateTime ) ) );
52
53         // Create auto refresh timer
54         iAutoRefresh = new QTimer;
55
56         iAutoRefresh->setInterval(Configuration::instance()->getRefreshinterval() * 1000);
57
58         iAutoRefresh->start();
59         connect( iAutoRefresh, SIGNAL( timeout() ), iAutoRefresh, SLOT( start() ) );
60         connect( iAutoRefresh, SIGNAL( timeout() ), this, SLOT( updateRoomInfo() ) );
61         // connect( iAutoRefresh, SIGNAL( timeout() ), this, SLOT( fetchMeetings() ) );
62         
63         if( iDevice->currentOperationMode() == DeviceManager::KioskMode )
64         {
65                 iWindowManager->setFullscreen();
66         }
67
68         connectSignals();
69         connect( Configuration::instance(), SIGNAL( configurationChanged() ), this, SLOT( configurationChanged() ) );
70         // QTimer::singleShot( 0, this, SLOT( fetchMeetings() ) );
71
72         // TODO: continue implementation
73 }
74
75 Engine::~Engine()
76 {
77         qDebug() << "Engine::~Engine()";
78         while ( !iMeetings.isEmpty() )
79                 delete iMeetings.takeFirst();
80         
81         if ( iIdleTimeCounter != 0 )
82         {
83                 iIdleTimeCounter->stop();
84                 delete iIdleTimeCounter;
85                 iIdleTimeCounter = 0;
86         }
87         QT_DELETE( iClock );
88         QT_DELETE( iDevice );
89
90         QT_DELETE( iUIManager );
91         QT_DELETE( iWindowManager );
92 }
93
94 void Engine::closeApplication()
95 {
96         qDebug() << "Engine::closeApplication()";
97         // closes application after 1 second
98         QTimer::singleShot( 1000, QApplication::instance(), SLOT( quit() ));
99 }
100
101 Room* Engine::defaultRoom()
102 {
103         qDebug() << "Engine::defaultRoom()";
104         return iConfiguration->defaultRoom();
105 }
106
107 void Engine::checkStatusOfAllRooms()
108 {
109         // TODO: Check if date has changed
110         // iterate trough on the rooms
111         for (int i = 0; i < iConfiguration->rooms().count(); i++)
112         {
113                 // and check the status
114                 roomStatusInfoNeeded( iConfiguration->rooms().at(i) );
115         }
116 }
117
118 int Engine::indexOfMeetingAt(Room *aRoom, QDateTime aAt)
119 {
120 //      qDebug() << "Engine::indexOfMeetingAt( Room *, QDateTime )";
121         for ( int i = 0; i < iMeetings.count(); i++ )
122         {
123                 // exchange server ensures that there is only one meeting in a room at a specified time
124                 if (aRoom->equals(iMeetings.at( i )->room() ) && iMeetings.at( i )->startsAt() <= aAt && iMeetings.at( i )->endsAt() >= aAt)
125                 {
126                         return i;
127                 }
128         }
129         return -1;
130 }
131
132 int Engine::indexOfMeetingAfter(Room *aRoom, QDateTime aAfter)
133 {
134 //      qDebug() << "Engine::indexOfMeetingAfter( Room *, QDateTime )";
135         // seeks for the next meeting on the SAME DAY
136         int min = -1;
137         for (int i = 0; i < iMeetings.count(); i++)
138         {
139                 // if the meeting is in the same room, on the same day but after the specified time
140                 if (aRoom->equals(iMeetings.at( i )->room() ) && iMeetings.at( i )->startsAt().date() == aAfter.date() && iMeetings.at( i )->startsAt() > aAfter)
141                 {
142                         // if there was not any meeting find yet or the previously found is a later one then the (i)th
143                         if (min == -1 || iMeetings.at( min )->startsAt() > iMeetings.at( i )->startsAt() )
144                         {
145                                 min = i;
146                         }
147                 }
148         }
149         return min;
150 }
151
152 void Engine::roomStatusInfoNeeded(Room *aRoom)
153 {
154 //      qDebug() << "Engine::roomStatusInfoNeeded( Room * )";
155         if ( aRoom == 0 )
156         {
157                 return;
158         }
159
160         int indexOfCurrentMeeting = indexOfMeetingAt(aRoom, iClock->datetime() );
161         int indexOfNextMeeting = indexOfMeetingAfter(aRoom, iClock->datetime() );
162
163         // if there is no meeting, then status is Free; otherwise Busy
164         Room::Status status = (indexOfCurrentMeeting == -1 ) ? Room::FreeStatus : Room::BusyStatus;
165         // if room is Busy, then check end time, otherwise...
166         QTime until = (status == Room::BusyStatus ) ? iMeetings.at( indexOfCurrentMeeting )->endsAt().time() :
167         // ...if there is meeting following on the same day then check end time, otherwise end is the of the working day
168         ( ( indexOfNextMeeting != -1 ) ? iMeetings.at( indexOfNextMeeting )->startsAt().time() : Engine::endOfTheDay );
169
170         //currently works only for default room
171         if ( aRoom->equals( *(iCurrentRoom) ) )
172         {
173                 emit roomStatusChanged( status, until );
174         }
175 }
176
177 void Engine::fetchMeetingDetails( Meeting *aMeeting )
178 {
179         qDebug() << "Engine::fetchMeetingDetails( Meeting* )";
180         iCommunication->fetchMeetingDetails( *aMeeting );
181 }
182
183 void Engine::meetingsFetched( const QList<Meeting*> &aMeetings )
184 {
185         qDebug() << "Engine::meetingsFetched( const QList<Meeting*> & )";
186         QTime c = QTime::currentTime();
187         iLastCommunication.setHMS( c.hour(), c.minute(), c.second() );
188
189         qDebug() << "Error length: "<< iCommunicationError.length();
190         qDebug() << "Error: "<< iCommunicationError;
191
192         if( iCommunicationError.length() == 0 )
193         {
194                 iCommunicationFailed = false;
195                 iUIManager->connectionEstablished();
196         }
197
198         for ( int i = 0; i < iMeetings.count(); ++i ) 
199         {
200                 // TODO: Check if these are current week's meetings and do not overwrite those
201                 Meeting* m = iMeetings.takeAt( i );
202                 delete m;
203         }
204         iMeetings.clear();
205         for ( int i = 0; i < aMeetings.count(); ++i ) {
206                 Meeting* m = new Meeting( *( aMeetings.at( i ) ) );
207                 iMeetings.append( m );
208         }
209
210         // refresh room status info
211         roomStatusInfoNeeded( iCurrentRoom /*defaultRoom()*/ );
212 }
213
214 void Engine::errorHandler( int aCode, const QString &aAddInfo )
215 {       
216         iCommunicationFailed = true;
217
218         if( aCode >= 100 && aCode < 150 )
219         {
220                 if ( iUIManager != 0 )
221                         {
222                                 iUIManager->connectionLost();
223                         }
224         }
225         if ( iWindowManager != 0 )
226         {
227                 iCommunicationError = ErrorMapper::codeToString( aCode, aAddInfo );
228                 //iWindowManager->error( ErrorMapper::codeToString( aCode, aAddInfo ) );
229         }
230 }
231
232 bool Engine::connected()
233 {
234         return !iCommunicationFailed;
235 }
236
237 QTime Engine::lastUpdated()
238 {
239         return iLastCommunication;
240 }
241
242 QString Engine::errorMessage()
243 {
244         return iCommunicationError;
245 }
246
247 void Engine::fetchMeetings( const int aWeek, const int aYear, const Room *aIn )
248 {
249         qDebug()
250                         << "Engine::fetchMeetings( const int aWeek, const int aYear, const Room * )";
251         iCommunicationError = "";
252         iCommunication->fetchMeetings(aWeek, aYear, *aIn);
253 }
254
255 void Engine::cancelFetchMeetingDetails()
256 {
257         iCommunication->cancelFetchMeetingDetails();
258 }
259
260 void Engine::shownWeekChanged( QDate aFrom )
261 {
262         qDebug() << "[Engine::shownWeekChanged] <Invoked>";
263         iCommunicationError = "";
264         iCommunication->fetchMeetings( aFrom.weekNumber(), aFrom.year(), *iCurrentRoom/*defaultRoom()*/ );
265 }
266
267 void Engine::changeDeviceMode()
268 {
269         connect( iDevice, SIGNAL( changeModeFailed() ), this, SLOT( changeModeFailed() ) );
270         iAutoRefresh->stop(); // Stop the meeting update
271         iDevice->changeMode();
272 }
273
274 void Engine::changeModeFailed()
275 {
276         qDebug() << "Engine::progressBarCancelled()";
277         iAutoRefresh->start(); //we start the metting updating
278 }
279
280 void Engine::initUserInterface()
281 {
282         qDebug() << "[Engine::initUserInterface] <Invoked>";
283         
284         // Initialize the window manager and connect what ever signals can be connected
285         iWindowManager = new WindowManager;
286         // Create the UIManager which internally handles most of the UI actions
287         iUIManager = new UIManager( this, iWindowManager );
288         
289         connect( iWindowManager, SIGNAL( eventDetected() ), this, SLOT( handleViewEvent() ) );
290         connect( iWindowManager, SIGNAL( previousViewRestored() ), iUIManager, SLOT( previousViewRestored() ) );
291         connect( iWindowManager, SIGNAL( dialogActivated() ), this, SLOT( dialogActivated() ) );
292         connect( iWindowManager, SIGNAL( dialogDeactivated() ), this, SLOT( dialogDeactivated() ) );
293         
294         // Show the UI
295         iWindowManager->setWindowState( Qt::WindowMaximized );
296         iWindowManager->show();
297         iUIManager->showMainView();
298         
299         // This triggers the meeting fetching
300         iUIManager->currentRoomChanged( this->iCurrentRoom );
301         
302         qDebug() << "[Engine::initUserInterface] <Finished>";
303 }
304
305 void Engine::handleViewEvent()
306 {
307         if ( iIdleTimeCounter != 0 && iIdleTimeCounter->isActive())
308         {
309                 // Restart the idle time counter when view event is received
310                 iIdleTimeCounter->stop();
311                 iIdleTimeCounter->start();
312         }
313 }
314
315 void Engine::initConfiguration()
316 {
317         iConfiguration = Configuration::instance();
318         if ( iConfiguration == 0 )
319         {
320                 QTimer::singleShot( 0, this, SLOT( closeApplication() ) );
321         }
322         iCurrentRoom = iConfiguration->defaultRoom();
323 }
324
325 void Engine::connectSignals()
326 {
327         // Connect engine objects signals to UIManager
328         connect( iClock, SIGNAL( tick( QDateTime ) ), iUIManager, SLOT( updateTime( QDateTime ) ) );
329         connect( iIdleTimeCounter, SIGNAL( timeout() ) , iUIManager, SLOT( roomStatusIndicatorRequested() ) );
330         
331         iUIManager->connectDeviceManager( iDevice );
332         iUIManager->connectCommunicationManager( iCommunication );
333 }
334
335 void Engine::initCommunication()
336 {
337         // initialize communication
338         iCommunication = new CommunicationManager(/* *(iConfiguration->connectionSettings()) */);
339         connect( iCommunication, SIGNAL( error( int, CommunicationManager::CommunicationType  ) ),
340                         this, SLOT( errorHandler( int ) ) );
341         connect( iCommunication, SIGNAL( meetingsFetched( const QList<Meeting*>& ) ),
342                         this, SLOT( meetingsFetched( const QList<Meeting*>& ) ) );
343 }
344
345 void Engine::initDevice()
346 {
347         // create device manager
348         iDevice = new DeviceManager( iConfiguration->startupSettings() );
349         connect( iDevice, SIGNAL( error( int, const QString& ) ), this, SLOT( errorHandler( int, const QString& ) ) );  
350         iDevice->initDeviceManager();
351 }
352
353 void Engine::dialogActivated()
354 {
355         if ( iIdleTimeCounter != 0 )
356         {
357                 iIdleTimeCounter->stop();
358         }
359 }
360
361 void Engine::dialogDeactivated()
362 {
363         if ( iIdleTimeCounter != 0 )
364         {
365                 iIdleTimeCounter->start();
366         }
367 }
368
369 void Engine::previousViewRestored()
370 {
371         if ( iIdleTimeCounter != 0 )
372         {
373                 iIdleTimeCounter->start();
374         }
375 }
376
377 void Engine::stopIdleTimeCounter()
378 {
379         if ( iIdleTimeCounter != 0 )
380         {
381                 iIdleTimeCounter->stop();
382         }
383 }
384
385 void Engine::startIdleTimeCounter()
386 {
387         if ( iIdleTimeCounter != 0 )
388         {
389                 iIdleTimeCounter->start();
390         }
391 }
392
393 void Engine::currentRoomChanged(Room *aRoom)
394 {
395         qDebug() << "[Engine::currentRoomChanged] <invoked>";
396         iCurrentRoom = aRoom;
397         roomStatusInfoNeeded( iCurrentRoom );
398 }
399
400 void Engine::tick( QDateTime aCurrentDateTime )
401 {
402         // Called once every second
403         checkStatusOfAllRooms();
404         if( aCurrentDateTime.date() !=  iCurrentDate)
405         {
406                 // Check if week has changed and fetch meetings for this week
407                 if( aCurrentDateTime.date().weekNumber() != iCurrentDate.weekNumber()
408                         || aCurrentDateTime.date().year() != iCurrentDate.year() )
409                 {
410                         qDebug() << "[Engine::tick] detected week change, fetching meetings";
411                         fetchMeetings( aCurrentDateTime.date().weekNumber(), aCurrentDateTime.date().year(), iCurrentRoom );
412                 }
413         }
414         iCurrentDate = aCurrentDateTime.date();
415 }
416
417
418 void Engine::updateRoomInfo()
419 {
420         qDebug() << "ENGINE::: updateMeetings";
421         roomStatusInfoNeeded(iCurrentRoom);
422 }
423
424 void Engine::configurationChanged()
425 {
426         iAutoRefresh->setInterval(Configuration::instance()->getRefreshinterval() * 1000);
427 }