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