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