reworked UI for conference editing
authorkirilma <kirilma@localhost>
Thu, 22 Apr 2010 14:26:31 +0000 (14:26 +0000)
committerkirilma <kirilma@localhost>
Thu, 22 Apr 2010 14:26:31 +0000 (14:26 +0000)
underlying representation of conference list is also changed

20 files changed:
src/gui/conferenceeditor.cpp [new file with mode: 0644]
src/gui/conferenceeditor.h [new file with mode: 0644]
src/gui/conferenceeditor.ui [new file with mode: 0644]
src/gui/gui.pro
src/gui/mainwindow.cpp
src/gui/mainwindow.h
src/gui/mainwindow.ui
src/gui/urlinputdialog.cpp [new file with mode: 0644]
src/gui/urlinputdialog.h [new file with mode: 0644]
src/gui/urlinputdialog.ui [new file with mode: 0644]
src/icons.qrc
src/icons/add.png [new file with mode: 0644]
src/icons/reload.png [new file with mode: 0644]
src/icons/remove.png [new file with mode: 0644]
src/mvc/conference.h
src/mvc/conferencemodel.cpp [new file with mode: 0644]
src/mvc/conferencemodel.h [new file with mode: 0644]
src/mvc/mvc.pro
src/sql/schedulexmlparser.cpp
src/sql/schedulexmlparser.h

diff --git a/src/gui/conferenceeditor.cpp b/src/gui/conferenceeditor.cpp
new file mode 100644 (file)
index 0000000..5f7459c
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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 "conferenceeditor.h"
+
+#include "conferencemodel.h"
+#include "urlinputdialog.h"
+
+#include <QInputDialog>
+#include <QItemSelectionModel>
+#include <QFileDialog>
+#include <QMessageBox>
+
+ConferenceEditor::ConferenceEditor(ConferenceModel* model, QWidget* parent)
+: QDialog(parent)
+, model(model)
+, selected_id(-1)
+{
+    setupUi(this);
+    progressBar->hide();
+
+    confView->setModel(model);
+
+    QItemSelectionModel* confViewSelection = new QItemSelectionModel(model, this);
+    confView->setSelectionModel(confViewSelection);
+
+    connect(confViewSelection, SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
+                                SLOT(itemSelected(const QModelIndex&, const QModelIndex&)));
+    connect(this, SIGNAL(wantCurrent(const QModelIndex&, QItemSelectionModel::SelectionFlags)),
+            confViewSelection, SLOT(setCurrentIndex(const QModelIndex&, QItemSelectionModel::SelectionFlags)));
+    connect(addBtn, SIGNAL(clicked()), SLOT(addClicked()));
+    connect(removeBtn, SIGNAL(clicked()), SLOT(removeClicked()));
+    connect(changeUrl, SIGNAL(clicked()), SLOT(changeUrlClicked()));
+    connect(refreshBtn, SIGNAL(clicked()), SLOT(refreshClicked()));
+
+    // it's OK to emit selection signals here
+    // because they are not yet connected to anybody
+    int active_id = Conference::activeConference();
+    if (active_id > 0) {
+        emit wantCurrent(model->indexFromId(active_id), QItemSelectionModel::SelectCurrent);
+    } else {
+        itemSelected(QModelIndex(), QModelIndex());
+    }
+}
+
+void ConferenceEditor::conferenceRemoved()
+{
+    if (model->rowCount() > 0) {
+        emit wantCurrent(model->index(0, 0), QItemSelectionModel::SelectCurrent);
+    } else {
+        itemSelected(QModelIndex(), QModelIndex());
+    }
+}
+
+void ConferenceEditor::itemSelected(const QModelIndex& current, const QModelIndex& previous)
+{
+    // TODO: fill all required fields
+    Q_UNUSED(previous);
+    if (!current.isValid()) {
+        selected_id = -1;
+
+        emit noneConferenceSelected();
+
+        conferenceInfo->setCurrentIndex(1);
+        removeBtn->hide();
+    } else {
+        const Conference& conf = model->conferenceFromIndex(current);
+        selected_id = conf.id();
+
+        emit haveConferenceSelected(selected_id);
+
+        conferenceTitle->setText(conf.title());
+        conferenceSubtitle->setText(conf.subtitle());
+        conferenceWhere->setText(conf.city() + ", " + conf.venue());
+        conferenceWhen->setText(
+                conf.start().toString("dd-MM-yyyy")
+                + ", " +
+                conf.end().toString("dd-MM-yyyy"));
+        conferenceInfo->setCurrentIndex(0);
+        removeBtn->show();
+    }
+}
+
+void ConferenceEditor::addClicked()
+{
+    UrlInputDialog url_input(this);
+    switch (url_input.exec()) {
+    case UrlInputDialog::HaveUrl: emit haveConferenceUrl(url_input.url()); break;
+    case UrlInputDialog::HaveFile: emit haveConferenceFile(url_input.url()); break;
+    case UrlInputDialog::Cancel: return;
+    }
+}
+
+void ConferenceEditor::removeClicked()
+{
+    if (selected_id < 0) {
+        // TODO: disable it when none is selected
+        return;
+    }
+
+    QMessageBox::StandardButton answer = 
+        QMessageBox::question(0
+            , "Deletion confirmation"
+            , QString("Really delete the %1 conference").arg(Conference::getById(selected_id).title())
+            , QMessageBox::Yes | QMessageBox::No
+            , QMessageBox::No);
+
+    if (answer == QMessageBox::Yes) {
+        emit removeConferenceRequested(selected_id);
+    }
+}
+
+void ConferenceEditor::changeUrlClicked()
+{
+    if (selected_id < 0) {
+        return;
+    }
+    const Conference& selected = Conference::getById(selected_id);
+
+    bool ok;
+    QString url = QInputDialog::getText(this, "URL Input", "Enter schedule URL", QLineEdit::Normal, selected.url(), &ok);
+
+    if (ok) {
+        emit changeUrlRequested(selected_id, url);
+    }
+}
+
+void ConferenceEditor::refreshClicked()
+{
+    if (selected_id < 0) {
+        return;
+    }
+    const Conference& selected = Conference::getById(selected_id);
+
+    QString url = selected.url();
+
+    if (!url.isEmpty()) {
+        emit haveConferenceUrl(url);
+    } else {
+        static const QString format("Schedule URL for %1 is not set. Enter the schedule URL:");
+        bool ok;
+        QString url = QInputDialog::getText(this, "URL Input", format.arg(selected.title()), QLineEdit::Normal, QString(), &ok);
+
+        if (ok) {
+            // first save it, to remain if fetch fails
+            emit changeUrlRequested(selected_id, url);
+            // then fetch
+            emit haveConferenceUrl(url);
+        }
+    }
+}
+
+void ConferenceEditor::importStarted()
+{
+    addBtn->hide();
+    removeBtn->hide();
+    progressBar->setValue(0);
+    progressBar->show();
+
+    QApplication::processEvents();
+}
+
+void ConferenceEditor::showParsingProgress(int progress)
+{
+    progressBar->setValue(progress);
+
+    QApplication::processEvents();
+}
+
+void ConferenceEditor::importFinished(const QString& title)
+{
+    qDebug() << __PRETTY_FUNCTION__ << title;
+    addBtn->show();
+    progressBar->hide();
+
+    QApplication::processEvents();
+
+    int num = model->rowCount();
+    for (int i = 0; i < num; i++) {
+        QModelIndex item = model->index(i, 0);
+        if (model->data(item) == title) {
+            emit wantCurrent(item, QItemSelectionModel::SelectCurrent);
+            return;
+        }
+    }
+    itemSelected(QModelIndex(), QModelIndex());
+}
diff --git a/src/gui/conferenceeditor.h b/src/gui/conferenceeditor.h
new file mode 100644 (file)
index 0000000..336375b
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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/>.
+ */
+#ifndef CONFERENCE_EDITOR_H
+#define CONFERENCE_EDITOR_H
+
+#include "ui_conferenceeditor.h"
+
+#include <QItemSelectionModel>
+
+class ConferenceModel;
+
+/** ConferenceEditor clas is used for managing list of conferences.
+
+That is, selecting an active conference, adding a new conference from URL or
+file, removing a conference, refreshing a conference from URL that is saved in
+the DB.
+
+It does not do anything of this itself, instead emitting controlling signals.
+On the ConferenceEditor creation, they are connected to proper listeners.
+
+\see MainWindow::showConferences()
+*/
+class ConferenceEditor : public QDialog, private Ui::ConferenceEditor {
+    Q_OBJECT
+
+public:
+    ConferenceEditor(ConferenceModel* model, QWidget* parent);
+    virtual ~ConferenceEditor() { }
+signals:
+    void haveConferenceSelected(int id);
+    void noneConferenceSelected();
+
+    void haveConferenceUrl(const QString& url);
+    void haveConferenceFile(const QString& path);
+    void removeConferenceRequested(int id);
+    void changeUrlRequested(int, const QString&);
+
+    void wantCurrent(const QModelIndex&, QItemSelectionModel::SelectionFlags);
+public slots:
+    void importStarted();
+    void importFinished(const QString& title);
+    void conferenceRemoved();
+    void showParsingProgress(int);
+private slots:
+    void itemSelected(const QModelIndex& current, const QModelIndex& previous);
+    void addClicked();
+    void removeClicked();
+    void changeUrlClicked();
+    void refreshClicked();
+
+private:
+    ConferenceModel* model;
+    int selected_id;
+    QString import_in_progress_title;
+};
+
+#endif
diff --git a/src/gui/conferenceeditor.ui b/src/gui/conferenceeditor.ui
new file mode 100644 (file)
index 0000000..2cd33ff
--- /dev/null
@@ -0,0 +1,345 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConferenceEditor</class>
+ <widget class="QDialog" name="ConferenceEditor">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>548</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Edit Conferences</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="../icons.qrc">
+    <normaloff>:/icons/brain-alone.png</normaloff>:/icons/brain-alone.png</iconset>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QWidget" name="widget_2" native="true">
+        <layout class="QVBoxLayout" name="verticalLayout_2">
+         <item>
+          <widget class="QWidget" name="widget_4" native="true">
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item>
+             <widget class="QPushButton" name="addBtn">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>38</width>
+                <height>27</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>38</width>
+                <height>27</height>
+               </size>
+              </property>
+              <property name="text">
+               <string notr="true"/>
+              </property>
+              <property name="icon">
+               <iconset resource="../icons.qrc">
+                <normaloff>:/icons/add.png</normaloff>:/icons/add.png</iconset>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="removeBtn">
+              <property name="text">
+               <string notr="true"/>
+              </property>
+              <property name="icon">
+               <iconset resource="../icons.qrc">
+                <normaloff>:/icons/remove.png</normaloff>:/icons/remove.png</iconset>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QProgressBar" name="progressBar">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+                <horstretch>10</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="value">
+               <number>0</number>
+              </property>
+              <property name="textVisible">
+               <bool>false</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>0</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QListView" name="confView"/>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_3" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <item>
+          <widget class="QStackedWidget" name="conferenceInfo">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="currentIndex">
+            <number>0</number>
+           </property>
+           <widget class="QWidget" name="conferenceInfoContents" native="true">
+            <layout class="QVBoxLayout" name="verticalLayout_4">
+             <item>
+              <widget class="QLabel" name="conferenceTitle">
+               <property name="font">
+                <font>
+                 <weight>75</weight>
+                 <bold>true</bold>
+                </font>
+               </property>
+               <property name="text">
+                <string>Conference Name</string>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignCenter</set>
+               </property>
+               <property name="wordWrap">
+                <bool>true</bool>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QLabel" name="conferenceSubtitle">
+               <property name="text">
+                <string>Conference Subtitle</string>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignCenter</set>
+               </property>
+               <property name="wordWrap">
+                <bool>true</bool>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <layout class="QGridLayout" name="gridLayout_7">
+               <item row="0" column="0">
+                <widget class="QLabel" name="label_3">
+                 <property name="font">
+                  <font>
+                   <weight>75</weight>
+                   <italic>true</italic>
+                   <bold>true</bold>
+                  </font>
+                 </property>
+                 <property name="text">
+                  <string>When:</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="0">
+                <widget class="QLabel" name="label_4">
+                 <property name="font">
+                  <font>
+                   <weight>75</weight>
+                   <italic>true</italic>
+                   <bold>true</bold>
+                  </font>
+                 </property>
+                 <property name="text">
+                  <string>Where:</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="2">
+                <widget class="QLabel" name="conferenceWhen">
+                 <property name="text">
+                  <string>DATE (FROM - TO)</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="2">
+                <widget class="QLabel" name="conferenceWhere">
+                 <property name="text">
+                  <string>CITY, CAMPUS</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="3">
+                <widget class="QPushButton" name="showMapButton_2">
+                 <property name="text">
+                  <string>MAP</string>
+                 </property>
+                 <property name="icon">
+                  <iconset resource="../icons.qrc">
+                   <normaloff>:/icons/compassBig.png</normaloff>:/icons/compassBig.png</iconset>
+                 </property>
+                 <property name="flat">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="4">
+                <spacer name="horizontalSpacer_4">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+               <item row="0" column="1">
+                <widget class="QLabel" name="spacer_2">
+                 <property name="text">
+                  <string/>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <widget class="QWidget" name="widget_5" native="true">
+               <layout class="QHBoxLayout" name="horizontalLayout_3">
+                <item>
+                 <spacer name="horizontalSpacer_2">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>40</width>
+                    <height>20</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item>
+                 <widget class="QPushButton" name="refreshBtn">
+                  <property name="text">
+                   <string notr="true"/>
+                  </property>
+                  <property name="icon">
+                   <iconset resource="../icons.qrc">
+                    <normaloff>:/icons/reload.png</normaloff>:/icons/reload.png</iconset>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QPushButton" name="changeUrl">
+                  <property name="text">
+                   <string>Change URL</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+           <widget class="QWidget" name="conferenceInfoEmpty"/>
+          </widget>
+         </item>
+         <item>
+          <widget class="QWidget" name="widget_6" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_4">
+            <item>
+             <spacer name="horizontalSpacer_5">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="closeButton">
+              <property name="text">
+               <string>Close</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../icons.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>closeButton</sender>
+   <signal>clicked()</signal>
+   <receiver>ConferenceEditor</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>469</x>
+     <y>249</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>273</x>
+     <y>149</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
index 20aed51..3515c56 100644 (file)
@@ -39,13 +39,14 @@ maemo {
 FORMS += searchhead.ui \
     mainwindow.ui \
     daynavigatorwidget.ui \
-    importschedulewidget.ui \
     about.ui \
     eventdialog.ui \
     conflictsdialog.ui \
     tabcontainer.ui \
     mapwindow.ui \
-    settingsdialog.ui
+    settingsdialog.ui \
+    conferenceeditor.ui \
+    urlinputdialog.ui
 
 HEADERS += roomstabcontainer.h \
     nowtabcontainer.h \
@@ -58,11 +59,12 @@ HEADERS += roomstabcontainer.h \
     conflictsdialog.h \
     mainwindow.h \
     daynavigatorwidget.h \
-    importschedulewidget.h \
     eventdialog.h \
     tabcontainer.h \
     mapwindow.h \
-    settingsdialog.h
+    settingsdialog.h \
+    conferenceeditor.h \
+    urlinputdialog.h
 
 SOURCES += roomstabcontainer.cpp \
     nowtabcontainer.cpp \
@@ -75,11 +77,12 @@ SOURCES += roomstabcontainer.cpp \
     conflictsdialog.cpp \
     mainwindow.cpp \
     daynavigatorwidget.cpp \
-    importschedulewidget.cpp \
     eventdialog.cpp \
     tabcontainer.cpp \
     mapwindow.cpp \
-    settingsdialog.cpp
+    settingsdialog.cpp \
+    conferenceeditor.cpp \
+    urlinputdialog.cpp
 
 HEADERS += errormessage.h
 SOURCES += errormessage.cpp
index 80321c3..f5b9dd7 100644 (file)
@@ -21,6 +21,8 @@
 #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>
@@ -47,6 +52,9 @@ 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);
 
@@ -73,10 +81,13 @@ MainWindow::MainWindow(int aEventId, QWidget *aParent)
             PROXY_PASSWD);
     QNetworkProxy::setApplicationProxy(proxy);
 
-    int confId = Conference::activeConference();
-
+    #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
     connect(dayTabContainer, SIGNAL(eventHasChanged(int,bool)), SLOT(eventHasChanged(int,bool)));
@@ -87,17 +98,26 @@ MainWindow::MainWindow(int aEventId, QWidget *aParent)
     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()));
 
-    selectConference->setDuplicatesEnabled(false);
+    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)
     {
         initTabs();
-        fillAndShowConferenceHeader();
+        // fillAndShowConferenceHeader();
         setWindowTitle(Conference::getById(confId).title());
 
         QList<Conference> confs = Conference::getAll();
@@ -105,20 +125,24 @@ MainWindow::MainWindow(int aEventId, QWidget *aParent)
         while(i.hasNext())
         {
             Conference conf = i.next();
-            selectConference->addItem(conf.title(),conf.id());
+            // TODO: remove GUI
+            // selectConference->addItem(conf.title(),conf.id());
         }
-        int idx = selectConference->findText(Conference::getById(Conference::activeConference()).title());
-        selectConference->setCurrentIndex(idx);
-        connect(selectConference, SIGNAL(currentIndexChanged(int)), SLOT(conferenceChanged(int)));
-        conferenceChanged(idx);
+        // 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
     {
-        conferenceHeader->hide();
-        selectConferenceWidget->hide();
-        // go to the 'conferenceTab', so the user can import the schedule
-        tabWidget->setCurrentIndex(6); // 6 - conference tab
+        // 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
@@ -132,12 +156,20 @@ MainWindow::MainWindow(int aEventId, QWidget *aParent)
         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)
 {
     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
     {
@@ -155,10 +187,14 @@ void MainWindow::scheduleImported(int aConfId)
 
         conferenceChanged(idx);
     }
+    #endif
 }
 
 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) {
@@ -176,6 +212,7 @@ void MainWindow::scheduleDeleted(const QString& title)
         // will it signal "changed"?
         selectConference->removeItem(idx);
     }
+    #endif
 }
 
 void MainWindow::aboutApp()
@@ -212,24 +249,28 @@ void MainWindow::eventHasChanged(int aEventId, bool aReloadModel)
     searchTabContainer->updateTreeViewModel(aEventId);
 }
 
-void MainWindow::fillAndShowConferenceHeader()
+void MainWindow::useConference(int id)
 {
-    int confId = Conference::activeConference();
-    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"));
-    conferenceHeader->show();
+    try {
+        Conference::getById(Conference::activeConference()).update("active",0);
+        Conference::getById(id).update("active",1);
+
+        initTabs();
+    } catch (OrmException& e) {
+        // cannon set an active conference
+        unsetConference();
+        return;
+    }
+
 }
 
 void MainWindow::initTabs()
 {
     int confId = Conference::activeConference();
-    QDate startDate = Conference::getById(confId).start();
-    QDate endDate = Conference::getById(confId).end();
+    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);
@@ -251,32 +292,11 @@ void MainWindow::unsetConference()
     searchTabContainer->searchAgainClicked();
     nowTabContainer->clearModel();
 
-    conferenceHeader->hide();
+    // TODO:  remove
+    // conferenceHeader->hide();
     setWindowTitle(saved_title);
 }
 
-void MainWindow::conferenceChanged(int aIndex)
-{
-    if (aIndex < 0) {
-        // no conferences left? reset all views
-        unsetConference();
-        return;
-    }
-
-    try {
-        Conference::getById(Conference::activeConference()).update("active",0);
-        Conference::getById(selectConference->itemData(aIndex).toInt()).update("active",1);
-    } catch (OrmException& e) {
-        // cannon set an active conference
-        unsetConference();
-        return;
-    }
-
-    initTabs();
-    fillAndShowConferenceHeader();
-    setWindowTitle(Conference::getById(Conference::activeConference()).title());
-}
-
 void MainWindow::setup()
 {
     SettingsDialog dialog;
@@ -291,3 +311,112 @@ void MainWindow::setup()
             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);
+
+    // 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(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();
+}
+
+void MainWindow::networkQueryFinished(QNetworkReply *aReply)
+{
+    if ( aReply->error() != QNetworkReply::NoError )
+    {
+        error_message(QString("Error occured during download: ") + aReply->errorString());
+    }
+    else
+    {
+        qDebug() << __PRETTY_FUNCTION__ << ": have data";
+        importData(aReply->readAll(), aReply->url().toEncoded());
+    }
+}
+
+void MainWindow::importData(const QByteArray &aData, const QString& url)
+{
+    // 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));
+    }
+}
+
+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);
+}
+
index c069636..0ac7e4f 100644 (file)
 
 #include <ui_mainwindow.h>
 
+#include "conferencemodel.h"
+
+class ScheduleXmlParser;
+class QNetworkAccessManager;
+class QNetworkReply;
+
 class MainWindow : public QMainWindow, private Ui::MainWindow
 {
     Q_OBJECT
@@ -31,20 +37,34 @@ public:
     // Event dialog for given Event ID
     MainWindow(int aEventId = 0, QWidget *aParent = NULL);
     ~MainWindow() {}
+signals:
+    void conferenceRemoved();
 private slots:
     void scheduleImported(int aConfId);
     void scheduleDeleted(const QString& title);
     void aboutApp();
     void conferenceMapClicked();
     void eventHasChanged(int aEventId, bool aReloadModel);
-    void conferenceChanged(int aIndex);
     void setup();
+    // TODO: remove
+    void showConferences();
+    void networkQueryFinished(QNetworkReply*);
+    void importFromNetwork(const QString&);
+    void importFromFile(const QString&);
+    void removeConference(int);
+    void changeConferenceUrl(int, const QString&);
+
+    void useConference(int id);
+    void unsetConference();
 private:
     void fillAndShowConferenceHeader();
     void initTabs();
-    void unsetConference();
+    void importData(const QByteArray &aData, const QString& url);
 
     QString saved_title;
+    ConferenceModel* conferenceModel;
+    ScheduleXmlParser *mXmlParser;
+    QNetworkAccessManager *mNetworkAccessManager;
 };
 
 #endif /* MAINWINDOW_H */
index 17c4cd5..d914ee9 100644 (file)
         </item>
        </layout>
       </widget>
-      <widget class="QWidget" name="conferenceTab">
-       <attribute name="title">
-        <string>Conference</string>
-       </attribute>
-       <layout class="QGridLayout" name="gridLayout_5">
-        <item row="0" column="0">
-         <layout class="QVBoxLayout" name="verticalLayout_4">
-          <item>
-           <widget class="QWidget" name="conferenceHeader" native="true">
-            <layout class="QGridLayout" name="gridLayout_9">
-             <item row="0" column="0">
-              <widget class="QLabel" name="conferenceTitle">
-               <property name="font">
-                <font>
-                 <weight>75</weight>
-                 <bold>true</bold>
-                </font>
-               </property>
-               <property name="text">
-                <string>Conference Name</string>
-               </property>
-               <property name="alignment">
-                <set>Qt::AlignCenter</set>
-               </property>
-               <property name="wordWrap">
-                <bool>true</bool>
-               </property>
-              </widget>
-             </item>
-             <item row="1" column="0">
-              <widget class="QLabel" name="conferenceSubtitle">
-               <property name="text">
-                <string>Conference Subtitle</string>
-               </property>
-               <property name="alignment">
-                <set>Qt::AlignCenter</set>
-               </property>
-               <property name="wordWrap">
-                <bool>true</bool>
-               </property>
-              </widget>
-             </item>
-             <item row="2" column="0">
-              <widget class="Line" name="line">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-              </widget>
-             </item>
-             <item row="3" column="0">
-              <layout class="QGridLayout" name="gridLayout_6">
-               <item row="0" column="0">
-                <widget class="QLabel" name="label">
-                 <property name="font">
-                  <font>
-                   <weight>75</weight>
-                   <italic>true</italic>
-                   <bold>true</bold>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string>When:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="0">
-                <widget class="QLabel" name="label_2">
-                 <property name="font">
-                  <font>
-                   <weight>75</weight>
-                   <italic>true</italic>
-                   <bold>true</bold>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string>Where:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="2">
-                <widget class="QLabel" name="conferenceWhen">
-                 <property name="text">
-                  <string>DATE (FROM - TO)</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="2">
-                <widget class="QLabel" name="conferenceWhere">
-                 <property name="text">
-                  <string>CITY, CAMPUS</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="3">
-                <widget class="QPushButton" name="showMapButton">
-                 <property name="text">
-                  <string>MAP</string>
-                 </property>
-                 <property name="icon">
-                  <iconset resource="../icons.qrc">
-                   <normaloff>:/icons/compassBig.png</normaloff>:/icons/compassBig.png</iconset>
-                 </property>
-                 <property name="flat">
-                  <bool>true</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="4">
-                <spacer name="horizontalSpacer_3">
-                 <property name="orientation">
-                  <enum>Qt::Horizontal</enum>
-                 </property>
-                 <property name="sizeHint" stdset="0">
-                  <size>
-                   <width>40</width>
-                   <height>20</height>
-                  </size>
-                 </property>
-                </spacer>
-               </item>
-               <item row="0" column="1">
-                <widget class="QLabel" name="spacer">
-                 <property name="text">
-                  <string/>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </item>
-             <item row="4" column="0">
-              <widget class="Line" name="line_2">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </widget>
-          </item>
-          <item>
-           <widget class="QWidget" name="selectConferenceWidget" native="true">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <layout class="QHBoxLayout" name="horizontalLayout">
-             <item>
-              <widget class="QLabel" name="selectConferenceLabel">
-               <property name="text">
-                <string>Select conference: </string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <spacer name="horizontalSpacer">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-               <property name="sizeHint" stdset="0">
-                <size>
-                 <width>40</width>
-                 <height>20</height>
-                </size>
-               </property>
-              </spacer>
-             </item>
-             <item>
-              <widget class="QComboBox" name="selectConference">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </widget>
-          </item>
-          <item>
-           <widget class="ImportScheduleWidget" name="importScheduleWidget" native="true">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <spacer name="verticalSpacer">
-            <property name="orientation">
-             <enum>Qt::Vertical</enum>
-            </property>
-            <property name="sizeHint" stdset="0">
-             <size>
-              <width>20</width>
-              <height>40</height>
-             </size>
-            </property>
-           </spacer>
-          </item>
-         </layout>
-        </item>
-       </layout>
-      </widget>
      </widget>
     </item>
    </layout>
     </property>
     <addaction name="settingsAction"/>
     <addaction name="aboutAction"/>
+    <addaction name="conferencesAction"/>
    </widget>
    <addaction name="menuMenu"/>
   </widget>
     <string>About</string>
    </property>
   </action>
+  <action name="conferencesAction">
+   <property name="text">
+    <string>Conferences</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
-  <customwidget>
-   <class>ImportScheduleWidget</class>
-   <extends>QWidget</extends>
-   <header>importschedulewidget.h</header>
-   <container>1</container>
-  </customwidget>
   <customwidget>
    <class>SearchTabContainer</class>
    <extends>QWidget</extends>
diff --git a/src/gui/urlinputdialog.cpp b/src/gui/urlinputdialog.cpp
new file mode 100644 (file)
index 0000000..2e088ae
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 "urlinputdialog.h"
+
+#include <QFileDialog>
+#include <QPushButton>
+
+UrlInputDialog::UrlInputDialog(QWidget* parent)
+: QDialog(parent)
+{
+    setupUi(this);
+
+    QPushButton* openFile = buttons->addButton("Open File...", QDialogButtonBox::ActionRole);
+
+    connect(openFile, SIGNAL(clicked()), SLOT(openFileClicked()));
+    connect(buttons, SIGNAL(accepted()), SLOT(acceptClicked()));
+    connect(buttons, SIGNAL(rejected()), SLOT(rejectClicked()));
+}
+
+void UrlInputDialog::openFileClicked()
+{
+    QString file = QFileDialog::getOpenFileName(this, "Select Conference Schedule", QString(), "Schedule Files (*.xml);;All Files(*)");
+
+    if (file.isNull()) {
+        return;
+    } else {
+        saved_result = file;
+        done(HaveFile);
+    }
+}
+
+void UrlInputDialog::acceptClicked()
+{
+    saved_result = urlEntry->text();
+    setResult(HaveUrl);
+}
+
+void UrlInputDialog::rejectClicked()
+{
+    setResult(Cancel);
+}
diff --git a/src/gui/urlinputdialog.h b/src/gui/urlinputdialog.h
new file mode 100644 (file)
index 0000000..c77ce64
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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/>.
+ */
+#ifndef URL_INPUT_DIALOG_H
+#define URL_INPUT_DIALOG_H
+
+#include "ui_urlinputdialog.h"
+
+class UrlInputDialog : public QDialog, private Ui::UrlInputDialog {
+    Q_OBJECT
+public:
+    enum {
+        Cancel,
+        HaveUrl,
+        HaveFile
+    };
+    UrlInputDialog(QWidget* parent);
+    virtual ~UrlInputDialog() { }
+
+    QString url() { return saved_result; }
+private slots:
+    void acceptClicked();
+    void rejectClicked();
+    void openFileClicked();
+private:
+    QString saved_result;
+};
+
+#endif
diff --git a/src/gui/urlinputdialog.ui b/src/gui/urlinputdialog.ui
new file mode 100644 (file)
index 0000000..c0bd2d5
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UrlInputDialog</class>
+ <widget class="QDialog" name="UrlInputDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>URL Input</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Enter schedule URL</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLineEdit" name="urlEntry"/>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttons">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Open</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttons</sender>
+   <signal>accepted()</signal>
+   <receiver>UrlInputDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttons</sender>
+   <signal>rejected()</signal>
+   <receiver>UrlInputDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
index 0e64f06..e77ebe3 100644 (file)
@@ -1,5 +1,8 @@
 <RCC>
     <qresource prefix="/">
+        <file>icons/add.png</file>
+        <file>icons/remove.png</file>
+        <file>icons/reload.png</file>
         <file>icons/expand.png</file>
         <file>icons/collapse.png</file>
         <file>icons/fosdem.png</file>
diff --git a/src/icons/add.png b/src/icons/add.png
new file mode 100644 (file)
index 0000000..297ef45
Binary files /dev/null and b/src/icons/add.png differ
diff --git a/src/icons/reload.png b/src/icons/reload.png
new file mode 100644 (file)
index 0000000..768375d
Binary files /dev/null and b/src/icons/reload.png differ
diff --git a/src/icons/remove.png b/src/icons/remove.png
new file mode 100644 (file)
index 0000000..abc465e
Binary files /dev/null and b/src/icons/remove.png differ
index 8e32c65..cd4f656 100644 (file)
@@ -49,7 +49,7 @@ public:
     int dayChange() const { return value("day_change").toInt(); } // in seconds from 00:00
     int timeslotDuration() const { return value("timeslot_duration").toInt(); } // in seconds
     bool isActive() const { return value("active").toBool(); }
-    QString getUrl() const
+    QString url() const
     {
         QVariant val = value("url");
         qDebug() << __PRETTY_FUNCTION__ << val;
diff --git a/src/mvc/conferencemodel.cpp b/src/mvc/conferencemodel.cpp
new file mode 100644 (file)
index 0000000..dfa98ea
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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 "conferencemodel.h"
+
+ConferenceModel::ConferenceModel(QObject* parent)
+: QAbstractListModel(parent)
+, conferences(Conference::getAll())
+{ }
+
+int ConferenceModel::rowCount(const QModelIndex& parent) const
+{
+    if (parent.isValid()) {
+        return 0;
+    } else {
+        return conferences.size();
+    }
+}
+
+QVariant ConferenceModel::data(const QModelIndex& index, int role) const
+{
+    if (role != Qt::DisplayRole) {
+        return QVariant();
+    }
+
+    return conferences[index.row()].title();
+
+    try {
+        const Conference& c = conferenceFromIndex(index);
+        return c.title();
+    } catch (OrmNoObjectException&) {
+        return QVariant();
+    }
+
+}
+
+const Conference& ConferenceModel::conferenceFromIndex(const QModelIndex& index) const
+{
+    if (index.parent().isValid()
+        or index.column() != 0
+        or index.row() >= conferences.size())
+    {
+        throw OrmNoObjectException();
+    }
+    return conferences[index.row()];
+}
+
+QModelIndex ConferenceModel::indexFromId(int id) const
+{
+    for (int i = 0; i < conferences.size(); ++i) {
+        if (conferences[i].id() == id) {
+            return index(i, 0);
+        }
+    }
+
+    return QModelIndex();
+}
+
+void ConferenceModel::newConferenceBegin()
+{
+}
+
+void ConferenceModel::newConferenceEnd(const QString& title)
+{
+    Q_UNUSED(title);
+    reinit();
+}
+
+void ConferenceModel::conferenceRemoved()
+{
+    reinit();
+}
diff --git a/src/mvc/conferencemodel.h b/src/mvc/conferencemodel.h
new file mode 100644 (file)
index 0000000..668a2e9
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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/>.
+ */
+#ifndef CONFERENCE_MODEL_H
+#define CONFERENCE_MODEL_H
+
+#include <QAbstractListModel>
+#include <QList>
+
+#include "conference.h"
+
+/** ConferenceModel class represents list of conferences for ListViews that may need it.
+
+It also provides typed access to the conferences from ConferenceEditor.
+
+It does not actually modify anything in DB, this is performed by other classes.
+
+\see ConferenceEditor, MainWindow::showConferences()
+*/
+class ConferenceModel : public QAbstractListModel {
+    Q_OBJECT
+public:
+    ConferenceModel(QObject* parent);
+    virtual ~ConferenceModel() { }
+
+    virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
+    virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+
+    const Conference& conferenceFromIndex(const QModelIndex&) const;
+    QModelIndex indexFromId(int id) const;
+public slots:
+    void newConferenceBegin();
+    void newConferenceEnd(const QString& title);
+    void conferenceRemoved();
+private:
+    // reinitialize list from database
+    void reinit()
+    {
+        conferences = Conference::getAll();
+        reset();
+    }
+
+    QList<Conference> conferences;
+};
+
+#endif
index 53c0973..492f6d2 100644 (file)
@@ -26,11 +26,13 @@ HEADERS += event.h \
     delegate.h \
     eventmodel.h \
     treeview.h \
-    room.h 
+    room.h \
+    conferencemodel.h
 SOURCES += event.cpp \
     conference.cpp \
     track.cpp \
     delegate.cpp \
     eventmodel.cpp \
     treeview.cpp \
-    room.cpp 
+    room.cpp \
+    conferencemodel.cpp
index 4da3b5d..ba06515 100644 (file)
@@ -45,6 +45,7 @@ int ScheduleXmlParser::parseData(const QByteArray &aData, const QString& url)
     SqlEngine::beginTransaction();
 
     int confId = 0;
+    QString conference_title;
     if (!scheduleElement.isNull())
     {
         QDomElement conferenceElement = scheduleElement.firstChildElement("conference");
@@ -64,7 +65,8 @@ int ScheduleXmlParser::parseData(const QByteArray &aData, const QString& url)
             conference["url"] = url;
             SqlEngine::addConferenceToDB(conference);
             confId = conference["id"].toInt();
-            emit(parsingSchedule(conference["title"]));
+            conference_title = conference["title"];
+            emit(parsingScheduleBegin());
         }
 
         // we need to get count of all events in order to emit 'progressStatus' signal
@@ -153,6 +155,7 @@ int ScheduleXmlParser::parseData(const QByteArray &aData, const QString& url)
         } // parsing day elements
     } // schedule element
     SqlEngine::commitTransaction();
+    emit parsingScheduleEnd(conference_title);
 
     return confId;
 }
index 13bd3b8..a2ad828 100644 (file)
@@ -32,7 +32,8 @@ class ScheduleXmlParser : public QObject
 
     signals:
         void progressStatus(int aStatus);
-        void parsingSchedule(const QString &aTitle);
+        void parsingScheduleBegin();
+        void parsingScheduleEnd(const QString& title);
 };
 
 #endif /* SCHEDULEXMLPARSER_H_ */