aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dive.c8
-rw-r--r--dive.h2
-rw-r--r--qt-ui/divelistview.cpp67
-rw-r--r--qt-ui/divelistview.h5
-rw-r--r--qt-ui/divepicturewidget.cpp4
-rw-r--r--qt-ui/simplewidgets.cpp14
-rw-r--r--qt-ui/simplewidgets.h10
-rw-r--r--qt-ui/urldialog.ui91
-rw-r--r--qthelper.cpp44
9 files changed, 219 insertions, 26 deletions
diff --git a/dive.c b/dive.c
index 037db594c..07b057be6 100644
--- a/dive.c
+++ b/dive.c
@@ -2885,7 +2885,7 @@ static bool new_picture_for_dive(struct dive *d, char *filename)
// only add pictures that have timestamps between 30 minutes before the dive and
// 30 minutes after the dive ends
#define D30MIN (30 * 60)
-bool dive_check_picture_time(struct dive *d, char *filename, int shift_time, timestamp_t timestamp)
+bool dive_check_picture_time(struct dive *d, int shift_time, timestamp_t timestamp)
{
offset_t offset;
if (timestamp) {
@@ -2905,7 +2905,7 @@ bool picture_check_valid(char *filename, int shift_time)
timestamp_t timestamp = picture_get_timestamp(filename);
for_each_dive (i, dive)
- if (dive->selected && dive_check_picture_time(dive, filename, shift_time, timestamp))
+ if (dive->selected && dive_check_picture_time(dive, shift_time, timestamp))
return true;
return false;
}
@@ -2915,11 +2915,11 @@ void dive_create_picture(struct dive *dive, char *filename, int shift_time)
timestamp_t timestamp = picture_get_timestamp(filename);
if (!new_picture_for_dive(dive, filename))
return;
- if (!dive_check_picture_time(dive, filename, shift_time, timestamp))
+ if (!dive_check_picture_time(dive, shift_time, timestamp))
return;
struct picture *picture = alloc_picture();
- picture->filename = filename;
+ picture->filename = strdup(filename);
picture->offset.seconds = timestamp - dive->when + shift_time;
picture_load_exif_data(picture);
diff --git a/dive.h b/dive.h
index 7e6ce2cf6..8065fe57a 100644
--- a/dive.h
+++ b/dive.h
@@ -383,7 +383,7 @@ struct picture {
for (struct picture *picture = (_divestruct).picture_list; picture; picture = picture->next)
extern struct picture *alloc_picture();
-extern bool dive_check_picture_time(struct dive *d, char *filename, int shift_time, timestamp_t timestamp);
+extern bool dive_check_picture_time(struct dive *d, int shift_time, timestamp_t timestamp);
extern void dive_create_picture(struct dive *d, char *filename, int shift_time);
extern void dive_add_picture(struct dive *d, struct picture *newpic);
extern void dive_remove_picture(char *filename);
diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index 92ae60b5d..fda170c56 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -4,17 +4,21 @@
* classes for the divelist of Subsurface
*
*/
-#include "divelistview.h"
#include "filtermodels.h"
#include "modeldelegates.h"
#include "mainwindow.h"
#include "divepicturewidget.h"
#include "display.h"
+#include <unistd.h>
#include <QSettings>
#include <QKeyEvent>
#include <QFileDialog>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QStandardPaths>
#include "qthelper.h"
#include "undocommands.h"
+#include "divelistview.h"
// # Date Rtg Dpth Dur Tmp Wght Suit Cyl Gas SAC OTU CNS Loc
static int defaultWidth[] = { 70, 140, 90, 50, 50, 50, 50, 70, 50, 50, 70, 50, 50, 500};
@@ -834,6 +838,7 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event)
popup.addAction(tr("Renumber dive(s)"), this, SLOT(renumberDives()));
popup.addAction(tr("Shift times"), this, SLOT(shiftTimes()));
popup.addAction(tr("Load images"), this, SLOT(loadImages()));
+ popup.addAction(tr("Load image(s) from web"), this, SLOT(loadWebImages()));
}
// "collapse all" really closes all trips,
@@ -859,8 +864,12 @@ void DiveListView::loadImages()
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open image files"), lastUsedImageDir(), tr("Image files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
if (fileNames.isEmpty())
return;
-
updateLastUsedImageDir(QFileInfo(fileNames[0]).dir().path());
+ matchImagesToDives(fileNames);
+}
+
+void DiveListView::matchImagesToDives(QStringList fileNames)
+{
ShiftImageTimesDialog shiftDialog(this, fileNames);
shiftDialog.setOffset(lastImageTimeOffset());
if (!shiftDialog.exec())
@@ -882,6 +891,60 @@ void DiveListView::loadImages()
DivePictureModel::instance()->updateDivePictures();
}
+void DiveListView::loadWebImages()
+{
+ URLDialog urlDialog(this);
+ if (!urlDialog.exec())
+ return;
+ loadImageFromURL(QUrl::fromUserInput(urlDialog.url()));
+
+}
+
+void DiveListView::loadImageFromURL(QUrl url)
+{
+ if (url.isValid()) {
+ QEventLoop loop;
+ QNetworkRequest request(url);
+ QNetworkReply *reply = manager.get(request);
+ while (reply->isRunning()) {
+ loop.processEvents();
+ sleep(1);
+ }
+ QByteArray imageData = reply->readAll();
+
+ QImage image = QImage();
+ image.loadFromData(imageData);
+ if (image.isNull())
+ // If this is not an image, maybe it's an html file and Miika can provide some xslr magic to extract images.
+ // In this case we would call the function recursively on the list of image source urls;
+ return;
+
+ // Since we already downloaded the image we can cache it as well.
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ hash.addData(imageData);
+ QString path = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first();
+ QDir dir(path);
+ if (!dir.exists())
+ dir.mkpath(path);
+ QFile imageFile(path.append("/").append(hash.result().toHex()));
+ if (imageFile.open(QIODevice::WriteOnly)) {
+ QDataStream stream(&imageFile);
+ stream.writeRawData(imageData.data(), imageData.length());
+ imageFile.waitForBytesWritten(-1);
+ imageFile.close();
+ add_hash(imageFile.fileName(), hash.result());
+ struct picture picture;
+ picture.hash = NULL;
+ picture.filename = strdup(url.toString().toUtf8().data());
+ learnHash(&picture, hash.result());
+ matchImagesToDives(QStringList(url.toString()));
+ }
+ }
+
+
+}
+
+
QString DiveListView::lastUsedImageDir()
{
QSettings settings;
diff --git a/qt-ui/divelistview.h b/qt-ui/divelistview.h
index a6522fa9a..6e9a18215 100644
--- a/qt-ui/divelistview.h
+++ b/qt-ui/divelistview.h
@@ -13,6 +13,7 @@
#include <QTreeView>
#include <QLineEdit>
+#include <QNetworkAccessManager>
#include "models.h"
class DiveListView : public QTreeView {
@@ -51,6 +52,7 @@ slots:
void renumberDives();
void shiftTimes();
void loadImages();
+ void loadWebImages();
static QString lastUsedImageDir();
signals:
@@ -78,6 +80,9 @@ private:
void updateLastImageTimeOffset(int offset);
int lastImageTimeOffset();
void addToTrip(int delta);
+ void matchImagesToDives(QStringList fileNames);
+ void loadImageFromURL(QUrl url);
+ QNetworkAccessManager manager;
};
#endif // DIVELISTVIEW_H
diff --git a/qt-ui/divepicturewidget.cpp b/qt-ui/divepicturewidget.cpp
index ce997fea1..8c1cb3571 100644
--- a/qt-ui/divepicturewidget.cpp
+++ b/qt-ui/divepicturewidget.cpp
@@ -63,6 +63,10 @@ void ImageDownloader::load(){
void ImageDownloader::saveImage(QNetworkReply *reply)
{
QByteArray imageData = reply->readAll();
+ QImage image = QImage();
+ image.loadFromData(imageData);
+ if (image.isNull())
+ return;
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(imageData);
QString path = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first();
diff --git a/qt-ui/simplewidgets.cpp b/qt-ui/simplewidgets.cpp
index 2b8605a69..a074ad18c 100644
--- a/qt-ui/simplewidgets.cpp
+++ b/qt-ui/simplewidgets.cpp
@@ -361,6 +361,20 @@ void ShiftImageTimesDialog::timeEditChanged(const QTime &time)
updateInvalid();
}
+URLDialog::URLDialog(QWidget *parent) : QDialog(parent)
+{
+ ui.setupUi(this);
+ QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this);
+ connect(close, SIGNAL(activated()), this, SLOT(close()));
+ QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
+ connect(quit, SIGNAL(activated()), parent, SLOT(close()));
+}
+
+QString URLDialog::url() const
+{
+ return ui.urlField->toPlainText();
+}
+
bool isGnome3Session()
{
#if defined(QT_OS_WIW) || defined(QT_OS_MAC)
diff --git a/qt-ui/simplewidgets.h b/qt-ui/simplewidgets.h
index 5f2402a86..dde30335f 100644
--- a/qt-ui/simplewidgets.h
+++ b/qt-ui/simplewidgets.h
@@ -14,6 +14,7 @@ class QNetworkReply;
#include "ui_setpoint.h"
#include "ui_shifttimes.h"
#include "ui_shiftimagetimes.h"
+#include "ui_urldialog.h"
#include "ui_divecomponentselection.h"
#include "ui_listfilter.h"
#include "ui_filterwidget.h"
@@ -115,6 +116,15 @@ private:
time_t dcImageEpoch;
};
+class URLDialog : public QDialog {
+ Q_OBJECT
+public:
+ explicit URLDialog(QWidget *parent);
+ QString url() const;
+private:
+ Ui::URLDialog ui;
+};
+
class QCalendarWidget;
class DateWidget : public QWidget {
diff --git a/qt-ui/urldialog.ui b/qt-ui/urldialog.ui
new file mode 100644
index 000000000..397f90a64
--- /dev/null
+++ b/qt-ui/urldialog.ui
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>URLDialog</class>
+ <widget class="QDialog" name="URLDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>397</width>
+ <height>103</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>60</y>
+ <width>341</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ <widget class="QPlainTextEdit" name="urlField">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>371</width>
+ <height>21</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>151</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Enter URL for images</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>URLDialog</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>URLDialog</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/qthelper.cpp b/qthelper.cpp
index a5597e3fb..030ed94c9 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -337,22 +337,6 @@ extern "C" xsltStylesheetPtr get_stylesheet(const char *name)
return xslt;
}
-extern "C" void picture_load_exif_data(struct picture *p)
-{
- EXIFInfo exif;
- memblock mem;
-
- if (readfile(p->filename, &mem) <= 0)
- goto picture_load_exit;
- if (exif.parseFrom((const unsigned char *)mem.buffer, (unsigned)mem.size) != PARSE_EXIF_SUCCESS)
- goto picture_load_exit;
- p->longitude.udeg= lrint(1000000.0 * exif.GeoLocation.Longitude);
- p->latitude.udeg = lrint(1000000.0 * exif.GeoLocation.Latitude);
-
-picture_load_exit:
- free(mem.buffer);
- return;
-}
extern "C" timestamp_t picture_get_timestamp(char *filename)
{
@@ -360,7 +344,8 @@ extern "C" timestamp_t picture_get_timestamp(char *filename)
memblock mem;
int retval;
- if (readfile(filename, &mem) <= 0)
+ // filename might not be the actual filename, so let's go via the hash.
+ if (readfile(localFilePath(QString(filename)).toUtf8().data(), &mem) <= 0)
return 0;
retval = exif.parseFrom((const unsigned char *)mem.buffer, (unsigned)mem.size);
free(mem.buffer);
@@ -853,7 +838,8 @@ QByteArray hashFile(const QString filename)
void learnHash(struct picture *picture, QByteArray hash)
{
- free(picture->hash);
+ if (picture->hash)
+ free(picture->hash);
QMutexLocker locker(&hashOfMutex);
hashOf[QString(picture->filename)] = hash;
picture->hash = strdup(hash.toHex());
@@ -861,7 +847,10 @@ void learnHash(struct picture *picture, QByteArray hash)
QString localFilePath(const QString originalFilename)
{
- return localFilenameOf[hashOf[originalFilename]];
+ if (hashOf.contains(originalFilename) && localFilenameOf.contains(hashOf[originalFilename]))
+ return localFilenameOf[hashOf[originalFilename]];
+ else
+ return originalFilename;
}
QString fileFromHash(char *hash)
@@ -899,3 +888,20 @@ void learnImages(const QDir dir, int max_recursions, bool recursed)
QtConcurrent::blockingMap(files, hashFile);
}
+
+extern "C" void picture_load_exif_data(struct picture *p)
+{
+ EXIFInfo exif;
+ memblock mem;
+
+ if (readfile(localFilePath(QString(p->filename)).toUtf8().data(), &mem) <= 0)
+ goto picture_load_exit;
+ if (exif.parseFrom((const unsigned char *)mem.buffer, (unsigned)mem.size) != PARSE_EXIF_SUCCESS)
+ goto picture_load_exit;
+ p->longitude.udeg= lrint(1000000.0 * exif.GeoLocation.Longitude);
+ p->latitude.udeg = lrint(1000000.0 * exif.GeoLocation.Latitude);
+
+picture_load_exit:
+ free(mem.buffer);
+ return;
+}