[kde-doc-english] [digikam] /: apply patch #91806 from Kristian Karl to make an optional rescan of files when files are modified
Maik Qualmann
metzpinguin at gmail.com
Wed Apr 1 17:07:11 UTC 2015
Git commit 937109fb0f32192308258437ccad7f8dac536acd by Maik Qualmann.
Committed on 01/04/2015 at 16:40.
Pushed by mqualmann into branch 'master'.
apply patch #91806 from Kristian Karl to make an optional rescan of files when files are modified
BUGS: 341772
FIXED-IN: 4.9.0
GUI:
M +2 -1 NEWS
M +9 -1 libs/database/collectionscanner.cpp
M +3 -0 libs/dmetadata/metadatasettingscontainer.cpp
M +1 -0 libs/dmetadata/metadatasettingscontainer.h
M +17 -0 tests/CMakeLists.txt
A +232 -0 tests/timestampupdatetest.cpp [License: GPL (v2+)]
A +48 -0 tests/timestampupdatetest.h [License: GPL (v2+)]
A +- -- tests/timestampupdatetestimages/1.jpg
M +19 -7 utilities/setup/setupmetadata.cpp
http://commits.kde.org/digikam/937109fb0f32192308258437ccad7f8dac536acd
diff --git a/NEWS b/NEWS
index 7412009..29de43c 100644
--- a/NEWS
+++ b/NEWS
@@ -33,4 +33,5 @@ BUGFIXES FROM KDE BUGZILLA (https://www.digikam.org/changelog):
025 ==> 338230 - digiKam stops refreshing download progress after de-selecting pictures.
026 ==> 345648 - Progress bar disappeared while importing pictures before importing finished.
027 ==> 340139 - digiKam hangs after selecting folder with pictures.
-028 ==>
+028 ==> 341772 - Re-read metadata when image file timestamp has changed [patch].
+029 ==>
diff --git a/libs/database/collectionscanner.cpp b/libs/database/collectionscanner.cpp
index ce2c923..5122388 100644
--- a/libs/database/collectionscanner.cpp
+++ b/libs/database/collectionscanner.cpp
@@ -65,6 +65,7 @@
#include "imagecopyright.h"
#include "imageinfo.h"
#include "imagescanner.h"
+#include "metadatasettings.h"
#include "tagscache.h"
#include "thumbnaildatabaseaccess.h"
#include "thumbnaildb.h"
@@ -1199,7 +1200,14 @@ void CollectionScanner::scanFileNormal(const QFileInfo& fi, const ItemScanInfo&
if (!modificationDateEquals(fi.lastModified(), scanInfo.modificationDate)
|| fi.size() != scanInfo.fileSize)
{
- scanModifiedFile(fi, scanInfo);
+ if (MetadataSettings::instance()->settings().rescanImageIfModified)
+ {
+ rescanFile(fi, scanInfo);
+ }
+ else
+ {
+ scanModifiedFile(fi, scanInfo);
+ }
}
}
diff --git a/libs/dmetadata/metadatasettingscontainer.cpp b/libs/dmetadata/metadatasettingscontainer.cpp
index 8f18e8a..a39f38b 100644
--- a/libs/dmetadata/metadatasettingscontainer.cpp
+++ b/libs/dmetadata/metadatasettingscontainer.cpp
@@ -50,6 +50,7 @@ MetadataSettingsContainer::MetadataSettingsContainer()
useXMPSidecar4Reading = false;
metadataWritingMode = KExiv2::WRITETOIMAGEONLY;
updateFileTimeStamp = true;
+ rescanImageIfModified = false;
rotationBehavior = RotatingFlags | RotateByLosslessRotation;
}
@@ -73,6 +74,7 @@ void MetadataSettingsContainer::readFromConfig(KConfigGroup& group)
metadataWritingMode = (KExiv2::MetadataWritingMode)
group.readEntry("Metadata Writing Mode", (int)KExiv2::WRITETOIMAGEONLY);
updateFileTimeStamp = group.readEntry("Update File Timestamp", true);
+ rescanImageIfModified = group.readEntry("Rescan File If Modified", false);
rotationBehavior = NoRotation;
@@ -116,6 +118,7 @@ void MetadataSettingsContainer::writeToConfig(KConfigGroup& group) const
group.writeEntry("Use XMP Sidecar For Reading", useXMPSidecar4Reading);
group.writeEntry("Metadata Writing Mode", (int)metadataWritingMode);
group.writeEntry("Update File Timestamp", updateFileTimeStamp);
+ group.writeEntry("Rescan File If Modified", rescanImageIfModified);
group.writeEntry("Rotate By Internal Flag", bool(rotationBehavior & RotateByInternalFlag));
group.writeEntry("Rotate By Metadata Flag", bool(rotationBehavior & RotateByMetadataFlag));
diff --git a/libs/dmetadata/metadatasettingscontainer.h b/libs/dmetadata/metadatasettingscontainer.h
index 38d3053..158b6d7 100644
--- a/libs/dmetadata/metadatasettingscontainer.h
+++ b/libs/dmetadata/metadatasettingscontainer.h
@@ -102,6 +102,7 @@ public:
bool writeRawFiles;
bool updateFileTimeStamp;
+ bool rescanImageIfModified;
bool useXMPSidecar4Reading;
KExiv2::MetadataWritingMode metadataWritingMode;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 271170c..6dd0f56 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -107,6 +107,23 @@ endif()
#------------------------------------------------------------------------
+set(timestampupdate_SRCS
+ timestampupdatetest.cpp
+ )
+
+KDE4_ADD_UNIT_TEST(timestampupdatetest ${timestampupdate_SRCS})
+
+target_link_libraries(timestampupdatetest
+ ${KDE4_KDECORE_LIBS}
+ ${QT_QTGUI_LIBRARY}
+ ${QT_QTTEST_LIBRARY}
+ ${KEXIV2_LIBRARIES}
+ digikamcore
+ digikamdatabase
+ )
+
+#------------------------------------------------------------------------
+
set(statesavingobject_SRCS
statesavingobjecttest.cpp
)
diff --git a/tests/timestampupdatetest.cpp b/tests/timestampupdatetest.cpp
new file mode 100644
index 0000000..95e2ea3
--- /dev/null
+++ b/tests/timestampupdatetest.cpp
@@ -0,0 +1,232 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2015
+ * Description : a test for timestamp trigger for re-reading metadata from image
+ *
+ * Copyright (C) 2015 by Kristian Karl <kristian dot hermann dot karl at gmail dot com>
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ============================================================ */
+
+#include "timestampupdatetest.h"
+
+#include <libkexiv2/kexiv2.h>
+
+#include "albumdb.h"
+#include "collectionlocation.h"
+#include "collectionmanager.h"
+#include "collectionscanner.h"
+#include "imageinfo.h"
+#include "metadatasettings.h"
+
+#include <QtTest>
+#include <QFileInfo>
+#include <QDBusConnection>
+
+#include <kdemacros.h>
+
+const QString originalImageFolder(KDESRCDIR"timestampupdatetestimages");
+const QString originalImageFile(KDESRCDIR"timestampupdatetestimages/1.jpg");
+
+QTEST_MAIN(TimeStampUpdateTest);
+
+using namespace Digikam;
+
+QString TimeStampUpdateTest::tempFileName(const QString& purpose) const
+{
+ return QString("digikamtests-") + metaObject()->className() + '-' + purpose + '-' + QTime::currentTime().toString();
+}
+
+QString TimeStampUpdateTest::tempFilePath(const QString& purpose) const
+{
+ return QDir::tempPath() + '/' + tempFileName(purpose);
+}
+
+/*
+ * Create a nd simulate a new startup of Digikam.
+ * A new temporary database is created.
+ * A collection is added, and scanned.
+ */
+void TimeStampUpdateTest::initTestCase()
+{
+ // Setup the collection folder
+ QDir collectionDir = QDir(originalImageFolder);
+ QVERIFY(collectionDir.exists());
+
+
+ // Create new temporary database
+ dbFile = tempFilePath("database");
+ DatabaseParameters params("QSQLITE", dbFile, "QSQLITE", dbFile);
+ DatabaseAccess::setParameters(params, DatabaseAccess::MainApplication);
+ QVERIFY(DatabaseAccess::checkReadyForUse(0));
+ QVERIFY(QFile(dbFile).exists());
+
+
+ // Add collection and scan
+ CollectionManager::instance()->addLocation(collectionDir.path());
+ CollectionScanner().completeScan();
+
+
+ // Verify that the scanned collection is correct
+ QList<AlbumShortInfo> albums = DatabaseAccess().db()->getAlbumShortInfos();
+ QVERIFY(albums.size() == 1);
+ QStringList readOnlyImages;
+ foreach(const AlbumShortInfo& album, albums)
+ {
+ readOnlyImages << DatabaseAccess().db()->getItemURLsInAlbum(album.id);
+ }
+ foreach(const QString& file, readOnlyImages)
+ {
+ ids << ImageInfo::fromLocalFile(file).id();
+ }
+ QVERIFY(!ids.contains(-1));
+ QVERIFY(ids.size() == 1);
+}
+
+/*
+ * Remove the database file
+ */
+void TimeStampUpdateTest::cleanupTestCase()
+{
+ QFile(dbFile).remove();
+}
+
+/*
+ * Re-set the database and image file to it's original metadata state
+ */
+void TimeStampUpdateTest::cleanup()
+{
+ KExiv2Iface::KExiv2 meta;
+ meta.setMetadataWritingMode(KExiv2Iface::KExiv2::WRITETOIMAGEONLY);
+ meta.setUpdateFileTimeStamp(true);
+ meta.load(originalImageFile);
+ meta.removeExifTag("Exif.Image.Model", false);
+ QVERIFY2(meta.applyChanges(), "Exif.Image.Model is removed");
+ QVERIFY(meta.getExifTagString("Exif.Image.Model").isEmpty());
+
+ CollectionScanner().scanFile(originalImageFile, CollectionScanner::Rescan);
+
+ // Check that Exif.Image.Model in database is empty
+ QVariantList dbModel = DatabaseAccess().db()->getImageMetadata(ids[0], DatabaseFields::Model);
+ QVERIFY2(dbModel.at(0).toString().isEmpty(), "Exif.Image.Model should be empty");
+}
+
+/*
+ * This test manipulates the Exif.Image.Model without updating
+ * the database.
+ * A CollectionScanner().completeScan() is then launched, simulating a
+ * startup of Digikam.
+ * The test verifies that the change in the file is detected and
+ * that new value of Exif.Image.Model is read into the database.
+ */
+void TimeStampUpdateTest::testRescanImageIfModifiedSet2True()
+{
+ // Setup metadata settings
+ MetadataSettingsContainer set;
+ set.updateFileTimeStamp = true; // Deafult value
+ set.rescanImageIfModified = true;
+ MetadataSettings::instance()->setSettings(set);
+
+
+ // Load the test image and verify that it's there
+ QFileInfo originalFileInfo(originalImageFile);
+ QVERIFY(originalFileInfo.isReadable());
+
+
+ // Check that Exif.Image.Model in database is empty
+ QVariantList dbModel = DatabaseAccess().db()->getImageMetadata(ids[0], DatabaseFields::Model);
+ QVERIFY2(dbModel.at(0).toString().isEmpty(), "Exif.Image.Model should be empty");
+
+
+ // Verify that Exif.Image.Model in image file is empty
+ KExiv2Iface::KExiv2 meta;
+ meta.setMetadataWritingMode(KExiv2Iface::KExiv2::WRITETOIMAGEONLY);
+ meta.setUpdateFileTimeStamp(true);
+ meta.load(originalImageFile);
+ QString model = meta.getExifTagString("Exif.Image.Model");
+ QVERIFY(model.isEmpty());
+
+
+ // Change the metadata in image file
+ meta.setExifTagString("Exif.Image.Model", "TimeStampUpdateTestCamera", false);
+ QVERIFY2(meta.applyChanges(), "Exif.Image.Model is added");
+ QVERIFY(meta.getExifTagString("Exif.Image.Model") == "TimeStampUpdateTestCamera");
+
+
+ // Simulate restart of Digikam
+ // The scan should detect that image file has changed
+ CollectionScanner().completeScan();
+
+
+ // Verify that the change is detected, and no exists in the database
+ dbModel = DatabaseAccess().db()->getImageMetadata(ids[0], DatabaseFields::Model);
+ QVERIFY(dbModel.at(0).toString() == "TimeStampUpdateTestCamera");
+}
+
+
+/*
+ * This test manipulates the Exif.Image.Model without updating
+ * the database.
+ * A CollectionScanner().completeScan() is then launched, simulating a
+ * startup of Digikam.
+ * The test verifies that the change in the file is disregarden and
+ * that the value of Exif.Image.Model is unchanged the database.
+ */
+void TimeStampUpdateTest::testRescanImageIfModifiedSet2False()
+{
+ // Setup metadata settings
+ MetadataSettingsContainer set;
+ set.updateFileTimeStamp = true; // Deafult value
+ set.rescanImageIfModified = false; // Deafult value
+ MetadataSettings::instance()->setSettings(set);
+
+
+ // Load the test image and verify that it's there
+ QFileInfo originalFileInfo(originalImageFile);
+ QVERIFY(originalFileInfo.isReadable());
+
+
+ // Check that Exif.Image.Model in database is empty
+ QVariantList dbModel = DatabaseAccess().db()->getImageMetadata(ids[0], DatabaseFields::Model);
+ QVERIFY2(dbModel.at(0).toString().isEmpty(), "Exif.Image.Model should be empty");
+
+
+ // Verify that Exif.Image.Model in image file is empty
+ KExiv2Iface::KExiv2 meta;
+ meta.setMetadataWritingMode(KExiv2Iface::KExiv2::WRITETOIMAGEONLY);
+ meta.setUpdateFileTimeStamp(true);
+ meta.load(originalImageFile);
+ QString model = meta.getExifTagString("Exif.Image.Model");
+ QVERIFY(model.isEmpty());
+
+
+ // Change the metadata in image file
+ meta.setExifTagString("Exif.Image.Model", "TimeStampUpdateTestCamera", false);
+ QVERIFY2(meta.applyChanges(), "Exif.Image.Model is added");
+ QVERIFY(meta.getExifTagString("Exif.Image.Model") == "TimeStampUpdateTestCamera");
+
+
+ // Simulate restart of Digikam
+ // The scan should detect that image file has changed
+ CollectionScanner().completeScan();
+
+
+ // Verify that the changed image did not change the database
+ dbModel = DatabaseAccess().db()->getImageMetadata(ids[0], DatabaseFields::Model);
+ QVERIFY(dbModel.at(0).toString().isEmpty());
+}
+
+#include "timestampupdatetest.moc"
diff --git a/tests/timestampupdatetest.h b/tests/timestampupdatetest.h
new file mode 100644
index 0000000..79927fd
--- /dev/null
+++ b/tests/timestampupdatetest.h
@@ -0,0 +1,48 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2015
+ * Description : a test for timestamp trigger for re-reading metadata from image
+ *
+ * Copyright (C) 2015 by Kristian Karl <kristian dot hermann dot karl at gmail dot com>
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ============================================================ */
+
+#ifndef TIMESTAMPUPDATETEST_H
+#define TIMESTAMPUPDATETEST_H
+
+#include <QtTest/QtTest>
+
+class TimeStampUpdateTest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void cleanup();
+ void testRescanImageIfModifiedSet2True();
+ void testRescanImageIfModifiedSet2False();
+
+private:
+ QString tempFileName(const QString& purpose) const;
+ QString tempFilePath(const QString& purpose) const;
+
+ QString dbFile;
+ QList<qlonglong> ids;
+};
+
+#endif // TIMESTAMPUPDATETEST_H
diff --git a/tests/timestampupdatetestimages/1.jpg b/tests/timestampupdatetestimages/1.jpg
new file mode 100644
index 0000000..3b376ce
Binary files /dev/null and b/tests/timestampupdatetestimages/1.jpg differ
diff --git a/utilities/setup/setupmetadata.cpp b/utilities/setup/setupmetadata.cpp
index 984128f..bfdac00 100644
--- a/utilities/setup/setupmetadata.cpp
+++ b/utilities/setup/setupmetadata.cpp
@@ -95,6 +95,7 @@ public:
writeXMPSidecarBox(0),
readXMPSidecarBox(0),
updateFileTimeStampBox(0),
+ rescanImageIfModifiedBox(0),
writingModeCombo(0),
rotateByFlag(0),
rotateByContents(0),
@@ -132,6 +133,7 @@ public:
QCheckBox* writeXMPSidecarBox;
QCheckBox* readXMPSidecarBox;
QCheckBox* updateFileTimeStampBox;
+ QCheckBox* rescanImageIfModifiedBox;
KComboBox* writingModeCombo;
QRadioButton* rotateByFlag;
@@ -279,13 +281,21 @@ SetupMetadata::SetupMetadata(QWidget* const parent)
"Note: disabling this option can introduce some dysfunctions with applications which use file timestamps properties to "
"detect file modifications automatically."));
- readWriteLayout->addWidget(readWriteIconLabel, 0, 0);
- readWriteLayout->addWidget(readWriteLabel, 0, 1);
- readWriteLayout->addWidget(d->readXMPSidecarBox, 1, 0, 1, 3);
- readWriteLayout->addWidget(d->writeXMPSidecarBox, 2, 0, 1, 3);
- readWriteLayout->addWidget(d->writingModeCombo, 3, 1, 1, 2);
- readWriteLayout->addWidget(d->writeRawFilesBox, 4, 0, 1, 3);
- readWriteLayout->addWidget(d->updateFileTimeStampBox, 5, 0, 1, 3);
+ d->rescanImageIfModifiedBox = new QCheckBox;
+ d->rescanImageIfModifiedBox->setText(i18nc("@option:check", "&Rescan file when files are modified"));
+ d->rescanImageIfModifiedBox->setWhatsThis(i18nc("@info:whatsthis",
+ "Turning this option on, will force Digikam to rescan files that has been modified outside Digikam. "
+ "If a file has changed it's file size or if the last modified timestamp has changed, a rescan of that"
+ "file will be performed when Digikam starts."));
+
+ readWriteLayout->addWidget(readWriteIconLabel, 0, 0);
+ readWriteLayout->addWidget(readWriteLabel, 0, 1);
+ readWriteLayout->addWidget(d->readXMPSidecarBox, 1, 0, 1, 3);
+ readWriteLayout->addWidget(d->writeXMPSidecarBox, 2, 0, 1, 3);
+ readWriteLayout->addWidget(d->writingModeCombo, 3, 1, 1, 2);
+ readWriteLayout->addWidget(d->writeRawFilesBox, 4, 0, 1, 3);
+ readWriteLayout->addWidget(d->updateFileTimeStampBox, 5, 0, 1, 3);
+ readWriteLayout->addWidget(d->rescanImageIfModifiedBox, 6, 0, 1, 3);
readWriteLayout->setColumnStretch(3, 1);
d->readWriteGroup->setLayout(readWriteLayout);
@@ -616,6 +626,7 @@ void SetupMetadata::applySettings()
}
set.updateFileTimeStamp = d->updateFileTimeStampBox->isChecked();
+ set.rescanImageIfModified = d->rescanImageIfModifiedBox->isChecked();
mSettings->setSettings(set);
@@ -676,6 +687,7 @@ void SetupMetadata::readSettings()
d->writeRawFilesBox->setChecked(set.writeRawFiles);
d->readXMPSidecarBox->setChecked(set.useXMPSidecar4Reading);
d->updateFileTimeStampBox->setChecked(set.updateFileTimeStamp);
+ d->rescanImageIfModifiedBox->setChecked(set.rescanImageIfModified);
if (set.metadataWritingMode == KExiv2::WRITETOIMAGEONLY)
{
More information about the kde-doc-english
mailing list