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