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