+/*
+ * Copyright (C) 2010 Ixonos Plc.
+ * Copyright (C) 2011-2012 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ *
+ * This file is part of ConfClerk.
+ *
+ * ConfClerk is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * ConfClerk is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ConfClerk. If not, see <http://www.gnu.org/licenses/>.
+ */
#include "mainwindow.h"
#include <QTreeView>
#include <QFile>
+#include <QNetworkProxy>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
#include <sqlengine.h>
#include <QDialog>
#include <QMessageBox>
+
#include "ui_about.h"
#include <eventdialog.h>
#include "daynavigatorwidget.h"
-#include "importschedulewidget.h"
-#include "mapwindow.h"
+#include "settingsdialog.h"
+#include "conferenceeditor.h"
+#include "schedulexmlparser.h"
+#include "errormessage.h"
#include <tabcontainer.h>
+#include <appsettings.h>
+
+const QString PROXY_USERNAME;
+const QString PROXY_PASSWD;
MainWindow::MainWindow(int aEventId, QWidget *aParent)
: QMainWindow(aParent)
+ , conferenceModel(new ConferenceModel(this))
+ , mXmlParser(new ScheduleXmlParser(this))
+ , mNetworkAccessManager(new QNetworkAccessManager(this))
{
setupUi(this);
- int confId = Conference::activeConference();
+ saved_title = windowTitle();
- QList<Conference> confs = Conference::getAll();
- if(confs.count())
+#ifdef N810
+ tabWidget->setTabText(1,"Favs");
+ //tabWidget->setTabText(2,"Day");
+#endif
+
+ // first time run aplication: -> let's have it direct connection in this case
+ if(!AppSettings::contains("proxyIsDirectConnection"))
+ AppSettings::setDirectConnection(true);
+
+ /*
+ if(AppSettings::isDirectConnection())
{
- setWindowTitle(confs[0].title());
+ qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
}
-
- connect(importScheduleWidget, SIGNAL(scheduleImported(int)), SLOT(scheduleImported(int)));
+ */
+ QNetworkProxy proxy(
+ AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
+ AppSettings::proxyAddress(),
+ AppSettings::proxyPort(),
+ PROXY_USERNAME,
+ PROXY_PASSWD);
+ QNetworkProxy::setApplicationProxy(proxy);
// event details have changed
- connect(dayTabContainer, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
- connect(favsTabContainer, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
- connect(favsTabContainer, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
- connect(roomsTabContainer, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
- connect(nowTabContainer, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
- connect(searchTabContainer, SIGNAL(eventHasChanged(int)), SLOT(eventHasChanged(int)));
+ connect(dayTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
+ connect(favsTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
+ connect(tracksTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
+ connect(roomsTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
+ connect(searchTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
+ // date has changed
+ connect(dayNavigator, SIGNAL(dateChanged(QDate)), dayTabContainer, SLOT(redisplayDate(QDate)));
+ connect(dayNavigator, SIGNAL(dateChanged(QDate)), favsTabContainer, SLOT(redisplayDate(QDate)));
+ connect(dayNavigator, SIGNAL(dateChanged(QDate)), tracksTabContainer, SLOT(redisplayDate(QDate)));
+ connect(dayNavigator, SIGNAL(dateChanged(QDate)), roomsTabContainer, SLOT(redisplayDate(QDate)));
+ connect(dayNavigator, SIGNAL(dateChanged(QDate)), searchTabContainer, SLOT(redisplayDate(QDate)));
- // event conference map button clicked
- connect(showMapButton, SIGNAL(clicked()), SLOT(conferenceMapClicked()));
+ // search result has changed
+ connect(searchTabContainer, SIGNAL(searchResultChanged()), SLOT(onSearchResultChanged()));
- connect(tabWidget, SIGNAL(infoIconClicked()), SLOT(aboutApp()));
- if(Conference::getAll().count()) // no conference(s) in the DB
- {
- QDate startDate = Conference::getById(confId).start();
- QDate endDate = Conference::getById(confId).end();
- //
- dayTabContainer->setDates(startDate, endDate);
- tracksTabContainer->setDates(startDate, endDate);
- roomsTabContainer->setDates(startDate, endDate);
- favsTabContainer->setDates(startDate, endDate);
- searchTabContainer->setDates(startDate, endDate);
- //
- conferenceTitle->setText(Conference::getById(confId).title());
- conferenceSubtitle->setText(Conference::getById(confId).subtitle());
- conferenceWhere->setText(Conference::getById(confId).city() + ", " + Conference::getById(confId).venue());
- conferenceWhen->setText(
- Conference::getById(confId).start().toString("dd-MM-yyyy")
- + ", " +
- Conference::getById(confId).end().toString("dd-MM-yyyy"));
+ useConference(Conference::activeConference());
+ // optimization, see useConference() code
+ try {
+ initTabs();
+ } catch (const OrmException& e) {
+ qDebug() << "OrmException:" << e.text();
+ clearTabs();
}
// open dialog for given Event ID
catch(OrmNoObjectException&) {} // just start application
catch(...) {} // just start application
}
+
+ connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
+
+ connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
+ connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), conferenceModel, SLOT(newConferenceEnd(const QString&)));
}
-void MainWindow::scheduleImported(int aConfId)
+void MainWindow::on_aboutAction_triggered()
{
- Q_UNUSED(aConfId);
+ QDialog dialog(this);
+ Ui::AboutDialog ui;
+ ui.setupUi(&dialog);
+ ui.labDescription->setText(ui.labDescription->text().arg(qApp->applicationVersion()));
+#ifdef N810
+ dialog.setFixedWidth(width());
+#endif
+ dialog.exec();
+}
+
+
+void MainWindow::on_reloadAction_triggered() {
+ int confId = Conference::activeConference();
+ if (confId== -1) return;
+ Conference active = Conference::getById(confId);
+ if (active.url().isEmpty()) return;
+ importFromNetwork(active.url());
+ setEnabled(false);
+}
+
+
+void MainWindow::on_nowAction_triggered() {
+ int confId = Conference::activeConference();
+ if (confId== -1) return;
+ dayNavigator->setCurDate(QDate::currentDate());
+ dayTabContainer->expandTimeGroup(QTime::currentTime(), confId);
+}
+
+
+void MainWindow::on_searchAction_triggered() {
+ if (tabWidget->currentWidget() == searchTab)
+ searchTabContainer->showSearchDialog(!searchTabContainer->searchDialogIsVisible());
+ else {
+ tabWidget->setCurrentWidget(searchTab);
+ searchTabContainer->showSearchDialog();
+ }
+}
+
+
+void MainWindow::on_expandAllAction_triggered() {
+ if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->expandAll();
+ if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->expandAll();
+ if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->expandAll();
+ if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->expandAll();
+ if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->expandAll();
+}
+
+
+void MainWindow::on_collapseAllAction_triggered() {
+ if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->collapseAll();
+ if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->collapseAll();
+ if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->collapseAll();
+ if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->collapseAll();
+ if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->collapseAll();
+}
+
+
+void MainWindow::onEventChanged(int aEventId, bool favouriteChanged) {
+ dayTabContainer->redisplayEvent(aEventId);
+ if (favouriteChanged) favsTabContainer->redisplayDate(dayNavigator->curDate());
+ else favsTabContainer->redisplayEvent(aEventId);
+ tracksTabContainer->redisplayEvent(aEventId);
+ roomsTabContainer->redisplayEvent(aEventId);
+ searchTabContainer->redisplayEvent(aEventId);
+}
+
+
+void MainWindow::onSearchResultChanged() {
+ // Are results found on the current date?
+ QDate date = dayNavigator->curDate();
+ int count = searchTabContainer->searchResultCount(date);
+ if (count > 0) {searchTabContainer->redisplayDate(date); return;}
+
+ // Are results found in the future?
+ for (date = date.addDays(1); date <= dayNavigator->endDate(); date = date.addDays(1)) {
+ int count = searchTabContainer->searchResultCount(date);
+ if (count > 0) {dayNavigator->setCurDate(date); return;}
+ }
+
+ // Are results found in the past?
+ for (date = dayNavigator->startDate(); date < dayNavigator->curDate(); date = date.addDays(1)) {
+ int count = searchTabContainer->searchResultCount(date);
+ if (count > 0) {dayNavigator->setCurDate(date); return;}
+ }
+ // No results were found
+ searchTabContainer->redisplayDate(dayNavigator->curDate());
+}
+
+
+void MainWindow::useConference(int id)
+{
+ if (id == -1) // in case no conference is active
+ {
+ unsetConference();
+ return;
+ }
+ try {
+ Conference::getById(Conference::activeConference()).update("active",0);
+ Conference new_active = Conference::getById(id);
+ new_active.update("active",1);
- QList<Conference> confs = Conference::getAll();
- if(confs.count())
+ // looks like it does not work at n900
+ setWindowTitle(new_active.title());
+
+ // optimization.
+ // dont run initTabs() here
+ // it takes much CPU, making travelling between conferences in ConferenceEditor longer
+ // and is not seen in maemo WM anyway
+ // instead run it explicitly
+ // 1. at startup
+ // 2. when ConferenceEditor finished
+ // dont forget to protect the calls by try-catch!
+
+ // just in case, clear conference selection instead
+ clearTabs();
+
+ // end of optimization
+ // initTabs();
+ } catch (OrmException& e) {
+ // cannon set an active conference
+ unsetConference(); // TODO: as no active conference is now correctly managed this should be handled as a fatal error
+ return;
+ }
+
+}
+
+void MainWindow::initTabs()
+{
+ int confId = Conference::activeConference();
+ if (confId != -1) // only init tabs if a conference is active
{
+ Conference active = Conference::getById(confId);
+ QDate startDate = active.start();
+ QDate endDate = active.end();
+
// 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
- QDate startDate = Conference::getById(Conference::activeConference()).start();
- QDate endDate = Conference::getById(Conference::activeConference()).end();
- dayTabContainer->setDates(startDate, endDate);
- tracksTabContainer->setDates(startDate, endDate);
- roomsTabContainer->setDates(startDate, endDate);
- favsTabContainer->setDates(startDate, endDate);
+ dayNavigator->setDates(startDate, endDate);
}
}
-void MainWindow::aboutApp()
+void MainWindow::clearTabs()
{
- QDialog dialog(this);
- Ui::AboutDialog ui;
- ui.setupUi(&dialog);
+ dayTabContainer->clearModel();
+ tracksTabContainer->clearModel();
+ roomsTabContainer->clearModel();
+ favsTabContainer->clearModel();
+ searchTabContainer->clearModel();
+}
+
+void MainWindow::unsetConference()
+{
+ clearTabs();
+ dayNavigator->unsetDates();
+ setWindowTitle(saved_title);
+}
+
+void MainWindow::on_settingsAction_triggered()
+{
+ SettingsDialog dialog;
+ dialog.loadDialogData();
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.saveDialogData();
+ QNetworkProxy proxy(
+ AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
+ AppSettings::proxyAddress(),
+ AppSettings::proxyPort(),
+ PROXY_USERNAME,
+ PROXY_PASSWD);
+ QNetworkProxy::setApplicationProxy(proxy);
+ }
+}
+
+/** Create and run ConferenceEditor dialog, making required connections for it.
+
+This method manages, which classes actually perform changes in conference list.
+
+There are several classes that modify the conferences:
+this:
+ deletion and URL update.
+this, mXmlParser and mNetworkAccessManager:
+ addition and refresh.
+*/
+void MainWindow::on_conferencesAction_triggered()
+{
+ ConferenceEditor dialog(conferenceModel, this);
+
+ connect(&dialog, SIGNAL(haveConferenceUrl(const QString&)), SLOT(importFromNetwork(const QString&)));
+ connect(&dialog, SIGNAL(haveConferenceFile(const QString&)), SLOT(importFromFile(const QString&)));
+ connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
+ connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
+ SLOT(changeConferenceUrl(int, const QString&)));
+
+ connect(&dialog, SIGNAL(haveConferenceSelected(int)), SLOT(useConference(int)));
+ connect(&dialog, SIGNAL(noneConferenceSelected()), SLOT(unsetConference()));
+
+ connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
+ connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
+ connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), &dialog, SLOT(importFinished(const QString&)));
+
+ connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
+
dialog.exec();
+
+ // optimization, see useConference() code
+ try {
+ initTabs();
+ } catch (OrmException) {
+ clearTabs();
+ }
+}
+
+void MainWindow::networkQueryFinished(QNetworkReply *aReply) {
+ if (aReply->error() != QNetworkReply::NoError) {
+ error_message(QString("Error occured during download: ") + aReply->errorString());
+ } else {
+ QUrl redirectUrl = aReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+ if (!redirectUrl.isEmpty()) {
+ if (redirectUrl != aReply->request().url()) {
+ importFromNetwork(redirectUrl.toString());
+ return; // don't enable controls
+ } else {
+ error_message(QString("Error: Cyclic redirection from %1 to itself.").arg(redirectUrl.toString()));
+ }
+ } else {
+ importData(aReply->readAll(), aReply->url().toEncoded());
+ }
+ }
+ setEnabled(true);
}
-void MainWindow::conferenceMapClicked()
+void MainWindow::importData(const QByteArray &aData, const QString& url)
{
- QString mapPath = QString(":/maps/campus.png");
- if(!QFile::exists(mapPath))
- mapPath = QString(":/maps/rooms/not-available.png");
+ mXmlParser->parseData(aData, url);
+}
+
+void MainWindow::importFromNetwork(const QString& url)
+{
+ QNetworkRequest request;
+ request.setUrl(QUrl(url));
- QString roomName;
+ mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
+ mNetworkAccessManager->get(request);
+}
+
+void MainWindow::importFromFile(const QString& filename)
+{
+ QFile file(filename);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ static const QString format("Cannot read \"%1\": error %2");
+ error_message(format.arg(filename, QString::number(file.error())));
+ }
+
+ importData(file.readAll(), "");
+}
+
+void MainWindow::removeConference(int id)
+{
+ Conference::deleteConference(id);
+ conferenceModel->conferenceRemoved();
- QPixmap map(mapPath);
- MapWindow window(map,roomName,this);
- window.exec();
+ emit conferenceRemoved();
}
-void MainWindow::eventHasChanged(int aEventId)
+void MainWindow::changeConferenceUrl(int id, const QString& url)
{
- dayTabContainer->updateTreeViewModel(aEventId);
- favsTabContainer->updateTreeViewModel(aEventId);
- tracksTabContainer->updateTreeViewModel(aEventId);
- nowTabContainer->updateTreeViewModel(aEventId);
- roomsTabContainer->updateTreeViewModel(aEventId);
- searchTabContainer->updateTreeViewModel(aEventId);
+ Conference::getById(id).setUrl(url);
}