From b431d47d9a2f508e37361c0eafd2b3407e591553 Mon Sep 17 00:00:00 2001 From: kirilma Date: Thu, 22 Apr 2010 14:26:31 +0000 Subject: [PATCH] reworked UI for conference editing underlying representation of conference list is also changed --- src/gui/conferenceeditor.cpp | 202 ++++++++++++++++++++ src/gui/conferenceeditor.h | 73 +++++++ src/gui/conferenceeditor.ui | 345 ++++++++++++++++++++++++++++++++++ src/gui/gui.pro | 15 +- src/gui/mainwindow.cpp | 227 +++++++++++++++++----- src/gui/mainwindow.h | 24 ++- src/gui/mainwindow.ui | 220 +--------------------- src/gui/urlinputdialog.cpp | 57 ++++++ src/gui/urlinputdialog.h | 44 +++++ src/gui/urlinputdialog.ui | 74 ++++++++ src/icons.qrc | 3 + src/icons/add.png | Bin 0 -> 596 bytes src/icons/reload.png | Bin 0 -> 2293 bytes src/icons/remove.png | Bin 0 -> 335 bytes src/mvc/conference.h | 2 +- src/mvc/conferencemodel.cpp | 88 +++++++++ src/mvc/conferencemodel.h | 61 ++++++ src/mvc/mvc.pro | 6 +- src/sql/schedulexmlparser.cpp | 5 +- src/sql/schedulexmlparser.h | 3 +- 20 files changed, 1173 insertions(+), 276 deletions(-) create mode 100644 src/gui/conferenceeditor.cpp create mode 100644 src/gui/conferenceeditor.h create mode 100644 src/gui/conferenceeditor.ui create mode 100644 src/gui/urlinputdialog.cpp create mode 100644 src/gui/urlinputdialog.h create mode 100644 src/gui/urlinputdialog.ui create mode 100644 src/icons/add.png create mode 100644 src/icons/reload.png create mode 100644 src/icons/remove.png create mode 100644 src/mvc/conferencemodel.cpp create mode 100644 src/mvc/conferencemodel.h diff --git a/src/gui/conferenceeditor.cpp b/src/gui/conferenceeditor.cpp new file mode 100644 index 0000000..5f7459c --- /dev/null +++ b/src/gui/conferenceeditor.cpp @@ -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 . + */ +#include "conferenceeditor.h" + +#include "conferencemodel.h" +#include "urlinputdialog.h" + +#include +#include +#include +#include + +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 index 0000000..336375b --- /dev/null +++ b/src/gui/conferenceeditor.h @@ -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 . + */ +#ifndef CONFERENCE_EDITOR_H +#define CONFERENCE_EDITOR_H + +#include "ui_conferenceeditor.h" + +#include + +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 index 0000000..2cd33ff --- /dev/null +++ b/src/gui/conferenceeditor.ui @@ -0,0 +1,345 @@ + + + ConferenceEditor + + + + 0 + 0 + 548 + 300 + + + + Edit Conferences + + + + :/icons/brain-alone.png:/icons/brain-alone.png + + + + + + + + + + + + + + + + 0 + 0 + + + + + 38 + 27 + + + + + 38 + 27 + + + + + + + + :/icons/add.png:/icons/add.png + + + + + + + + + + + :/icons/remove.png:/icons/remove.png + + + + + + + + 10 + 0 + + + + 0 + + + false + + + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + 0 + + + + + + + + 75 + true + + + + Conference Name + + + Qt::AlignCenter + + + true + + + + + + + Conference Subtitle + + + Qt::AlignCenter + + + true + + + + + + + + + + 75 + true + true + + + + When: + + + + + + + + 75 + true + true + + + + Where: + + + + + + + DATE (FROM - TO) + + + + + + + CITY, CAMPUS + + + + + + + MAP + + + + :/icons/compassBig.png:/icons/compassBig.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + :/icons/reload.png:/icons/reload.png + + + + + + + Change URL + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + + + + + + + + + + + closeButton + clicked() + ConferenceEditor + close() + + + 469 + 249 + + + 273 + 149 + + + + + diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 20aed51..3515c56 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -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 diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 80321c3..f5b9dd7 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -32,12 +34,15 @@ #include #include + #include "ui_about.h" #include #include "daynavigatorwidget.h" -#include "importschedulewidget.h" #include "mapwindow.h" #include "settingsdialog.h" +#include "conferenceeditor.h" +#include "schedulexmlparser.h" +#include "errormessage.h" #include #include @@ -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 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); +} + diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index c069636..0ac7e4f 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -23,6 +23,12 @@ #include +#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 */ diff --git a/src/gui/mainwindow.ui b/src/gui/mainwindow.ui index 17c4cd5..d914ee9 100644 --- a/src/gui/mainwindow.ui +++ b/src/gui/mainwindow.ui @@ -93,214 +93,6 @@ - - - Conference - - - - - - - - - - - - 75 - true - - - - Conference Name - - - Qt::AlignCenter - - - true - - - - - - - Conference Subtitle - - - Qt::AlignCenter - - - true - - - - - - - Qt::Horizontal - - - - - - - - - - 75 - true - true - - - - When: - - - - - - - - 75 - true - true - - - - Where: - - - - - - - DATE (FROM - TO) - - - - - - - CITY, CAMPUS - - - - - - - MAP - - - - :/icons/compassBig.png:/icons/compassBig.png - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - - - - - - - - 0 - 0 - - - - - - - Select conference: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - - - - - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - @@ -321,6 +113,7 @@ + @@ -347,14 +140,13 @@ About + + + Conferences + + - - ImportScheduleWidget - QWidget -
importschedulewidget.h
- 1 -
SearchTabContainer QWidget diff --git a/src/gui/urlinputdialog.cpp b/src/gui/urlinputdialog.cpp new file mode 100644 index 0000000..2e088ae --- /dev/null +++ b/src/gui/urlinputdialog.cpp @@ -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 . + */ +#include "urlinputdialog.h" + +#include +#include + +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 index 0000000..c77ce64 --- /dev/null +++ b/src/gui/urlinputdialog.h @@ -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 . + */ +#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 index 0000000..c0bd2d5 --- /dev/null +++ b/src/gui/urlinputdialog.ui @@ -0,0 +1,74 @@ + + + UrlInputDialog + + + + 0 + 0 + 400 + 300 + + + + URL Input + + + + + + Enter schedule URL + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Open + + + + + + + + + buttons + accepted() + UrlInputDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttons + rejected() + UrlInputDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/icons.qrc b/src/icons.qrc index 0e64f06..e77ebe3 100644 --- a/src/icons.qrc +++ b/src/icons.qrc @@ -1,5 +1,8 @@ + icons/add.png + icons/remove.png + icons/reload.png icons/expand.png icons/collapse.png icons/fosdem.png diff --git a/src/icons/add.png b/src/icons/add.png new file mode 100644 index 0000000000000000000000000000000000000000..297ef4500381c8579d0cd86ba880eb0837a6af0d GIT binary patch literal 596 zcmV-a0;~OrP)OugAF8Zv-@?+OXe-qs-qr``MG^I>42VMaqZ=)1Z9c{e z7j3uO-8EU7n>`RnAT#F&nK?;lW~frGQujFk04-X$zR`-3G+icX0L-cT{O;((%8db} zS=M~Hw@-jHGweKnx?H4Bxko^v(``evc$?BQPuh!aXGTiIpaH`6ew@2?Uh1E!aBu!Rc?Z3X@4H)dt zDFHLU(ZLC!s&L}4^K93jv&j~IC9AK@{k<2v;W*>4b|>4~+zvg@gQtpvHwWMQ@rh2eOwgbz4G@Yye{C0Y3zVBNQ1Qy4! z1wml7TFs&;N~Z!iJUl!Da5fI0wYCaz4yp iK1rPan#}>K2KWtUKc8m0j#Od*0000@YK z*LmzmKinkTL@M~HYi7+pANJY*-(F{}z4ihAPqtuPYYG6wr%jr-rgfI#_D+D^Obm;x zv6W!NU@aq1K#Yco=!jBkA1Ul&g+er_$U zO{S8RNT%X3FM*`zf(rpxa&XQ79YRG4xqLwl4xGtnMzRiL{2x&eK4**Jw)Cz|{^Yf1 zuWOwdBepk+)a-QI2Kod*{jII*iSSreO--z#s+w`m!8ikF3~bCfgTonIha={4c&`nAp>D(~@a_+VL*`1VF>Bty{Pd z4^5dlBPpc=#!A9mFmTQxc?p0RL2wSi365lN1cww1uES92NmO_eMn(AGP*1S`K$kHV zztqNV6@qQMZ|(A$`EzIRjZgd$>9!3to&$BOw%p1De{jl-nMol8hzMa2K!pK}R>p!z z3Zi%{hGf!1RZRtAt^^Um62KUNh~P&CIT&XGSmVn>EE0B1IpND?@M)|!f;?in7*lRAFlgi(4) zWhxoXZMd|ean2z0aK!2Y_9>HYor*0qmT&rghfA!^ghYaisU#H!NS^UUyZ42sI%z zb~GXkfieh`fgftXo=ZIj0M?onDhxFMw(Q!)ZzR3gL05{yt|JfUeLqfwJ?AUeG3(sE z{&?4)AAQ6`X5sGrN8fzrrML3Aku0XAoYCqb1d%}y8I-cgP6U84)AHFYYnU_p?^TJ| z`_8Di>+lX0+3DKi<4*%92l@E5@2?)ruv~Uz&XJfi$GZfs+4@JtoQ@~SU|Wj z_t?V5x<7Evav&;lLV*z#gk-OVibod%004DsHh4Z^78rD{1h zf4mIiuGkTC*&#txu#5`AiXwz4NP{QcFn_`06#(j6e!Sdu#OvR>=LRoTkw88$a0DOU z{aD~>as&u$o9o1$bpw4E^REdv-9)Nv-NB0yZ)n-Fh;#P0Z`^%DV%CgmNKU9t3K(mV za7)jC1!n|S7J>8jg3oGmS8blB`Nic)xs4yi^(~vNBRK%TT8l`TPkj*pxJF~wjt!lk zRdlkA=fL9+e+7}Y(8dBF#2td?a4;f-N+Hq~-MvHj)$e!Zw6fQC?fAiG7T@%i6*&5? z)3)zljRU7LPotQrR}7C3M$4{ajP@Rwnl}20=hKA1K`K@mkBBgIhw{1Ll zA+hGK|0brLip#%n%i>o<4RUu3YY!z}ySq%M&7C?YYCj6%3AGFxJ9z7;@Ph zp8nnLq95qBJ=-_#yQuAY2@#oKy(tubQ8Xs5Exa(Yo>3~1^TU?0Y2yG&TUcx13I>8FyT^a;X1q&0m%?54Pz{fvB)WnC~q)- z-Yi~s=~VCij-Ce(bfh0>y#2{{BBh^7c>Y_5UfvXrt#sA>FV-=JjnisVxiE~H`uYcJ z(&=MyPFz<{n=Uhhr_UN?UmOQuM3K@)x`JUwl?zW=_)1_XXW)mW($v}_6DU|qxME?0 zv!L-ZbanUN{BhUuWy2%nG_HH+G(A;8!f{}Xfr=C|1N~VB^Wf-x;@l_TjBvE8 zPrvxu-r-`l@6J8@gFD(k?0MjtMfL3JE9bb?Nf#q|gHQp+SSV!?Dvc;Ih?D_y;;5{N zBV{xqZJ@O#tqim=C22ijja zHr%zVUFAkz87xZk!I4u<$4?F_M@U&y6^9fY)>tT0I<}RzrBhTJXk8LC#=;s4V+=-y zGv-WxzpsMqPtt#RY;#%i8v?-UTQ+OXS!O7`=f=#z*9HMNWiCa$I$7PcW@W|Hxwny% zxVj?cscBPdV~JFfODRFzfif0hq@k2Tz7W7K)9?Lu2!I?DKF=tHNW_wJufN=@Zdl?}Oj*E%cbO%s07zH>WT8MN zYoh3AR2QUJ^ z+0T0)pfUhHNtjI%pA0YtVJ3m-GSPEQ=YIg4&!|k8T>!w8f!I&1G|B!8P=G}|8eA(? P00000NkvXXu0mjfIOspK literal 0 HcmV?d00001 diff --git a/src/icons/remove.png b/src/icons/remove.png new file mode 100644 index 0000000000000000000000000000000000000000..abc465e62201adc1f36b20178c9e374cdcab6af6 GIT binary patch literal 335 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@+C`LBT9nv z(@M${i&7cN%ggmL^RkPR6AM!H@{7`Ezq647DthSY;usRq`u3VVcawv}@sIaQ+r6Ch zwprXboz)TNe&s@d%NHx97pXTdB~4J#n^(#^)%D*=gAEUNI`&mxd7o~xY>Lz5)mJm- zGO#ExFmin0XP8)SA@Qx;v#796PPk@&WPY_gW6-?2Pm`v~Zm4SbnDQhoz*V37;6wR8 zRY!j(^&H%``{&$6{YjdMrEBuFmL_XHe#LO^XQA2rZHy0!sy9SGmJIZoDklH=I(Pqr zM-iL}8M*3RO0o. + */ + +#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 index 0000000..668a2e9 --- /dev/null +++ b/src/mvc/conferencemodel.h @@ -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 . + */ +#ifndef CONFERENCE_MODEL_H +#define CONFERENCE_MODEL_H + +#include +#include + +#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 conferences; +}; + +#endif diff --git a/src/mvc/mvc.pro b/src/mvc/mvc.pro index 53c0973..492f6d2 100644 --- a/src/mvc/mvc.pro +++ b/src/mvc/mvc.pro @@ -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 diff --git a/src/sql/schedulexmlparser.cpp b/src/sql/schedulexmlparser.cpp index 4da3b5d..ba06515 100644 --- a/src/sql/schedulexmlparser.cpp +++ b/src/sql/schedulexmlparser.cpp @@ -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; } diff --git a/src/sql/schedulexmlparser.h b/src/sql/schedulexmlparser.h index 13bd3b8..a2ad828 100644 --- a/src/sql/schedulexmlparser.h +++ b/src/sql/schedulexmlparser.h @@ -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_ */ -- 2.39.5