mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Merge branch '112_webservices' of https://github.com/tcanabrava/subsurface
This commit is contained in:
commit
c774bab6e6
7 changed files with 400 additions and 4 deletions
|
@ -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)
|
||||
|
|
2
Makefile
2
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)
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
239
qt-ui/subsurfacewebservices.cpp
Normal file
239
qt-ui/subsurfacewebservices.cpp
Normal file
|
@ -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;
|
||||
}
|
38
qt-ui/subsurfacewebservices.h
Normal file
38
qt-ui/subsurfacewebservices.h
Normal file
|
@ -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
|
106
qt-ui/subsurfacewebservices.ui
Normal file
106
qt-ui/subsurfacewebservices.ui
Normal file
|
@ -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>
|
13
webservice.h
13
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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue