reimplemented 'import schedule'
[toast/confclerk.git] / src / gui / mainwindow.cpp
1 #include "mainwindow.h"
2 #include <appsettings.h>
3
4 #include <QTreeView>
5 #include <QDirModel>
6
7 #include <sqlengine.h>
8
9 #include <track.h>
10 #include <eventmodel.h>
11 #include <delegate.h>
12
13 #include <conference.h>
14
15 #include <QDialog>
16 #include <QMessageBox>
17 #include <QTimer>
18 #include "ui_about.h"
19 #include "eventdialog.h"
20 #include "daynavigatorwidget.h"
21 #include "importschedulewidget.h"
22 #include "mapwindow.h"
23
24 MainWindow::MainWindow(int aEventId, QWidget *aParent)
25     : QMainWindow(aParent)
26 {
27     setupUi(this);
28
29     // create "SQLITE" DB instance/connection
30     // opens DB connection (needed for EventModel)
31     mSqlEngine = new SqlEngine(this);
32     mSqlEngine->initialize();
33     importScheduleWidget->setSqlEngine(mSqlEngine);
34
35     // Sanity check for existence of any Conference in the DB
36     // it AppSettings::confId() is 0, but there are any Conference(s) in the DB
37     // set the confId in the AppSettings for the ID of the first conference in the DB
38     QList<Conference> confs = Conference::getAll();
39     if(!confs.count()) // no conference(s) in the DB
40     {
41         AppSettings::setConfId(0); // no conference in the DB
42     }
43     else
44     {
45         if(AppSettings::confId() == 0)
46             AppSettings::setConfId(confs[0].id());
47
48         setWindowTitle(confs[0].title());
49     }
50
51     connect(importScheduleWidget, SIGNAL(scheduleImported(int)), SLOT(scheduleImported(int)));
52
53     connect(dayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateDayView(const QDate &)));
54     connect(trackDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateTracksView(const QDate &)));
55     connect(favouriteDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateFavouritesView(const QDate &)));
56     connect(searchDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateSearchView(const QDate &)));
57     connect(roomDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateRoomView(const QDate &)));
58
59     // DAY EVENTS View
60     dayTreeView->setHeaderHidden(true);
61     dayTreeView->setRootIsDecorated(false);
62     dayTreeView->setIndentation(0);
63     dayTreeView->setAnimated(true);
64     dayTreeView->setModel(new EventModel());
65     dayTreeView->setItemDelegate(new Delegate(dayTreeView));
66
67     // FAVOURITIES View
68     favTreeView->setHeaderHidden(true);
69     favTreeView->setRootIsDecorated(false);
70     favTreeView->setIndentation(0);
71     favTreeView->setAnimated(true);
72     favTreeView->setModel(new EventModel());
73     favTreeView->setItemDelegate(new Delegate(favTreeView));
74
75     // TRACKS View
76     trackTreeView->setHeaderHidden(true);
77     trackTreeView->setRootIsDecorated(false);
78     trackTreeView->setIndentation(0);
79     trackTreeView->setAnimated(true);
80     trackTreeView->setModel(new EventModel());
81     trackTreeView->setItemDelegate(new Delegate(trackTreeView));
82
83     // SEARCH EVENTS View
84         searchTreeView->setHeaderHidden(true);
85         searchTreeView->setRootIsDecorated(false);
86         searchTreeView->setIndentation(0);
87         searchTreeView->setAnimated(true);
88         searchTreeView->setModel(new EventModel());
89         searchTreeView->setItemDelegate(new Delegate(searchTreeView));
90
91     // NOW View
92         nowTreeView->setHeaderHidden(true);
93         nowTreeView->setRootIsDecorated(false);
94         nowTreeView->setIndentation(0);
95         nowTreeView->setAnimated(true);
96         nowTreeView->setModel(new EventModel());
97         nowTreeView->setItemDelegate(new Delegate(nowTreeView));
98
99         // NOW View refresh timer
100     QTimer *timer = new QTimer( this );
101     connect( timer, SIGNAL(timeout()), SLOT(timerUpdateNowView()) );
102     timer->start( 30000); // 30 seconds timer
103
104     // ROOMS View
105     roomTreeView->setHeaderHidden(true);
106     roomTreeView->setRootIsDecorated(false);
107     roomTreeView->setIndentation(0);
108     roomTreeView->setAnimated(true);
109     roomTreeView->setModel(new EventModel());
110     roomTreeView->setItemDelegate(new Delegate(roomTreeView));
111
112     // event details have changed
113     connect(dayTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
114     connect(favTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
115     connect(trackTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
116     connect(searchTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
117     connect(nowTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
118     connect(roomTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
119
120     // event clicked
121     connect(dayTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
122     connect(favTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
123     connect(trackTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
124     connect(searchTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
125     connect(nowTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
126     connect(roomTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
127     // request for map to be displayed
128     connect(dayTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
129     connect(favTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
130     connect(trackTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
131     connect(searchTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
132     connect(nowTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
133     connect(roomTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
134     // request for warning to be displayed
135     connect(dayTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
136     connect(favTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
137     connect(trackTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
138     connect(searchTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
139     connect(nowTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
140     connect(roomTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
141     // event search button clicked
142     connect(searchButton, SIGNAL(clicked()), SLOT(searchClicked()));
143     connect(searchAgainButton, SIGNAL(clicked()), SLOT(searchAgainClicked()));
144     // event conference map button clicked
145     connect(showMapButton, SIGNAL(clicked()), SLOT(conferenceMapClicked()));
146     //
147     connect(tabWidget, SIGNAL(currentChanged(int)), SLOT(tabHasChanged(int)));
148     connect(tabWidget, SIGNAL(infoIconClicked()), SLOT(aboutApp()));
149
150     if(!Conference::getAll().count()) // no conference(s) in the DB
151     {
152         dayNavigator->hide(); // hide DayNavigatorWidget
153         trackDayNavigator->hide();
154         roomDayNavigator->hide();
155     }
156     else
157     {
158         QDate aStartDate = Conference::getById(AppSettings::confId()).start();
159         QDate aEndDate = Conference::getById(AppSettings::confId()).end();
160         dayNavigator->setDates(aStartDate, aEndDate);
161         trackDayNavigator->setDates(aStartDate, aEndDate);
162         favouriteDayNavigator->setDates(aStartDate, aEndDate);
163         searchDayNavigator->setDates(aStartDate, aEndDate);
164         roomDayNavigator->setDates(aStartDate, aEndDate);
165         //
166         conferenceTitle->setText(Conference::getById(AppSettings::confId()).title());
167         conferenceSubtitle->setText(Conference::getById(AppSettings::confId()).subtitle());
168         conferenceWhere->setText(Conference::getById(AppSettings::confId()).city() + ", " + Conference::getById(AppSettings::confId()).venue());
169         conferenceWhen->setText(
170                 Conference::getById(AppSettings::confId()).start().toString("dd-MM-yyyy")
171                 + ", " +
172                 Conference::getById(AppSettings::confId()).end().toString("dd-MM-yyyy"));
173     }
174
175     searchTreeView->hide();
176     searchVerticalWidget->hide();
177     searchHead->show();
178
179     // open dialog for given Event ID
180     // this is used in case Alarm Dialog request application to start
181     if(aEventId)
182     {
183         try
184         {
185             EventDialog dialog(aEventId,this);
186             dialog.exec();
187         }
188         catch(OrmNoObjectException&) {} // just start application
189         catch(...) {} // just start application
190     }
191 }
192
193 MainWindow::~MainWindow()
194 {
195     if(mSqlEngine)
196     {
197         delete mSqlEngine;
198         mSqlEngine = NULL;
199     }
200 }
201
202 void MainWindow::scheduleImported(int aConfId)
203 {
204     Q_UNUSED(aConfId);
205
206     QList<Conference> confs = Conference::getAll();
207     if(!confs.count()) // no conference(s) in the DB
208     {
209         AppSettings::setConfId(0); // no conference in the DB
210     }
211     else
212     {
213         if(AppSettings::confId() == 0)
214             AppSettings::setConfId(confs[0].id());
215
216         // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
217         QDate aStartDate = Conference::getById(AppSettings::confId()).start();
218         QDate aEndDate = Conference::getById(AppSettings::confId()).end();
219         dayNavigator->setDates(aStartDate, aEndDate);
220         trackDayNavigator->setDates(aStartDate, aEndDate);
221         roomDayNavigator->setDates(aStartDate, aEndDate);
222     }
223 }
224
225 void MainWindow::aboutApp()
226 {
227     QDialog dialog(this);
228     Ui::AboutDialog ui;
229     ui.setupUi(&dialog);
230     dialog.exec();
231 }
232
233 void MainWindow::updateDayView(const QDate &aDate)
234 {
235     static_cast<EventModel*>(dayTreeView->model())->loadEvents(aDate,AppSettings::confId());
236     dayTreeView->reset();
237     dayNavigator->show();
238 }
239
240 void MainWindow::updateTracksView(const QDate &aDate)
241 {
242     static_cast<EventModel*>(trackTreeView->model())->loadEventsByTrack(aDate, AppSettings::confId());
243     trackTreeView->reset();
244     trackDayNavigator->show();
245 }
246
247 void MainWindow::updateFavouritesView(const QDate &aDate)
248 {
249     static_cast<EventModel*>(favTreeView->model())->loadFavEvents(aDate,AppSettings::confId());
250     favTreeView->reset();
251     favouriteDayNavigator->show();
252 }
253
254 void MainWindow::updateSearchView(const QDate &aDate)
255 {
256     qDebug() << "MainWindow::updateSearchView(), aDate: " << aDate.toString() ;
257     searchTreeView->reset();
258     int eventsCount = static_cast<EventModel*>(searchTreeView->model())->loadSearchResultEvents(aDate,AppSettings::confId());
259     if( eventsCount ||
260             searchDayNavigator->getCurrentDate() != Conference::getById(AppSettings::confId()).start() ){
261         searchVerticalWidget->show();
262         //searchAgainButton->show();
263         searchTreeView->show();
264         searchHead->hide();
265     }
266     else{
267         searchTreeView->hide();
268         searchVerticalWidget->hide();
269         searchHead->show();
270     }
271 }
272
273 void MainWindow::updateNowView()
274 {
275     EventModel *model = static_cast<EventModel*>(nowTreeView->model());
276     model->loadNowEvents(AppSettings::confId());
277     nowTreeView->reset();
278     nowTreeView->setAllExpanded(true);
279 }
280
281 void MainWindow::updateRoomView(const QDate &aDate)
282 {
283     static_cast<EventModel*>(roomTreeView->model())->loadEventsByRoom(aDate, AppSettings::confId());
284     roomTreeView->reset();
285     roomDayNavigator->show();
286 }
287
288 void MainWindow::itemClicked(const QModelIndex &aIndex)
289 {
290     // have to handle only events, not time-groups
291     if(!aIndex.parent().isValid()) // time-group
292         return;
293
294     EventDialog dialog(static_cast<Event*>(aIndex.internalPointer())->id(),this);
295     dialog.exec();
296 }
297
298 void MainWindow::displayMap(const QModelIndex &aIndex)
299 {
300     Event *event = static_cast<Event*>(aIndex.internalPointer());
301
302     // room names are stored in lower-case format
303     // room names are stored without dots in the name, eg. "aw.1124.png" -> "aw1124.png"
304     QString mapPath = QString(":/maps/rooms/%1.png").arg(event->room().toLower().remove("."));
305     if(!QFile::exists(mapPath))
306         mapPath = QString(":/maps/rooms/not-available.png");
307
308     QString roomName;
309     if(mapPath.contains("not-available", Qt::CaseInsensitive))
310         roomName = QString("Map is not available: %1").arg(event->room());
311     else
312         roomName = event->room();
313
314     QPixmap map(mapPath);
315     MapWindow window(map,roomName,this);
316     window.exec();
317 }
318
319 void MainWindow::searchClicked()
320 {
321     QHash<QString,QString> columns;
322
323     if( searchTitle->isChecked() )
324         columns.insertMulti("EVENT", "title");
325     if( searchAbstract->isChecked() )
326         columns.insertMulti("EVENT", "abstract");
327     if( searchTag->isChecked() )
328         columns.insertMulti("EVENT", "tag");
329     if( searchSpeaker->isChecked() )
330         columns["PERSON"] = "name";
331     if( searchRoom->isChecked() )
332         columns["ROOM"] = "name";
333
334     QString keyword = searchEdit->text().replace( QString("%"), QString("\\%") );
335     qDebug() << "\nKeyword to search: " << keyword;
336     mSqlEngine->searchEvent( AppSettings::confId(), columns, keyword );
337
338     QDate aStartDate = Conference::getById(AppSettings::confId()).start();
339     QDate aEndDate = Conference::getById(AppSettings::confId()).end();
340     searchDayNavigator->setDates(aStartDate, aEndDate);
341     updateSearchView( Conference::getById(AppSettings::confId()).start() );
342 }
343
344 void MainWindow::searchAgainClicked()
345 {
346     searchHead->show();
347     //searchAgainButton->hide();
348     searchVerticalWidget->hide();
349     searchTreeView->hide();
350
351 }
352
353 void MainWindow::conferenceMapClicked()
354 {
355
356     QString mapPath = QString(":/maps/campus.png");
357     if(!QFile::exists(mapPath))
358         mapPath = QString(":/maps/rooms/not-available.png");
359
360     QString roomName;
361
362     QPixmap map(mapPath);
363     MapWindow window(map,roomName,this);
364     window.exec();
365 }
366
367 void MainWindow::displayWarning(const QModelIndex &aIndex)
368 {
369     Q_UNUSED(aIndex);
370
371     QMessageBox::warning(
372     this,
373     tr("Time Conflict Warning"),
374     tr("This event happens at the same time than another one of your favourites.") );
375 }
376
377 void MainWindow::eventHasChanged(int aEventId)
378 {
379     static_cast<EventModel*>(dayTreeView->model())->updateModel(aEventId);
380
381     // we need to reload favourites, because some favourite could be deleted
382     //static_cast<EventModel*>(favTreeView->model())->updateModel(aEventId);
383     QDate aStartDate = Conference::getById(AppSettings::confId()).start();
384     QDate aEndDate = Conference::getById(AppSettings::confId()).end();
385     favouriteDayNavigator->setDates(aStartDate, aEndDate);
386     updateFavouritesView( Conference::getById(AppSettings::confId()).start() );
387
388     static_cast<EventModel*>(trackTreeView->model())->updateModel(aEventId);
389     static_cast<EventModel*>(searchTreeView->model())->updateModel(aEventId);
390     static_cast<EventModel*>(nowTreeView->model())->updateModel(aEventId);
391     static_cast<EventModel*>(roomTreeView->model())->updateModel(aEventId);
392 }
393
394 void MainWindow::tabHasChanged(int aIndex)
395 {
396     Q_UNUSED(aIndex);
397
398     // TODO: only if it changed to favourities tab
399     updateFavouritesView(favouriteDayNavigator->getCurrentDate());
400     // TODO: only if it changed to now tab
401     updateNowView();
402 }
403
404 void MainWindow::timerUpdateNowView()
405 {
406         QWidget * pCurrentWidget = tabWidget->widget(tabWidget->currentIndex());
407
408         if( pCurrentWidget != NULL )
409         {
410                 if( pCurrentWidget == tab )
411                     updateNowView();
412         }
413 }