2 * Copyright (C) 2010 Ixonos Plc.
3 * Copyright (C) 2011-2012 Philipp Spitzer, gregor herrmann, Stefan Stahl
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(QWidget* parent): QMainWindow(parent) {
57 sqlEngine = new SqlEngine(this);
58 searchTabContainer->setSqlEngine(sqlEngine);
59 connect(sqlEngine, SIGNAL(dbError(QString)), this, SLOT(showError(QString)));
61 sqlEngine->createOrUpdateDbSchema();
63 conferenceModel = new ConferenceModel(this);
64 mXmlParser = new ScheduleXmlParser(sqlEngine, this);
65 mNetworkAccessManager = new QNetworkAccessManager(this);
67 saved_title = windowTitle();
70 tabWidget->setTabText(1,"Favs");
71 //tabWidget->setTabText(2,"Day");
74 // first time run aplication: -> let's have it direct connection in this case
75 if(!AppSettings::contains("proxyIsDirectConnection"))
76 AppSettings::setDirectConnection(true);
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 connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
114 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
115 connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), conferenceModel, SLOT(newConferenceEnd(int)));
118 void MainWindow::on_aboutAction_triggered()
120 QDialog dialog(this);
123 ui.labDescription->setText(ui.labDescription->text().arg(qApp->applicationVersion()));
125 dialog.setFixedWidth(width());
131 void MainWindow::on_reloadAction_triggered() {
132 int confId = Conference::activeConference();
133 if (confId== -1) return;
134 Conference active = Conference::getById(confId);
135 if (active.url().isEmpty()) return;
136 importFromNetwork(active.url(), confId);
141 void MainWindow::on_nowAction_triggered() {
142 int confId = Conference::activeConference();
143 if (confId== -1) return;
144 dayNavigator->setCurDate(QDate::currentDate());
145 dayTabContainer->expandTimeGroup(QTime::currentTime(), confId);
149 void MainWindow::on_searchAction_triggered() {
150 if (tabWidget->currentWidget() == searchTab)
151 searchTabContainer->showSearchDialog(!searchTabContainer->searchDialogIsVisible());
153 tabWidget->setCurrentWidget(searchTab);
154 searchTabContainer->showSearchDialog();
159 void MainWindow::on_expandAllAction_triggered() {
160 if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->expandAll();
161 if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->expandAll();
162 if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->expandAll();
163 if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->expandAll();
164 if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->expandAll();
168 void MainWindow::on_collapseAllAction_triggered() {
169 if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->collapseAll();
170 if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->collapseAll();
171 if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->collapseAll();
172 if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->collapseAll();
173 if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->collapseAll();
177 void MainWindow::onEventChanged(int aEventId, bool favouriteChanged) {
178 dayTabContainer->redisplayEvent(aEventId);
179 if (favouriteChanged) favsTabContainer->redisplayDate(dayNavigator->curDate());
180 else favsTabContainer->redisplayEvent(aEventId);
181 tracksTabContainer->redisplayEvent(aEventId);
182 roomsTabContainer->redisplayEvent(aEventId);
183 searchTabContainer->redisplayEvent(aEventId);
187 void MainWindow::onSearchResultChanged() {
188 // Are results found on the current date?
189 QDate date = dayNavigator->curDate();
190 int count = searchTabContainer->searchResultCount(date);
191 if (count > 0) {searchTabContainer->redisplayDate(date); return;}
193 // Are results found in the future?
194 for (date = date.addDays(1); date <= dayNavigator->endDate(); date = date.addDays(1)) {
195 int count = searchTabContainer->searchResultCount(date);
196 if (count > 0) {dayNavigator->setCurDate(date); return;}
199 // Are results found in the past?
200 for (date = dayNavigator->startDate(); date < dayNavigator->curDate(); date = date.addDays(1)) {
201 int count = searchTabContainer->searchResultCount(date);
202 if (count > 0) {dayNavigator->setCurDate(date); return;}
204 // No results were found
205 searchTabContainer->redisplayDate(dayNavigator->curDate());
209 void MainWindow::useConference(int conferenceId)
211 if (conferenceId == -1) // in case no conference is active
217 int oldActiveConferenceId = Conference::activeConference();
218 bool switchActiveConference = conferenceId != oldActiveConferenceId;
219 if (switchActiveConference) Conference::getById(oldActiveConferenceId).update("active", 0);
220 Conference activeConference = Conference::getById(conferenceId);
221 if (switchActiveConference) activeConference.update("active",1);
223 // looks like it does not work at n900
224 setWindowTitle(activeConference.title());
227 // dont run initTabs() here
228 // it takes much CPU, making travelling between conferences in ConferenceEditor longer
229 // and is not seen in maemo WM anyway
230 // instead run it explicitly
232 // 2. when ConferenceEditor finished
233 // dont forget to protect the calls by try-catch!
235 // just in case, clear conference selection instead
238 // end of optimization
240 } catch (OrmException& e) {
241 // cannon set an active conference
242 unsetConference(); // TODO: as no active conference is now correctly managed this should be handled as a fatal error
248 void MainWindow::initTabs()
250 int confId = Conference::activeConference();
251 if (confId != -1) // only init tabs if a conference is active
253 Conference active = Conference::getById(confId);
254 QDate startDate = active.start();
255 QDate endDate = active.end();
257 // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
258 dayNavigator->setDates(startDate, endDate);
259 nowAction->trigger();
263 void MainWindow::clearTabs()
265 dayTabContainer->clearModel();
266 tracksTabContainer->clearModel();
267 roomsTabContainer->clearModel();
268 favsTabContainer->clearModel();
269 searchTabContainer->clearModel();
272 void MainWindow::unsetConference()
275 dayNavigator->unsetDates();
276 setWindowTitle(saved_title);
280 void MainWindow::showError(const QString& message) {
281 error_message(message);
285 void MainWindow::on_settingsAction_triggered()
287 SettingsDialog dialog;
288 dialog.loadDialogData();
289 if (dialog.exec() == QDialog::Accepted) {
290 dialog.saveDialogData();
292 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
293 AppSettings::proxyAddress(),
294 AppSettings::proxyPort(),
297 QNetworkProxy::setApplicationProxy(proxy);
301 /** Create and run ConferenceEditor dialog, making required connections for it.
303 This method manages, which classes actually perform changes in conference list.
305 There are several classes that modify the conferences:
307 deletion and URL update.
308 this, mXmlParser and mNetworkAccessManager:
309 addition and refresh.
311 void MainWindow::on_conferencesAction_triggered()
313 ConferenceEditor dialog(conferenceModel, this);
315 connect(&dialog, SIGNAL(haveConferenceUrl(const QString&, int)), SLOT(importFromNetwork(const QString&, int)));
316 connect(&dialog, SIGNAL(haveConferenceFile(const QString&, int)), SLOT(importFromFile(const QString&, int)));
317 connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
318 connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
319 SLOT(changeConferenceUrl(int, const QString&)));
321 connect(&dialog, SIGNAL(haveConferenceSelected(int)), SLOT(useConference(int)));
322 connect(&dialog, SIGNAL(noneConferenceSelected()), SLOT(unsetConference()));
324 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
325 connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
326 connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), &dialog, SLOT(importFinished(int)));
328 connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
332 // optimization, see useConference() code
335 } catch (OrmException) {
340 void MainWindow::networkQueryFinished(QNetworkReply *aReply) {
341 if (aReply->error() != QNetworkReply::NoError) {
342 error_message(QString("Error occured during download: ") + aReply->errorString());
344 QUrl redirectUrl = aReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
345 if (!redirectUrl.isEmpty()) {
346 if (redirectUrl != aReply->request().url()) {
347 importFromNetwork(redirectUrl.toString(), aReply->request().attribute(QNetworkRequest::User).toInt());
348 return; // don't enable controls
350 error_message(QString("Error: Cyclic redirection from %1 to itself.").arg(redirectUrl.toString()));
353 importData(aReply->readAll(), aReply->url().toEncoded(), aReply->request().attribute(QNetworkRequest::User).toInt());
359 void MainWindow::importData(const QByteArray &aData, const QString& url, int conferenceId)
361 mXmlParser->parseData(aData, url, conferenceId);
364 void MainWindow::importFromNetwork(const QString& url, int conferenceId)
366 QNetworkRequest request;
367 request.setUrl(QUrl(url));
368 request.setAttribute(QNetworkRequest::User, conferenceId);
370 mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
371 mNetworkAccessManager->get(request);
374 void MainWindow::importFromFile(const QString& filename, int conferenceId)
376 QFile file(filename);
377 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
378 static const QString format("Cannot read \"%1\": error %2");
379 error_message(format.arg(filename, QString::number(file.error())));
382 importData(file.readAll(), "", conferenceId);
386 void MainWindow::removeConference(int id) {
387 sqlEngine->deleteConference(id);
388 conferenceModel->conferenceRemoved();
389 emit conferenceRemoved();
393 void MainWindow::changeConferenceUrl(int id, const QString& url) {
394 Conference::getById(id).setUrl(url);