diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2013-06-07 13:31:42 +0900 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2013-06-07 13:31:42 +0900 |
commit | c774bab6e62a112dd186142a7a55a4776388eaba (patch) | |
tree | 0fcd269255f70fed4bed097c2a7b6e0d96967c3b | |
parent | 6f7e13ac70499ccc74ecf9d03aea65883f530b5c (diff) | |
parent | 2d05f4227e5538f3e8976a8244b54a5247ec833c (diff) | |
download | subsurface-c774bab6e62a112dd186142a7a55a4776388eaba.tar.gz |
Merge branch '112_webservices' of https://github.com/tcanabrava/subsurface
-rw-r--r-- | Configure.mk | 2 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | qt-ui/mainwindow.cpp | 4 | ||||
-rw-r--r-- | qt-ui/subsurfacewebservices.cpp | 239 | ||||
-rw-r--r-- | qt-ui/subsurfacewebservices.h | 38 | ||||
-rw-r--r-- | qt-ui/subsurfacewebservices.ui | 106 | ||||
-rw-r--r-- | webservice.h | 13 |
7 files changed, 400 insertions, 4 deletions
diff --git a/Configure.mk b/Configure.mk index a09fcbbf1..a532d4138 100644 --- a/Configure.mk +++ b/Configure.mk @@ -106,7 +106,7 @@ ifeq ($(strip $(QMAKE)),) $(error Could not find qmake or qmake-qt4 in $$PATH for the Qt4 version they failed) endif - QT_MODULES = QtGui QtSvg + QT_MODULES = QtGui QtSvg QtNetwork QT_CORE = QtCore MOC = $(shell $(PKGCONFIG) --variable=moc_location QtCore) UIC = $(shell $(PKGCONFIG) --variable=uic_location QtGui) @@ -48,6 +48,7 @@ HEADERS = \ qt-ui/downloadfromdivecomputer.h \ qt-ui/preferences.h \ qt-ui/simplewidgets.h \ + qt-ui/subsurfacewebservices.h \ SOURCES = \ @@ -80,6 +81,7 @@ SOURCES = \ qt-ui/downloadfromdivecomputer.cpp \ qt-ui/preferences.cpp \ qt-ui/simplewidgets.cpp \ + qt-ui/subsurfacewebservices.cpp \ $(RESFILE) diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index f3dbf2889..286aba43e 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -28,6 +28,7 @@ #include "models.h" #include "downloadfromdivecomputer.h" #include "preferences.h" +#include "subsurfacewebservices.h" static MainWindow* instance = 0; @@ -181,7 +182,8 @@ void MainWindow::on_actionDownloadDC_triggered() void MainWindow::on_actionDownloadWeb_triggered() { - qDebug("actionDownloadWeb");} + SubsurfaceWebServices::instance()->runDialog(); +} void MainWindow::on_actionEditDeviceNames_triggered() { diff --git a/qt-ui/subsurfacewebservices.cpp b/qt-ui/subsurfacewebservices.cpp new file mode 100644 index 000000000..2f82d6d26 --- /dev/null +++ b/qt-ui/subsurfacewebservices.cpp @@ -0,0 +1,239 @@ +#include "subsurfacewebservices.h" +#include "ui_subsurfacewebservices.h" +#include "../webservice.h" + +#include <libxml/parser.h> + +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QDebug> +#include <QSettings> +#include <qdesktopservices.h> + +#include "../dive.h" +#include "../divelist.h" + +struct dive_table gps_location_table; +static gboolean merge_locations_into_dives(void); + +SubsurfaceWebServices* SubsurfaceWebServices::instance() +{ + static SubsurfaceWebServices *self = new SubsurfaceWebServices(); + return self; +} + +SubsurfaceWebServices::SubsurfaceWebServices(QWidget* parent, Qt::WindowFlags f) +: ui( new Ui::SubsurfaceWebServices()){ + ui->setupUi(this); + connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*))); + connect(ui->download, SIGNAL(clicked(bool)), this, SLOT(startDownload())); + ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); + QSettings s; + ui->userID->setText(s.value("webservice_uid").toString()); +} + + +static void clear_table(struct dive_table *table) +{ + int i; + for (i = 0; i < table->nr; i++) + free(table->dives[i]); + table->nr = 0; +} + +void SubsurfaceWebServices::buttonClicked(QAbstractButton* button) +{ + ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); + switch(ui->buttonBox->buttonRole(button)){ + case QDialogButtonBox::ApplyRole:{ + clear_table(&gps_location_table); + QByteArray url = tr("Webservice").toLocal8Bit(); + parse_xml_buffer(url.data(), downloadedData.data(), downloadedData.length(), &gps_location_table, NULL); + + /* now merge the data in the gps_location table into the dive_table */ + if (merge_locations_into_dives()) { + mark_divelist_changed(TRUE); + } + + /* store last entered uid in config */ + QSettings s; + s.setValue("webservice_uid", ui->userID->text()); + s.sync(); + } + break; + case QDialogButtonBox::RejectRole: + manager->deleteLater(); + reply->deleteLater(); + ui->progressBar->setMaximum(1); + break; + case QDialogButtonBox::HelpRole: + QDesktopServices::openUrl(QUrl("http://api.hohndel.org")); + break; + default: + break; + } +} + +void SubsurfaceWebServices::startDownload() +{ + QUrl url("http://api.hohndel.org/api/dive/get/"); + url.setQueryItems( QList<QPair<QString,QString> >() << qMakePair(QString("login"), ui->userID->text())); + + manager = new QNetworkAccessManager(this); + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Accept", "text/xml"); + reply = manager->get(request); + ui->status->setText(tr("Wait a bit untill we have something...")); + ui->progressBar->setRange(0,0); // this makes the progressbar do an 'infinite spin' + ui->download->setEnabled(false); + ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); + + connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(downloadError(QNetworkReply::NetworkError))); +} + +void SubsurfaceWebServices::downloadFinished() +{ + ui->progressBar->setRange(0,1); + downloadedData = reply->readAll(); + + ui->download->setEnabled(true); + ui->status->setText(tr("Download Finished")); + + uint resultCode = download_dialog_parse_response(downloadedData); + setStatusText(resultCode); + if (resultCode == DD_STATUS_OK){ + ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); + } + manager->deleteLater(); + reply->deleteLater(); +} + +void SubsurfaceWebServices::downloadError(QNetworkReply::NetworkError error) +{ + ui->download->setEnabled(true); + ui->progressBar->setRange(0,1); + ui->status->setText(QString::number((int)QNetworkRequest::HttpStatusCodeAttribute)); + manager->deleteLater(); + reply->deleteLater(); +} + +void SubsurfaceWebServices::setStatusText(int status) +{ + QString text; + switch (status) { + case DD_STATUS_ERROR_CONNECT: text = tr("Connection Error: "); break; + case DD_STATUS_ERROR_ID: text = tr("Invalid user identifier!"); break; + case DD_STATUS_ERROR_PARSE: text = tr("Cannot parse response!"); break; + case DD_STATUS_OK: text = tr("Download Success!"); break; + } + ui->status->setText(text); +} + +void SubsurfaceWebServices::runDialog() +{ + show(); +} + +/* requires that there is a <download> or <error> tag under the <root> tag */ +void SubsurfaceWebServices::download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status) +{ + xmlNodePtr cur_node; + for (cur_node = node; cur_node; cur_node = cur_node->next) { + if ((!strcmp((const char *)cur_node->name, (const char *)"download")) && + (!strcmp((const char *)xmlNodeGetContent(cur_node), (const char *)"ok"))) { + *download_status = DD_STATUS_OK; + return; + } else if (!strcmp((const char *)cur_node->name, (const char *)"error")) { + *download_status = DD_STATUS_ERROR_ID; + return; + } + } +} + +unsigned int SubsurfaceWebServices::download_dialog_parse_response(const QByteArray& xml) +{ + xmlNodePtr root; + xmlDocPtr doc = xmlParseMemory(xml.data(), xml.length()); + unsigned int status = DD_STATUS_ERROR_PARSE; + + if (!doc) + return DD_STATUS_ERROR_PARSE; + root = xmlDocGetRootElement(doc); + if (!root) { + status = DD_STATUS_ERROR_PARSE; + goto end; + } + if (root->children) + download_dialog_traverse_xml(root->children, &status); + end: + xmlFreeDoc(doc); + return status; +} + +static gboolean is_automatic_fix(struct dive *gpsfix) +{ + if (gpsfix && gpsfix->location && + (!strcmp(gpsfix->location, "automatic fix") || + !strcmp(gpsfix->location, "Auto-created dive"))) + return TRUE; + return FALSE; +} + +#define SAME_GROUP 6 * 3600 // six hours + +static gboolean merge_locations_into_dives(void) +{ + int i, nr = 0, changed = 0; + struct dive *gpsfix, *last_named_fix = NULL, *dive; + + sort_table(&gps_location_table); + + for_each_gps_location(i, gpsfix) { + if (is_automatic_fix(gpsfix)) { + dive = find_dive_including(gpsfix->when); + if (dive && !dive_has_gps_location(dive)) { +#if DEBUG_WEBSERVICE + struct tm tm; + utc_mkdate(gpsfix->when, &tm); + printf("found dive named %s @ %04d-%02d-%02d %02d:%02d:%02d\n", + gpsfix->location, + tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif + changed++; + copy_gps_location(gpsfix, dive); + } + } else { + if (last_named_fix && dive_within_time_range(last_named_fix, gpsfix->when, SAME_GROUP)) { + nr++; + } else { + nr = 1; + last_named_fix = gpsfix; + } + dive = find_dive_n_near(gpsfix->when, nr, SAME_GROUP); + if (dive) { + if (!dive_has_gps_location(dive)) { + copy_gps_location(gpsfix, dive); + changed++; + } + if (!dive->location) { + dive->location = strdup(gpsfix->location); + changed++; + } + } else { + struct tm tm; + utc_mkdate(gpsfix->when, &tm); +#if DEBUG_WEBSERVICE + printf("didn't find dive matching gps fix named %s @ %04d-%02d-%02d %02d:%02d:%02d\n", + gpsfix->location, + tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif + } + } + } + return changed > 0; +} diff --git a/qt-ui/subsurfacewebservices.h b/qt-ui/subsurfacewebservices.h new file mode 100644 index 000000000..9e85db155 --- /dev/null +++ b/qt-ui/subsurfacewebservices.h @@ -0,0 +1,38 @@ +#ifndef SUBSURFACEWEBSERVICES_H +#define SUBSURFACEWEBSERVICES_H + +#include <QDialog> +#include <QNetworkReply> +#include <libxml/tree.h> + +namespace Ui{ + class SubsurfaceWebServices; +}; +class QAbstractButton; +class QNetworkReply; + +class SubsurfaceWebServices : public QDialog { + Q_OBJECT +public: + static SubsurfaceWebServices* instance(); + void runDialog(); + +private slots: + void startDownload(); + void buttonClicked(QAbstractButton* button); + void downloadFinished(); + void downloadError(QNetworkReply::NetworkError error); + +private: + void setStatusText(int status); + void download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status); + unsigned int download_dialog_parse_response(const QByteArray& length); + + explicit SubsurfaceWebServices(QWidget* parent = 0, Qt::WindowFlags f = 0); + Ui::SubsurfaceWebServices *ui; + QNetworkReply *reply; + QNetworkAccessManager *manager; + QByteArray downloadedData; +}; + +#endif
\ No newline at end of file diff --git a/qt-ui/subsurfacewebservices.ui b/qt-ui/subsurfacewebservices.ui new file mode 100644 index 000000000..899eea909 --- /dev/null +++ b/qt-ui/subsurfacewebservices.ui @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SubsurfaceWebServices</class> + <widget class="QDialog" name="SubsurfaceWebServices"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>399</width> + <height>104</height> + </rect> + </property> + <property name="windowTitle"> + <string>Download Location Data</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0" colspan="3"> + <widget class="QProgressBar" name="progressBar"> + <property name="value"> + <number>0</number> + </property> + </widget> + </item> + <item row="3" column="0" colspan="3"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help</set> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="download"> + <property name="text"> + <string>Download</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="userID"> + <property name="placeholderText"> + <string>Enter your ID here</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>User ID</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Status:</string> + </property> + </widget> + </item> + <item row="2" column="1" colspan="2"> + <widget class="QLabel" name="status"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>SubsurfaceWebServices</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>buttonBox</sender> + <signal>rejected()</signal> + <receiver>SubsurfaceWebServices</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> diff --git a/webservice.h b/webservice.h index c1951acd1..739f1057e 100644 --- a/webservice.h +++ b/webservice.h @@ -2,9 +2,18 @@ extern "C" { #endif -extern void webservice_download_dialog(void); -extern gboolean webservice_request_user_xml(const gchar *, gchar **, guint *, guint *); +//extern void webservice_download_dialog(void); +//extern bool webservice_request_user_xml(const gchar *, gchar **, unsigned int *, unsigned int *); extern int divelogde_upload(char *fn, char **error); +extern unsigned int download_dialog_parse_response(char *xmldata, unsigned int len); + +enum { + DD_STATUS_OK, + DD_STATUS_ERROR_CONNECT, + DD_STATUS_ERROR_ID, + DD_STATUS_ERROR_PARSE, +}; + #ifdef __cplusplus } |