UIManager and some functionality
[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 {
33         qDebug() << "Engine::Engine()";
34         
35         initConfiguration();
36         initDevice();
37         initCommunication();
38         initUserInterface();
39         
40         //initialize idle time counter
41         iIdleTimeCounter = new QTimer();
42         iIdleTimeCounter->setSingleShot( true );
43         // iIdleTimeCounter->setInterval( IDLE_TIME_MULTIPLIER * iConfiguration->displaySettings()->screensaver() );
44         iIdleTimeCounter->setInterval( 10000 );
45         iIdleTimeCounter->start();
46
47         // create application clock
48         iClock = new Clock;
49         connect( iClock, SIGNAL( tick( QDateTime ) ), this, SLOT( checkStatusOfAllRooms() ) );
50         // connect( iClock, SIGNAL( tick( QDateTime ) ), iWindowManager, SLOT( distributeDateTimeInfo( QDateTime ) ) );
51
52         // Create auto refresh timer
53         iAutoRefresh = new QTimer;
54         iAutoRefresh->setInterval( iConfiguration->connectionSettings()->refreshInterval() * 1000 );
55         iAutoRefresh->start();
56         connect( iAutoRefresh, SIGNAL( timeout() ), iAutoRefresh, SLOT( start() ) );
57         connect( iAutoRefresh, SIGNAL( timeout() ), this, SLOT( fetchMeetings() ) );
58         
59         if( iDevice->currentOperationMode() == DeviceManager::KioskMode )
60         {
61                 iWindowManager->setFullscreen();
62         }
63
64         connectSignals();
65         
66         QTimer::singleShot( 0, this, SLOT( fetchMeetings() ) );
67
68         // TODO: continue implementation
69 }
70
71 Engine::~Engine()
72 {
73         qDebug() << "Engine::~Engine()";
74         while ( !iMeetings.isEmpty() )
75                 delete iMeetings.takeFirst();
76         
77         if ( iIdleTimeCounter != 0 )
78         {
79                 iIdleTimeCounter->stop();
80                 delete iIdleTimeCounter;
81                 iIdleTimeCounter = 0;
82         }
83         QT_DELETE( iClock );
84         QT_DELETE( iDevice );
85
86         QT_DELETE( iUIManager );
87         QT_DELETE( iWindowManager );
88 }
89
90 void Engine::closeApplication()
91 {
92         qDebug() << "Engine::closeApplication()";
93         // closes application after 1 second
94         QTimer::singleShot( 1000, QApplication::instance(), SLOT( quit() ) );
95 }
96
97 Room* Engine::defaultRoom()
98 {
99         qDebug() << "Engine::defaultRoom()";
100         return iConfiguration->defaultRoom();
101 }
102
103 void Engine::checkStatusOfAllRooms()
104 {
105 //      qDebug() << "Engine::checkStatusOfAllRooms()";
106         // iterate trough on the rooms
107         for ( int i = 0; i < iConfiguration->rooms().count(); i++ )
108         {
109                 // and check the status
110                 roomStatusInfoNeeded( iConfiguration->rooms().at( i ) );
111         }
112 }
113
114 int Engine::indexOfMeetingAt( Room *aRoom, QDateTime aAt )
115 {
116 //      qDebug() << "Engine::indexOfMeetingAt( Room *, QDateTime )";
117         for ( int i = 0; i < iMeetings.count(); i++ )
118         {
119                 // exchange server ensures that there is only one meeting in a room at a specified time
120                 if ( aRoom->equals( iMeetings.at( i )->room() )
121                           && iMeetings.at( i )->startsAt() <= aAt
122                           && iMeetings.at( i )->endsAt() >= aAt )
123                 {
124                         return i;
125                 }
126         }
127         return -1;
128 }
129
130 int Engine::indexOfMeetingAfter( Room *aRoom, QDateTime aAfter )
131 {
132 //      qDebug() << "Engine::indexOfMeetingAfter( Room *, QDateTime )";
133         // seeks for the next meeting on the SAME DAY
134         int min = -1;
135         for ( int i = 0; i < iMeetings.count(); i++ )
136         {
137                 // if the meeting is in the same room, on the same day but after the specified time
138                 if ( aRoom->equals( iMeetings.at( i )->room() )
139                           && iMeetings.at( i )->startsAt().date() == aAfter.date()
140                           && 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
144                                   || iMeetings.at( min )->startsAt() > iMeetings.at( i )->startsAt() )
145                         {
146                                 min = i;
147                         }
148                 }
149         }
150         return min;
151 }
152
153 void Engine::roomStatusInfoNeeded( Room *aRoom )
154 {
155 //      qDebug() << "Engine::roomStatusInfoNeeded( Room * )";
156         if ( aRoom == 0 )
157         {
158                 return;
159         }
160
161         int indexOfCurrentMeeting = indexOfMeetingAt( aRoom, iClock->datetime() );
162         int indexOfNextMeeting = indexOfMeetingAfter( aRoom, iClock->datetime() );
163
164         // if there is no meeting, then status is Free; otherwise Busy
165         Room::Status status = ( indexOfCurrentMeeting == -1 ) ? Room::FreeStatus : Room::BusyStatus;
166         // if room is Busy, then check end time, otherwise...
167         QTime until = ( status == Room::BusyStatus ) ? iMeetings.at( indexOfCurrentMeeting )->endsAt().time() :
168                           // ...if there is meeting following on the same day then check end time, otherwise end is the of the working day
169                           (( indexOfNextMeeting != -1 ) ? iMeetings.at( indexOfNextMeeting )->startsAt().time() : Engine::endOfTheDay );
170
171         //currently works only for deafult room
172 //      if( aRoom->equals( *(defaultRoom() ) ) )
173 //              iWindowManager->roomStatusChanged( aRoom, status, until );
174 }
175
176 void Engine::fetchMeetings()
177 {
178         Room *room = defaultRoom();
179         qDebug() << "Engine::fetchMeetings for " << room->name();
180         fetchMeetings( iClock->datetime(), iClock->datetime().addDays( 7 ), room );
181 }
182
183 void Engine::fetchMeetingDetails( Meeting *aMeeting )
184 {
185         qDebug() << "Engine::fetchMeetingDetails( Meeting* )";
186 //      iWindowManager->showProgressBar( tr("Please Wait"), true );
187 //      iWindowManager->updateProgressBar( tr("Fetching Meeting Details...") );
188 /*      connect( iWindowManager,
189                          SIGNAL( progressBarCancelled() ),
190                          this,
191                          SLOT( fetchMeetingDetailsCancelled() )
192                         ); */
193         iCommunication->fetchMeetingDetails( *aMeeting );
194 }
195
196 bool Engine::isMeetingInList( const QList<Meeting*> &aList, const Meeting *aMeeting )
197 {
198         qDebug() << "Engine::isMeetingInList( const QList<Meeting*> &, const Meeting * )";
199         for ( int i = 0; i < aList.count(); i++ )
200         {
201                 if ( aMeeting->equals( *(aList.at( i )) ) )
202                 {
203                         return true;
204                 }
205         }
206         return false;
207 }
208
209 void Engine::meetingsFetched( const QList<Meeting*> &aMeetings )
210 {
211         qDebug() << "Engine::meetingsFetched( const QList<Meeting*> & )";
212         // check if there is any new meeting in the list came from the server -> added
213         for ( int i = 0; i < aMeetings.count(); i++ )
214         {
215                 // if the (i)th meeting is not in the local meeting list
216                 if ( !isMeetingInList( iMeetings, aMeetings.at( i ) ) )
217                 {
218                         // add to the local database =)
219                         Meeting* m = new Meeting( *(aMeetings.at( i )) );
220                         iMeetings.append( m );
221                         // and signal the changes
222 //                      iWeeklyView->insertMeeting( m );
223                 }
224         }
225
226         // check if there is any meeting NOT in the list came from the server -> deleted
227         for ( int i = 0; i < iMeetings.count(); i++ )
228         {
229                 // if the (i)th meeting is in the local but NOT in the server's meeting list
230                 if ( !isMeetingInList( aMeetings, iMeetings.at( i ) ) )
231                 {
232                         Meeting* m = iMeetings.takeAt( i );
233                         // signal the changes
234 //                      iWeeklyView->deleteMeeting( m );
235                         // delete the meeting from the local list
236                         delete m;
237                 }
238         }
239
240         // refresh room status info
241         roomStatusInfoNeeded( defaultRoom() );
242 }
243
244 void Engine::errorHandler( int aCode, const QString &aAddInfo )
245 {
246         qDebug() << "Engine::ErrorHandler, aCode: " << aCode;
247         // inform UI about the problem
248         if( aCode >= 100 && aCode <= 150 )
249                 qDebug() << "CommunicationManager signaled an error:" << aCode;
250         // iWindowManager->closeProgressBar();
251         // iWindowManager->error( ErrorMapper::codeToString( aCode, aAddInfo ) );
252 }
253
254 void Engine::fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, const Room *aIn )
255 {
256         qDebug() << "Engine::fetchMeetings( const QDateTime &, const QDateTime &, const Room * )";
257         iCommunication->fetchMeetings( aFrom, aUntil, *aIn );
258 }
259
260 void Engine::shownWeekChanged( QDate aFrom )
261 {
262         qDebug() << "Engine::shownWeekChanged( QDate )";
263         QDateTime from( aFrom );
264         QDateTime to( aFrom.addDays( 7 ), QTime( 23, 59 ) );
265         qDebug() << "Engine::shownWeekChanged " << aFrom.toString( "d.m. h:mm" ) << " to " << to.toString( "d.m. h:mm" );
266 //      fetchMeetings( from, to, iWindowManager->weeklyView()->currentRoom() );
267 }
268
269 void Engine::passwordEntered( PasswordDialog::PasswordStatus aPasswordStatus )
270 {
271         qDebug() << "Engine::passwordEntered( PasswordDialog::PasswordStatus )";
272 //      iWindowManager->closePasswordDialog();
273         
274         switch ( aPasswordStatus )
275         {
276                 case PasswordDialog::Correct :
277                 {
278                         connect( iDevice, SIGNAL( changingModeFailed() ), this, SLOT( progressBarCancelled() ) );
279                         iDevice->changeMode( true );
280                         break;
281                 }
282                 case PasswordDialog::Incorrect :
283                 {
284 //                      iWindowManager->error( tr( "Incorrect password." ) );
285                         iDevice->changeMode( false );
286                         break;
287                 }
288                 default : //case PasswordDialog::Canceled
289                 {
290                         iDevice->changeMode( false );
291                 }
292         }
293 }
294
295 void Engine::progressBarCancelled()
296 {
297         qDebug() << "Engine::progressBarCancelled()";
298         iDevice->changeMode( false );
299 }
300
301 void Engine::initUserInterface()
302 {
303         qDebug() << "[Engine::initUserInterface] <Invoked>";
304         
305         // Initialize the window manager and connect what ever signals can be connected
306         iWindowManager = new WindowManager;
307         // Create the UIManager which internally handles most of the UI actions
308         iUIManager = new UIManager( this, iWindowManager );
309         
310         connect( iWindowManager, SIGNAL( eventDetected() ), this, SLOT( handleViewEvent() ) );
311         connect( iWindowManager, SIGNAL( previousViewRestored() ), iUIManager, SLOT( previousViewRestored() ) );
312         connect( iWindowManager, SIGNAL( dialogActivated() ), this, SLOT( dialogActivated() ) );
313         connect( iWindowManager, SIGNAL( dialogDeactivated() ), this, SLOT( dialogDeactivated() ) );
314         
315         // Show the UI
316         iWindowManager->setWindowState( Qt::WindowMaximized );
317         iWindowManager->show();
318         iUIManager->showMainView();
319         
320         qDebug() << "[Engine::initUserInterface] <Finished>";
321 }
322
323 void Engine::handleViewEvent()
324 {
325         if ( iIdleTimeCounter != 0 )
326         {
327                 // Restart the idle time counter when view event is received
328                 iIdleTimeCounter->stop();
329                 iIdleTimeCounter->start();
330         }
331 }
332
333 void Engine::initConfiguration()
334 {
335         iConfiguration = Configuration::instance();
336         if ( iConfiguration == 0 )
337         {
338                 QTimer::singleShot( 0, this, SLOT( closeApplication() ) );
339         }
340 }
341
342 void Engine::connectSignals()
343 {
344         // Connect engine objects signals to UIManager
345         connect( iClock, SIGNAL( tick( QDateTime ) ), iUIManager, SLOT( updateTime( QDateTime ) ) );
346         connect( iIdleTimeCounter, SIGNAL( timeout() ) , iUIManager, SLOT( roomStatusIndicatorRequested() ) );
347         
348         iUIManager->connectDeviceManager( iDevice );
349         iUIManager->connectCommunicationManager( iCommunication );
350 }
351
352 void Engine::initCommunication()
353 {
354         // initialize communication
355         iCommunication = new CommunicationManager( *(iConfiguration->connectionSettings()) );
356         connect( iCommunication, SIGNAL( error( int, CommunicationManager::CommunicationType  ) ),
357                         this, SLOT( errorHandler( int ) ) );
358         connect( iCommunication, SIGNAL( meetingsFetched( const QList<Meeting*>& ) ),
359                         this, SLOT( meetingsFetched( const QList<Meeting*>& ) ) );
360 }
361
362 void Engine::initDevice()
363 {
364         // create device manager
365         iDevice = new DeviceManager( iConfiguration->startupSettings() );
366         connect( iDevice, SIGNAL( error( int, const QString& ) ), this, SLOT( errorHandler( int, const QString& ) ) );  
367         iDevice->initDeviceManager();
368 }
369
370 void Engine::dialogActivated()
371 {
372         if ( iIdleTimeCounter != 0 )
373         {
374                 iIdleTimeCounter->stop();
375         }
376 }
377
378 void Engine::dialogDeactivated()
379 {
380         if ( iIdleTimeCounter != 0 )
381         {
382                 iIdleTimeCounter->start();
383         }
384 }
385
386 void Engine::previousViewRestored()
387 {
388         if ( iIdleTimeCounter != 0 )
389         {
390                 iIdleTimeCounter->start();
391         }
392 }
393
394 void Engine::fetchMeetingDetailsCancelled()
395 {
396         iCommunication->cancelFetchMeetingDetails();
397 //      iWindowManager->closeProgressBar();
398 }
399
400 void Engine::stopIdleTimeCounter()
401 {
402         if ( iIdleTimeCounter != 0 )
403         {
404                 iIdleTimeCounter->stop();
405         }
406 }
407
408 void Engine::startIdleTimeCounter()
409 {
410         if ( iIdleTimeCounter != 0 )
411         {
412                 iIdleTimeCounter->start();
413         }
414 }