Skip to content

Commit

Permalink
AnalyzeView: Fix GeoTagWorker Threading
Browse files Browse the repository at this point in the history
  • Loading branch information
HTRamsey committed Oct 19, 2024
1 parent 68afef9 commit 22d007a
Show file tree
Hide file tree
Showing 22 changed files with 611 additions and 370 deletions.
1 change: 0 additions & 1 deletion src/AnalyzeView/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ if(NOT exiv2_FOUND AND NOT LibExiv2_FOUND)
GIT_REPOSITORY https://github.com/Exiv2/exiv2.git
GIT_TAG v0.28.3
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
set(EXIV2_ENABLE_XMP OFF CACHE INTERNAL "" FORCE)
set(EXIV2_ENABLE_EXTERNAL_XMP OFF CACHE INTERNAL "" FORCE)
Expand Down
16 changes: 8 additions & 8 deletions src/AnalyzeView/ExifParser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void init()
::atexit(Exiv2::XmpParser::terminate);
}

double readTime(const QByteArray &buf)
QDateTime readTime(const QByteArray &buf)
{
try {
// Convert QByteArray to std::string for Exiv2
Expand All @@ -36,7 +36,7 @@ double readTime(const QByteArray &buf)
const Exiv2::ExifData &exifData = image->exifData();
if (exifData.empty()) {
qCWarning(ExifParserLog) << "No EXIF data found in the image.";
return -1.0;
return QDateTime();
}

// Read DateTimeOriginal
Expand All @@ -45,7 +45,7 @@ double readTime(const QByteArray &buf)
const Exiv2::ExifData::const_iterator pos = exifData.findKey(key);
if (pos == exifData.end()) {
qCWarning(ExifParserLog) << "No DateTimeOriginal found.";
return -1.0;
return QDateTime();
}

const std::string dateTimeOriginal = pos->toString();
Expand All @@ -54,30 +54,30 @@ double readTime(const QByteArray &buf)

if (createDateList.size() < 2) {
qCWarning(ExifParserLog) << "Invalid date/time format: " << createDateList;
return -1.0;
return QDateTime();
}

const QStringList dateList = createDateList[0].split(':');
const QStringList timeList = createDateList[1].split(':');

if ((dateList.size() < 3) || (timeList.size() < 3)) {
qCWarning(ExifParserLog) << "Could not parse creation date/time: " << dateList << " " << timeList;
return -1.0;
return QDateTime();
}

const QDate date(dateList[0].toInt(), dateList[1].toInt(), dateList[2].toInt());
const QTime time(timeList[0].toInt(), timeList[1].toInt(), timeList[2].toInt());

const QDateTime tagTime(date, time);

return (tagTime.toMSecsSinceEpoch() / 1000.0);
return tagTime;
} catch (const Exiv2::Error &e) {
qCWarning(ExifParserLog) << "Error reading EXIF data:" << e.what();
return -1.0;
return QDateTime();
}
}

bool write(QByteArray &buf, const GeoTagWorker::cameraFeedbackPacket &geotag)
bool write(QByteArray &buf, const GeoTagWorker::CameraFeedbackPacket &geotag)
{
try {
// Convert QByteArray to std::string for Exiv2
Expand Down
7 changes: 4 additions & 3 deletions src/AnalyzeView/ExifParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ class QByteArray;

Q_DECLARE_LOGGING_CATEGORY(ExifParserLog)

namespace ExifParser {
namespace ExifParser
{
void init();
double readTime(const QByteArray &buf);
bool write(QByteArray &buf, const GeoTagWorker::cameraFeedbackPacket &geotag);
QDateTime readTime(const QByteArray &buf);
bool write(QByteArray &buf, const GeoTagWorker::CameraFeedbackPacket &geotag);
}
196 changes: 124 additions & 72 deletions src/AnalyzeView/GeoTagController.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,120 +8,172 @@
****************************************************************************/

#include "GeoTagController.h"
#include "GeoTagWorker.h"
#include "QGCLoggingCategory.h"

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QThread>
#include <QtCore/QUrl>

QGC_LOGGING_CATEGORY(GeoTagControllerLog, "qgc.analyzeview.geotagcontroller")

GeoTagController::GeoTagController()
: _progress(0)
, _inProgress(false)
GeoTagController::GeoTagController(QObject *parent)
: QObject(parent)
, _worker(new GeoTagWorker())
, _workerThread(new QThread(this))
{
connect(&_worker, &GeoTagWorker::progressChanged, this, &GeoTagController::_workerProgressChanged);
connect(&_worker, &GeoTagWorker::error, this, &GeoTagController::_workerError);
connect(&_worker, &GeoTagWorker::started, this, &GeoTagController::inProgressChanged);
connect(&_worker, &GeoTagWorker::finished, this, &GeoTagController::inProgressChanged);
// qCDebug(GeoTagControllerLog) << Q_FUNC_INFO << this;

_worker->moveToThread(_workerThread);

(void) connect(_worker, &GeoTagWorker::progressChanged, this, &GeoTagController::_workerProgressChanged);
(void) connect(_worker, &GeoTagWorker::error, this, &GeoTagController::_workerError);
(void) connect(_workerThread, &QThread::started, _worker, &GeoTagWorker::process);
(void) connect(_workerThread, &QThread::started, this, &GeoTagController::inProgressChanged);
(void) connect(_workerThread, &QThread::finished, this, &GeoTagController::inProgressChanged);
}

GeoTagController::~GeoTagController()
{
cancelTagging();
delete _worker;

// qCDebug(GeoTagControllerLog) << Q_FUNC_INFO << this;
}

void GeoTagController::setLogFile(QString filename)
void GeoTagController::cancelTagging()
{
filename = QUrl(filename).toLocalFile();
if (!filename.isEmpty()) {
_worker.setLogFile(filename);
emit logFileChanged(filename);
}
(void) QMetaObject::invokeMethod(_worker, "cancelTagging", Qt::AutoConnection);
(void) QMetaObject::invokeMethod(_workerThread, "quit", Qt::AutoConnection);

_workerThread->wait();
}

void GeoTagController::setImageDirectory(QString dir)
QString GeoTagController::logFile() const
{
dir = QUrl(dir).toLocalFile();
if (!dir.isEmpty()) {
_worker.setImageDirectory(dir);
emit imageDirectoryChanged(dir);
if(_worker.saveDirectory() == "") {
QDir saveDirectory = QDir(_worker.imageDirectory() + kTagged);
if(saveDirectory.exists()) {
_setErrorMessage(tr("Images have alreay been tagged. Existing images will be removed."));
return;
}
}
return _worker->logFile();
}

QString GeoTagController::imageDirectory() const
{
return _worker->imageDirectory();
}

QString GeoTagController::saveDirectory() const
{
return _worker->saveDirectory();
}

bool GeoTagController::inProgress() const
{
return _workerThread->isRunning();
}

void GeoTagController::setLogFile(const QString &filename)
{
if (filename.isEmpty()) {
_setErrorMessage(tr("Empty Filename."));
return;
}

const QFileInfo logFileInfo = QFileInfo(filename);
if (!logFileInfo.exists() || !logFileInfo.isFile()) {
_setErrorMessage(tr("Invalid Filename."));
return;
}
_errorMessage.clear();
emit errorMessageChanged(_errorMessage);

_worker->setLogFile(filename);
emit logFileChanged(filename);

_setErrorMessage(QString());
}

void GeoTagController::setSaveDirectory(QString dir)
void GeoTagController::setImageDirectory(const QString &dir)
{
dir = QUrl(dir).toLocalFile();
if (!dir.isEmpty()) {
_worker.setSaveDirectory(dir);
emit saveDirectoryChanged(dir);
//-- Check and see if there are images already there
QDir saveDirectory = QDir(_worker.saveDirectory());
saveDirectory.setFilter(QDir::Files | QDir::Readable | QDir::NoSymLinks | QDir::Writable);
QStringList nameFilters;
nameFilters << "*.jpg" << "*.JPG";
saveDirectory.setNameFilters(nameFilters);
QStringList imageList = saveDirectory.entryList();
if(!imageList.isEmpty()) {
_setErrorMessage(tr("The save folder already contains images."));
if (dir.isEmpty()) {
_setErrorMessage(tr("Invalid Directory."));
return;
}

const QFileInfo imageDirectoryInfo = QFileInfo(dir);
if (!imageDirectoryInfo.exists() || !imageDirectoryInfo.isDir()) {
_setErrorMessage(tr("Invalid Directory."));
return;
}

_worker->setImageDirectory(dir);
emit imageDirectoryChanged(dir);

if (_worker->saveDirectory().isEmpty()) {
const QDir saveDirectory = QDir(_worker->imageDirectory() + kTagged);
if (saveDirectory.exists()) {
_setErrorMessage(tr("Images have already been tagged. Existing images will be removed."));
return;
}
}
_errorMessage.clear();
emit errorMessageChanged(_errorMessage);

_setErrorMessage(QString());
}

void GeoTagController::setSaveDirectory(const QString &dir)
{
if (dir.isEmpty()) {
_setErrorMessage(tr("Invalid Directory."));
return;
}

const QFileInfo saveDirectoryInfo = QFileInfo(dir);
if (!saveDirectoryInfo.exists() || !saveDirectoryInfo.isDir()) {
_setErrorMessage(tr("Invalid Directory."));
return;
}

_worker->setSaveDirectory(dir);
emit saveDirectoryChanged(dir);

QDir saveDirectory = QDir(_worker->saveDirectory());
saveDirectory.setFilter(QDir::Files | QDir::Readable | QDir::NoSymLinks | QDir::Writable);

QStringList nameFilters;
nameFilters << "*.jpg" << "*.JPG";
saveDirectory.setNameFilters(nameFilters);

const QStringList imageList = saveDirectory.entryList();
if (!imageList.isEmpty()) {
_setErrorMessage(tr("The save folder already contains images."));
return;
}

_setErrorMessage(QString());
}

void GeoTagController::startTagging()
{
_errorMessage.clear();
emit errorMessageChanged(_errorMessage);
QDir imageDirectory = QDir(_worker.imageDirectory());
if(!imageDirectory.exists()) {
_setErrorMessage(QString());

const QDir imageDirectory = QDir(_worker->imageDirectory());
if (!imageDirectory.exists()) {
_setErrorMessage(tr("Cannot find the image directory."));
return;
}
if(_worker.saveDirectory() == "") {
QDir oldTaggedFolder = QDir(_worker.imageDirectory() + kTagged);
if(oldTaggedFolder.exists()) {

if (_worker->saveDirectory().isEmpty()) {
QDir oldTaggedFolder = QDir(_worker->imageDirectory() + kTagged);
if (oldTaggedFolder.exists()) {
oldTaggedFolder.removeRecursively();
if(!imageDirectory.mkdir(_worker.imageDirectory() + kTagged)) {
if (!imageDirectory.mkdir(_worker->imageDirectory() + kTagged)) {
_setErrorMessage(tr("Couldn't replace the previously tagged images"));
return;
}
}
} else {
QDir saveDirectory = QDir(_worker.saveDirectory());
if(!saveDirectory.exists()) {
const QDir saveDirectory = QDir(_worker->saveDirectory());
if (!saveDirectory.exists()) {
_setErrorMessage(tr("Cannot find the save directory."));
return;
}
}
_worker.start();
}

void GeoTagController::_workerProgressChanged(double progress)
{
_progress = progress;
emit progressChanged(progress);
}

void GeoTagController::_workerError(QString errorMessage)
{
_errorMessage = errorMessage;
emit errorMessageChanged(errorMessage);
}


void GeoTagController::_setErrorMessage(const QString& error)
{
_errorMessage = error;
emit errorMessageChanged(error);
(void) QMetaObject::invokeMethod(_workerThread, "start", Qt::AutoConnection);
}
Loading

0 comments on commit 22d007a

Please sign in to comment.