restore viewing of conference map
[toast/confclerk.git] / src / gui / mainwindow.cpp
index d068c74..2cee85c 100644 (file)
+/*
+ * Copyright (C) 2010 Ixonos Plc.
+ *
+ * This file is part of fosdem-schedule.
+ *
+ * fosdem-schedule 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.
+ *
+ * fosdem-schedule 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
+ * fosdem-schedule.  If not, see <http://www.gnu.org/licenses/>.
+ */
 #include "mainwindow.h"
 
 #include <QTreeView>
-#include <QDirModel>
+#include <QFile>
+#include <QNetworkProxy>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
 
 #include <sqlengine.h>
-#include <schedulexmlparser.h>
 
+#include <track.h>
 #include <eventmodel.h>
 #include <delegate.h>
 
 #include <conference.h>
 
 #include <QDialog>
+#include <QMessageBox>
+
 #include "ui_about.h"
+#include <eventdialog.h>
 #include "daynavigatorwidget.h"
+#include "settingsdialog.h"
+#include "conferenceeditor.h"
+#include "schedulexmlparser.h"
+#include "errormessage.h"
+
+#include <tabcontainer.h>
+#include <appsettings.h>
 
-MainWindow::MainWindow(QWidget *parent)
-    : QMainWindow(parent)
+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);
 
-    // connect Menu actions
-    connect(actionImportSchedule, SIGNAL(triggered()), SLOT(importSchedule()));
-    connect(actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
-    connect(actionAboutApplication, SIGNAL(triggered()), SLOT(aboutApp()));
-
-    // create "SQLITE" DB instance/connection
-    // opens DB connection (needed for EventModel)
-    mSqlEngine = new SqlEngine(this);
-    mSqlEngine->initialize();
-
-    mXmlParser = new ScheduleXmlParser(this);
-    connect(mXmlParser, SIGNAL(progressStatus(int)), this, SLOT(showParsingProgress(int)));
-    statusBar()->showMessage(tr("Ready"));
-
-    connect(dayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateDayView(const QDate &)));
-    connect(activityDayNavigator, SIGNAL(dateChanged(const QDate &)), SLOT(updateActivitiesDayView(const QDate &)));
-    //connect(tabWidget, SIGNAL(currentChanged(int)), SLOT(updateView(int)));
-
-    // DAY EVENTS View
-    dayTreeView->setHeaderHidden(true);
-    dayTreeView->setRootIsDecorated(false);
-    dayTreeView->setIndentation(0);
-    dayTreeView->setAnimated(true);
-    dayTreeView->setModel(new EventModel());
-    dayTreeView->setItemDelegate(new Delegate(dayTreeView));
-
-    // FAVOURITIES View
-    favTreeView->setHeaderHidden(true);
-    favTreeView->setRootIsDecorated(false);
-    favTreeView->setIndentation(0);
-    favTreeView->setAnimated(true);
-    favTreeView->setModel(new EventModel());
-    favTreeView->setItemDelegate(new Delegate(favTreeView));
-
-    //ACTIVITIES View
-    activityDayTreeView->setHeaderHidden(true);
-    activityDayTreeView->setRootIsDecorated(false);
-    activityDayTreeView->setIndentation(0);
-    activityDayTreeView->setAnimated(true);
-    activityDayTreeView->setModel(new EventModel());
-    activityDayTreeView->setItemDelegate(new Delegate(activityDayTreeView));
-
-    // TESTING: load some 'fav' data
-    if(Conference::getAll().count()) // no conference(s) in the DB
-    {
-        int confId = 1;
-        static_cast<EventModel*>(favTreeView->model())->loadFavEvents(Conference::getById(confId).start(),confId);
-        favTreeView->reset();
-    }
+    saved_title = windowTitle();
 
-    if(!Conference::getAll().count()) // no conference(s) in the DB
-    {
-        dayNavigator->hide(); // hide DayNavigatorWidget
-        activityDayNavigator->hide();
-    }
-    else
-    {
-        int confId = 1;
-        QDate aStartDate = Conference::getById(confId).start();
-        QDate aEndDate = Conference::getById(confId).end();
-        dayNavigator->setDates(aStartDate, aEndDate);
-        activityDayNavigator->setDates(aStartDate, aEndDate);
-    }
-    connect(static_cast<EventModel*>(dayTreeView->model()), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(updateFavView()));
-    connect(static_cast<EventModel*>(favTreeView->model()), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(updateFavView()));
-/*    connect(static_cast<EventModel*>(favTreeView->model()), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(updateFavViewComplete()));*/
-}
+#ifdef N810
+    tabWidget->setTabText(1,"Favs");
+    //tabWidget->setTabText(2,"Day");
+#endif
 
-MainWindow::~MainWindow()
-{
-    if(mSqlEngine)
-    {
-        delete mSqlEngine;
-        mSqlEngine = NULL;
-    }
-    if(mXmlParser)
+    // first time run aplication: -> let's have it direct connection in this case
+    if(!AppSettings::contains("proxyIsDirectConnection"))
+        AppSettings::setDirectConnection(true);
+
+    if(AppSettings::isDirectConnection())
     {
-        delete mXmlParser;
-        mXmlParser = NULL;
+        qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
     }
-}
+    QNetworkProxy proxy(
+            AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
+            AppSettings::proxyAddress(),
+            AppSettings::proxyPort(),
+            PROXY_USERNAME,
+            PROXY_PASSWD);
+    QNetworkProxy::setApplicationProxy(proxy);
 
-void MainWindow::importSchedule()
-{
-    QFile file("../schedule.en.xml");
-    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
-    {
-        QString currPath = QDir::currentPath();
-        qDebug() << "current path: " << currPath;
-        qDebug() << "can't open " << file.fileName();
-        return;
+    // event details have changed
+    connect(dayTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
+    connect(favsTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
+    connect(tracksTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
+    connect(roomsTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
+    connect(nowTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
+    connect(searchTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
+
+    connect(aboutAction, SIGNAL(triggered()), SLOT(aboutApp()));
+    connect(settingsAction, SIGNAL(triggered()), SLOT(setup()));
+    connect(conferencesAction, SIGNAL(triggered()), SLOT(showConferences()));
+
+    useConference(Conference::activeConference());
+    // optimization, see useConference() code
+    try {
+       initTabs();
+    } catch (OrmException) {
+       clearTabs();
     }
 
-    QByteArray data = file.readAll();
-    mXmlParser->parseData(data,mSqlEngine);
+    // TODO: open conferences at startup?
+    #if 0
+    if(!confCount)
+        tabWidget->setCurrentIndex(6); // 6 - conference tab
+    }
+    #endif
 
-    if(Conference::getAll().count())
+    // open dialog for given Event ID
+    // this is used in case Alarm Dialog request application to start
+    if(aEventId)
     {
-        int confId = 1;
-        // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
-        dayNavigator->setDates(Conference::getById(confId).start(), Conference::getById(confId).end());
+        try
+        {
+            EventDialog dialog(aEventId,this);
+            dialog.exec();
+        }
+        catch(OrmNoObjectException&) {} // just start application
+        catch(...) {} // just start application
     }
-}
 
-void MainWindow::showParsingProgress(int aStatus)
-{
-    QString msg = QString("Parsing completed: %1\%").arg(aStatus);
-    statusBar()->showMessage(msg,1000);
+    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::aboutApp()
@@ -135,61 +131,192 @@ void MainWindow::aboutApp()
     QDialog dialog(this);
     Ui::AboutDialog ui;
     ui.setupUi(&dialog);
+#ifdef N810
+    dialog.setFixedWidth(width());
+#endif
     dialog.exec();
 }
 
-void MainWindow::updateDayView(const QDate &aDate)
+void MainWindow::eventHasChanged(int aEventId, bool aReloadModel)
 {
-    int confId = 1;
-    static_cast<EventModel*>(dayTreeView->model())->loadEvents(aDate,confId);
-    dayTreeView->reset();
-    dayNavigator->show();
+    dayTabContainer->updateTreeViewModel(aEventId);
+    favsTabContainer->updateTreeViewModel(aEventId,aReloadModel);
+    tracksTabContainer->updateTreeViewModel(aEventId);
+    nowTabContainer->updateTreeViewModel(aEventId);
+    roomsTabContainer->updateTreeViewModel(aEventId);
+    searchTabContainer->updateTreeViewModel(aEventId);
 }
 
-void MainWindow::updateFavView()
+void MainWindow::useConference(int id)
 {
-    int confId = 1;
-    static_cast<EventModel*>(favTreeView->model())->loadFavEvents(Conference::getById(confId).start(),confId);
-    favTreeView->reset(); //Necessary reset:
-                        //  if favourite event unselected as favourite is the only one in its time, and reset is not produced, crashed
+    try {
+        Conference::getById(Conference::activeConference()).update("active",0);
+        Conference new_active = Conference::getById(id);
+        new_active.update("active",1);
+
+       // 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();
+        return;
+    }
 
-    dayNavigator->show();
 }
 
-/*
-void MainWindow::updateFavViewComplete()
+void MainWindow::initTabs()
 {
-    int confId = 1;
-    updateFavView();
-    updateDayView(Conference::getById(confId).start());
+    int confId = Conference::activeConference();
+    Conference active = Conference::getById(confId);
+    QDate startDate = active.start();
+    QDate endDate = active.end();
+
+    // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
+    dayTabContainer->setDates(startDate, endDate);
+    tracksTabContainer->setDates(startDate, endDate);
+    roomsTabContainer->setDates(startDate, endDate);
+    favsTabContainer->setDates(startDate, endDate);
+    searchTabContainer->setDates(startDate, endDate);
+    searchTabContainer->searchAgainClicked();
+    nowTabContainer->updateTreeView(QDate::currentDate());
 }
-*/
 
-void MainWindow::updateActivitiesDayView(const QDate &aDate)
+void MainWindow::clearTabs()
 {
-    int confId = 1;
-    static_cast<EventModel*>(activityDayTreeView->model())->loadEventsByActivities(aDate,confId);
-    activityDayTreeView->reset();
-    activityDayNavigator->show();
+    dayTabContainer->clearModel();
+    tracksTabContainer->clearModel();
+    roomsTabContainer->clearModel();
+    favsTabContainer->clearModel();
+    searchTabContainer->clearModel();
+    searchTabContainer->searchAgainClicked();
+    nowTabContainer->clearModel();
 }
 
-void MainWindow::updateView(int tabIndex)
+void MainWindow::unsetConference()
 {
-    //TODO korinpa: change to enum or names ?
-    qDebug() << "updateView index: " << tabIndex;
-    if (tabIndex == 0)
-    {
-        QDate date = dayNavigator->getCurrentDate();
-        updateDayView(date);
+    clearTabs();
+    setWindowTitle(saved_title);
+}
+
+void MainWindow::setup()
+{
+    SettingsDialog dialog;
+    dialog.exec();
+
+    qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
+    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::showConferences()
+{
+    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();
     }
-    else if (tabIndex == 1)
+}
+
+void MainWindow::networkQueryFinished(QNetworkReply *aReply)
+{
+    if ( aReply->error() != QNetworkReply::NoError )
     {
-        updateFavView();
+        error_message(QString("Error occured during download: ") + aReply->errorString());
     }
-    else if (tabIndex == 2)
+    else
     {
-        QDate date = activityDayNavigator->getCurrentDate();
-        updateActivitiesDayView(date);
+        qDebug() << __PRETTY_FUNCTION__ << ": have data";
+        importData(aReply->readAll(), aReply->url().toEncoded());
     }
 }
 
+void MainWindow::importData(const QByteArray &aData, const QString& url)
+{
+    mXmlParser->parseData(aData, url);
+}
+
+void MainWindow::importFromNetwork(const QString& url)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    QNetworkRequest request;
+    request.setUrl(QUrl(url));
+
+    mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
+    mNetworkAccessManager->get(request);
+}
+
+void MainWindow::importFromFile(const QString& filename)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    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();
+
+    emit conferenceRemoved();
+}
+
+void MainWindow::changeConferenceUrl(int id, const QString& url)
+{
+    Conference::getById(id).setUrl(url);
+}
+