Conference map
[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 "ui_about.h"
18 #include "eventdialog.h"
19 #include "daynavigatorwidget.h"
20 #include "importscheduledialog.h"
21 #include "mapwindow.h"
22
23 MainWindow::MainWindow(int aEventId, QWidget *aParent)
24     : QMainWindow(aParent)
25 {
26     setupUi(this);
27
28     // create "SQLITE" DB instance/connection
29     // opens DB connection (needed for EventModel)
30     mSqlEngine = new SqlEngine(this);
31     mSqlEngine->initialize();
32
33     // Sanity check for existence of any Conference in the DB
34     // it AppSettings::confId() is 0, but there are any Conference(s) in the DB
35     // set the confId in the AppSettings for the ID of the first conference in the DB
36     QList<Conference> confs = Conference::getAll();
37     if(!confs.count()) // no conference(s) in the DB
38     {
39         AppSettings::setConfId(0); // no conference in the DB
40     }
41     else
42     {
43         if(AppSettings::confId() == 0)
44             AppSettings::setConfId(confs[0].id());
45     }
46
47     // connect Menu actions
48     connect(actionImportSchedule, SIGNAL(triggered()), SLOT(importSchedule()));
49     connect(actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
50     connect(actionAboutApplication, SIGNAL(triggered()), SLOT(aboutApp()));
51
52     connect(dayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateDayView(const QDate &)));
53     connect(trackDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateTracksView(const QDate &)));
54     connect(favouriteDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateFavouritesView(const QDate &)));
55     connect(searchDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateSearchView(const QDate &)));
56
57     // DAY EVENTS View
58     dayTreeView->setHeaderHidden(true);
59     dayTreeView->setRootIsDecorated(false);
60     dayTreeView->setIndentation(0);
61     dayTreeView->setAnimated(true);
62     dayTreeView->setModel(new EventModel());
63     dayTreeView->setItemDelegate(new Delegate(dayTreeView));
64
65     // FAVOURITIES View
66     favTreeView->setHeaderHidden(true);
67     favTreeView->setRootIsDecorated(false);
68     favTreeView->setIndentation(0);
69     favTreeView->setAnimated(true);
70     favTreeView->setModel(new EventModel());
71     favTreeView->setItemDelegate(new Delegate(favTreeView));
72
73     // TRACKS View
74     trackTreeView->setHeaderHidden(true);
75     trackTreeView->setRootIsDecorated(false);
76     trackTreeView->setIndentation(0);
77     trackTreeView->setAnimated(true);
78     trackTreeView->setModel(new EventModel());
79     trackTreeView->setItemDelegate(new Delegate(trackTreeView));
80
81     // SEARCH EVENTS View
82         searchTreeView->setHeaderHidden(true);
83         searchTreeView->setRootIsDecorated(false);
84         searchTreeView->setIndentation(0);
85         searchTreeView->setAnimated(true);
86         searchTreeView->setModel(new EventModel());
87         searchTreeView->setItemDelegate(new Delegate(searchTreeView));
88
89     // NOW View
90         nowTreeView->setHeaderHidden(true);
91         nowTreeView->setRootIsDecorated(false);
92         nowTreeView->setIndentation(0);
93         nowTreeView->setAnimated(true);
94         nowTreeView->setModel(new EventModel());
95         nowTreeView->setItemDelegate(new Delegate(nowTreeView));
96
97     // event details have changed
98     connect(dayTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
99     connect(favTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
100     connect(trackTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
101     connect(searchTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
102     connect(nowTreeView, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
103
104     // event clicked
105     connect(dayTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
106     connect(favTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
107     connect(trackTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
108     connect(searchTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
109     connect(nowTreeView, SIGNAL(clicked(const QModelIndex &)), SLOT(itemClicked(const QModelIndex &)));
110     // request for map to be displayed
111     connect(dayTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
112     connect(favTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
113     connect(trackTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
114     connect(searchTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
115     connect(nowTreeView, SIGNAL(requestForMap(const QModelIndex &)), SLOT(displayMap(const QModelIndex &)));
116     // request for warning to be displayed
117     connect(dayTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
118     connect(favTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
119     connect(trackTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
120     connect(searchTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
121     connect(nowTreeView, SIGNAL(requestForWarning(const QModelIndex &)), SLOT(displayWarning(const QModelIndex &)));
122     // event search button clicked
123     connect(searchButton, SIGNAL(clicked()), SLOT(searchClicked()));
124     // event conference map button clicked
125     connect(showMapButton, SIGNAL(clicked()), SLOT(conferenceMapClicked()));
126     //
127     connect(tabWidget, SIGNAL(currentChanged(int)), SLOT(tabHasChanged(int)));
128
129     if(!Conference::getAll().count()) // no conference(s) in the DB
130     {
131         dayNavigator->hide(); // hide DayNavigatorWidget
132         trackDayNavigator->hide();
133     }
134     else
135     {
136         QDate aStartDate = Conference::getById(AppSettings::confId()).start();
137         QDate aEndDate = Conference::getById(AppSettings::confId()).end();
138         dayNavigator->setDates(aStartDate, aEndDate);
139         trackDayNavigator->setDates(aStartDate, aEndDate);
140         favouriteDayNavigator->setDates(aStartDate, aEndDate);
141         searchDayNavigator->setDates(aStartDate, aEndDate);
142         //
143         conferenceTitle->setText(Conference::getById(AppSettings::confId()).title());
144         conferenceSubtitle->setText(Conference::getById(AppSettings::confId()).subtitle());
145         conferenceWhere->setText(Conference::getById(AppSettings::confId()).city() + ", " + Conference::getById(AppSettings::confId()).venue());
146         conferenceWhen->setText(
147                 Conference::getById(AppSettings::confId()).start().toString("dd-MM-yyyy")
148                 + ", " +
149                 Conference::getById(AppSettings::confId()).end().toString("dd-MM-yyyy"));
150     }
151
152     searchTreeView->hide();
153     searchDayNavigator->hide();
154
155     // open dialog for given Event ID
156     // this is used in case Alarm Dialog request application to start
157     if(aEventId)
158     {
159         try
160         {
161             EventDialog dialog(aEventId,this);
162             dialog.exec();
163         }
164         catch(OrmNoObjectException&) {} // just start application
165         catch(...) {} // just start application
166     }
167 }
168
169 MainWindow::~MainWindow()
170 {
171     if(mSqlEngine)
172     {
173         delete mSqlEngine;
174         mSqlEngine = NULL;
175     }
176 }
177
178 void MainWindow::importSchedule()
179 {
180     ImportScheduleDialog dialog(mSqlEngine,this);
181     dialog.exec();
182
183     QList<Conference> confs = Conference::getAll();
184     if(!confs.count()) // no conference(s) in the DB
185     {
186         AppSettings::setConfId(0); // no conference in the DB
187     }
188     else
189     {
190         if(AppSettings::confId() == 0)
191             AppSettings::setConfId(confs[0].id());
192
193         // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
194         QDate aStartDate = Conference::getById(AppSettings::confId()).start();
195         QDate aEndDate = Conference::getById(AppSettings::confId()).end();
196         dayNavigator->setDates(aStartDate, aEndDate);
197         trackDayNavigator->setDates(aStartDate, aEndDate);
198     }
199 }
200
201 void MainWindow::aboutApp()
202 {
203     QDialog dialog(this);
204     Ui::AboutDialog ui;
205     ui.setupUi(&dialog);
206     dialog.exec();
207 }
208
209 void MainWindow::updateDayView(const QDate &aDate)
210 {
211     static_cast<EventModel*>(dayTreeView->model())->loadEvents(aDate,AppSettings::confId());
212     dayTreeView->reset();
213     dayNavigator->show();
214 }
215
216 void MainWindow::updateTracksView(const QDate &aDate)
217 {
218     static_cast<EventModel*>(trackTreeView->model())->loadEventsByTrack(aDate, AppSettings::confId());
219     trackTreeView->reset();
220     trackDayNavigator->show();
221 }
222
223 void MainWindow::updateFavouritesView(const QDate &aDate)
224 {
225     static_cast<EventModel*>(favTreeView->model())->loadFavEvents(aDate,AppSettings::confId());
226     favTreeView->reset();
227     favouriteDayNavigator->show();
228 }
229
230 void MainWindow::updateSearchView(const QDate &aDate)
231 {
232     searchTreeView->reset();
233     int eventsCount = static_cast<EventModel*>(searchTreeView->model())->loadSearchResultEvents(aDate,AppSettings::confId());
234     if( eventsCount ){
235         searchDayNavigator->show();
236         searchTreeView->show();
237     }
238     else{
239         searchTreeView->hide();
240         searchDayNavigator->hide();
241     }
242 }
243
244 void MainWindow::updateNowView()
245 {
246     EventModel *model = static_cast<EventModel*>(nowTreeView->model());
247     model->loadNowEvents(AppSettings::confId());
248     nowTreeView->reset();
249     nowTreeView->setAllExpanded(true);
250 }
251
252 void MainWindow::itemClicked(const QModelIndex &aIndex)
253 {
254     // have to handle only events, not time-groups
255     if(!aIndex.parent().isValid()) // time-group
256         return;
257
258     EventDialog dialog(static_cast<Event*>(aIndex.internalPointer())->id(),this);
259     dialog.exec();
260 }
261
262 void MainWindow::displayMap(const QModelIndex &aIndex)
263 {
264     Event *event = static_cast<Event*>(aIndex.internalPointer());
265
266     // room names are stored in lower-case format
267     // room names are stored without dots in the name, eg. "aw.1124.png" -> "aw1124.png"
268     QString mapPath = QString(":/maps/rooms/%1.png").arg(event->room().toLower().remove("."));
269     if(!QFile::exists(mapPath))
270         mapPath = QString(":/maps/rooms/not-available.png");
271
272     QString roomName;
273     if(mapPath.contains("not-available", Qt::CaseInsensitive))
274         roomName = QString("Map is not available: %1").arg(event->room());
275     else
276         roomName = event->room();
277
278     QPixmap map(mapPath);
279     MapWindow window(map,roomName,this);
280     window.exec();
281 }
282
283 void MainWindow::searchClicked()
284 {
285     QList<QString> columns;
286
287     if( searchTitle->isChecked() )
288         columns.append( "title" );
289     if( searchAbstract->isChecked() )
290         columns.append( "abstract" );
291
292     mSqlEngine->searchEvent( AppSettings::confId(), columns, searchEdit->text() );
293     updateSearchView( Conference::getById(AppSettings::confId()).start() );
294 }
295
296 void MainWindow::conferenceMapClicked()
297 {
298
299     QString mapPath = QString(":/maps/campus.png");
300     if(!QFile::exists(mapPath))
301         mapPath = QString(":/maps/rooms/not-available.png");
302
303     QString roomName;
304
305     QPixmap map(mapPath);
306     MapWindow window(map,roomName,this);
307     window.exec();
308 }
309
310 void MainWindow::displayWarning(const QModelIndex &aIndex)
311 {
312     Q_UNUSED(aIndex);
313
314     QMessageBox::warning(
315     this,
316     tr("Time Conflict Warning"),
317     tr("This event happens at the same time than another one of your favourites.") );
318 }
319
320 void MainWindow::eventHasChanged(int aEventId)
321 {
322     static_cast<EventModel*>(dayTreeView->model())->updateModel(aEventId);
323     static_cast<EventModel*>(favTreeView->model())->updateModel(aEventId);
324     static_cast<EventModel*>(trackTreeView->model())->updateModel(aEventId);
325     static_cast<EventModel*>(searchTreeView->model())->updateModel(aEventId);
326     static_cast<EventModel*>(nowTreeView->model())->updateModel(aEventId);
327 }
328
329 void MainWindow::tabHasChanged(int aIndex)
330 {
331     Q_UNUSED(aIndex);
332
333     // TODO: only if it changed to favourities tab
334     updateFavouritesView(favouriteDayNavigator->getCurrentDate());
335     // TODO: only if it changed to now tab
336     //updateNowView();
337 }
338