Hi,

here is a series of patches that should make our handling of images less computer dependent.

From 05381eb7e06a778e47aee13c96bc6b4282e923ec Mon Sep 17 00:00:00 2001
From: "Robert C. Helling" <[email protected]>
Date: Thu, 19 Feb 2015 18:23:24 +0100
Subject: [PATCH 1/4] Add hashes to pictures

This adds SHA1 hashes to successfully loaded images and saves those to xml.

Signed-off-by: Robert C. Helling <[email protected]>
---
 dive.c                      |  2 ++
 dive.h                      |  1 +
 parse-xml.c                 |  2 ++
 qt-ui/divepicturewidget.cpp | 43 +++++++++++++++++++++++++++++++------------
 qt-ui/divepicturewidget.h   |  7 +++++++
 qt-ui/mainwindow.h          |  4 ++++
 qthelper.cpp                |  6 ++++++
 qthelper.h                  |  1 -
 save-xml.c                  |  5 +++++
 9 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/dive.c b/dive.c
index 7583686..fc0fbb8 100644
--- a/dive.c
+++ b/dive.c
@@ -392,6 +392,7 @@ static void copy_pl(struct picture *sp, struct picture *dp)
 {
        *dp = *sp;
        dp->filename = copy_string(sp->filename);
+       dp->hash = copy_string(sp->hash);
 }
 
 /* copy an element in a list of tags */
@@ -2936,6 +2937,7 @@ static void picture_free(struct picture *p)
        if (!p)
                return;
        free(p->filename);
+       free(p->hash);
        free(p);
 }
 void dive_remove_picture(char *filename)
diff --git a/dive.h b/dive.h
index 8247a5f..653b113 100644
--- a/dive.h
+++ b/dive.h
@@ -364,6 +364,7 @@ struct dive_components {
 /* picture list and methods related to dive picture handling */
 struct picture {
        char *filename;
+       char *hash;
        offset_t offset;
        degrees_t latitude;
        degrees_t longitude;
diff --git a/parse-xml.c b/parse-xml.c
index 1ac2b41..a957102 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -1294,6 +1294,8 @@ static void try_to_fill_dive(struct dive *dive, const 
char *name, char *buf)
                return;
        if (MATCH("gps.picture", gps_picture_location, cur_picture))
                return;
+       if (MATCH("hash.picture", utf8_string, &cur_picture->hash))
+               return;
        if (MATCH("cylinderstartpressure", pressure, &dive->cylinder[0].start))
                return;
        if (MATCH("cylinderendpressure", pressure, &dive->cylinder[0].end))
diff --git a/qt-ui/divepicturewidget.cpp b/qt-ui/divepicturewidget.cpp
index 92695b6..4a205da 100644
--- a/qt-ui/divepicturewidget.cpp
+++ b/qt-ui/divepicturewidget.cpp
@@ -4,6 +4,23 @@
 #include "divelist.h"
 #include <QtConcurrentMap>
 #include <QDir>
+#include <QCryptographicHash>
+#include <mainwindow.h>
+
+SHashedImage::SHashedImage(struct picture *picture) : QImage(picture->filename)
+{
+       if (isNull()) {
+               // Hash lookup.
+       } else {
+               QCryptographicHash hash(QCryptographicHash::Sha1);
+               QFile imagefile(picture->filename);
+               imagefile.open(QIODevice::ReadOnly);
+               hash.addData(&imagefile);
+               free(picture->hash);
+               picture->hash = strdup(hash.result().toHex().data());
+               
MainWindow::instance()->hashOf.insert(QString(picture->filename), 
hash.result());
+       }
+}
 
 DivePictureModel *DivePictureModel::instance()
 {
@@ -15,20 +32,21 @@ DivePictureModel::DivePictureModel() : numberOfPictures(0)
 {
 }
 
-typedef QPair<QString, QImage> SPixmap;
-typedef QList<SPixmap> SPixmapList;
+typedef struct picture *picturepointer;
+typedef QPair<picturepointer, QImage> SPixmap;
+typedef QList<struct picture *> SPictureList;
 
-SPixmap scaleImages(const QString &s)
+SPixmap scaleImages(picturepointer picture)
 {
        static QHash <QString, QImage > cache;
        SPixmap ret;
-       ret.first = s;
-       if (cache.contains(s)) {
-               ret.second = cache.value(s);
+       ret.first = picture;
+       if (cache.contains(picture->filename)) {
+               ret.second = cache.value(picture->filename);
        } else {
                int dim = defaultIconMetrics().sz_pic;
-               QImage p = QImage(s).scaled(dim, dim, Qt::KeepAspectRatio);
-               cache.insert(s, p);
+               QImage p = SHashedImage(picture).scaled(dim, dim, 
Qt::KeepAspectRatio);
+               cache.insert(picture->filename, p);
                ret.second = p;
        }
        return ret;
@@ -49,14 +67,15 @@ void DivePictureModel::updateDivePictures()
        }
 
        stringPixmapCache.clear();
-       QStringList pictures;
+       SPictureList pictures;
        FOR_EACH_PICTURE_NON_PTR(displayed_dive) {
                stringPixmapCache[QString(picture->filename)].offsetSeconds = 
picture->offset.seconds;
-               pictures.push_back(QString(picture->filename));
+               pictures.push_back(picture);
        }
 
-       Q_FOREACH (const SPixmap &pixmap, 
QtConcurrent::blockingMapped<SPixmapList>(pictures, scaleImages))
-               stringPixmapCache[pixmap.first].image = pixmap.second;
+       QList<SPixmap> list = QtConcurrent::blockingMapped(pictures, 
scaleImages);
+       Q_FOREACH (const SPixmap &pixmap, list)
+               stringPixmapCache[pixmap.first->filename].image = pixmap.second;
 
        beginInsertRows(QModelIndex(), 0, numberOfPictures - 1);
        endInsertRows();
diff --git a/qt-ui/divepicturewidget.h b/qt-ui/divepicturewidget.h
index aa524e1..e8104a1 100644
--- a/qt-ui/divepicturewidget.h
+++ b/qt-ui/divepicturewidget.h
@@ -5,11 +5,18 @@
 #include <QListView>
 #include <QThread>
 
+typedef QPair<QString, QByteArray> SHashedFilename;
+
 struct PhotoHelper {
        QImage image;
        int offsetSeconds;
 };
 
+class SHashedImage : public QImage {
+public:
+       SHashedImage(struct picture *picture);
+};
+
 class DivePictureModel : public QAbstractTableModel {
        Q_OBJECT
 public:
diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
index 85a6312..1782953 100644
--- a/qt-ui/mainwindow.h
+++ b/qt-ui/mainwindow.h
@@ -11,6 +11,7 @@
 #include <QAction>
 #include <QUrl>
 #include <QUuid>
+#include <QHash>
 
 #include "ui_mainwindow.h"
 
@@ -91,6 +92,9 @@ public:
        void checkSurvey(QSettings *s);
        void setApplicationState(const QByteArray& state);
        QUndoStack *undoStack;
+       QHash<QString, QByteArray> hashOf;
+       QHash<QByteArray, QString> localFilenameOf;
+
 private
 slots:
        /* file menu action */
diff --git a/qthelper.cpp b/qthelper.cpp
index b26bdf4..d449268 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -5,6 +5,7 @@
 #include "subsurfacewebservices.h"
 #include "usersurvey.h"
 #include "membuffer.h"
+#include "mainwindow.h"
 #include <exif.h>
 #include "file.h"
 #include <QFile>
@@ -401,3 +402,8 @@ extern "C" void reverseGeoLookup(degrees_t latitude, 
degrees_t longitude, uint32
                ds->notes = add_to_string(ds->notes, "countrytag: %s", 
address.value("country").toString().toUtf8().data());
        }
 }
+
+extern "C" char * hashstring(char * filename)
+{
+       return MainWindow::instance()->hashOf[QString(filename)].toHex().data();
+}
diff --git a/qthelper.h b/qthelper.h
index a367a9d..61e968c 100644
--- a/qthelper.h
+++ b/qthelper.h
@@ -16,5 +16,4 @@ bool gpsHasChanged(struct dive *dive, struct dive *master, 
const QString &gps_te
 extern "C" const char *printGPSCoords(int lat, int lon);
 QList<int> getDivesInTrip(dive_trip_t *trip);
 QString gasToStr(struct gasmix gas);
-
 #endif // QTHELPER_H
diff --git a/save-xml.c b/save-xml.c
index d5f1e15..f5e1d5e 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -359,6 +359,8 @@ static void save_dc(struct membuffer *b, struct dive *dive, 
struct divecomputer
        put_format(b, "  </divecomputer>\n");
 }
 
+extern char * hashstring(char * filename);
+
 static void save_picture(struct membuffer *b, struct picture *pic)
 {
        put_string(b, "  <picture filename='");
@@ -377,6 +379,9 @@ static void save_picture(struct membuffer *b, struct 
picture *pic)
                put_degrees(b, pic->latitude, " gps='", " ");
                put_degrees(b, pic->longitude, "", "'");
        }
+       if (hashstring(pic->filename))
+               put_format(b, " hash='%s'", hashstring(pic->filename));
+
        put_string(b, "/>\n");
 }
 
-- 
1.9.3 (Apple Git-50)

From 33a6cce45a86b74f2e596253876f8bad71844ea4 Mon Sep 17 00:00:00 2001
From: "Robert C. Helling" <[email protected]>
Date: Mon, 23 Feb 2015 12:00:55 +0100
Subject: [PATCH 2/4] Save and use database of image hashes.

This patch adds a directory crawler to compute hashes of image files and load 
and save those to a persistent file.

Signed-off-by: Robert C. Helling <[email protected]>
---
 qt-ui/divepicturewidget.cpp | 16 +++++++----
 qt-ui/mainwindow.cpp        |  4 +++
 qthelper.cpp                | 70 +++++++++++++++++++++++++++++++++++++++++++++
 qthelper.h                  |  6 ++++
 4 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/qt-ui/divepicturewidget.cpp b/qt-ui/divepicturewidget.cpp
index 4a205da..d4b29e6 100644
--- a/qt-ui/divepicturewidget.cpp
+++ b/qt-ui/divepicturewidget.cpp
@@ -3,22 +3,26 @@
 #include "dive.h"
 #include "divelist.h"
 #include <QtConcurrentMap>
+#include <QtConcurrentRun>
 #include <QDir>
 #include <QCryptographicHash>
 #include <mainwindow.h>
+#include <qthelper.h>
 
 SHashedImage::SHashedImage(struct picture *picture) : QImage(picture->filename)
 {
        if (isNull()) {
                // Hash lookup.
+               qDebug() << picture->filename << "not found, trying" << 
picture->hash << 
MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)];
+               
load(MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)]);
+               if (!isNull())
+                       QtConcurrent::run(updateHash, picture);
        } else {
-               QCryptographicHash hash(QCryptographicHash::Sha1);
-               QFile imagefile(picture->filename);
-               imagefile.open(QIODevice::ReadOnly);
-               hash.addData(&imagefile);
+               QByteArray hash = hashFile(picture->filename);
                free(picture->hash);
-               picture->hash = strdup(hash.result().toHex().data());
-               
MainWindow::instance()->hashOf.insert(QString(picture->filename), 
hash.result());
+               picture->hash = strdup(hash.toHex().data());
+               
MainWindow::instance()->hashOf.insert(QString(picture->filename), hash);
+               MainWindow::instance()->localFilenameOf[hash] = 
QString(picture->filename);
        }
 }
 
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 648ead1..a0fbaeb 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -37,6 +37,7 @@
 #endif
 #include <QNetworkProxy>
 #include <QUndoStack>
+#include <qthelper.h>
 
 MainWindow *MainWindow::m_Instance = NULL;
 
@@ -50,6 +51,8 @@ MainWindow::MainWindow() : QMainWindow(),
        Q_ASSERT_X(m_Instance == NULL, "MainWindow", "MainWindow recreated!");
        m_Instance = this;
        ui.setupUi(this);
+       read_hashes();
+       learnImages(QDir("/Users/helling/Pictures/subsurfaceimages.away"), 3);
        // Define the States of the Application Here, Currently the states are 
situations where the different
        // widgets will change on the mainwindow.
 
@@ -201,6 +204,7 @@ MainWindow::MainWindow() : QMainWindow(),
 
 MainWindow::~MainWindow()
 {
+       write_hashes();
        m_Instance = NULL;
 }
 
diff --git a/qthelper.cpp b/qthelper.cpp
index d449268..a58a21d 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -22,6 +22,10 @@
 #include <QNetworkAccessManager>
 #include <QUrlQuery>
 #include <QEventLoop>
+#include <QSaveFile>
+#include <QDir>
+#include <QImageReader>
+#include <QtConcurrent>
 
 #include <libxslt/documents.h>
 
@@ -407,3 +411,69 @@ extern "C" char * hashstring(char * filename)
 {
        return MainWindow::instance()->hashOf[QString(filename)].toHex().data();
 }
+
+void read_hashes()
+{
+       QFile hashfile(QString(system_default_directory()).append("/hashes"));
+       qDebug() << QString(system_default_directory()).append("/hashes");
+       if (hashfile.open(QIODevice::ReadOnly)) {
+               QDataStream stream(&hashfile);
+               stream >> MainWindow::instance()->localFilenameOf;
+               hashfile.close();
+       }
+}
+
+void write_hashes()
+{
+       QSaveFile 
hashfile(QString(system_default_directory()).append("/hashes"));
+       if (hashfile.open(QIODevice::WriteOnly)) {
+               QDataStream stream(&hashfile);
+               stream << MainWindow::instance()->localFilenameOf;
+               hashfile.commit();
+       } else {
+               qDebug() << "cannot open" << hashfile.fileName();
+       }
+}
+
+QByteArray hashFile(const char *filename)
+{
+       QCryptographicHash hash(QCryptographicHash::Sha1);
+       QFile imagefile(filename);
+       imagefile.open(QIODevice::ReadOnly);
+       hash.addData(&imagefile);
+       return hash.result();
+}
+
+void updateHash(struct picture *picture) {
+       char *old = picture->hash;
+       picture->hash = 
strdup(hashFile(MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)].toUtf8().data()).toHex());
+       free(old);
+}
+
+void learnImage(const QByteArray filename)
+{
+       MainWindow::instance()->localFilenameOf[hashFile(filename.data())] = 
strdup(filename.data());
+}
+
+void learnImages(const QDir &dir, int maxdepth)
+{
+       QDir current(dir);
+       QList<QByteArray> files;
+       QStringList filters;
+
+       if (maxdepth) {
+               foreach (QString dirname, dir.entryList(QStringList(), 
QDir::NoDotAndDotDot | QDir::Dirs)) {
+                       learnImages(QDir(dir.filePath(dirname)), maxdepth - 1);
+               }
+       }
+
+       foreach (QString format, QImageReader::supportedImageFormats()) {
+               filters.append(QString("*.").append(format));
+       }
+
+       foreach (QString file, dir.entryList(filters, QDir::Files)) {
+               files.append(dir.absoluteFilePath(file).toUtf8());
+       }
+
+       QtConcurrent::blockingMap(files, learnImage);
+}
diff --git a/qthelper.h b/qthelper.h
index 61e968c..3826efa 100644
--- a/qthelper.h
+++ b/qthelper.h
@@ -7,6 +7,7 @@
 #include "dive.h"
 #include "divelist.h"
 #include <QTranslator>
+#include <QDir>
 
 // global pointers for our translation
 extern QTranslator *qtTranslator, *ssrfTranslator;
@@ -16,4 +17,9 @@ bool gpsHasChanged(struct dive *dive, struct dive *master, 
const QString &gps_te
 extern "C" const char *printGPSCoords(int lat, int lon);
 QList<int> getDivesInTrip(dive_trip_t *trip);
 QString gasToStr(struct gasmix gas);
+void read_hashes();
+void write_hashes();
+void updateHash(struct picture *picture);
+QByteArray hashFile(const char *filename);
+void learnImages(const QDir &dir, int maxdepth);
 #endif // QTHELPER_H
-- 
1.9.3 (Apple Git-50)

From ed6bc97fd0e12a2e9c4bd0a3d02029c9bb88dbab Mon Sep 17 00:00:00 2001
From: "Robert C. Helling" <[email protected]>
Date: Mon, 23 Feb 2015 12:45:54 +0100
Subject: [PATCH 3/4] Make double click on picture open the correct local file

... and update hash-databases correctly.

Signed-off-by: Robert C. Helling <[email protected]>
---
 qt-ui/divepicturewidget.cpp | 2 +-
 qthelper.cpp                | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/qt-ui/divepicturewidget.cpp b/qt-ui/divepicturewidget.cpp
index d4b29e6..9a4a7e3 100644
--- a/qt-ui/divepicturewidget.cpp
+++ b/qt-ui/divepicturewidget.cpp
@@ -144,5 +144,5 @@ DivePictureWidget::DivePictureWidget(QWidget *parent) : 
QListView(parent)
 void DivePictureWidget::doubleClicked(const QModelIndex &index)
 {
        QString filePath = model()->data(index, 
Qt::DisplayPropertyRole).toString();
-       emit photoDoubleClicked(filePath);
+       emit 
photoDoubleClicked(MainWindow::instance()->localFilenameOf[MainWindow::instance()->hashOf[filePath]]);
 }
diff --git a/qthelper.cpp b/qthelper.cpp
index a58a21d..a784e57 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -441,12 +441,16 @@ QByteArray hashFile(const char *filename)
        QFile imagefile(filename);
        imagefile.open(QIODevice::ReadOnly);
        hash.addData(&imagefile);
+       MainWindow::instance()->hashOf[QString(filename)] = hash.result();
+       MainWindow::instance()->localFilenameOf[hash.result()] = 
QString(filename);
        return hash.result();
 }
 
 void updateHash(struct picture *picture) {
+       QByteArray hash = 
hashFile(MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)].toUtf8().data());
+       MainWindow::instance()->hashOf[QString(picture->filename)] = hash;
        char *old = picture->hash;
-       picture->hash = 
strdup(hashFile(MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)].toUtf8().data()).toHex());
+       picture->hash = strdup(hash.toHex());
        free(old);
 }
 
-- 
1.9.3 (Apple Git-50)

From bd10a28d5189a3d15bb34de22333730974f8e4fb Mon Sep 17 00:00:00 2001
From: "Robert C. Helling" <[email protected]>
Date: Mon, 23 Feb 2015 14:50:11 +0100
Subject: [PATCH 4/4] Add UI for update image hash

Signed-off-by: Robert C. Helling <[email protected]>
---
 qt-ui/divepicturewidget.cpp |  2 +-
 qt-ui/mainwindow.cpp        | 20 +++++++++++++++++++-
 qt-ui/mainwindow.h          |  1 +
 qt-ui/mainwindow.ui         |  8 +++++++-
 qthelper.cpp                |  2 ++
 5 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/qt-ui/divepicturewidget.cpp b/qt-ui/divepicturewidget.cpp
index 9a4a7e3..20f5fa0 100644
--- a/qt-ui/divepicturewidget.cpp
+++ b/qt-ui/divepicturewidget.cpp
@@ -45,7 +45,7 @@ SPixmap scaleImages(picturepointer picture)
        static QHash <QString, QImage > cache;
        SPixmap ret;
        ret.first = picture;
-       if (cache.contains(picture->filename)) {
+       if (cache.contains(picture->filename) && 
!cache.value(picture->filename).isNull()) {
                ret.second = cache.value(picture->filename);
        } else {
                int dim = defaultIconMetrics().sz_pic;
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index a0fbaeb..f2d7869 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -38,6 +38,7 @@
 #include <QNetworkProxy>
 #include <QUndoStack>
 #include <qthelper.h>
+#include <QtConcurrentRun>
 
 MainWindow *MainWindow::m_Instance = NULL;
 
@@ -52,7 +53,6 @@ MainWindow::MainWindow() : QMainWindow(),
        m_Instance = this;
        ui.setupUi(this);
        read_hashes();
-       learnImages(QDir("/Users/helling/Pictures/subsurfaceimages.away"), 3);
        // Define the States of the Application Here, Currently the states are 
situations where the different
        // widgets will change on the mainwindow.
 
@@ -319,6 +319,24 @@ void MainWindow::on_actionSaveAs_triggered()
        file_save_as();
 }
 
+void MainWindow::on_actionHash_images_triggered()
+{
+       QFileDialog dialog(this, tr("Traverse image directories"), 
lastUsedDir(), filter());
+       dialog.setFileMode(QFileDialog::Directory);
+       dialog.setViewMode(QFileDialog::Detail);
+       dialog.setLabelText(QFileDialog::Accept, tr("Scan"));
+       dialog.setLabelText(QFileDialog::Reject, tr("Cancel"));
+       QStringList dirnames;
+       if (dialog.exec())
+               dirnames = dialog.selectedFiles();
+       if (dirnames.isEmpty())
+               return;
+       foreach (QString dir, dirnames) {
+               QtConcurrent::run(learnImages, QDir(dir), 10);
+       }
+
+}
+
 ProfileWidget2 *MainWindow::graphics() const
 {
        return 
qobject_cast<ProfileWidget2*>(applicationState["Default"].topRight->layout()->itemAt(1)->widget());
diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
index 1782953..55f08ef 100644
--- a/qt-ui/mainwindow.h
+++ b/qt-ui/mainwindow.h
@@ -107,6 +107,7 @@ slots:
        void on_actionPrint_triggered();
        void on_actionPreferences_triggered();
        void on_actionQuit_triggered();
+       void on_actionHash_images_triggered();
 
        /* log menu actions */
        void on_actionDownloadDC_triggered();
diff --git a/qt-ui/mainwindow.ui b/qt-ui/mainwindow.ui
index b6cd4a3..41a85bf 100644
--- a/qt-ui/mainwindow.ui
+++ b/qt-ui/mainwindow.ui
@@ -50,7 +50,7 @@
      <x>0</x>
      <y>0</y>
      <width>861</width>
-     <height>25</height>
+     <height>22</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -67,6 +67,7 @@
     <addaction name="actionPrint"/>
     <addaction name="actionPreferences"/>
     <addaction name="separator"/>
+    <addaction name="actionHash_images"/>
     <addaction name="actionConfigure_Dive_Computer"/>
     <addaction name="separator"/>
     <addaction name="actionRecent1"/>
@@ -690,6 +691,11 @@
     <string>Ctrl+Shift+Z</string>
    </property>
   </action>
+  <action name="actionHash_images">
+   <property name="text">
+    <string>Hash images</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
   <customwidget>
diff --git a/qthelper.cpp b/qthelper.cpp
index a784e57..09d84d8 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -26,6 +26,7 @@
 #include <QDir>
 #include <QImageReader>
 #include <QtConcurrent>
+#include "divepicturewidget.h"
 
 #include <libxslt/documents.h>
 
@@ -480,4 +481,5 @@ void learnImages(const QDir &dir, int maxdepth)
        }
 
        QtConcurrent::blockingMap(files, learnImage);
+       DivePictureModel::instance()->updateDivePictures();
 }
-- 
1.9.3 (Apple Git-50)


Upon successfully loading an image, we also compute a SHA1-hash of the image file and store it with he (“original”) filename. In addition we build up dictionaries between hashes and filenames that are read from disk upon startup and saved in the destructor of the main window (BTW: I found the AppData Path on my mac not writeable per default maybe that needs looking into).

When reading an image file from disk fails, we check the dictionary if the dictionary knows about a different path for the file with the appropriate hash and we display that instead. But to the user we always show the “original” file name.

In addition, there is a new entry to the file menu “hash images”. With that the user can point subsurface to a directory that is scanned recursively (in the background without any visual feedback besides possibly appearing images) for image files of which the hash is computed and stored in the dictionary.

So, when moving the divelog form one computer to the other, the user only has to bulk transfer all images and tell subsurface about the location of those and it will figure out the details itself.

Alternatively, the user can keep her files in a cloud synched directory and tell subsurface about it even when the patch to that directory differs on different machines.

Best
Robert

PS: 2677f3ca breaks the build for me. What am I supposed to do about it besides reverting it?

-- 
.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oO
Robert C. Helling     Elite Master Course Theoretical and Mathematical Physics
                      Scientific Coordinator
                      Ludwig Maximilians Universitaet Muenchen, Dept. Physik
                      Phone: +49 89 2180-4523  Theresienstr. 39, rm. B339
                      http://www.atdotde.de

Enhance your privacy, use cryptography! My PGP keys have fingerprints
A9D1 A01D 13A5 31FA 6515  BB44 0820 367C 36BC 0C1D    and
DCED 37B6 251C 7861 270D  5613 95C7 9D32 9A8D 9B8F





Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

_______________________________________________
subsurface mailing list
[email protected]
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to