[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