2 * Copyright (C) 2010 Ixonos Plc.
4 * This file is part of fosdem-schedule.
6 * fosdem-schedule is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 2 of the License, or (at your option)
11 * fosdem-schedule is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * fosdem-schedule. If not, see <http://www.gnu.org/licenses/>.
19 #include "mainwindow.h"
23 #include <QNetworkProxy>
24 #include <QNetworkAccessManager>
25 #include <QNetworkReply>
27 #include <sqlengine.h>
30 #include <eventmodel.h>
33 #include <conference.h>
36 #include <QMessageBox>
39 #include <eventdialog.h>
40 #include "daynavigatorwidget.h"
41 #include "mapwindow.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);
72 if(AppSettings::isDirectConnection())
74 qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
77 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
78 AppSettings::proxyAddress(),
79 AppSettings::proxyPort(),
82 QNetworkProxy::setApplicationProxy(proxy);
85 // list of conferences must be maintained by ConferenceEditor
86 // here must be one of the signals from the closing ConferenceEditor (or model):
87 // selectedConf(conference), noConf()
88 connect(importScheduleWidget, SIGNAL(scheduleImported(int)), SLOT(scheduleImported(int)));
89 connect(importScheduleWidget, SIGNAL(scheduleDeleted(const QString&)), SLOT(scheduleDeleted(const QString&)));
92 // event details have changed
93 connect(dayTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
94 connect(favsTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
95 connect(tracksTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
96 connect(roomsTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
97 connect(nowTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
98 connect(searchTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
100 // event conference map button clicked
102 // TODO: think about it when return to maps
103 connect(showMapButton, SIGNAL(clicked()), SLOT(conferenceMapClicked()));
106 connect(aboutAction, SIGNAL(triggered()), SLOT(aboutApp()));
107 connect(settingsAction, SIGNAL(triggered()), SLOT(setup()));
108 connect(conferencesAction, SIGNAL(triggered()), SLOT(showConferences()));
110 useConference(Conference::activeConference());
114 // initialisation of model and pick active conference from there and call conferenceChanged()
115 // selectConference->setDuplicatesEnabled(false);
116 int confCount = Conference::getAll().count();
120 // fillAndShowConferenceHeader();
121 setWindowTitle(Conference::getById(confId).title());
123 QList<Conference> confs = Conference::getAll();
124 QListIterator<Conference> i(confs);
127 Conference conf = i.next();
129 // selectConference->addItem(conf.title(),conf.id());
132 // int idx = selectConference->findText(Conference::getById(Conference::activeConference()).title());
133 // selectConference->setCurrentIndex(idx);
134 // connect(selectConference, SIGNAL(currentIndexChanged(int)), SLOT(conferenceChanged(int)));
135 // conferenceChanged(idx);
140 // conferenceHeader->hide();
141 // selectConferenceWidget->hide();
142 // // go to the 'conferenceTab', so the user can import the schedule
143 // tabWidget->setCurrentIndex(6); // 6 - conference tab
147 // open dialog for given Event ID
148 // this is used in case Alarm Dialog request application to start
153 EventDialog dialog(aEventId,this);
156 catch(OrmNoObjectException&) {} // just start application
157 catch(...) {} // just start application
160 connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
162 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
163 connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), conferenceModel, SLOT(newConferenceEnd(const QString&)));
166 void MainWindow::scheduleImported(int aConfId)
170 // TODO: this all goes to ConferenceEditor and model of conferences
173 Conference conf = Conference::getById(aConfId);
174 if( selectConference->findText(conf.title()) < 0 ) // item doesn't exist
176 disconnect(selectConference, SIGNAL(currentIndexChanged(int)), this, SLOT(conferenceChanged(int)));
177 selectConference->addItem(conf.title(),conf.id());
178 connect(selectConference, SIGNAL(currentIndexChanged(int)), SLOT(conferenceChanged(int)));
180 int confCount = Conference::getAll().count();
183 int idx = selectConference->findText(conf.title());
184 selectConference->setCurrentIndex(idx);
186 selectConferenceWidget->show();
188 conferenceChanged(idx);
193 void MainWindow::scheduleDeleted(const QString& title)
196 // TODO: this all goes to ConferenceEditor and model of conferences
198 int idx = selectConference->findText(title);
202 qWarning() << __PRETTY_FUNCTION__ << "removed non-existent item:" << title;
203 // this happens when you remove the only conference (the list is not ptoperly inited in this case)
204 // now make sure that conferencet
205 if (selectConference->count() > 0) {
206 selectConference->setCurrentIndex(0);
207 conferenceChanged(0);
209 conferenceChanged(-1);
212 // will it signal "changed"?
213 selectConference->removeItem(idx);
218 void MainWindow::aboutApp()
220 QDialog dialog(this);
224 dialog.setFixedWidth(width());
229 void MainWindow::conferenceMapClicked()
231 QString mapPath = QString(":/maps/campus.png");
232 if(!QFile::exists(mapPath))
233 mapPath = QString(":/maps/rooms/not-available.png");
237 QPixmap map(mapPath);
238 MapWindow window(map,roomName,this);
242 void MainWindow::eventHasChanged(int aEventId, bool aReloadModel)
244 dayTabContainer->updateTreeViewModel(aEventId);
245 favsTabContainer->updateTreeViewModel(aEventId,aReloadModel);
246 tracksTabContainer->updateTreeViewModel(aEventId);
247 nowTabContainer->updateTreeViewModel(aEventId);
248 roomsTabContainer->updateTreeViewModel(aEventId);
249 searchTabContainer->updateTreeViewModel(aEventId);
252 void MainWindow::useConference(int id)
255 Conference::getById(Conference::activeConference()).update("active",0);
256 Conference::getById(id).update("active",1);
259 } catch (OrmException& e) {
260 // cannon set an active conference
267 void MainWindow::initTabs()
269 int confId = Conference::activeConference();
270 Conference active = Conference::getById(confId);
271 QDate startDate = active.start();
272 QDate endDate = active.end();
273 setWindowTitle(active.title());
275 // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
276 dayTabContainer->setDates(startDate, endDate);
277 tracksTabContainer->setDates(startDate, endDate);
278 roomsTabContainer->setDates(startDate, endDate);
279 favsTabContainer->setDates(startDate, endDate);
280 searchTabContainer->setDates(startDate, endDate);
281 searchTabContainer->searchAgainClicked();
282 nowTabContainer->updateTreeView(QDate::currentDate());
285 void MainWindow::unsetConference()
287 dayTabContainer->clearModel();
288 tracksTabContainer->clearModel();
289 roomsTabContainer->clearModel();
290 favsTabContainer->clearModel();
291 searchTabContainer->clearModel();
292 searchTabContainer->searchAgainClicked();
293 nowTabContainer->clearModel();
296 // conferenceHeader->hide();
297 setWindowTitle(saved_title);
300 void MainWindow::setup()
302 SettingsDialog dialog;
305 qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
307 AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
308 AppSettings::proxyAddress(),
309 AppSettings::proxyPort(),
312 QNetworkProxy::setApplicationProxy(proxy);
315 /** Create and run ConferenceEditor dialog, making required connections for it.
317 This method manages, which classes actually perform changes in conference list.
319 There are several classes that modify the conferences:
321 deletion and URL update.
322 this, mXmlParser and mNetworkAccessManager:
323 addition and refresh.
325 void MainWindow::showConferences()
327 ConferenceEditor dialog(conferenceModel, this);
329 // TODO: connect signals about progress of network and parsing
331 connect(&dialog, SIGNAL(haveConferenceUrl(const QString&)), SLOT(importFromNetwork(const QString&)));
332 connect(&dialog, SIGNAL(haveConferenceFile(const QString&)), SLOT(importFromFile(const QString&)));
333 connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
334 connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
335 SLOT(changeConferenceUrl(int, const QString&)));
337 connect(&dialog, SIGNAL(haveConferenceSelected(int)), SLOT(useConference(int)));
338 connect(&dialog, SIGNAL(noneConferenceSelected()), SLOT(unsetConference()));
340 connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
341 connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
342 connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), &dialog, SLOT(importFinished(const QString&)));
344 connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
349 void MainWindow::networkQueryFinished(QNetworkReply *aReply)
351 if ( aReply->error() != QNetworkReply::NoError )
353 error_message(QString("Error occured during download: ") + aReply->errorString());
357 qDebug() << __PRETTY_FUNCTION__ << ": have data";
358 importData(aReply->readAll(), aReply->url().toEncoded());
362 void MainWindow::importData(const QByteArray &aData, const QString& url)
365 // instead send signals to the child dialog
370 // proxySettings->hide();
373 int confId = mXmlParser->parseData(aData, url);
379 // proxySettings->show();
380 importScheduleLabel->setText("Schedule:");
384 emit(scheduleImported(confId));
388 void MainWindow::importFromNetwork(const QString& url)
390 qDebug() << __PRETTY_FUNCTION__;
391 QNetworkRequest request;
392 request.setUrl(QUrl(url));
394 mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
395 mNetworkAccessManager->get(request);
398 void MainWindow::importFromFile(const QString& filename)
400 qDebug() << __PRETTY_FUNCTION__;
401 QFile file(filename);
402 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
403 static const QString format("Cannot read \"%1\": error %2");
404 error_message(format.arg(filename, QString::number(file.error())));
407 importData(file.readAll(), "");
410 void MainWindow::removeConference(int id)
412 Conference::deleteConference(id);
413 conferenceModel->conferenceRemoved();
415 emit conferenceRemoved();
418 void MainWindow::changeConferenceUrl(int id, const QString& url)
420 Conference::getById(id).setUrl(url);