New upstream release.
[debian/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     connect(aboutAction, SIGNAL(triggered()), SLOT(aboutApp()));
95     connect(settingsAction, SIGNAL(triggered()), SLOT(setup()));
96     connect(conferencesAction, SIGNAL(triggered()), SLOT(showConferences()));
97
98     useConference(Conference::activeConference());
99     // optimization, see useConference() code
100     try {
101         initTabs();
102     } catch (const OrmException& e) {
103         qDebug() << "OrmException:" << e.text();
104         clearTabs();
105     }
106
107     // TODO: open conferences at startup?
108     #if 0
109     if(!confCount)
110         tabWidget->setCurrentIndex(6); // 6 - conference tab
111     }
112     #endif
113
114     // open dialog for given Event ID
115     // this is used in case Alarm Dialog request application to start
116     if(aEventId)
117     {
118         try
119         {
120             EventDialog dialog(aEventId,this);
121             dialog.exec();
122         }
123         catch(OrmNoObjectException&) {} // just start application
124         catch(...) {} // just start application
125     }
126
127     connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
128
129     connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
130     connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), conferenceModel, SLOT(newConferenceEnd(const QString&)));
131 }
132
133 void MainWindow::aboutApp()
134 {
135     QDialog dialog(this);
136     Ui::AboutDialog ui;
137     ui.setupUi(&dialog);
138     ui.labDescription->setText(ui.labDescription->text().arg(qApp->applicationVersion()));
139 #ifdef N810
140     dialog.setFixedWidth(width());
141 #endif
142     dialog.exec();
143 }
144
145 void MainWindow::eventHasChanged(int aEventId, bool aReloadModel)
146 {
147     dayTabContainer->updateTreeViewModel(aEventId);
148     favsTabContainer->updateTreeViewModel(aEventId,aReloadModel);
149     tracksTabContainer->updateTreeViewModel(aEventId);
150     nowTabContainer->updateTreeViewModel(aEventId);
151     roomsTabContainer->updateTreeViewModel(aEventId);
152     searchTabContainer->updateTreeViewModel(aEventId);
153 }
154
155 void MainWindow::useConference(int id)
156 {
157     if (id == -1)  // in case no conference is active
158     {
159         unsetConference();
160         return;
161     }
162     try {
163         Conference::getById(Conference::activeConference()).update("active",0);
164         Conference new_active = Conference::getById(id);
165         new_active.update("active",1);
166
167         // looks like it does not work at n900
168         setWindowTitle(new_active.title());
169
170         // optimization.
171         // dont run initTabs() here
172         // it takes much CPU, making travelling between conferences in ConferenceEditor longer
173         // and is not seen in maemo WM anyway
174         // instead run it explicitly
175         // 1. at startup
176         // 2. when ConferenceEditor finished
177         // dont forget to protect the calls by try-catch!
178
179         // just in case, clear conference selection instead
180         clearTabs();
181
182         // end of optimization
183         // initTabs();
184     } catch (OrmException& e) {
185         // cannon set an active conference
186         unsetConference();   // TODO: as no active conference is now correctly managed this should be handled as a fatal error
187         return;
188     }
189
190 }
191
192 void MainWindow::initTabs()
193 {
194     int confId = Conference::activeConference();
195     if (confId != -1)   // only init tabs if a conference is active
196     {
197         Conference active = Conference::getById(confId);
198         QDate startDate = active.start();
199         QDate endDate = active.end();
200
201         // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
202         dayTabContainer->setDates(startDate, endDate);
203         tracksTabContainer->setDates(startDate, endDate);
204         roomsTabContainer->setDates(startDate, endDate);
205         favsTabContainer->setDates(startDate, endDate);
206         searchTabContainer->setDates(startDate, endDate);
207         searchTabContainer->searchAgainClicked();
208         nowTabContainer->updateTreeView(QDate::currentDate());
209     }
210 }
211
212 void MainWindow::clearTabs()
213 {
214     dayTabContainer->clearModel();
215     tracksTabContainer->clearModel();
216     roomsTabContainer->clearModel();
217     favsTabContainer->clearModel();
218     searchTabContainer->clearModel();
219     searchTabContainer->searchAgainClicked();
220     nowTabContainer->clearModel();
221 }
222
223 void MainWindow::unsetConference()
224 {
225     clearTabs();
226     setWindowTitle(saved_title);
227 }
228
229 void MainWindow::setup()
230 {
231     SettingsDialog dialog;
232     dialog.loadDialogData();
233     if (dialog.exec() == QDialog::Accepted) {
234         dialog.saveDialogData();
235         QNetworkProxy proxy(
236                 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
237                 AppSettings::proxyAddress(),
238                 AppSettings::proxyPort(),
239                 PROXY_USERNAME,
240                 PROXY_PASSWD);
241         QNetworkProxy::setApplicationProxy(proxy);
242     }
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     dialog.exec();
275
276     // optimization, see useConference() code
277     try {
278         initTabs();
279     } catch (OrmException) {
280         clearTabs();
281     }
282 }
283
284 void MainWindow::networkQueryFinished(QNetworkReply *aReply)
285 {
286     if ( aReply->error() != QNetworkReply::NoError )
287     {
288         error_message(QString("Error occured during download: ") + aReply->errorString());
289     }
290     else
291     {
292         importData(aReply->readAll(), aReply->url().toEncoded());
293     }
294 }
295
296 void MainWindow::importData(const QByteArray &aData, const QString& url)
297 {
298     mXmlParser->parseData(aData, url);
299 }
300
301 void MainWindow::importFromNetwork(const QString& url)
302 {
303     QNetworkRequest request;
304     request.setUrl(QUrl(url));
305
306     mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
307     mNetworkAccessManager->get(request);
308 }
309
310 void MainWindow::importFromFile(const QString& filename)
311 {
312     QFile file(filename);
313     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {    
314         static const QString format("Cannot read \"%1\": error %2");
315         error_message(format.arg(filename, QString::number(file.error())));
316     }
317
318     importData(file.readAll(), "");
319 }
320
321 void MainWindow::removeConference(int id)
322 {
323     Conference::deleteConference(id);
324     conferenceModel->conferenceRemoved();
325
326     emit conferenceRemoved();
327 }
328
329 void MainWindow::changeConferenceUrl(int id, const QString& url)
330 {
331     Conference::getById(id).setUrl(url);
332 }
333