minor UI fixes
[toast/confclerk.git] / src / gui / mainwindow.cpp
1 /*
2  * Copyright (C) 2010 Ixonos Plc.
3  *
4  * This file is part of fosdem-schedule.
5  *
6  * fosdem-schedule is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 2 of the License, or (at your option)
9  * any later version.
10  *
11  * fosdem-schedule is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * fosdem-schedule.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "mainwindow.h"
20
21 #include <QTreeView>
22 #include <QFile>
23 #include <QNetworkProxy>
24 #include <QNetworkAccessManager>
25 #include <QNetworkReply>
26
27 #include <sqlengine.h>
28
29 #include <track.h>
30 #include <eventmodel.h>
31 #include <delegate.h>
32
33 #include <conference.h>
34
35 #include <QDialog>
36 #include <QMessageBox>
37
38 #include "ui_about.h"
39 #include <eventdialog.h>
40 #include "daynavigatorwidget.h"
41 #include "mapwindow.h"
42 #include "settingsdialog.h"
43 #include "conferenceeditor.h"
44 #include "schedulexmlparser.h"
45 #include "errormessage.h"
46
47 #include <tabcontainer.h>
48 #include <appsettings.h>
49
50 const QString PROXY_USERNAME;
51 const QString PROXY_PASSWD;
52
53 MainWindow::MainWindow(int aEventId, QWidget *aParent)
54     : QMainWindow(aParent)
55     , conferenceModel(new ConferenceModel(this))
56     , mXmlParser(new ScheduleXmlParser(this))
57     , mNetworkAccessManager(new QNetworkAccessManager(this))
58 {
59     setupUi(this);
60
61     saved_title = windowTitle();
62
63 #ifdef N810
64     tabWidget->setTabText(1,"Favs");
65     //tabWidget->setTabText(2,"Day");
66 #endif
67
68     // first time run aplication: -> let's have it direct connection in this case
69     if(!AppSettings::contains("proxyIsDirectConnection"))
70         AppSettings::setDirectConnection(true);
71
72     if(AppSettings::isDirectConnection())
73     {
74         qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
75     }
76     QNetworkProxy proxy(
77             AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
78             AppSettings::proxyAddress(),
79             AppSettings::proxyPort(),
80             PROXY_USERNAME,
81             PROXY_PASSWD);
82     QNetworkProxy::setApplicationProxy(proxy);
83
84     // event details have changed
85     connect(dayTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
86     connect(favsTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
87     connect(tracksTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
88     connect(roomsTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
89     connect(nowTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
90     connect(searchTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
91
92     connect(aboutAction, SIGNAL(triggered()), SLOT(aboutApp()));
93     connect(settingsAction, SIGNAL(triggered()), SLOT(setup()));
94     connect(conferencesAction, SIGNAL(triggered()), SLOT(showConferences()));
95
96     useConference(Conference::activeConference());
97     // optimization, see useConference() code
98     try {
99         initTabs();
100     } catch (OrmException) {
101         clearTabs();
102     }
103
104     // TODO: open conferences at startup?
105     #if 0
106     if(!confCount)
107         tabWidget->setCurrentIndex(6); // 6 - conference tab
108     }
109     #endif
110
111     // open dialog for given Event ID
112     // this is used in case Alarm Dialog request application to start
113     if(aEventId)
114     {
115         try
116         {
117             EventDialog dialog(aEventId,this);
118             dialog.exec();
119         }
120         catch(OrmNoObjectException&) {} // just start application
121         catch(...) {} // just start application
122     }
123
124     connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
125
126     connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
127     connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), conferenceModel, SLOT(newConferenceEnd(const QString&)));
128 }
129
130 void MainWindow::aboutApp()
131 {
132     QDialog dialog(this);
133     Ui::AboutDialog ui;
134     ui.setupUi(&dialog);
135 #ifdef N810
136     dialog.setFixedWidth(width());
137 #endif
138     dialog.exec();
139 }
140
141 void MainWindow::conferenceMapClicked()
142 {
143     QString mapPath = QString(":/maps/campus.png");
144     if(!QFile::exists(mapPath))
145         mapPath = QString(":/maps/rooms/not-available.png");
146
147     QString roomName;
148
149     QPixmap map(mapPath);
150     MapWindow window(map,roomName,this);
151     window.exec();
152 }
153
154 void MainWindow::eventHasChanged(int aEventId, bool aReloadModel)
155 {
156     dayTabContainer->updateTreeViewModel(aEventId);
157     favsTabContainer->updateTreeViewModel(aEventId,aReloadModel);
158     tracksTabContainer->updateTreeViewModel(aEventId);
159     nowTabContainer->updateTreeViewModel(aEventId);
160     roomsTabContainer->updateTreeViewModel(aEventId);
161     searchTabContainer->updateTreeViewModel(aEventId);
162 }
163
164 void MainWindow::useConference(int id)
165 {
166     try {
167         Conference::getById(Conference::activeConference()).update("active",0);
168         Conference new_active = Conference::getById(id);
169         new_active.update("active",1);
170
171         // looks like it does not work at n900
172         setWindowTitle(new_active.title());
173
174         // optimization.
175         // dont run initTabs() here
176         // it takes much CPU, making travelling between conferences in ConferenceEditor longer
177         // and is not seen in maemo WM anyway
178         // instead run it explicitly
179         // 1. at startup
180         // 2. when ConferenceEditor finished
181         // dont forget to protect the calls by try-catch!
182
183         // just in case, clear conference selection instead
184         clearTabs();
185
186         // end of optimization
187         // initTabs();
188     } catch (OrmException& e) {
189         // cannon set an active conference
190         unsetConference();
191         return;
192     }
193
194 }
195
196 void MainWindow::initTabs()
197 {
198     int confId = Conference::activeConference();
199     Conference active = Conference::getById(confId);
200     QDate startDate = active.start();
201     QDate endDate = active.end();
202
203     // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
204     dayTabContainer->setDates(startDate, endDate);
205     tracksTabContainer->setDates(startDate, endDate);
206     roomsTabContainer->setDates(startDate, endDate);
207     favsTabContainer->setDates(startDate, endDate);
208     searchTabContainer->setDates(startDate, endDate);
209     searchTabContainer->searchAgainClicked();
210     nowTabContainer->updateTreeView(QDate::currentDate());
211 }
212
213 void MainWindow::clearTabs()
214 {
215     dayTabContainer->clearModel();
216     tracksTabContainer->clearModel();
217     roomsTabContainer->clearModel();
218     favsTabContainer->clearModel();
219     searchTabContainer->clearModel();
220     searchTabContainer->searchAgainClicked();
221     nowTabContainer->clearModel();
222 }
223
224 void MainWindow::unsetConference()
225 {
226     clearTabs();
227     setWindowTitle(saved_title);
228 }
229
230 void MainWindow::setup()
231 {
232     SettingsDialog dialog;
233     dialog.exec();
234
235     qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
236     QNetworkProxy proxy(
237             AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
238             AppSettings::proxyAddress(),
239             AppSettings::proxyPort(),
240             PROXY_USERNAME,
241             PROXY_PASSWD);
242     QNetworkProxy::setApplicationProxy(proxy);
243 }
244
245 /** Create and run ConferenceEditor dialog, making required connections for it.
246
247 This method manages, which classes actually perform changes in conference list.
248
249 There are several classes that modify the conferences:
250 this:
251  deletion and URL update.
252 this, mXmlParser and mNetworkAccessManager:
253  addition and refresh.
254 */
255 void MainWindow::showConferences()
256 {
257     ConferenceEditor dialog(conferenceModel, this);
258
259     connect(&dialog, SIGNAL(haveConferenceUrl(const QString&)), SLOT(importFromNetwork(const QString&)));
260     connect(&dialog, SIGNAL(haveConferenceFile(const QString&)), SLOT(importFromFile(const QString&)));
261     connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
262     connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
263                     SLOT(changeConferenceUrl(int, const QString&)));
264
265     connect(&dialog, SIGNAL(haveConferenceSelected(int)), SLOT(useConference(int)));
266     connect(&dialog, SIGNAL(noneConferenceSelected()), SLOT(unsetConference()));
267
268     connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
269     connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
270     connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), &dialog, SLOT(importFinished(const QString&)));
271
272     connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
273
274     // TODO: propagate press of showMapButton here
275     // connect(showMapButton, SIGNAL(clicked()), SLOT(conferenceMapClicked()));
276
277     dialog.exec();
278
279     // optimization, see useConference() code
280     try {
281         initTabs();
282     } catch (OrmException) {
283         clearTabs();
284     }
285 }
286
287 void MainWindow::networkQueryFinished(QNetworkReply *aReply)
288 {
289     if ( aReply->error() != QNetworkReply::NoError )
290     {
291         error_message(QString("Error occured during download: ") + aReply->errorString());
292     }
293     else
294     {
295         qDebug() << __PRETTY_FUNCTION__ << ": have data";
296         importData(aReply->readAll(), aReply->url().toEncoded());
297     }
298 }
299
300 void MainWindow::importData(const QByteArray &aData, const QString& url)
301 {
302     mXmlParser->parseData(aData, url);
303 }
304
305 void MainWindow::importFromNetwork(const QString& url)
306 {
307     qDebug() << __PRETTY_FUNCTION__;
308     QNetworkRequest request;
309     request.setUrl(QUrl(url));
310
311     mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
312     mNetworkAccessManager->get(request);
313 }
314
315 void MainWindow::importFromFile(const QString& filename)
316 {
317     qDebug() << __PRETTY_FUNCTION__;
318     QFile file(filename);
319     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {    
320         static const QString format("Cannot read \"%1\": error %2");
321         error_message(format.arg(filename, QString::number(file.error())));
322     }
323
324     importData(file.readAll(), "");
325 }
326
327 void MainWindow::removeConference(int id)
328 {
329     Conference::deleteConference(id);
330     conferenceModel->conferenceRemoved();
331
332     emit conferenceRemoved();
333 }
334
335 void MainWindow::changeConferenceUrl(int id, const QString& url)
336 {
337     Conference::getById(id).setUrl(url);
338 }
339