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(int aEventId, QWidget *aParent): QMainWindow(aParent) {
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 if(AppSettings::isDirectConnection())
81 qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
85 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
86 AppSettings::proxyAddress(),
87 AppSettings::proxyPort(),
90 QNetworkProxy::setApplicationProxy(proxy);
92 // event details have changed
93 connect(dayTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
94 connect(favsTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
95 connect(tracksTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
96 connect(roomsTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
97 connect(searchTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
100 connect(dayNavigator, SIGNAL(dateChanged(QDate)), dayTabContainer, SLOT(redisplayDate(QDate)));
101 connect(dayNavigator, SIGNAL(dateChanged(QDate)), favsTabContainer, SLOT(redisplayDate(QDate)));
102 connect(dayNavigator, SIGNAL(dateChanged(QDate)), tracksTabContainer, SLOT(redisplayDate(QDate)));
103 connect(dayNavigator, SIGNAL(dateChanged(QDate)), roomsTabContainer, SLOT(redisplayDate(QDate)));
104 connect(dayNavigator, SIGNAL(dateChanged(QDate)), searchTabContainer, SLOT(redisplayDate(QDate)));
106 // search result has changed
107 connect(searchTabContainer, SIGNAL(searchResultChanged()), SLOT(onSearchResultChanged()));
110 useConference(Conference::activeConference());
111 // optimization, see useConference() code
114 } catch (const OrmException& e) {
115 qDebug() << "OrmException:" << e.text();
119 // open dialog for given Event ID
120 // this is used in case Alarm Dialog request application to start
125 EventDialog dialog(aEventId,this);
128 catch(OrmNoObjectException&) {} // just start application
129 catch(...) {} // just start application
132 connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
134 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
135 connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), conferenceModel, SLOT(newConferenceEnd(int)));
138 void MainWindow::on_aboutAction_triggered()
140 QDialog dialog(this);
143 ui.labDescription->setText(ui.labDescription->text().arg(qApp->applicationVersion()));
145 dialog.setFixedWidth(width());
151 void MainWindow::on_reloadAction_triggered() {
152 int confId = Conference::activeConference();
153 if (confId== -1) return;
154 Conference active = Conference::getById(confId);
155 if (active.url().isEmpty()) return;
156 importFromNetwork(active.url(), confId);
161 void MainWindow::on_nowAction_triggered() {
162 int confId = Conference::activeConference();
163 if (confId== -1) return;
164 dayNavigator->setCurDate(QDate::currentDate());
165 dayTabContainer->expandTimeGroup(QTime::currentTime(), confId);
169 void MainWindow::on_searchAction_triggered() {
170 if (tabWidget->currentWidget() == searchTab)
171 searchTabContainer->showSearchDialog(!searchTabContainer->searchDialogIsVisible());
173 tabWidget->setCurrentWidget(searchTab);
174 searchTabContainer->showSearchDialog();
179 void MainWindow::on_expandAllAction_triggered() {
180 if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->expandAll();
181 if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->expandAll();
182 if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->expandAll();
183 if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->expandAll();
184 if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->expandAll();
188 void MainWindow::on_collapseAllAction_triggered() {
189 if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->collapseAll();
190 if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->collapseAll();
191 if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->collapseAll();
192 if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->collapseAll();
193 if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->collapseAll();
197 void MainWindow::onEventChanged(int aEventId, bool favouriteChanged) {
198 dayTabContainer->redisplayEvent(aEventId);
199 if (favouriteChanged) favsTabContainer->redisplayDate(dayNavigator->curDate());
200 else favsTabContainer->redisplayEvent(aEventId);
201 tracksTabContainer->redisplayEvent(aEventId);
202 roomsTabContainer->redisplayEvent(aEventId);
203 searchTabContainer->redisplayEvent(aEventId);
207 void MainWindow::onSearchResultChanged() {
208 // Are results found on the current date?
209 QDate date = dayNavigator->curDate();
210 int count = searchTabContainer->searchResultCount(date);
211 if (count > 0) {searchTabContainer->redisplayDate(date); return;}
213 // Are results found in the future?
214 for (date = date.addDays(1); date <= dayNavigator->endDate(); date = date.addDays(1)) {
215 int count = searchTabContainer->searchResultCount(date);
216 if (count > 0) {dayNavigator->setCurDate(date); return;}
219 // Are results found in the past?
220 for (date = dayNavigator->startDate(); date < dayNavigator->curDate(); date = date.addDays(1)) {
221 int count = searchTabContainer->searchResultCount(date);
222 if (count > 0) {dayNavigator->setCurDate(date); return;}
224 // No results were found
225 searchTabContainer->redisplayDate(dayNavigator->curDate());
229 void MainWindow::useConference(int id)
231 if (id == -1) // in case no conference is active
237 Conference::getById(Conference::activeConference()).update("active",0);
238 Conference new_active = Conference::getById(id);
239 new_active.update("active",1);
241 // looks like it does not work at n900
242 setWindowTitle(new_active.title());
245 // dont run initTabs() here
246 // it takes much CPU, making travelling between conferences in ConferenceEditor longer
247 // and is not seen in maemo WM anyway
248 // instead run it explicitly
250 // 2. when ConferenceEditor finished
251 // dont forget to protect the calls by try-catch!
253 // just in case, clear conference selection instead
256 // end of optimization
258 } catch (OrmException& e) {
259 // cannon set an active conference
260 unsetConference(); // TODO: as no active conference is now correctly managed this should be handled as a fatal error
266 void MainWindow::initTabs()
268 int confId = Conference::activeConference();
269 if (confId != -1) // only init tabs if a conference is active
271 Conference active = Conference::getById(confId);
272 QDate startDate = active.start();
273 QDate endDate = active.end();
275 // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
276 dayNavigator->setDates(startDate, endDate);
280 void MainWindow::clearTabs()
282 dayTabContainer->clearModel();
283 tracksTabContainer->clearModel();
284 roomsTabContainer->clearModel();
285 favsTabContainer->clearModel();
286 searchTabContainer->clearModel();
289 void MainWindow::unsetConference()
292 dayNavigator->unsetDates();
293 setWindowTitle(saved_title);
297 void MainWindow::showError(const QString& message) {
298 error_message(message);
302 void MainWindow::on_settingsAction_triggered()
304 SettingsDialog dialog;
305 dialog.loadDialogData();
306 if (dialog.exec() == QDialog::Accepted) {
307 dialog.saveDialogData();
309 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
310 AppSettings::proxyAddress(),
311 AppSettings::proxyPort(),
314 QNetworkProxy::setApplicationProxy(proxy);
318 /** Create and run ConferenceEditor dialog, making required connections for it.
320 This method manages, which classes actually perform changes in conference list.
322 There are several classes that modify the conferences:
324 deletion and URL update.
325 this, mXmlParser and mNetworkAccessManager:
326 addition and refresh.
328 void MainWindow::on_conferencesAction_triggered()
330 ConferenceEditor dialog(conferenceModel, this);
332 connect(&dialog, SIGNAL(haveConferenceUrl(const QString&, int)), SLOT(importFromNetwork(const QString&, int)));
333 connect(&dialog, SIGNAL(haveConferenceFile(const QString&, int)), SLOT(importFromFile(const QString&, int)));
334 connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
335 connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
336 SLOT(changeConferenceUrl(int, const QString&)));
338 connect(&dialog, SIGNAL(haveConferenceSelected(int)), SLOT(useConference(int)));
339 connect(&dialog, SIGNAL(noneConferenceSelected()), SLOT(unsetConference()));
341 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
342 connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
343 connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), &dialog, SLOT(importFinished(int)));
345 connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
349 // optimization, see useConference() code
352 } catch (OrmException) {
357 void MainWindow::networkQueryFinished(QNetworkReply *aReply) {
358 if (aReply->error() != QNetworkReply::NoError) {
359 error_message(QString("Error occured during download: ") + aReply->errorString());
361 QUrl redirectUrl = aReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
362 if (!redirectUrl.isEmpty()) {
363 if (redirectUrl != aReply->request().url()) {
364 importFromNetwork(redirectUrl.toString(), aReply->request().attribute(QNetworkRequest::User).toInt());
365 return; // don't enable controls
367 error_message(QString("Error: Cyclic redirection from %1 to itself.").arg(redirectUrl.toString()));
370 importData(aReply->readAll(), aReply->url().toEncoded(), aReply->request().attribute(QNetworkRequest::User).toInt());
376 void MainWindow::importData(const QByteArray &aData, const QString& url, int conferenceId)
378 mXmlParser->parseData(aData, url, conferenceId);
381 void MainWindow::importFromNetwork(const QString& url, int conferenceId)
383 QNetworkRequest request;
384 request.setUrl(QUrl(url));
385 request.setAttribute(QNetworkRequest::User, conferenceId);
387 mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
388 mNetworkAccessManager->get(request);
391 void MainWindow::importFromFile(const QString& filename, int conferenceId)
393 QFile file(filename);
394 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
395 static const QString format("Cannot read \"%1\": error %2");
396 error_message(format.arg(filename, QString::number(file.error())));
399 importData(file.readAll(), "", conferenceId);
403 void MainWindow::removeConference(int id) {
404 sqlEngine->deleteConference(id);
405 conferenceModel->conferenceRemoved();
406 emit conferenceRemoved();
410 void MainWindow::changeConferenceUrl(int id, const QString& url) {
411 Conference::getById(id).setUrl(url);