aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2013-06-07 13:31:42 +0900
committerGravatar Dirk Hohndel <dirk@hohndel.org>2013-06-07 13:31:42 +0900
commitc774bab6e62a112dd186142a7a55a4776388eaba (patch)
tree0fcd269255f70fed4bed097c2a7b6e0d96967c3b
parent6f7e13ac70499ccc74ecf9d03aea65883f530b5c (diff)
parent2d05f4227e5538f3e8976a8244b54a5247ec833c (diff)
downloadsubsurface-c774bab6e62a112dd186142a7a55a4776388eaba.tar.gz
Merge branch '112_webservices' of https://github.com/tcanabrava/subsurface
-rw-r--r--Configure.mk2
-rw-r--r--Makefile2
-rw-r--r--qt-ui/mainwindow.cpp4
-rw-r--r--qt-ui/subsurfacewebservices.cpp239
-rw-r--r--qt-ui/subsurfacewebservices.h38
-rw-r--r--qt-ui/subsurfacewebservices.ui106
-rw-r--r--webservice.h13
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)
diff --git a/Makefile b/Makefile
index e870fa3b9..ab4c8b2ef 100644
--- a/Makefile
+++ b/Makefile
@@ -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
}