diff options
-rw-r--r-- | dive.c | 8 | ||||
-rw-r--r-- | dive.h | 2 | ||||
-rw-r--r-- | qt-ui/divelistview.cpp | 67 | ||||
-rw-r--r-- | qt-ui/divelistview.h | 5 | ||||
-rw-r--r-- | qt-ui/divepicturewidget.cpp | 4 | ||||
-rw-r--r-- | qt-ui/simplewidgets.cpp | 14 | ||||
-rw-r--r-- | qt-ui/simplewidgets.h | 10 | ||||
-rw-r--r-- | qt-ui/urldialog.ui | 91 | ||||
-rw-r--r-- | qthelper.cpp | 44 |
9 files changed, 219 insertions, 26 deletions
@@ -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); @@ -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; +} |