diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2013-12-04 16:21:44 -0800 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2013-12-04 16:21:44 -0800 |
commit | 421dceba1ed37b5000c4ad5796f4924fb15587b4 (patch) | |
tree | 57830cf95bf9ea3af32f2253673c5d145fa76dea /qt-ui | |
parent | 28b8d177c3b10d32201615d15c2aba2f969cf3f4 (diff) | |
parent | 662e642ac9f650ccafda75d53ff54ff587b3d97c (diff) | |
download | subsurface-421dceba1ed37b5000c4ad5796f4924fb15587b4.tar.gz |
Merge branch 'improve-subsurfaceweb' of git://github.com/thiagomacieira/subsurface
Diffstat (limited to 'qt-ui')
-rw-r--r-- | qt-ui/mainwindow.cpp | 2 | ||||
-rw-r--r-- | qt-ui/subsurfacewebservices.cpp | 611 | ||||
-rw-r--r-- | qt-ui/subsurfacewebservices.h | 33 | ||||
-rw-r--r-- | qt-ui/webservices.ui | 3 |
4 files changed, 520 insertions, 129 deletions
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index ee77fc72d..e049179e8 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -269,7 +269,7 @@ void MainWindow::on_actionDownloadWeb_triggered() void MainWindow::on_actionDivelogs_de_triggered() { - DivelogsDeWebServices::instance()->exec(); + DivelogsDeWebServices::instance()->downloadDives(); } void MainWindow::on_actionEditDeviceNames_triggered() diff --git a/qt-ui/subsurfacewebservices.cpp b/qt-ui/subsurfacewebservices.cpp index 1acccda7d..69dd7e1cd 100644 --- a/qt-ui/subsurfacewebservices.cpp +++ b/qt-ui/subsurfacewebservices.cpp @@ -3,27 +3,111 @@ #include "mainwindow.h" #include <libxml/parser.h> +#include <zip.h> +#include <QDir> +#include <QHttpMultiPart> +#include <QMessageBox> #include <QNetworkAccessManager> #include <QNetworkReply> #include <QDebug> #include <QSettings> +#include <QXmlStreamReader> #include <qdesktopservices.h> #include "../dive.h" #include "../divelist.h" +#ifdef Q_OS_UNIX +# include <unistd.h> // for dup(2) +#endif + struct dive_table gps_location_table; static bool merge_locations_into_dives(void); +static bool 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 bool 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; +} + +static void clear_table(struct dive_table *table) +{ + int i; + for (i = 0; i < table->nr; i++) + free(table->dives[i]); + table->nr = 0; +} + WebServices::WebServices(QWidget* parent, Qt::WindowFlags f): QDialog(parent, f) , reply(0) { ui.setupUi(this); connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*))); connect(ui.download, SIGNAL(clicked(bool)), this, SLOT(startDownload())); + connect(ui.upload, SIGNAL(clicked(bool)), this, SLOT(startUpload())); + connect(&timeout, SIGNAL(timeout()), this, SLOT(downloadTimedOut())); ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); - + timeout.setSingleShot(true); } void WebServices::hidePassword() @@ -35,6 +119,74 @@ void WebServices::hidePassword() void WebServices::hideUpload() { ui.upload->hide(); + ui.download->show(); +} + +void WebServices::hideDownload() +{ + ui.download->hide(); + ui.upload->show(); +} + +QNetworkAccessManager *WebServices::manager() +{ + static QNetworkAccessManager *manager = new QNetworkAccessManager(qApp); + return manager; +} + +void WebServices::downloadTimedOut() +{ + if (!reply) + return; + + reply->deleteLater(); + reply = NULL; + resetState(); + ui.status->setText(tr("Operation timed out")); +} + +void WebServices::updateProgress(qint64 current, qint64 total) +{ + if (!reply) + return; + + if (total >= INT_MAX / 2) { + // over a gigabyte! + if (total >= Q_INT64_C(1) << 47) { + total >>= 16; + current >>= 16; + } + total >>= 16; + current >>= 16; + } + ui.progressBar->setRange(0, total); + ui.progressBar->setValue(current); + ui.status->setText(tr("Transfering data...")); + + // reset the timer: 30 seconds after we last got any data + timeout.start(); +} + +void WebServices::connectSignalsForDownload(QNetworkReply *reply) +{ + connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(downloadError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, + SLOT(updateProgress(qint64,qint64))); + + timeout.start(30000); // 30s +} + +void WebServices::resetState() +{ + ui.download->setEnabled(true); + ui.upload->setEnabled(true); + ui.userID->setEnabled(true); + ui.password->setEnabled(true); + ui.progressBar->reset(); + ui.progressBar->setRange(0,1); + ui.status->setText(QString()); } // # @@ -58,95 +210,85 @@ SubsurfaceWebServices::SubsurfaceWebServices(QWidget* parent, Qt::WindowFlags f) hideUpload(); } -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, 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("subsurface_webservice_uid", ui.userID->text().toUpper()); - s.sync(); - hide(); - close(); + 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, 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("subsurface_webservice_uid", ui.userID->text().toUpper()); + s.sync(); + hide(); + close(); + resetState(); + } + break; + case QDialogButtonBox::RejectRole: + // we may want to clean up after ourselves + // reply->deleteLater(); + reply = NULL; + resetState(); + break; + case QDialogButtonBox::HelpRole: + QDesktopServices::openUrl(QUrl("http://api.hohndel.org")); + break; + default: break; - case QDialogButtonBox::RejectRole: - // we may want to clean up after ourselves, but this - // makes Subsurface throw a SIGSEGV... - // 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().toUpper())); + url.addQueryItem("login", ui.userID->text().toUpper()); - 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 until we have something...")); + reply = manager()->get(request); + ui.status->setText(tr("Connecting...")); 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))); + connectSignalsForDownload(reply); } void SubsurfaceWebServices::downloadFinished() { + if (!reply) + return; + ui.progressBar->setRange(0,1); downloadedData = reply->readAll(); ui.download->setEnabled(true); - ui.status->setText(tr("Download Finished")); + 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(); + reply = NULL; } -void SubsurfaceWebServices::downloadError(QNetworkReply::NetworkError error) +void SubsurfaceWebServices::downloadError(QNetworkReply::NetworkError) { - ui.download->setEnabled(true); - ui.progressBar->setRange(0,1); - ui.status->setText(QString::number((int)QNetworkRequest::HttpStatusCodeAttribute)); - manager->deleteLater(); + resetState(); + ui.status->setText(tr("Download error: %1").arg(reply->errorString())); reply->deleteLater(); + reply = NULL; } void SubsurfaceWebServices::setStatusText(int status) @@ -167,7 +309,7 @@ void SubsurfaceWebServices::download_dialog_traverse_xml(xmlNodePtr node, unsign 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"))) { + (!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")) { @@ -192,74 +334,9 @@ unsigned int SubsurfaceWebServices::download_dialog_parse_response(const QByteAr } if (root->children) download_dialog_traverse_xml(root->children, &status); - end: - xmlFreeDoc(doc); - return status; -} - -static bool 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 bool 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; +end: + xmlFreeDoc(doc); + return status; } // # @@ -268,6 +345,92 @@ static bool merge_locations_into_dives(void) // # // # +struct DiveListResult +{ + QString errorCondition; + QString errorDetails; + QByteArray idList; // comma-separated, suitable to be sent in the fetch request + int idCount; +}; + +static DiveListResult parseDiveLogsDeDiveList(const QByteArray &xmlData) +{ + /* XML format seems to be: + * <DiveDateReader version="1.0"> + * <DiveDates> + * <date diveLogsId="nnn" lastModified="YYYY-MM-DD hh:mm:ss">DD.MM.YYYY hh:mm</date> + * [repeat <date></date>] + * </DiveDates> + * </DiveDateReader> + */ + QXmlStreamReader reader(xmlData); + const QString invalidXmlError = DivelogsDeWebServices::tr("Invalid response from server"); + bool seenDiveDates = false; + DiveListResult result; + result.idCount = 0; + + if (reader.readNextStartElement() && reader.name() != "DiveDateReader") { + result.errorCondition = invalidXmlError; + result.errorDetails = + DivelogsDeWebServices::tr("Expected XML tag 'DiveDateReader', got instead '%1") + .arg(reader.name().toString()); + goto out; + } + + while (reader.readNextStartElement()) { + if (reader.name() != "DiveDates") { + if (reader.name() == "Login") { + QString status = reader.readElementText(); + // qDebug() << "Login status:" << status; + + // Note: there has to be a better way to determine a successful login... + if (status == "failed") { + result.errorCondition = "Login failed"; + goto out; + } + } else { + // qDebug() << "Skipping" << reader.name(); + } + continue; + } + + // process <DiveDates> + seenDiveDates = true; + while (reader.readNextStartElement()) { + if (reader.name() != "date") { + // qDebug() << "Skipping" << reader.name(); + continue; + } + QStringRef id = reader.attributes().value("divelogsId"); + // qDebug() << "Found" << reader.name() << "with id =" << id; + if (!id.isEmpty()) { + result.idList += id.toLatin1(); + result.idList += ','; + ++result.idCount; + } + + reader.skipCurrentElement(); + } + } + + // chop the ending comma, if any + result.idList.chop(1); + + if (!seenDiveDates) { + result.errorCondition = invalidXmlError; + result.errorDetails = DivelogsDeWebServices::tr("Expected XML tag 'DiveDates' not found"); + } + +out: + if (reader.hasError()) { + // if there was an XML error, overwrite the result or other error conditions + result.errorCondition = invalidXmlError; + result.errorDetails = DivelogsDeWebServices::tr("Malformed XML response. Line %1: %2") + .arg(reader.lineNumber()).arg(reader.errorString()); + } + return result; +} + DivelogsDeWebServices* DivelogsDeWebServices::instance() { static DivelogsDeWebServices *self = new DivelogsDeWebServices(mainWindow()); @@ -275,24 +438,217 @@ DivelogsDeWebServices* DivelogsDeWebServices::instance() return self; } -DivelogsDeWebServices::DivelogsDeWebServices(QWidget* parent, Qt::WindowFlags f): WebServices(parent, f) +void DivelogsDeWebServices::downloadDives() { + hideUpload(); + exec(); +} +void DivelogsDeWebServices::uploadDives(QIODevice *dldContent) +{ + QHttpMultiPart mp(QHttpMultiPart::FormDataType); + QHttpPart part; + part.setRawHeader("Content-Disposition", "form-data; name=\"userfile\""); + part.setBodyDevice(dldContent); + mp.append(part); + + multipart = ∓ + hideDownload(); + exec(); + multipart = NULL; + + delete reply; // we need to ensure it has stopped using our QHttpMultiPart +} + +DivelogsDeWebServices::DivelogsDeWebServices(QWidget* parent, Qt::WindowFlags f): WebServices(parent, f) +{ + QSettings s; + ui.userID->setText(s.value("divelogde_user").toString()); + ui.password->setText(s.value("divelogde_pass").toString()); + hideUpload(); } void DivelogsDeWebServices::startUpload() { + ui.status->setText(tr("Uploading dive list...")); + ui.progressBar->setRange(0,0); // this makes the progressbar do an 'infinite spin' + ui.upload->setEnabled(false); + ui.userID->setEnabled(false); + ui.password->setEnabled(false); + QNetworkRequest request; + request.setUrl(QUrl("https://divelogs.de/DivelogsDirectImport.php")); + request.setRawHeader("Accept", "text/xml, application/xml"); + + QHttpPart part; + part.setRawHeader("Content-Disposition", "form-data; name=\"user\""); + part.setBody(ui.userID->text().toUtf8()); + multipart->append(part); + + part.setRawHeader("Content-Disposition", "form-data; name=\"pass\""); + part.setBody(ui.password->text().toUtf8()); + multipart->append(part); + + reply = manager()->post(request, multipart); + connect(reply, SIGNAL(finished()), this, SLOT(uploadFinished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, + SLOT(uploadError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(uploadProgress(qint64,qint64)), this, + SLOT(updateProgress(qint64,qint64))); + + timeout.start(30000); // 30s } void DivelogsDeWebServices::startDownload() { + ui.status->setText(tr("Downloading dive list...")); + ui.progressBar->setRange(0,0); // this makes the progressbar do an 'infinite spin' + ui.download->setEnabled(false); + ui.userID->setEnabled(false); + ui.password->setEnabled(false); + + QNetworkRequest request; + request.setUrl(QUrl("https://divelogs.de/xml_available_dives.php")); + request.setRawHeader("Accept", "text/xml, application/xml"); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) + QUrl body; + body.addQueryItem("user", ui.userID->text()); + body.addQueryItem("pass", ui.password->text()); + + reply = manager()->post(request, body.encodedQuery()); +#else + QUrlQuery body; + body.addQueryItem("user", ui.userID->text()); + body.addQueryItem("pass", ui.password->text()); + + reply = manager()->post(request, body.query(QUrl::FullyEncoded).toLatin1()) +#endif + connect(reply, SIGNAL(finished()), this, SLOT(listDownloadFinished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(downloadError(QNetworkReply::NetworkError))); + + timeout.start(30000); // 30s +} + +void DivelogsDeWebServices::listDownloadFinished() +{ + if (!reply) + return; + QByteArray xmlData = reply->readAll(); + reply->deleteLater(); + reply = NULL; + + // parse the XML data we downloaded + DiveListResult diveList = parseDiveLogsDeDiveList(xmlData); + if (!diveList.errorCondition.isEmpty()) { + // error condition + resetState(); + ui.status->setText(diveList.errorCondition); + return; + } + + ui.status->setText(tr("Downloading %1 dives...").arg(diveList.idCount)); + + QNetworkRequest request; +// request.setUrl(QUrl("https://divelogs.de/DivelogsDirectExport.php")); + request.setUrl(QUrl("http://divelogs.de/DivelogsDirectExport.php")); + request.setRawHeader("Accept", "application/zip, */*"); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) + QUrl body; + body.addQueryItem("user", ui.userID->text()); + body.addQueryItem("pass", ui.password->text()); + body.addQueryItem("ids", diveList.idList); + + reply = manager()->post(request, body.encodedQuery()); +#else + QUrlQuery body; + body.addQueryItem("user", ui.userID->text()); + body.addQueryItem("pass", ui.password->text()); + body.addQueryItem("ids", diveList.idList); + + reply = manager()->post(request, body.query(QUrl::FullyEncoded).toLatin1()) +#endif + + connect(reply, SIGNAL(readyRead()), this, SLOT(saveToZipFile())); + connectSignalsForDownload(reply); +} + +void DivelogsDeWebServices::saveToZipFile() +{ + if (!zipFile.isOpen()) { + zipFile.setFileTemplate(QDir::tempPath() + "/import-XXXXXX.dld"); + zipFile.open(); + } + zipFile.write(reply->readAll()); } void DivelogsDeWebServices::downloadFinished() { + if (!reply) + return; + + ui.download->setEnabled(true); + ui.status->setText(tr("Download finished - %1").arg(reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString())); + reply->deleteLater(); + reply = NULL; + + int errorcode; + zipFile.seek(0); +#ifdef Q_OS_UNIX + int duppedfd = dup(zipFile.handle()); + struct zip *zip = zip_fdopen(duppedfd, 0, &errorcode); + if (!zip) + ::close(duppedfd); +#else + struct zip *zip = zip_open(zipFile.fileName().toLocal8Bit().data(), 0, &errorcode); +#endif + if (!zip) { + char buf[512]; + zip_error_to_str(buf, sizeof(buf), errorcode, errno); + QMessageBox::critical(this, tr("Corrupted download"), + tr("The archive could not be opened:\n%1").arg(QString::fromLocal8Bit(buf))); + zipFile.close(); + return; + } + + quint64 entries = zip_get_num_entries(zip, 0); + for (quint64 i = 0; i < entries; ++i) { + struct zip_file *zip_file = zip_fopen_index(zip, i, 0); + if (!zip_file) { + QMessageBox::critical(this, tr("Corrupted download"), + tr("The archive contains corrupt data:\n%1").arg(QString::fromLocal8Bit(zip_strerror(zip)))); + goto close_zip; + } + // ### FIXME: What do I do with this? + + zip_fclose(zip_file); + } + +close_zip: + zip_close(zip); + zipFile.close(); +} + +void DivelogsDeWebServices::uploadFinished() +{ + if (!reply) + return; + + ui.progressBar->setRange(0,1); + ui.upload->setEnabled(true); + ui.status->setText(tr("Upload finished")); + + // check what the server sent us: it might contain + // an error condition, such as a failed login + QByteArray xmlData = reply->readAll(); + + // ### FIXME: what's the format? } void DivelogsDeWebServices::setStatusText(int status) @@ -300,12 +656,21 @@ void DivelogsDeWebServices::setStatusText(int status) } -void DivelogsDeWebServices::downloadError(QNetworkReply::NetworkError error) +void DivelogsDeWebServices::downloadError(QNetworkReply::NetworkError) { + resetState(); + ui.status->setText(tr("Download error: %1").arg(reply->errorString())); + reply->deleteLater(); + reply = NULL; +} +void DivelogsDeWebServices::uploadError(QNetworkReply::NetworkError error) +{ + downloadError(error); } void DivelogsDeWebServices::buttonClicked(QAbstractButton* button) { } + diff --git a/qt-ui/subsurfacewebservices.h b/qt-ui/subsurfacewebservices.h index 515e3fe9c..3c41b08d1 100644 --- a/qt-ui/subsurfacewebservices.h +++ b/qt-ui/subsurfacewebservices.h @@ -3,29 +3,43 @@ #include <QDialog> #include <QNetworkReply> +#include <QTemporaryFile> +#include <QTimer> #include <libxml/tree.h> #include "ui_webservices.h" class QAbstractButton; class QNetworkReply; +class QHttpMultiPart; class WebServices : public QDialog{ Q_OBJECT public: - explicit WebServices(QWidget* parent = 0, Qt::WindowFlags f = 0); + explicit WebServices(QWidget* parent = 0, Qt::WindowFlags f = 0); void hidePassword(); void hideUpload(); + void hideDownload(); + + static QNetworkAccessManager *manager(); private slots: virtual void startDownload() = 0; virtual void startUpload() = 0; virtual void buttonClicked(QAbstractButton* button) = 0; + virtual void downloadTimedOut(); + +protected slots: + void updateProgress(qint64 current, qint64 total); protected: + void resetState(); + void connectSignalsForDownload(QNetworkReply *reply); + void connectSignalsForUpload(); + Ui::WebServices ui; QNetworkReply *reply; - QNetworkAccessManager *manager; + QTimer timeout; QByteArray downloadedData; }; @@ -41,7 +55,7 @@ private slots: void downloadError(QNetworkReply::NetworkError error); void startUpload(){} /*no op*/ private: - explicit SubsurfaceWebServices(QWidget* parent = 0, Qt::WindowFlags f = 0); + explicit SubsurfaceWebServices(QWidget* parent = 0, Qt::WindowFlags f = 0); void setStatusText(int status); void download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status); unsigned int download_dialog_parse_response(const QByteArray& length); @@ -51,18 +65,27 @@ class DivelogsDeWebServices : public WebServices { Q_OBJECT public: static DivelogsDeWebServices * instance(); + void downloadDives(); + void uploadDives(QIODevice *dldContent); private slots: void startDownload(); void buttonClicked(QAbstractButton* button); + void saveToZipFile(); + void listDownloadFinished(); void downloadFinished(); + void uploadFinished(); void downloadError(QNetworkReply::NetworkError error); - void startUpload(); + void uploadError(QNetworkReply::NetworkError error); + void startUpload(); private: - explicit DivelogsDeWebServices (QWidget* parent = 0, Qt::WindowFlags f = 0); + explicit DivelogsDeWebServices (QWidget* parent = 0, Qt::WindowFlags f = 0); void setStatusText(int status); void download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status); unsigned int download_dialog_parse_response(const QByteArray& length); + + QHttpMultiPart *multipart; + QTemporaryFile zipFile; }; #endif diff --git a/qt-ui/webservices.ui b/qt-ui/webservices.ui index 123a95eae..942ff1fa3 100644 --- a/qt-ui/webservices.ui +++ b/qt-ui/webservices.ui @@ -69,6 +69,9 @@ <property name="text"> <string/> </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> </widget> </item> <item row="1" column="0"> |