Set some SSL parameters for network request.
[toast/confclerk.git] / src / gui / mainwindow.cpp
index f5b9dd7..a2e28d1 100644 (file)
@@ -1,20 +1,21 @@
 /*
  * Copyright (C) 2010 Ixonos Plc.
 /*
  * Copyright (C) 2010 Ixonos Plc.
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
  *
  *
- * This file is part of fosdem-schedule.
+ * This file is part of ConfClerk.
  *
  *
- * fosdem-schedule is free software: you can redistribute it and/or modify it
+ * 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.
  *
  * 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
+ * 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
  * 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/>.
+ * ConfClerk.  If not, see <http://www.gnu.org/licenses/>.
  */
 #include "mainwindow.h"
 
  */
 #include "mainwindow.h"
 
 #include <QNetworkProxy>
 #include <QNetworkAccessManager>
 #include <QNetworkReply>
 #include <QNetworkProxy>
 #include <QNetworkAccessManager>
 #include <QNetworkReply>
+#include <QSslConfiguration>
 
 
-#include <sqlengine.h>
+#include "sqlengine.h"
 
 
-#include <track.h>
-#include <eventmodel.h>
-#include <delegate.h>
+#include "track.h"
+#include "eventmodel.h"
+#include "delegate.h"
+#include "room.h"
 
 
-#include <conference.h>
+#include "conference.h"
 
 #include <QDialog>
 #include <QMessageBox>
 
 #include "ui_about.h"
 
 #include <QDialog>
 #include <QMessageBox>
 
 #include "ui_about.h"
-#include <eventdialog.h>
+#include "eventdialog.h"
 #include "daynavigatorwidget.h"
 #include "daynavigatorwidget.h"
-#include "mapwindow.h"
 #include "settingsdialog.h"
 #include "conferenceeditor.h"
 #include "schedulexmlparser.h"
 #include "errormessage.h"
 
 #include "settingsdialog.h"
 #include "conferenceeditor.h"
 #include "schedulexmlparser.h"
 #include "errormessage.h"
 
-#include <tabcontainer.h>
-#include <appsettings.h>
+#include "tabcontainer.h"
+#include "appsettings.h"
 
 const QString PROXY_USERNAME;
 const QString PROXY_PASSWD;
 
 
 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))
-{
+MainWindow::MainWindow(QWidget* parent): QMainWindow(parent) {
     setupUi(this);
 
     setupUi(this);
 
+    // Open database
+    sqlEngine = new SqlEngine(this);
+    searchTabContainer->setSqlEngine(sqlEngine);
+    connect(sqlEngine, SIGNAL(dbError(QString)), this, SLOT(showError(QString)));
+    sqlEngine->open();
+    sqlEngine->createOrUpdateDbSchema();
+
+    conferenceModel = new ConferenceModel(this);
+    mXmlParser = new ScheduleXmlParser(sqlEngine, this);
+    mNetworkAccessManager = new QNetworkAccessManager(this);
+    systemTrayIcon = new QSystemTrayIcon(qApp->windowIcon(), this);
+    alarmTimer = new QTimer(this);
+
+    alarmTimer->setInterval(60000);
+    alarmTimer->start();
     saved_title = windowTitle();
 
 #ifdef N810
     saved_title = windowTitle();
 
 #ifdef N810
@@ -69,10 +81,6 @@ MainWindow::MainWindow(int aEventId, QWidget *aParent)
     if(!AppSettings::contains("proxyIsDirectConnection"))
         AppSettings::setDirectConnection(true);
 
     if(!AppSettings::contains("proxyIsDirectConnection"))
         AppSettings::setDirectConnection(true);
 
-    if(AppSettings::isDirectConnection())
-    {
-        qDebug() << "Setting-up proxy: " << AppSettings::proxyAddress() << ":" << AppSettings::proxyPort();
-    }
     QNetworkProxy proxy(
             AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
             AppSettings::proxyAddress(),
     QNetworkProxy proxy(
             AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
             AppSettings::proxyAddress(),
@@ -81,184 +89,229 @@ MainWindow::MainWindow(int aEventId, QWidget *aParent)
             PROXY_PASSWD);
     QNetworkProxy::setApplicationProxy(proxy);
 
             PROXY_PASSWD);
     QNetworkProxy::setApplicationProxy(proxy);
 
-    #if 0
-    // list of conferences must be maintained by ConferenceEditor
-    // here must be one of the signals from the closing ConferenceEditor (or model):
-    // selectedConf(conference), noConf()
-    connect(importScheduleWidget, SIGNAL(scheduleImported(int)), SLOT(scheduleImported(int)));
-    connect(importScheduleWidget, SIGNAL(scheduleDeleted(const QString&)), SLOT(scheduleDeleted(const QString&)));
-    #endif
-
     // event details have changed
     // 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)));
-
-    // event conference map button clicked
-    #if 0
-    // TODO: think about it when return to maps
-    connect(showMapButton, SIGNAL(clicked()), SLOT(conferenceMapClicked()));
-    #endif
-
-    connect(aboutAction, SIGNAL(triggered()), SLOT(aboutApp()));
-    connect(settingsAction, SIGNAL(triggered()), SLOT(setup()));
-    connect(conferencesAction, SIGNAL(triggered()), SLOT(showConferences()));
-
+    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)));
+
+    // search result has changed
+    connect(searchTabContainer, SIGNAL(searchResultChanged()), SLOT(onSearchResultChanged()));
+
+    // systm tray icon
+    connect(systemTrayIcon, SIGNAL(messageClicked()), SLOT(onSystemTrayMessageClicked()));
+    connect(systemTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(onSystemTrayMessageClicked()));
+
+    // timer
+    connect(alarmTimer, SIGNAL(timeout()), SLOT(onAlarmTimerTimeout()));
+
+    // add the actions from the main menu to the window, otherwise the shortcuts don't work on MAEMO
+    addAction(conferencesAction);
+    addAction(settingsAction);
+    addAction(quitAction);
+
+    // make it impossible to hide the toolbar by disallowing its context menu
+    toolBar->setContextMenuPolicy(Qt::PreventContextMenu);
+
+    // open conference
     useConference(Conference::activeConference());
     useConference(Conference::activeConference());
-
-    #if 0
-    // TODO: remove GUI
-    // initialisation of model and pick active conference from there and call conferenceChanged()
-    // selectConference->setDuplicatesEnabled(false);
-    int confCount = Conference::getAll().count();
-    if(confCount)
-    {
+    // optimization, see useConference() code
+    try {
         initTabs();
         initTabs();
-        // fillAndShowConferenceHeader();
-        setWindowTitle(Conference::getById(confId).title());
-
-        QList<Conference> confs = Conference::getAll();
-        QListIterator<Conference> i(confs);
-        while(i.hasNext())
-        {
-            Conference conf = i.next();
-            // TODO: remove GUI
-            // selectConference->addItem(conf.title(),conf.id());
-        }
-        // TODO: remove GUI
-        // int idx = selectConference->findText(Conference::getById(Conference::activeConference()).title());
-        // selectConference->setCurrentIndex(idx);
-        // connect(selectConference, SIGNAL(currentIndexChanged(int)), SLOT(conferenceChanged(int)));
-        // conferenceChanged(idx);
-    }
-    else
-    {
-        // TODO: remove GUI
-        // conferenceHeader->hide();
-        // selectConferenceWidget->hide();
-        // // go to the 'conferenceTab', so the user can import the schedule
-        // tabWidget->setCurrentIndex(6); // 6 - conference tab
-    }
-    #endif
-
-    // open dialog for given Event ID
-    // this is used in case Alarm Dialog request application to start
-    if(aEventId)
-    {
-        try
-        {
-            EventDialog dialog(aEventId,this);
-            dialog.exec();
-        }
-        catch(OrmNoObjectException&) {} // just start application
-        catch(...) {} // just start application
+    } catch (const OrmException& e) {
+        qDebug() << "OrmException:" << e.text();
+        clearTabs();
     }
 
     connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
     }
 
     connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
-
     connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
     connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
-    connect(mXmlParser, SIGNAL(parsingScheduleEnd(const QString&)), conferenceModel, SLOT(newConferenceEnd(const QString&)));
+    connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), conferenceModel, SLOT(newConferenceEnd(int)));
 }
 
 }
 
-void MainWindow::scheduleImported(int aConfId)
-{
-    Q_UNUSED(aConfId);
-
-    // TODO: this all goes to ConferenceEditor and model of conferences
-    #if 0
-
-    Conference conf = Conference::getById(aConfId);
-    if( selectConference->findText(conf.title()) < 0 ) // item doesn't exist
-    {
-        disconnect(selectConference, SIGNAL(currentIndexChanged(int)), this, SLOT(conferenceChanged(int)));
-        selectConference->addItem(conf.title(),conf.id());
-        connect(selectConference, SIGNAL(currentIndexChanged(int)), SLOT(conferenceChanged(int)));
-    }
-    int confCount = Conference::getAll().count();
-    if(confCount)
-    {
-        int idx = selectConference->findText(conf.title());
-        selectConference->setCurrentIndex(idx);
-
-        selectConferenceWidget->show();
 
 
-        conferenceChanged(idx);
-    }
-    #endif
+MainWindow::~MainWindow() {
+    sqlEngine->close();
 }
 
 }
 
-void MainWindow::scheduleDeleted(const QString& title)
-{
-    Q_UNUSED(title);
-    // TODO: this all goes to ConferenceEditor and model of conferences
-    #if 0
-    int idx = selectConference->findText(title);
-
-    if (idx == -1) {
-        // should not happen
-        qWarning() << __PRETTY_FUNCTION__ << "removed non-existent item:" << title;
-        // this happens when you remove the only conference (the list is not ptoperly inited in this case)
-        // now make sure that conferencet
-        if (selectConference->count() > 0) {
-            selectConference->setCurrentIndex(0);
-            conferenceChanged(0);
-        } else {
-            conferenceChanged(-1);
-        }
-    } else {
-        // will it signal "changed"?
-        selectConference->removeItem(idx);
-    }
-    #endif
-}
 
 
-void MainWindow::aboutApp()
+void MainWindow::on_aboutAction_triggered()
 {
     QDialog dialog(this);
     Ui::AboutDialog ui;
     ui.setupUi(&dialog);
 {
     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();
 }
 
 #ifdef N810
     dialog.setFixedWidth(width());
 #endif
     dialog.exec();
 }
 
-void MainWindow::conferenceMapClicked()
-{
-    QString mapPath = QString(":/maps/campus.png");
-    if(!QFile::exists(mapPath))
-        mapPath = QString(":/maps/rooms/not-available.png");
 
 
-    QString roomName;
+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(), confId);
+    setEnabled(false);
+}
+
 
 
-    QPixmap map(mapPath);
-    MapWindow window(map,roomName,this);
-    window.exec();
+void MainWindow::on_nowAction_triggered() {
+    int confId = Conference::activeConference();
+    if (confId== -1) return;
+    dayNavigator->setCurDate(QDate::currentDate());
+    dayTabContainer->expandTimeGroup(QTime::currentTime(), confId);
 }
 
 }
 
-void MainWindow::eventHasChanged(int aEventId, bool aReloadModel)
-{
-    dayTabContainer->updateTreeViewModel(aEventId);
-    favsTabContainer->updateTreeViewModel(aEventId,aReloadModel);
-    tracksTabContainer->updateTreeViewModel(aEventId);
-    nowTabContainer->updateTreeViewModel(aEventId);
-    roomsTabContainer->updateTreeViewModel(aEventId);
-    searchTabContainer->updateTreeViewModel(aEventId);
+
+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::onSystemTrayMessageClicked() {
+    systemTrayIcon->hide();
 }
 
 }
 
-void MainWindow::useConference(int id)
+
+void MainWindow::onAlarmTimerTimeout() {
+    // determine if an alarm is set on an event that's starting soon
+    QList<Event> events = Event::getImminentAlarmEvents(AppSettings::preEventAlarmSec(), Conference::activeConference());
+    if (events.empty()) return;
+
+    // build a message string
+    Event event;
+    QString title;
+    QString message;
+    if (events.size() == 1) {
+        event = events.first();
+        title = tr("Next event at %1").arg(event.start().toString("HH:mm"));
+        message = tr("\"%1\"\n(%2)").arg(event.title()).arg(event.room()->name());
+    } else {
+        title = tr("%1 upcoming events").arg(events.size());
+        QStringList messages;
+        foreach (event, events) {
+            messages += tr("%1: \"%2\" (%3)").arg(event.start().toString("HH:mm")).arg(event.title()).arg(event.room()->name());
+        }
+        message = messages.join("\n");
+    }
+
+    // and delete the corresponding alarm
+    foreach (event, events) {
+        event.setHasAlarm(false);
+        event.update("alarm");
+        onEventChanged(event.id(), false);
+    }
+
+    // show message
+    systemTrayIcon->show();
+    // The next two lines are to prevent a very strange position of the message box the first time at X11/aweseome (not Win32/XP)
+    systemTrayIcon->showMessage("ConfClerk", "Your upcoming events", QSystemTrayIcon::Information);
+    qApp->processEvents();
+    systemTrayIcon->showMessage(title, message, QSystemTrayIcon::Information, 60*60*24*1000);
+    QApplication::alert(this);
+    QApplication::beep();
+}
+
+
+void MainWindow::useConference(int conferenceId)
 {
 {
+    if (conferenceId == -1)  // in case no conference is active
+    {
+        unsetConference();
+        return;
+    }
     try {
     try {
-        Conference::getById(Conference::activeConference()).update("active",0);
-        Conference::getById(id).update("active",1);
-
-        initTabs();
+        int oldActiveConferenceId = Conference::activeConference();
+        bool switchActiveConference = conferenceId != oldActiveConferenceId;
+        if (switchActiveConference) Conference::getById(oldActiveConferenceId).update("active", 0);
+        Conference activeConference = Conference::getById(conferenceId);
+        if (switchActiveConference) activeConference.update("active",1);
+
+        // looks like it does not work at n900
+        setWindowTitle(activeConference.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
     } catch (OrmException& e) {
         // cannon set an active conference
-        unsetConference();
+        unsetConference();   // TODO: as no active conference is now correctly managed this should be handled as a fatal error
         return;
     }
 
         return;
     }
 
@@ -267,49 +320,54 @@ void MainWindow::useConference(int id)
 void MainWindow::initTabs()
 {
     int confId = Conference::activeConference();
 void MainWindow::initTabs()
 {
     int confId = Conference::activeConference();
-    Conference active = Conference::getById(confId);
-    QDate startDate = active.start();
-    QDate endDate = active.end();
-    setWindowTitle(active.title());
-
-    // '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());
+    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
+        dayNavigator->setDates(startDate, endDate);
+        nowAction->trigger();
+    }
 }
 
 }
 
-void MainWindow::unsetConference()
+void MainWindow::clearTabs()
 {
     dayTabContainer->clearModel();
     tracksTabContainer->clearModel();
     roomsTabContainer->clearModel();
     favsTabContainer->clearModel();
     searchTabContainer->clearModel();
 {
     dayTabContainer->clearModel();
     tracksTabContainer->clearModel();
     roomsTabContainer->clearModel();
     favsTabContainer->clearModel();
     searchTabContainer->clearModel();
-    searchTabContainer->searchAgainClicked();
-    nowTabContainer->clearModel();
+}
 
 
-    // TODO:  remove
-    // conferenceHeader->hide();
+void MainWindow::unsetConference()
+{
+    clearTabs();
+    dayNavigator->unsetDates();
     setWindowTitle(saved_title);
 }
 
     setWindowTitle(saved_title);
 }
 
-void MainWindow::setup()
+
+void MainWindow::showError(const QString& message) {
+    error_message(message);
+}
+
+
+void MainWindow::on_settingsAction_triggered()
 {
     SettingsDialog dialog;
 {
     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);
+    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.
 }
 
 /** Create and run ConferenceEditor dialog, making required connections for it.
@@ -322,14 +380,12 @@ this:
 this, mXmlParser and mNetworkAccessManager:
  addition and refresh.
 */
 this, mXmlParser and mNetworkAccessManager:
  addition and refresh.
 */
-void MainWindow::showConferences()
+void MainWindow::on_conferencesAction_triggered()
 {
     ConferenceEditor dialog(conferenceModel, this);
 
 {
     ConferenceEditor dialog(conferenceModel, this);
 
-    // TODO: connect signals about progress of network and parsing
-
-    connect(&dialog, SIGNAL(haveConferenceUrl(const QString&)), SLOT(importFromNetwork(const QString&)));
-    connect(&dialog, SIGNAL(haveConferenceFile(const QString&)), SLOT(importFromFile(const QString&)));
+    connect(&dialog, SIGNAL(haveConferenceUrl(const QString&, int)), SLOT(importFromNetwork(const QString&, int)));
+    connect(&dialog, SIGNAL(haveConferenceFile(const QString&, int)), SLOT(importFromFile(const QString&, int)));
     connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
     connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
                     SLOT(changeConferenceUrl(int, const QString&)));
     connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
     connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
                     SLOT(changeConferenceUrl(int, const QString&)));
@@ -339,84 +395,78 @@ void MainWindow::showConferences()
 
     connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
     connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
 
     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(mXmlParser, SIGNAL(parsingScheduleEnd(int)), &dialog, SLOT(importFinished(int)));
 
     connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
 
     dialog.exec();
 
     connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
 
     dialog.exec();
-}
 
 
-void MainWindow::networkQueryFinished(QNetworkReply *aReply)
-{
-    if ( aReply->error() != QNetworkReply::NoError )
-    {
-        error_message(QString("Error occured during download: ") + aReply->errorString());
+    // optimization, see useConference() code
+    try {
+        initTabs();
+    } catch (OrmException) {
+        clearTabs();
     }
     }
-    else
-    {
-        qDebug() << __PRETTY_FUNCTION__ << ": have data";
-        importData(aReply->readAll(), aReply->url().toEncoded());
+}
+
+void MainWindow::networkQueryFinished(QNetworkReply *aReply) {
+    if (aReply->error() != QNetworkReply::NoError) {
+        error_message(QString("Error occurred during download: ") + aReply->errorString());
+    } else {
+        QUrl redirectUrl = aReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+        if (!redirectUrl.isEmpty()) {
+            if (redirectUrl != aReply->request().url()) {
+                importFromNetwork(redirectUrl.toString(), aReply->request().attribute(QNetworkRequest::User).toInt());
+                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(), aReply->request().attribute(QNetworkRequest::User).toInt());
+        }
     }
     }
+    setEnabled(true);
 }
 
 }
 
-void MainWindow::importData(const QByteArray &aData, const QString& url)
+void MainWindow::importData(const QByteArray &aData, const QString& url, int conferenceId)
 {
 {
-    // TODO: remove GUI
-    // instead send signals to the child dialog
-    #if 0
-    browse->hide();
-    online->hide();
-    progressBar->show();
-    // proxySettings->hide();
-    #endif
-
-    int confId = mXmlParser->parseData(aData, url);
-
-    #if 0
-    progressBar->hide();
-    browse->show();
-    online->show();
-    // proxySettings->show();
-    importScheduleLabel->setText("Schedule:");
-
-    #endif
-    if (confId > 0) {
-        emit(scheduleImported(confId));
-    }
+    mXmlParser->parseData(aData, url, conferenceId);
 }
 
 }
 
-void MainWindow::importFromNetwork(const QString& url)
+void MainWindow::importFromNetwork(const QString& url, int conferenceId)
 {
 {
-    qDebug() << __PRETTY_FUNCTION__;
     QNetworkRequest request;
     QNetworkRequest request;
+    QSslConfiguration qSslConfiguration = request.sslConfiguration();
+    qSslConfiguration.setProtocol(QSsl::AnyProtocol);
+    qSslConfiguration.setPeerVerifyMode(QSslSocket::QueryPeer);
     request.setUrl(QUrl(url));
     request.setUrl(QUrl(url));
+    request.setSslConfiguration(qSslConfiguration);
+    request.setAttribute(QNetworkRequest::User, conferenceId);
 
     mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
     mNetworkAccessManager->get(request);
 }
 
 
     mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
     mNetworkAccessManager->get(request);
 }
 
-void MainWindow::importFromFile(const QString& filename)
+void MainWindow::importFromFile(const QString& filename, int conferenceId)
 {
 {
-    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())));
     }
 
     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(), "");
+    importData(file.readAll(), "", conferenceId);
 }
 
 }
 
-void MainWindow::removeConference(int id)
-{
-    Conference::deleteConference(id);
-    conferenceModel->conferenceRemoved();
 
 
+void MainWindow::removeConference(int id) {
+    sqlEngine->deleteConference(id);
+    conferenceModel->conferenceRemoved();
     emit conferenceRemoved();
 }
 
     emit conferenceRemoved();
 }
 
-void MainWindow::changeConferenceUrl(int id, const QString& url)
-{
+
+void MainWindow::changeConferenceUrl(int id, const QString& url) {
     Conference::getById(id).setUrl(url);
 }
 
     Conference::getById(id).setUrl(url);
 }