From f9cab0e497d0f8112054fdf7073ca40a5faa9c94 Mon Sep 17 00:00:00 2001
From: "Robert C. Helling" <helling@atdotde.de>
Date: Thu, 13 Feb 2014 16:43:55 +0100
Subject: [PATCH 2/2] Compute dive computer/camera time offset from sample
 picture

Signed-off-by: Robert C. Helling <helling@atdotde.de>
---
 qt-ui/divelistview.cpp   |  16 ++---
 qt-ui/divelistview.h     |   2 +-
 qt-ui/shiftimagetimes.ui | 152 ++++++++++++++++++++++++++++++++++++++++++-----
 qt-ui/simplewidgets.cpp  |  70 ++++++++++++++++++++--
 qt-ui/simplewidgets.h    |  11 +++-
 5 files changed, 216 insertions(+), 35 deletions(-)

diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index fa19f21..ae81dda 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -804,6 +804,7 @@ void DiveListView::loadImages()
 {
 	struct memblock mem;
 	EXIFInfo exif;
+	int retval;
 	time_t imagetime;
 	QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Image Files"), lastUsedImageDir(), tr("Image Files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
 
@@ -818,23 +819,16 @@ void DiveListView::loadImages()
 	updateLastImageTimeOffset(shiftDialog.amount());
 
 	for (int i = 0; i < fileNames.size(); ++i) {
-		struct tm tm;
-		int year, month, day, hour, min, sec;
-		int retval;
 		if (readfile(fileNames.at(i).toUtf8().data(), &mem) <= 0)
 			continue;
 		retval = exif.parseFrom((const unsigned char *) mem.buffer, (unsigned) mem.size);
 		free(mem.buffer);
 		if (retval != PARSE_EXIF_SUCCESS)
 			continue;
-		sscanf(exif.DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
-		tm.tm_year = year;
-		tm.tm_mon = month - 1;
-		tm.tm_mday = day;
-		tm.tm_hour = hour;
-		tm.tm_min = min;
-		tm.tm_sec = sec;
-		imagetime = utc_mktime(&tm) + shiftDialog.amount();
+		imagetime = shiftDialog.epochFromExiv(&exif);
+		if (!imagetime)
+			continue;
+		imagetime += shiftDialog.amount();
 		int j = 0;
 		struct dive *dive;
 		for_each_dive(j, dive){
diff --git a/qt-ui/divelistview.h b/qt-ui/divelistview.h
index c632122..c77b85f 100644
--- a/qt-ui/divelistview.h
+++ b/qt-ui/divelistview.h
@@ -52,6 +52,7 @@ public slots:
 	void shiftTimes();
 	void loadImages();
 	void uploadToDivelogsDE();
+	QString lastUsedImageDir();
 
 signals:
 	void currentDiveChanged(int divenr);
@@ -73,7 +74,6 @@ private:
 	void restoreExpandedRows();
 	int lastVisibleColumn();
 	void selectTrip ( dive_trip_t* trip );
-	QString lastUsedImageDir();
 	void updateLastUsedImageDir(const QString& s);
 	void updateLastImageTimeOffset(int offset);
 	int lastImageTimeOffset();
diff --git a/qt-ui/shiftimagetimes.ui b/qt-ui/shiftimagetimes.ui
index 653103b..0e91ad6 100644
--- a/qt-ui/shiftimagetimes.ui
+++ b/qt-ui/shiftimagetimes.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>343</width>
-    <height>177</height>
+    <width>693</width>
+    <height>606</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -25,7 +25,7 @@
    </iconset>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_2">
-   <item alignment="Qt::AlignTop">
+   <item>
     <widget class="QGroupBox" name="groupBox">
      <property name="title">
       <string>Shift times of image(s) by</string>
@@ -40,6 +40,16 @@
           <day>1</day>
          </date>
         </property>
+        <property name="maximumDateTime">
+         <datetime>
+          <hour>23</hour>
+          <minute>59</minute>
+          <second>59</second>
+          <year>2010</year>
+          <month>12</month>
+          <day>31</day>
+         </datetime>
+        </property>
         <property name="minimumDateTime">
          <datetime>
           <hour>0</hour>
@@ -52,13 +62,31 @@
         </property>
         <property name="maximumDate">
          <date>
+          <year>2010</year>
+          <month>12</month>
+          <day>31</day>
+         </date>
+        </property>
+        <property name="minimumDate">
+         <date>
           <year>2000</year>
           <month>1</month>
           <day>1</day>
          </date>
         </property>
-        <property name="displayFormat">
-         <string>h:mm</string>
+        <property name="maximumTime">
+         <time>
+          <hour>23</hour>
+          <minute>59</minute>
+          <second>59</second>
+         </time>
+        </property>
+        <property name="minimumTime">
+         <time>
+          <hour>0</hour>
+          <minute>0</minute>
+          <second>0</second>
+         </time>
         </property>
         <property name="timeSpec">
          <enum>Qt::LocalTime</enum>
@@ -82,19 +110,113 @@
         </property>
        </widget>
       </item>
+      <item>
+       <widget class="QDialogButtonBox" name="buttonBox">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="standardButtons">
+         <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="Line" name="line">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>60</height>
+         </size>
+        </property>
+        <property name="layoutDirection">
+         <enum>Qt::LeftToRight</enum>
+        </property>
+        <property name="text">
+         <string>To compute the offset between the clocks of your dive computer and your camera use your camera to take a picture of your dive compuer displaying the current time. Download that image to your computer and press this button.</string>
+        </property>
+        <property name="wordWrap">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="syncCamera">
+        <property name="toolTip">
+         <string>Determine camera time offset</string>
+        </property>
+        <property name="text">
+         <string>Select image of divecomputer showing time</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QGroupBox" name="displayDC">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="title">
+         <string/>
+        </property>
+        <widget class="QDateTimeEdit" name="dcTime">
+         <property name="geometry">
+          <rect>
+           <x>0</x>
+           <y>70</y>
+           <width>161</width>
+           <height>24</height>
+          </rect>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_2">
+         <property name="geometry">
+          <rect>
+           <x>0</x>
+           <y>10</y>
+           <width>234</width>
+           <height>60</height>
+          </rect>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>16777215</width>
+           <height>60</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Which date and time are displayed on the image?</string>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+        <widget class="QGraphicsView" name="DCImage">
+         <property name="geometry">
+          <rect>
+           <x>260</x>
+           <y>10</y>
+           <width>361</width>
+           <height>281</height>
+          </rect>
+         </property>
+         <property name="verticalScrollBarPolicy">
+          <enum>Qt::ScrollBarAlwaysOff</enum>
+         </property>
+         <property name="horizontalScrollBarPolicy">
+          <enum>Qt::ScrollBarAlwaysOff</enum>
+         </property>
+        </widget>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
   </layout>
  </widget>
  <resources>
diff --git a/qt-ui/simplewidgets.cpp b/qt-ui/simplewidgets.cpp
index f4d69ff..70a2722 100644
--- a/qt-ui/simplewidgets.cpp
+++ b/qt-ui/simplewidgets.cpp
@@ -12,8 +12,11 @@
 #include <QStringList>
 #include <QDebug>
 #include <QTime>
-
+#include <QFileDialog>
+#include <QDateTime>
+#include "exif.h"
 #include "../dive.h"
+#include "../file.h"
 #include "mainwindow.h"
 
 class MinMaxAvgWidgetPrivate {
@@ -168,24 +171,81 @@ void ShiftImageTimesDialog::buttonClicked(QAbstractButton* button)
 	}
 }
 
+void ShiftImageTimesDialog::syncCameraClicked()
+{
+	struct memblock mem;
+	EXIFInfo exiv;
+	int retval;
+	QPixmap picture;
+	QDateTime dcDateTime = QDateTime::QDateTime();
+	QStringList fileNames = QFileDialog::getOpenFileNames(this, 
+							      tr("Open Image File"), 
+							      MainWindow().dive_list()->lastUsedImageDir(), 
+							      tr("Image Files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
+
+	if (fileNames.isEmpty())
+		return;
+	
+	picture.load(fileNames.at(0));
+	ui.displayDC->setEnabled(TRUE);
+	QGraphicsScene *scene = new QGraphicsScene (this);
+
+	scene->addPixmap(picture.scaled(ui.DCImage->size()));
+	ui.DCImage->setScene(scene);
+	if (readfile(fileNames.at(0).toUtf8().data(), &mem) <= 0)
+		return;
+	retval = exiv.parseFrom((const unsigned char *) mem.buffer, (unsigned) mem.size);
+	free(mem.buffer);
+	if (retval != PARSE_EXIF_SUCCESS)
+		return;
+	dcImageEpoch = epochFromExiv(&exiv);
+	dcDateTime.setTime_t(dcImageEpoch);
+	ui.dcTime->setDateTime(dcDateTime);
+	connect(ui.dcTime, SIGNAL(dateTimeChanged(const QDateTime &)), this, SLOT(dcDateTimeChanged(const QDateTime &)));
+}
+
+time_t ShiftImageTimesDialog::epochFromExiv(EXIFInfo *exif)
+{
+	struct tm tm;
+	int year, month, day, hour, min, sec;
+	
+	sscanf(exif->DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
+	tm.tm_year = year;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+	return (utc_mktime(&tm));
+}
+
+void ShiftImageTimesDialog::dcDateTimeChanged(const QDateTime &newDateTime)
+{
+	if (!dcImageEpoch)
+		return;
+	setOffset(newDateTime.toTime_t() - dcImageEpoch);
+}
+
 ShiftImageTimesDialog::ShiftImageTimesDialog(QWidget *parent): QDialog(parent), m_amount(0)
 {
 	ui.setupUi(this);
 	connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
+	connect(ui.syncCamera, SIGNAL(clicked()), this, SLOT(syncCameraClicked()));
+	dcImageEpoch = (time_t) 0;
 }
 
-int ShiftImageTimesDialog::amount() const
+time_t ShiftImageTimesDialog::amount() const
 {
 	return m_amount;
 }
 
-void ShiftImageTimesDialog::setOffset(int offset)
+void ShiftImageTimesDialog::setOffset(time_t offset)
 {
 	if (offset >= 0){
-		ui.forward->setDown(TRUE);
+		ui.forward->setChecked(TRUE);
 	}
 	else{
-		ui.backwards->setDown(TRUE);
+		ui.backwards->setChecked(TRUE);
 		offset *= -1;
 	}
 	ui.timeEdit->setTime(QTime::QTime(offset / 3600, (offset % 3600) / 60, offset % 60));
diff --git a/qt-ui/simplewidgets.h b/qt-ui/simplewidgets.h
index d227c91..098b227 100644
--- a/qt-ui/simplewidgets.h
+++ b/qt-ui/simplewidgets.h
@@ -10,6 +10,7 @@ class QAbstractButton;
 #include "ui_renumber.h"
 #include "ui_shifttimes.h"
 #include "ui_shiftimagetimes.h"
+#include "exif.h"
 
 class MinMaxAvgWidget : public QWidget{
 	Q_OBJECT
@@ -59,13 +60,17 @@ class ShiftImageTimesDialog : public QDialog {
 	Q_OBJECT
 public:
 	explicit ShiftImageTimesDialog(QWidget *parent);
-	int amount() const;
-	void setOffset(int offset);
+	time_t amount() const;
+	void setOffset(time_t offset);
+	time_t epochFromExiv(EXIFInfo *exif);
 private slots:
 	void buttonClicked(QAbstractButton *button);
+	void syncCameraClicked();
+	void dcDateTimeChanged(const QDateTime &);
 private:
 	Ui::ShiftImageTimesDialog ui;
-	int m_amount;
+	time_t m_amount;
+	time_t dcImageEpoch;
 };
 
 bool isGnome3Session();
-- 
1.8.3.4 (Apple Git-47)

