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