2 * Copyright (C) 2010 Ixonos Plc.
3 * Copyright (C) 2011-2012 Philipp Spitzer, gregor herrmann
5 * This file is part of ConfClerk.
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)
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
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/>.
20 #include "mainwindow.h"
24 #include <QNetworkProxy>
25 #include <QNetworkAccessManager>
26 #include <QNetworkReply>
28 #include <sqlengine.h>
31 #include <eventmodel.h>
34 #include <conference.h>
37 #include <QMessageBox>
40 #include <eventdialog.h>
41 #include "daynavigatorwidget.h"
42 #include "settingsdialog.h"
43 #include "conferenceeditor.h"
44 #include "schedulexmlparser.h"
45 #include "errormessage.h"
47 #include <tabcontainer.h>
48 #include <appsettings.h>
50 const QString PROXY_USERNAME;
51 const QString PROXY_PASSWD;
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))
61 saved_title = windowTitle();
64 tabWidget->setTabText(1,"Favs");
65 //tabWidget->setTabText(2,"Day");
68 // first time run aplication: -> let's have it direct connection in this case
69 if(!AppSettings::contains("proxyIsDirectConnection"))
70 AppSettings::setDirectConnection(true);
73 if(AppSettings::isDirectConnection())
75 qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
79 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
80 AppSettings::proxyAddress(),
81 AppSettings::proxyPort(),
84 QNetworkProxy::setApplicationProxy(proxy);
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)));
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)));
100 // search result has changed
101 connect(searchTabContainer, SIGNAL(searchResultChanged()), SLOT(onSearchResultChanged()));
104 useConference(Conference::activeConference());
105 // optimization, see useConference() code
108 } catch (const OrmException& e) {
109 qDebug() << "OrmException:" << e.text();
113 // open dialog for given Event ID
114 // this is used in case Alarm Dialog request application to start
119 EventDialog dialog(aEventId,this);
122 catch(OrmNoObjectException&) {} // just start application
123 catch(...) {} // just start application
126 connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
128 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
129 connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), conferenceModel, SLOT(newConferenceEnd(const QString&)));
132 void MainWindow::on_aboutAction_triggered()
134 QDialog dialog(this);
137 ui.labDescription->setText(ui.labDescription->text().arg(qApp->applicationVersion()));
139 dialog.setFixedWidth(width());
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());
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);
163 void MainWindow::on_searchAction_triggered() {
164 if (tabWidget->currentWidget() == searchTab)
165 searchTabContainer->showSearchDialog(!searchTabContainer->searchDialogIsVisible());
167 tabWidget->setCurrentWidget(searchTab);
168 searchTabContainer->showSearchDialog();
173 void MainWindow::on_expandAllAction_triggered() {
178 void MainWindow::on_collapseAllAction_triggered() {
183 void MainWindow::onEventChanged(int aEventId, bool favouriteChanged) {
184 dayTabContainer->redisplayEvent(aEventId);
185 if (favouriteChanged) favsTabContainer->redisplayDate(dayNavigator->curDate());
186 else favsTabContainer->redisplayEvent(aEventId);
187 tracksTabContainer->redisplayEvent(aEventId);
188 roomsTabContainer->redisplayEvent(aEventId);
189 searchTabContainer->redisplayEvent(aEventId);
193 void MainWindow::onSearchResultChanged() {
194 // Are results found on the current date?
195 QDate date = dayNavigator->curDate();
196 int count = searchTabContainer->searchResultCount(date);
197 if (count > 0) {searchTabContainer->redisplayDate(date); return;}
199 // Are results found in the future?
200 for (date = date.addDays(1); date <= dayNavigator->endDate(); date = date.addDays(1)) {
201 int count = searchTabContainer->searchResultCount(date);
202 if (count > 0) {dayNavigator->setCurDate(date); return;}
205 // Are results found in the past?
206 for (date = dayNavigator->startDate(); date < dayNavigator->curDate(); date = date.addDays(1)) {
207 int count = searchTabContainer->searchResultCount(date);
208 if (count > 0) {dayNavigator->setCurDate(date); return;}
210 // No results were found
211 searchTabContainer->redisplayDate(dayNavigator->curDate());
215 void MainWindow::useConference(int id)
217 if (id == -1) // in case no conference is active
223 Conference::getById(Conference::activeConference()).update("active",0);
224 Conference new_active = Conference::getById(id);
225 new_active.update("active",1);
227 // looks like it does not work at n900
228 setWindowTitle(new_active.title());
231 // dont run initTabs() here
232 // it takes much CPU, making travelling between conferences in ConferenceEditor longer
233 // and is not seen in maemo WM anyway
234 // instead run it explicitly
236 // 2. when ConferenceEditor finished
237 // dont forget to protect the calls by try-catch!
239 // just in case, clear conference selection instead
242 // end of optimization
244 } catch (OrmException& e) {
245 // cannon set an active conference
246 unsetConference(); // TODO: as no active conference is now correctly managed this should be handled as a fatal error
252 void MainWindow::initTabs()
254 int confId = Conference::activeConference();
255 if (confId != -1) // only init tabs if a conference is active
257 Conference active = Conference::getById(confId);
258 QDate startDate = active.start();
259 QDate endDate = active.end();
261 // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
262 dayNavigator->setDates(startDate, endDate);
266 void MainWindow::clearTabs()
268 dayTabContainer->clearModel();
269 tracksTabContainer->clearModel();
270 roomsTabContainer->clearModel();
271 favsTabContainer->clearModel();
272 searchTabContainer->clearModel();
275 void MainWindow::unsetConference()
278 dayNavigator->unsetDates();
279 setWindowTitle(saved_title);
282 void MainWindow::on_settingsAction_triggered()
284 SettingsDialog dialog;
285 dialog.loadDialogData();
286 if (dialog.exec() == QDialog::Accepted) {
287 dialog.saveDialogData();
289 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
290 AppSettings::proxyAddress(),
291 AppSettings::proxyPort(),
294 QNetworkProxy::setApplicationProxy(proxy);
298 /** Create and run ConferenceEditor dialog, making required connections for it.
300 This method manages, which classes actually perform changes in conference list.
302 There are several classes that modify the conferences:
304 deletion and URL update.
305 this, mXmlParser and mNetworkAccessManager:
306 addition and refresh.
308 void MainWindow::on_conferencesAction_triggered()
310 ConferenceEditor dialog(conferenceModel, this);
312 connect(&dialog, SIGNAL(haveConferenceUrl(const QString&)), SLOT(importFromNetwork(const QString&)));
313 connect(&dialog, SIGNAL(haveConferenceFile(const QString&)), SLOT(importFromFile(const QString&)));
314 connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
315 connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
316 SLOT(changeConferenceUrl(int, const QString&)));
318 connect(&dialog, SIGNAL(haveConferenceSelected(int)), SLOT(useConference(int)));
319 connect(&dialog, SIGNAL(noneConferenceSelected()), SLOT(unsetConference()));
321 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
322 connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
323 connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), &dialog, SLOT(importFinished(const QString&)));
325 connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
329 // optimization, see useConference() code
332 } catch (OrmException) {
337 void MainWindow::networkQueryFinished(QNetworkReply *aReply) {
338 if (aReply->error() != QNetworkReply::NoError) {
339 error_message(QString("Error occured during download: ") + aReply->errorString());
341 QUrl redirectUrl = aReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
342 if (!redirectUrl.isEmpty()) {
343 if (redirectUrl != aReply->request().url()) {
344 importFromNetwork(redirectUrl.toString());
345 return; // don't enable controls
347 error_message(QString("Error: Cyclic redirection from %1 to itself.").arg(redirectUrl.toString()));
350 importData(aReply->readAll(), aReply->url().toEncoded());
356 void MainWindow::importData(const QByteArray &aData, const QString& url)
358 mXmlParser->parseData(aData, url);
361 void MainWindow::importFromNetwork(const QString& url)
363 QNetworkRequest request;
364 request.setUrl(QUrl(url));
366 mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
367 mNetworkAccessManager->get(request);
370 void MainWindow::importFromFile(const QString& filename)
372 QFile file(filename);
373 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
374 static const QString format("Cannot read \"%1\": error %2");
375 error_message(format.arg(filename, QString::number(file.error())));
378 importData(file.readAll(), "");
381 void MainWindow::removeConference(int id)
383 Conference::deleteConference(id);
384 conferenceModel->conferenceRemoved();
386 emit conferenceRemoved();
389 void MainWindow::changeConferenceUrl(int id, const QString& url)
391 Conference::getById(id).setUrl(url);