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