Auto refresh of meetings showed wrong meetings (Task id 1166)
[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 "WeeklyViewWidget.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 Engine::Engine() :
22         iClock( 0), iConfiguration(Configuration::instance() ), iCommunication( 0)
23 {
24         qDebug() << "Engine::Engine()";
25         // if reading of configuration fails, signal that initialization failed
26         if (iConfiguration == 0)
27         {
28                 QTimer::singleShot( 0, this, SLOT( closeApplication() ));
29                 return;
30         }
31
32         //initialize window manager
33         iWindowManager = new WindowManager( iConfiguration );
34         connect(iWindowManager, SIGNAL( roomStatusInfoNeeded( Room * ) ), this, SLOT( roomStatusInfoNeeded( Room * ) ));
35         connect(iWindowManager, SIGNAL( observedEventDetected() ), this, SLOT( observedEventDetected() ));
36         connect(iWindowManager, SIGNAL( meetingActivated( Meeting * ) ), this, SLOT( fetchMeetingDetails( Meeting * ) ));
37         connect(iWindowManager, SIGNAL( currentRoomChanged( Room * ) ), this, SLOT( currentRoomChanged( Room * ) ));
38         connect(iWindowManager, SIGNAL( shownWeekChanged( QDate ) ), this, SLOT( shownWeekChanged( QDate ) ));
39         connect(iWindowManager, SIGNAL( passwordEntered( PasswordDialog::PasswordStatus ) ), this, SLOT( passwordEntered( PasswordDialog::PasswordStatus ) ));
40
41         // initialize communication
42         iCommunication = new CommunicationManager( *(iConfiguration->connectionSettings()) );
43         connect(iCommunication, SIGNAL( error( int, CommunicationManager::CommunicationType ) ), this, SLOT( errorHandler( int ) ));
44         connect(iCommunication, SIGNAL( meetingsFetched( const QList<Meeting*>& ) ), this, SLOT( meetingsFetched( const QList<Meeting*>& ) ));
45         connect(iCommunication, SIGNAL( meetingDetailsFetched( Meeting& ) ), this, SLOT( meetingDetailsFetched( Meeting& ) ));
46
47         //initialize idle time counter
48         iIdleTimeCounter = new QTimer();
49         iIdleTimeCounter->setSingleShot( true);
50         iIdleTimeCounter->setInterval(IDLE_TIME_MULTIPLIER * iConfiguration->displaySettings()->screensaver() );
51         iIdleTimeCounter->start();
52         connect(iIdleTimeCounter, SIGNAL( timeout() ), iWindowManager, SLOT( showRoomStatus() ));
53
54         // create application clock
55         iClock = new Clock;
56         connect(iClock, SIGNAL( tick( QDateTime ) ), this, SLOT( checkStatusOfAllRooms() ));
57         connect(iClock, SIGNAL( tick( QDateTime ) ), iWindowManager, SLOT( distributeDateTimeInfo( QDateTime ) ));
58
59         iAutoRefresh = new QTimer;
60         iAutoRefresh->setInterval(iConfiguration->connectionSettings()->refreshInterval() * 1000);
61         iAutoRefresh->start();
62         connect(iAutoRefresh, SIGNAL( timeout() ), iAutoRefresh, SLOT( start() ));
63         connect(iAutoRefresh, SIGNAL( timeout() ), this, SLOT( fetchMeetings() ));
64
65         // create device manager
66         iDevice = new DeviceManager( iConfiguration->startupSettings() );
67         connect(iDevice, SIGNAL( error( int, const QString& ) ), this, SLOT( errorHandler( int, const QString& ) ));
68         connect(iDevice, SIGNAL( changeModeOrdered( DeviceManager::OperationMode ) ), this, SLOT( changeModeOrdered( DeviceManager::OperationMode ) ));
69         iDevice->initDeviceManager();
70
71         if (iDevice->currentOperationMode() == DeviceManager::KioskMode)
72                 iWindowManager->fullScreen();
73
74         QTimer::singleShot( 0, this, SLOT( fetchMeetings() ));
75
76         // TODO: continue implementation
77 }
78
79 Engine::~Engine()
80 {
81         qDebug() << "Engine::~Engine()";
82         while ( !iMeetings.isEmpty() )
83                 delete iMeetings.takeFirst();
84         iIdleTimeCounter->stop();
85         delete iIdleTimeCounter;
86         iIdleTimeCounter = 0;
87         delete iWindowManager;
88         iWindowManager = 0;
89         delete iClock;
90         iClock = 0;
91         delete iDevice;
92         iDevice = 0;
93 }
94
95 void Engine::closeApplication()
96 {
97         qDebug() << "Engine::closeApplication()";
98         // closes application after 1 second
99         QTimer::singleShot( 1000, QApplication::instance(), SLOT( quit() ));
100 }
101
102 void Engine::observedEventDetected()
103 {
104         qDebug() << "Engine::observedEventDetected()";
105
106         if ( !iIdleTimeCounter->isActive() )
107         {
108                 iWindowManager->weeklyView()->showCurrentWeek();
109         }
110         iWindowManager->showWeeklyView();
111         // prepare to restart idle counter
112         if (iIdleTimeCounter->isActive() )
113         {
114                 iIdleTimeCounter->stop();
115         }
116         // (re)start idle counter
117         iIdleTimeCounter->start();
118 }
119
120 Room* Engine::defaultRoom()
121 {
122         qDebug() << "Engine::defaultRoom()";
123         return iConfiguration->defaultRoom();
124 }
125
126 void Engine::checkStatusOfAllRooms()
127 {
128         qDebug() << "Engine::checkStatusOfAllRooms()";
129         // iterate trough on the rooms
130         for (int i = 0; i < iConfiguration->rooms().count(); i++)
131         {
132                 // and check the status
133                 roomStatusInfoNeeded(iConfiguration->rooms().at(i) );
134         }
135 }
136
137 int Engine::indexOfMeetingAt(Room *aRoom, QDateTime aAt)
138 {
139         qDebug() << "Engine::indexOfMeetingAt( Room *, QDateTime )";
140         for (int i = 0; i < iMeetings.count(); i++)
141         {
142                 // exchange server ensures that there is only one meeting in a room at a specified time
143                 if (aRoom->equals(iMeetings.at( i )->room() ) && iMeetings.at( i )->startsAt() <= aAt && iMeetings.at( i )->endsAt() >= aAt)
144                 {
145                         return i;
146                 }
147         }
148         return -1;
149 }
150
151 int Engine::indexOfMeetingAfter(Room *aRoom, QDateTime aAfter)
152 {
153         qDebug() << "Engine::indexOfMeetingAfter( Room *, QDateTime )";
154         // seeks for the next meeting on the SAME DAY
155         int min = -1;
156         for (int i = 0; i < iMeetings.count(); i++)
157         {
158                 // if the meeting is in the same room, on the same day but after the specified time
159                 if (aRoom->equals(iMeetings.at( i )->room() ) && iMeetings.at( i )->startsAt().date() == aAfter.date() && iMeetings.at( i )->startsAt() > aAfter)
160                 {
161                         // if there was not any meeting find yet or the previously found is a later one then the (i)th
162                         if (min == -1 || iMeetings.at( min )->startsAt() > iMeetings.at( i )->startsAt() )
163                         {
164                                 min = i;
165                         }
166                 }
167         }
168         return min;
169 }
170
171 void Engine::roomStatusInfoNeeded(Room *aRoom)
172 {
173         qDebug() << "Engine::roomStatusInfoNeeded( Room * )";
174         if (aRoom == 0)
175         {
176                 return;
177         }
178
179         int indexOfCurrentMeeting = indexOfMeetingAt(aRoom, iClock->datetime() );
180         int indexOfNextMeeting = indexOfMeetingAfter(aRoom, iClock->datetime() );
181
182         // if there is no meeting, then status is Free; otherwise Busy
183         Room::Status status = (indexOfCurrentMeeting == -1 ) ? Room::FreeStatus : Room::BusyStatus;
184         // if room is Busy, then check end time, otherwise...
185         QTime until = (status == Room::BusyStatus ) ? iMeetings.at( indexOfCurrentMeeting )->endsAt().time() :
186         // ...if there is meeting following on the same day then check end time, otherwise end is the of the working day
187         ( ( indexOfNextMeeting != -1 ) ? iMeetings.at( indexOfNextMeeting )->startsAt().time() : Engine::endOfTheDay );
188
189         //currently works only for deafult room
190         if (aRoom->equals( *(defaultRoom() )) )
191                 iWindowManager->roomStatusChanged(aRoom, status, until);
192 }
193
194 void Engine::fetchMeetings()
195 {
196         qDebug() << "Engine::fetchMeetings for " << iWindowManager->weeklyView()->currentRoom();
197         QDateTime from( iWindowManager->weeklyView()->beginnigOfShownWeek() );
198         QDateTime to( from.addDays( 7 ) );
199         fetchMeetings( from, to, iWindowManager->weeklyView()->currentRoom() );
200 }
201
202 void Engine::fetchMeetingDetails( Meeting *aMeeting )
203 {
204         qDebug() << "Engine::fetchMeetingDetails( Meeting* )";
205         iWindowManager->showProgressBar( tr( "Please Wait" ), true );
206         iWindowManager->updateProgressBar( tr( "Fetching Meeting Details..." ) );
207         connect(iWindowManager, SIGNAL( progressBarCancelled() ), this, SLOT( fetchMeetingDetailsCancelled() ));
208         iCommunication->fetchMeetingDetails( *aMeeting );
209 }
210
211 void Engine::meetingsFetched( const QList<Meeting*> &aMeetings )
212 {
213         qDebug() << "Engine::meetingsFetched( const QList<Meeting*> & )";
214         
215         for ( int i = 0; i < iMeetings.count(); ++i ) {
216                 Meeting* m = iMeetings.takeAt( i );
217                 delete m;
218         }
219         iMeetings.clear();
220         for ( int i = 0; i < aMeetings.count(); ++i ) {
221                 Meeting* m = new Meeting( *( aMeetings.at( i ) ) );
222                 iMeetings.append( m );
223         }
224
225         iWindowManager->refreshMeetings( iMeetings );
226         // refresh room status info
227         roomStatusInfoNeeded( defaultRoom() );
228 }
229
230 void Engine::meetingDetailsFetched( Meeting &aDetailedMeeting )
231 {
232         qDebug() << "Engine::meetingDetailsFetched( Meeting & )";
233         iWindowManager->closeProgressBar();
234         iWindowManager->showMeetingInfo( &aDetailedMeeting );
235 }
236
237 void Engine::errorHandler( int aCode, const QString &aAddInfo )
238 {
239         qDebug() << "Engine::ErrorHandler, aCode: " << aCode;
240         // inform UI about the problem
241         if( aCode >= 100 && aCode <= 150 ) { //communication errors
242                 //we don't want these to close operation changing
243                 qDebug() << "CommunicationManager signaled an error:" << aCode;
244                 iWindowManager->closeProgressBar();
245         }
246         iWindowManager->error( ErrorMapper::codeToString(aCode, aAddInfo ) );
247 }
248
249 void Engine::currentRoomChanged( Room *aCurrentRoom )
250 {
251         qDebug() << "Engine::currentRoomChanged to " << aCurrentRoom->name();
252         QDateTime from(iWindowManager->weeklyView()->beginnigOfShownWeek() );
253         QDateTime to( from.addDays( 7 ) );
254         fetchMeetings( from, to, aCurrentRoom );
255 }
256
257 void Engine::fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, const Room *aIn )
258 {
259         qDebug() << "Engine::fetchMeetings( const QDateTime &, const QDateTime &, const Room * )";
260         iCommunication->fetchMeetings( aFrom, aUntil, *aIn );
261 }
262
263 void Engine::shownWeekChanged( QDate aFrom )
264 {
265         qDebug() << "Engine::shownWeekChanged( QDate )";
266         QDateTime from( aFrom );
267         QDateTime to( aFrom.addDays( 7 ), QTime( 23, 59 ) );
268         qDebug() << "Engine::shownWeekChanged " << aFrom.toString( "d.m. h:mm" ) << " to " << to.toString( "d.m. h:mm" );
269         fetchMeetings( from, to, iWindowManager->weeklyView()->currentRoom() );
270 }
271
272 void Engine::changeModeOrdered( DeviceManager::OperationMode aMode )
273 {
274         qDebug() << "Engine::changeModeOrdered( DeviceManager::OperationMode )";
275         QString message = tr( "You are about to change operation mode to %1." ).arg( iDevice->operationModeToString(aMode ) );
276
277         iWindowManager->showPasswordDialog( iConfiguration->adminPassword(), message );
278 }
279
280 void Engine::passwordEntered( PasswordDialog::PasswordStatus aPasswordStatus )
281 {
282         qDebug() << "Engine::passwordEntered( PasswordDialog::PasswordStatus )";
283         iWindowManager->closePasswordDialog();
284
285         switch ( aPasswordStatus ) {
286                 case PasswordDialog::Correct:
287                         iAutoRefresh->stop(); //we stop the metting updating
288                         iWindowManager->showProgressBar( "Changing current operation mode." );
289                         connect(iDevice, SIGNAL( changingMode( const QString & ) ), iWindowManager, SLOT( updateProgressBar( const QString & ) ));
290                         connect( iDevice, SIGNAL( changingMode( const QString & ) ),
291                                         iWindowManager, SLOT( updateProgressBar( const QString & ) ) );
292                         connect( iDevice, SIGNAL( changeModeFailed() ), this, SLOT( changeModeFailed() ) );
293                         iDevice->changeMode( true);
294                         break;
295                 case PasswordDialog::Incorrect:
296                         iWindowManager->error( tr( "Incorrect password." ) );
297                         iDevice->changeMode( false );
298                         break;
299                 default: //case PasswordDialog::Canceled
300                         iDevice->changeMode( false );
301         }
302 }
303
304 void Engine::changeModeFailed()
305 {
306         qDebug() << "Engine::changeModeFailed()";
307         iWindowManager->closeProgressBar();
308         iAutoRefresh->start(); //we start the metting updating
309 }
310
311 void Engine::fetchMeetingDetailsCancelled()
312 {
313         iCommunication->cancelFetchMeetingDetails();
314         iWindowManager->closeProgressBar();
315 }